Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:42.3
gnome-shell
SLEClassicExt.js
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File SLEClassicExt.js of Package gnome-shell
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // // // Extra features needed by SLE Classic mode. A lot of features here are // designed as modular functions or classes, so it's cumbersome to fit in a // patch. However, most functionality requires a patch to the GNOME Shell core // to work. A design principle is to keep this adapter patch as small and clear as possible. // // NOTE This file should be packed into GNOME Shell GResource files, with inner // path "%{_datadir}/gnome-shell/js/ui/" and used by "imports.ui.SLEClassicExt". // // [5-5] Major Update: SLE Classic is no longer a full-fledged GNOME session, // instead it's a runtime modified GNOME Classic. const Clutter = imports.gi.Clutter; const GLib = imports.gi.GLib; const Gtk = imports.gi.Gtk; const Gio = imports.gi.Gio; const Lang = imports.lang; const Shell = imports.gi.Shell; const Signals = imports.signals; const St = imports.gi.St; const Atk = imports.gi.Atk; const BoxPointer = imports.ui.boxpointer; const GrabHelper = imports.ui.grabHelper; const Main = imports.ui.main; const Params = imports.misc.params; const Separator = imports.ui.separator; const Slider = imports.ui.slider; const Tweener = imports.ui.tweener; const GNOME_CLASSIC_SESSION_NAME = "classic"; // NOTE About `global.session_mode`, which maps // normal GNOME session -> "user" // GNOME classic -> "classic" (i.e. the "gnome-" prefix is stripped) // SLE classic -> "sle-classic" (depreciated) // // This var is defined in the C code and some parts of the Shell use it instead // of `Main.sessionMode.currentMode`, notably `exensionSystem`. An important // difference is that `global.session_mode` is initialized much earlier than // `currentMode` and it does NOT reflect in-Session mode change, e.g. the // lock/unlock screen. // NOTE a dedicated env var to mark this classic mode a SLE classic, see // sle-classic.desktop. var isSLEClassicEnv = ( GLib.getenv('SLE_CLASSIC_MODE') !== null ); // NOTE: A mode can be verified as SLE classic iff it's GNOME Classic and it has // SLE_CLASSIC_MODE envar set. function isSLEClassicMode() { // NOTE: must check this part so lock screen is not SLE Classic. if ( Main.sessionMode.currentMode !== GNOME_CLASSIC_SESSION_NAME ) return false; return isSLEClassicEnv; } // NOTE: safe to use BEFORE `sessionMode` has been properly initialized function isSLEClassicModeGlobal () { if ( global.session_mode !== GNOME_CLASSIC_SESSION_NAME ) return false; return isSLEClassicEnv; } // NOTE: Originally "sle-classic.json" under "gnome-shell/modes" dir. // // TODO: strip down to differences with "classic.json" var SLE_CLASSIC_JSON = { "parentMode": "user", "stylesheetName": "gnome-classic.css", "enabledExtensions": [ "apps-menu@gnome-shell-extensions.gcampax.github.com", "places-menu@gnome-shell-extensions.gcampax.github.com", "alternate-tab@gnome-shell-extensions.gcampax.github.com", "launch-new-instance@gnome-shell-extensions.gcampax.github.com", "window-list@gnome-shell-extensions.gcampax.github.com", "workspace-indicator@gnome-shell-extensions.gcampax.github.com" ], "panel": { "left": ["activities"], "center": [], "right": ["a11y", "keyboard", "dateMenu", "aggregateMenu"] } }; // NOTE: used in "sessionMode.js::_loadMode" // // If the current mode is SLE Classic, return `SLE_CLASSIC_JSON`. O/w no // changes. function convertClassic2SLE(json) { // NOTE: `Main.sessionMode` have not initialized. if ( ! isSLEClassicModeGlobal() ) return json; return SLE_CLASSIC_JSON; } // NOTE: used in `SLEClassicExt.init` // // NOTE: it's mandatory to disable app menu in SLE Classic but restore the old // settings after switching back. A more proper solution would be to introduce a // dconf overrides key AND change the GSD part to read the overriden value. Too // much work, keep it a hack for now. function toggleAppMenu() { let xsetting = new Gio.Settings({ schema: 'org.gnome.settings-daemon.plugins.xsettings' }); let valueObj = xsetting.get_value('overrides').unpack(); // NOTE: as dictated by the definitions in gschema, the values for the // following flags can NOT be booleans, but instead 0 or 1. // NOTE: special handling, as if `Gtk/ShellShowsAppMenu` is NOT set, it's // treated as true by XSettings const showAppMenuKey = 'Gtk/ShellShowsAppMenu'; const showAppMenuSLESetKey = 'Gtk/ShellShowsAppMenu/SLESet'; // NOTE double `unpack` is needed as 'a{sv}' construction would wrap the value // in an extra Variant container. let showAppMenuP = valueObj[showAppMenuKey] ? valueObj[showAppMenuKey].unpack().unpack() : 1; let showAppMenuSLESet = valueObj[showAppMenuSLESetKey] ? valueObj[showAppMenuSLESetKey].unpack().unpack() : 0; // NOTE extra check to make sure `showAppMenuP` and `showAppMenuSLESet` are // numbers. ('v' can be many other types and it's possible the user sets so) // The fallback value is the same as above defaults. if (typeof showAppMenuP !== 'number') { showAppMenuP = 1; } if (typeof showAppMenuSLESet !== 'number') { showAppMenuSLESet = 0; } // NOTE: In SLE Classic mode, if app menu is set to shown, hide it and set a // special flag to mark this change for restoring. if (isSLEClassicModeGlobal() && showAppMenuP) { showAppMenuP = 0; showAppMenuSLESet = 1; } // NOTE: in none-SLE Classic mode, if app menu is hidden AND `SLESet` flag // is set, show the app menu and reset the `SLESet` flag. if ( !isSLEClassicModeGlobal() && showAppMenuSLESet) { showAppMenuP = 1; showAppMenuSLESet = 0; } valueObj[showAppMenuKey] = GLib.Variant.new('i', showAppMenuP); valueObj[showAppMenuSLESetKey] = GLib.Variant.new('i', showAppMenuSLESet); xsetting.set_value('overrides', GLib.Variant.new('a{sv}', valueObj)); } // NOTE: used in `main.js::start` function init() { toggleAppMenu(); } var panelPosUpdateId = null; // layout.js: Replace the origin "box.set_position" call function setMainPanelPosition (mainPanel, primaryMonitor) { if ( isSLEClassicMode() ){ // FIXME: "mainPanel.height" may be uninitialized at this point: fixed to // a known value for now. let mainPanelHeight = 28; // Main Panel at the bottom mainPanel.set_position(primaryMonitor.x, primaryMonitor.y + primaryMonitor.height - mainPanelHeight); // NOTE: needed s.t. lock screen would have top panel // // TODO use the `updated` signal to change main panel to remove the patch? if ( !panelPosUpdateId ){ panelPosUpdateId = Main.sessionMode.connect('updated', function(){ setMainPanelPosition(Main.layoutManager.panelBox, Main.layoutManager.primaryMonitor); }); } } else { mainPanel.set_position(primaryMonitor.x, primaryMonitor.y); } } // panel.js: Replace the original "Panel._allocate". // // The differences are quite subtle but yet pervasive, so despite the // similarity, there will be two versions of allocation functions. // // The main difference is to use the empty(in Classic) _centerBox for window // list. // // NOTE: has to be a *direct* replacement to have proper `this` setup function _allocate (actor, box, flags) { // NOTE: for convenience, the followings are shared. The params of this // function is also shared. let allocWidth = box.x2 - box.x1; let allocHeight = box.y2 - box.y1; let [leftMinWidth, leftNaturalWidth] = this._leftBox.get_preferred_width(-1); let [centerMinWidth, centerNaturalWidth] = this._centerBox.get_preferred_width(-1); let [rightMinWidth, rightNaturalWidth] = this._rightBox.get_preferred_width(-1); // bind sub function's `this` to the current `this`, i.e. Main.panel let allocateSC = _allocateSC.bind(this); // For convenience, defined here to allow access to local vars function _allocateSC () { let isTextDirRTL = ( this.actor.get_text_direction() === Clutter.TextDirection.RTL ); // A mask to create allocation. let maskBox = new Clutter.ActorBox(); // NOTE: policy here is to satisfy left&right boxes space needs first with // center box can be shrinked. (This is the opposite of the original // allocator, this idea here is to accomodate SLE-Classic window list within // center box first. ) let maxSideWidth = Math.floor( (allocWidth - centerMinWidth) / 2 ); let leftWidth = Math.min(maxSideWidth, leftNaturalWidth); let rightWidth = Math.min(maxSideWidth, rightNaturalWidth); // NOTE: in the case, flooring for maxSideWidth does happen, the following equation yields: // : centerWidth = centerMinWidth + 1 // this avoids the cumbersome floor/ceil in orginal code. // // `centerWidth` is shrinkable with an lower bound `centerMinWidth` or `centerMinWidth + 1` let centerWidth = allocWidth - leftWidth - rightWidth; // Adjust left/center/right boxes start Y position // // After moving the panel to the bottom side, the top border will be // added instead of the bottom border. However all 3 box of the main // panel are absolutely positioned starting from the top edge of the // panel originally, this results that the bottom pixel line is not // clickable. Add a Y offset to fix it. // // NOTE: we can set y1 as (MainLayoutManager.primaryMonitor.height - // allocHeight), which seems to be easier, however the solution below is // more generic and versatile. let node = Main.panel.actor.get_theme_node(); let borderTopWidth = node.get_length("border-top"); let y_offset = borderTopWidth; maskBox.y1 = y_offset; // TODO: in previous version of SLE Classic the following is // `allocHeight + y_offset`, why? maskBox.y2 = allocHeight; // Normal order, from left to right if ( ! isTextDirRTL ) { maskBox.x1 = 0; maskBox.x2 = maskBox.x1 + leftWidth; this._leftBox.allocate(maskBox, flags); maskBox.x1 = maskBox.x2; maskBox.x2 = maskBox.x1 + centerWidth; this._centerBox.allocate(maskBox, flags); maskBox.x1 = maskBox.x2; maskBox.x2 = maskBox.x1 + rightWidth; this._rightBox.allocate(maskBox, flags); } // Right to Left: essentially right box left box are swapped else { maskBox.x2 = allocWidth; maskBox.x1 = maskBox.x2 - leftWidth; this._leftBox.allocate(maskBox, flags); maskBox.x2 = maskBox.x1; maskBox.x1 = maskBox.x2 - centerWidth; this._centerBox.allocate(maskBox, flags) maskBox.x2 = maskBox.x1; maskBox.x1 = maskBox.x2 - rightWidth; this._rightBox.allocate(maskBox, flags) } } // Real work... if (isSLEClassicMode()) { // SC: Sle Classic allocateSC(); } else { this._allocateOrigin(actor, box, flags); } // TODO: what are these corners for? They are zero on my test machines. // Without proper understanding of their purposes, they are the same for // both original code and SLE Classic. let cornerMinWidth, cornerMinHeight; let cornerWidth, cornerHeight; let childBox = new Clutter.ActorBox(); [cornerMinWidth, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1); [cornerMinHeight, cornerHeight] = this._leftCorner.actor.get_preferred_height(-1); childBox.x1 = 0; childBox.x2 = cornerWidth; childBox.y1 = allocHeight; childBox.y2 = allocHeight + cornerHeight; this._leftCorner.actor.allocate(childBox, flags); [cornerMinWidth, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1); [cornerMinHeight, cornerHeight] = this._rightCorner.actor.get_preferred_height(-1); childBox.x1 = allocWidth - cornerWidth; childBox.x2 = allocWidth; childBox.y1 = allocHeight; childBox.y2 = allocHeight + cornerHeight; this._rightCorner.actor.allocate(childBox, flags); }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor