...
 
Commits (29)
  • Georges Basile Stavracas Neto's avatar
    panel: Stop using Shell.GenericContainer · 286ffbe2
    Georges Basile Stavracas Neto authored
    Shell.GenericContainer exposes the size negotiation machinery
    through the use of signals. Signals are not specially performant.
    One of the reasons is that they acquire a global lock for signal
    handlers lookup. GNOME Shell has more than 2,000 actors at any
    given point in time, up to 20 levels deep in hierarchy, making
    size negotiation and painting non-trivial tasks. Such a critical
    section of Clutter's machinery shouldn't rely on signals
    whatsoever.
    
    Regardless of that, Shell.GenericContainer is a workaround to
    a non-existing issue anymore. It shouldn't be used anyway, and
    any performance improvements that removing it can potentially
    yield are bonuses to it.
    
    This commit starts this work by removing Shell.GenericContainer
    usage from Panel.Panel class. The class now extends St.Widget,
    and as such, it has no "this.actor" field set anymore. A couple
    of places where this actor field was used are adjuste as well.
    
    It is important to notice that we now allocate the Panel itself
    inside vfunc_allocate(). This was previously done before emitting
    the signal by Shell.GenericContainer.
    
    !153
    286ffbe2
  • Georges Basile Stavracas Neto's avatar
    switcherPopup: Rename destroy() to fadeAndDestroy() · e82c68ac
    Georges Basile Stavracas Neto authored
    In the process of purging all usages of Shell.GenericContainer
    of GNOME Shell, one specific problematic situation that might
    occur is when classes have functions that would clash with any
    ClutterActor or StWidget function name.
    
    One of such example is SwitcherPopup.destroy(). Right now, this
    class is a pure JavaScript class that wraps a real actor, but
    soon this will change, and it'll become a St.Widget subclass.
    
    Another problem with functions that mimic the toolkit ones is
    the predictability of them; after calling destroy(), that widget
    is expected to not be available anymore. In SwitcherPopup case,
    it is still available for a short while. In this case, that's not
    a big problem, but the show() and hide() functions in other clases
    are more problematic because the actor's visibility does not
    follow that.
    
    This commit is a first step in cleaning that up, and changes the
    SwitcherPopup.destroy() to fadeAndDestroy().
    
    !153
    e82c68ac
  • Georges Basile Stavracas Neto's avatar
    switcherPopup: Subclass St.Widget · a315e75e
    Georges Basile Stavracas Neto authored
    This commit turns SwitcherPopup.SwitcherPopup into a St.Widget
    subclass, and gets rid of Shell.GenericContainer usage. Subclasses
    were adapted to that too.
    
    This class introduced a new challenge: it overrides show(). As per
    discussions, we now call this.visible = true inside show().
    
    !153
    a315e75e
  • Georges Basile Stavracas Neto's avatar
    switcherPopup: Use MonitorConstraint instead of vfunc overrides · 0ec36fc5
    Georges Basile Stavracas Neto authored
    Instead of overriding vfunc_get_preferred_width|height(), use the
    already available Layout.MonitorConstraint to bind SwitcherPopup
    to the primary monitor.
    0ec36fc5
  • Georges Basile Stavracas Neto's avatar
    switcherList: Remove unused variable · 9a47b4b3
    Georges Basile Stavracas Neto authored
    The title is self-explanatory, 'primary' was not being used
    anywhere.
    
    !153
    9a47b4b3
  • Georges Basile Stavracas Neto's avatar
    switcherList: Stop using Shell.GenericContainer · c6cea277
    Georges Basile Stavracas Neto authored
    This commit removes all the uses of Shell.GenericContainer from
    SwitcherPopup.SwitcherList. Compared to the other patches, this
    one was specially trickier to get right, and a few invasive
    changes needed to be done.
    
    The most noticeable one is that the allocation of the items is
    done entirely by St.BoxLayout -- we don't manually allocate them
    anymore. To make it work, get_preferred_width() had to calculate
    the correct value. It now assumes that:
    
     * Minimum width: the minimum width of the widest child.
     * Natural width: the minimum width of the StBoxLayout (use it
       instead of the natural width to force the labels to ellipsize
       when too long.)
    
    The AppIcon class became a St.Widget subclass as well, to override
    get_preferred_width() and be able to keep the squared shape.
    
    Besides that, add a new SwitcherButton class to reimplement squared
    icons without having to resort to hacks in the size allocation
    machinery. This class has a single vfunc override to ensure that it
    is squared when the SwitcherList is.
    
    The arrows indicating multiple windows are now in this._list
    actor to the SwitcherPopup itself, since this._list automatically
    manages its own children now.
    
    At last, adapt (but preserve) the hack in CyclerPopup.
    
    !153
    c6cea277
  • Georges Basile Stavracas Neto's avatar
    st-box-layout: Pass correct allocation box to layout manager · 2717ca9d
    Georges Basile Stavracas Neto authored
    StBoxLayout implements StScrollable, which, semantically, means that
    the StBoxLayout size may not match the minimum size reported by the
    layout manager. In this specific case, the layout manager by is a
    ClutterBoxLayout by default. For example:
    
            +--------------+
            |   Viewport   |
     +------+--------------+-----------------+
     |      |              |                 |
     |      |              |     Content     |
     |      |              |                 |
     +------+--------------+-----------------+
            |              |
            +--------------+
    
    So, assuming that:
    
     - ContentSize = the minimum size of the content;
     - ViewportSize = the allocated size of the viewport;
    
    When allocating StBoxLayout, it must assume ViewportSize, but must
    pass ContentSize to the layout manager. That way, the children of
    StBoxLayout are correctly placed within it, even if it's bigger than
    ViewportSize.
    
    And here's the problem: right now, StBoxLayout assumes ViewportSize
    AND also passes it to layout manager. Commit 77c4c6b6 specifically
    exposed this bug by relying entirely on StBoxLayout to arrange the
    app and window icons.
    
    Fix that by using ViewportSize to allocate StBoxLayout itself, but
    passing ContentSize to the layout manager.
    
    !153
    2717ca9d
  • Georges Basile Stavracas Neto's avatar
    windowIcon: Subclass St.BoxLayout · 4be66ecf
    Georges Basile Stavracas Neto authored
    Following the previous work, turn WindowIcon into a
    St.BoxLayout subclass, and remove the this.actor
    field from it.
    4be66ecf
  • Georges Basile Stavracas Neto's avatar
    baseIcon: Stop using Shell.GenericContainer · 81ec8215
    Georges Basile Stavracas Neto authored
    Pretty much like the previous patches, this extends St.Bin. The
    most interesting aspect of this patch is that most of the sizing
    routines of the icons is now delegated to the actors and layout
    managers, removing quite a bunch of code.
    
    The 'spacing' theme property is now redirected to StBoxLayout's
    spacing property. Also adjust the Dash code to stop forcing a
    potentially invalid width in the first icon too.
    
    !153
    81ec8215
  • Georges Basile Stavracas Neto's avatar
    dash: Set scale and opacity on parent actor · efb3025d
    Georges Basile Stavracas Neto authored
    DashItemContainer currently animates the scale and opacity
    of its child when zooming in. This is visible when adding
    a new favorite item to the dash; the items will zoom in from
    the center.
    
    After the previous commit, however, the zoom animation got
    slightly broken, and looked like the icon was coming from
    the bottom instead of the center.
    
    Fix that by setting the scale and opacity of DashItemContainer
    itself, instead of its child. Remove the unused code after that
    too.
    
    !153
    efb3025d
  • Georges Basile Stavracas Neto's avatar
    iconGrid: Rename ::key-focus-in signal · 034a7236
    Georges Basile Stavracas Neto authored
    As part of our quest to obsolete Shell.GenericContainer, IconGrid will
    become a Clutter.Actor subclass. As the ::key-focus-in signal would
    clash with Clutter.Actor::key-focus-in, rename it to ::child-focused.
    
    !153
    034a7236
  • Georges Basile Stavracas Neto's avatar
    iconGrid: Stop using Shell.GenericContainer · 197c0eee
    Georges Basile Stavracas Neto authored
    Removing Shell.GenericContainer from the IconGrid class was
    challenging because it needs the "skip paint" API from it.
    This API was added, too, as a workaround to the inability
    to override vfuncs from GJS.
    
    The overrides are largely copy-pasted and translated versions
    of the Shell.GenericContainer code.
    
    The IconGrid:key-focus-in signal was renamed to :child-focused
    to avoid clashing with ClutterActor:key-focus-in.
    
    In GridSearchResults, the internal IconGrid had it's y_expand
    set to false, so it doesn't push other search elements (the
    list results mainly) to the bottom of the screen.
    
    Because skip paint wasn't and still isn't a GObject property,
    rename it to _skipPaint to reflect that.
    
    !153
    197c0eee
  • Georges Basile Stavracas Neto's avatar
    thumbnailBox: Stop using Shell.GenericContainer · e9f4f2e8
    Georges Basile Stavracas Neto authored
    This is another straight port from Shell.GenericContainer.
    The important thing to notice is that the calculation is
    broken if the StThemeNode helpers (adjust_preferred_* and
    adjust_for_*) aren't used.
    
    The downside of this patch is that it removed the skip_paint
    from the thumbnails. Keeping it would add an unecessarily
    large amount of code.
    
    !153
    e9f4f2e8
  • Georges Basile Stavracas Neto's avatar
    appMenuButton: Rename show/hide to fadeIn/fadeOut · dd4709bb
    Georges Basile Stavracas Neto authored
    In the next commit, we will turn PanelMenu.ButtonBox into a
    St.Widget subclass. As a domino effect, PanelMenu.Button will
    become one too, and so will Panel.AppMenuButton.
    
    When that happens, the current show() and hide() functions in
    Panel.AppMenuButton will clash with Clutter.Actor's ones.
    
    To avoid that, rename these functions to fadeIn() and fadeOut()
    and avoid a name clash.
    
    !153
    dd4709bb
  • Georges Basile Stavracas Neto's avatar
    buttonBox: Drop Shell.GenericContainer usage · fc342fe8
    Georges Basile Stavracas Neto authored
    Another easy port.
    
    !153
    fc342fe8
  • Georges Basile Stavracas Neto's avatar
    messageTray: Drop Shell.GenericContainer usage · ac314cfb
    Georges Basile Stavracas Neto authored
    Nothing particularly outstanding with this class - it was
    a straightforward removal and subclassing.
    
    !153
    ac314cfb
  • Georges Basile Stavracas Neto's avatar
    workspaceSwitcherPopup: Stop using Shell.GenericContainer · b058e891
    Georges Basile Stavracas Neto authored
    Removing Shell.GenericContainer here was slightly trickier
    because it required factoring out a new JavaScript class.
    
    It's nevertheless a straightforward removal.
    
    !153
    b058e891
  • Georges Basile Stavracas Neto's avatar
    layoutManager: Stop using Shell.GenericContainer · f4682748
    Georges Basile Stavracas Neto authored
    This one was remarkably easy to port. In order to make it,
    replace the Shell.GenericContainer handlers by a constraint
    and simply replace it by a St.Widget.
    
    !153
    f4682748
  • Georges Basile Stavracas Neto's avatar
    layoutManager: Subclass GObject.Object · dd225713
    Georges Basile Stavracas Neto authored
    LayoutManager is currently a pure JavaScript class that
    relies on the rudimentary Signals.addSignalMethods() to
    handle signals. This is an inefficient implementation of
    one of the most central classes in GNOME Shell.
    
    In addition to removing Shell.GenericContainer, then,
    turn LayoutManager into a proper GObject.Object subclass.
    
    !153
    dd225713
  • Georges Basile Stavracas Neto's avatar
    loginDialog: Stop using Shell.GenericContainer · 0c0d76f7
    Georges Basile Stavracas Neto authored
    Removing the Shell.GenericContainer from the login dialog
    was remarkably easier, since it only overrides 'allocate'.
    
    !153
    0c0d76f7
  • Georges Basile Stavracas Neto's avatar
    boxPointer: Rename show/hide to open/close · 8b215b24
    Georges Basile Stavracas Neto authored
    Pretty much like dd4709bb, BoxPointer's show() and hide()
    functions will clash with Clutter.Actor's ones.
    
    In addition to that, on a conceptual level, the current API
    is not great, because calling boxPointer.hide() won't result
    in boxPointer.actor.visible == false.
    
    For these reasons, rename show() and hide() to open() and
    close(). A compatibility layer will be added in a following
    commit, warning about the usage of show() and hide().
    
    !153
    8b215b24
  • Georges Basile Stavracas Neto's avatar
    boxPointer: Add compatibility API · f460f274
    Georges Basile Stavracas Neto authored
    Because we're late in the cycle, and don't know how many
    extensions actually rely on this API, this commit adds
    back the BoxPointer.show() and .hide() functions, with
    warning messages to notify consumers that this is going
    to be removed.
    
    !153
    f460f274
  • Georges Basile Stavracas Neto's avatar
    boxPointer: Stop using Shell.GenericContainer · 3fa19e58
    Georges Basile Stavracas Neto authored
    An easy removal too.
    
    !153
    3fa19e58
  • Georges Basile Stavracas Neto's avatar
    inspector: Stop using Shell.GenericContainer · b4c67490
    Georges Basile Stavracas Neto authored
    No alarms and no surprises here.
    
    !153
    b4c67490
  • Georges Basile Stavracas Neto's avatar
    tests: Stop using Shell.GenericContainer · 2ee321e0
    Georges Basile Stavracas Neto authored
    The test doesn't look and behave like before, but they are
    already broken in master anyway. This commit makes it work
    without Shell.GenericContainer, but the test itself remains
    to be fixed.
    
    !153
    2ee321e0
  • Georges Basile Stavracas Neto's avatar
    keyboard: Stop using Shell.GenericContainer · 038f8b6e
    Georges Basile Stavracas Neto authored
    This is the last remaining usage of Shell.GenericContainer
    in the codebase, and posed small challenges compared to the
    other removals.
    
    A new St.Widget subclass called InputSourceIndicatorContainer
    was added as a replacement to the Shell.GenericContainer. It
    was needed because GNOME Shell needs to override the regular
    size allocation functions, but InputSourceIndicator already
    is a St.Widget with its own size allocation overrides.
    
    !153
    038f8b6e
  • Georges Basile Stavracas Neto's avatar
    st-bin: Destroy child in ClutterActor:destroy vfunc · b719744e
    Georges Basile Stavracas Neto authored
    According to Clutter documentation, "[…] actors implementing the
    ClutterContainer interface should override the default implementation
    of the class handler of this signal and call clutter_actor_destroy()
    on their  children."
    
    StBin was doing that in GObject:dispose() instead. Move the child
    destruction to a new ClutterActor:destroy() vfunc override.
    b719744e
  • Georges Basile Stavracas Neto's avatar
    panel: Delegate container destruction to PanelMenu.ButtonBox · 557b232c
    Georges Basile Stavracas Neto authored
    Instead of taking care of the PanelMenu.ButtonBox.container
    destruction by itself, delegate that to the very object that
    created it in the first place: PanelMenu.ButtonBox itself.
    557b232c
  • Georges Basile Stavracas Neto's avatar
    dash: expand and center align DashItemContainer · 38c1ebba
    Georges Basile Stavracas Neto authored
    This is necessary to keep the small actor that shows up
    during drag motion center aligned.
    38c1ebba
......@@ -408,16 +408,18 @@ Signals.addSignalMethods(SessionMenuButton.prototype);
var LoginDialog = new Lang.Class({
Name: 'LoginDialog',
Extends: St.Widget,
Signals: { 'failed': {} },
_init(parentActor) {
this.actor = new Shell.GenericContainer({ style_class: 'login-dialog',
visible: false });
this.actor.get_accessible().set_role(Atk.Role.WINDOW);
this.parent({ style_class: 'login-dialog',
visible: false });
this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
this.actor.connect('allocate', this._onAllocate.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
parentActor.add_child(this.actor);
this.get_accessible().set_role(Atk.Role.WINDOW);
this.add_constraint(new Layout.MonitorConstraint({ primary: true }));
this.connect('destroy', this._onDestroy.bind(this));
parentActor.add_child(this);
this._userManager = AccountsService.UserManager.get_default()
this._gdmClient = new Gdm.Client();
......@@ -442,7 +444,7 @@ var LoginDialog = new Lang.Class({
y_align: Clutter.ActorAlign.CENTER,
vertical: true,
visible: false });
this.actor.add_child(this._userSelectionBox);
this.add_child(this._userSelectionBox);
this._userList = new UserList();
this._userSelectionBox.add(this._userList.actor,
......@@ -454,7 +456,7 @@ var LoginDialog = new Lang.Class({
this._authPrompt.connect('prompted', this._onPrompted.bind(this));
this._authPrompt.connect('reset', this._onReset.bind(this));
this._authPrompt.hide();
this.actor.add_child(this._authPrompt.actor);
this.add_child(this._authPrompt.actor);
// translators: this message is shown below the user list on the
// login screen. It can be activated to reveal an entry for
......@@ -482,7 +484,7 @@ var LoginDialog = new Lang.Class({
opacity: 0,
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
hscrollbar_policy: Gtk.PolicyType.NEVER });
this.actor.add_child(this._bannerView);
this.add_child(this._bannerView);
let bannerBox = new St.BoxLayout({ vertical: true });
......@@ -497,7 +499,7 @@ var LoginDialog = new Lang.Class({
this._logoBin = new St.Widget({ style_class: 'login-dialog-logo-bin',
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.END });
this.actor.add_child(this._logoBin);
this.add_child(this._logoBin);
this._updateLogo();
this._userList.connect('activate', (userList, item) => {
......@@ -576,7 +578,12 @@ var LoginDialog = new Lang.Class({
return actorBox;
},
_onAllocate(actor, dialogBox, flags) {
vfunc_allocate(dialogBox, flags) {
this.set_allocation(dialogBox, flags);
let themeNode = this.get_theme_node();
dialogBox = themeNode.get_content_box(dialogBox);
let dialogWidth = dialogBox.x2 - dialogBox.x1;
let dialogHeight = dialogBox.y2 - dialogBox.y1;
......@@ -919,10 +926,10 @@ var LoginDialog = new Lang.Class({
},
_loginScreenSessionActivated() {
if (this.actor.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
return;
Tweener.addTween(this.actor,
Tweener.addTween(this,
{ opacity: 255,
time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
......@@ -931,7 +938,7 @@ var LoginDialog = new Lang.Class({
for (let i = 0; i < children.length; i++) {
if (children[i] != Main.layoutManager.screenShieldGroup)
children[i].opacity = this.actor.opacity;
children[i].opacity = this.opacity;
}
},
onUpdateScope: this,
......@@ -952,7 +959,7 @@ var LoginDialog = new Lang.Class({
},
_startSession(serviceName) {
Tweener.addTween(this.actor,
Tweener.addTween(this,
{ opacity: 0,
time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
......@@ -961,7 +968,7 @@ var LoginDialog = new Lang.Class({
for (let i = 0; i < children.length; i++) {
if (children[i] != Main.layoutManager.screenShieldGroup)
children[i].opacity = this.actor.opacity;
children[i].opacity = this.opacity;
}
},
onUpdateScope: this,
......@@ -1230,17 +1237,17 @@ var LoginDialog = new Lang.Class({
},
open() {
Main.ctrlAltTabManager.addGroup(this.actor,
Main.ctrlAltTabManager.addGroup(this,
_("Login Window"),
'dialog-password-symbolic',
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE });
this._userList.actor.grab_key_focus();
this.actor.show();
this.actor.opacity = 0;
this.show();
this.opacity = 0;
Main.pushModal(this.actor, { actionMode: Shell.ActionMode.LOGIN_SCREEN });
Main.pushModal(this, { actionMode: Shell.ActionMode.LOGIN_SCREEN });
Tweener.addTween(this.actor,
Tweener.addTween(this,
{ opacity: 255,
time: 1,
transition: 'easeInQuad' });
......@@ -1249,8 +1256,8 @@ var LoginDialog = new Lang.Class({
},
close() {
Main.popModal(this.actor);
Main.ctrlAltTabManager.removeGroup(this.actor);
Main.popModal(this);
Main.ctrlAltTabManager.removeGroup(this);
},
cancel() {
......@@ -1265,4 +1272,3 @@ var LoginDialog = new Lang.Class({
this._authPrompt.finish(onComplete);
},
});
Signals.addSignalMethods(LoginDialog.prototype);
......@@ -3,6 +3,7 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
......@@ -80,41 +81,41 @@ var AppSwitcherPopup = new Lang.Class({
this._items = this._switcherList.icons;
},
_allocate(actor, box, flags) {
this.parent(actor, box, flags);
vfunc_allocate(box, flags) {
this.parent(box, flags);
// Allocate the thumbnails
// We try to avoid overflowing the screen so we base the resulting size on
// those calculations
if (this._thumbnails) {
let childBox = this._switcherList.actor.get_allocation_box();
let childBox = this._switcherList.get_allocation_box();
let primary = Main.layoutManager.primaryMonitor;
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
let bottomPadding = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
let leftPadding = this.get_theme_node().get_padding(St.Side.LEFT);
let rightPadding = this.get_theme_node().get_padding(St.Side.RIGHT);
let bottomPadding = this.get_theme_node().get_padding(St.Side.BOTTOM);
let hPadding = leftPadding + rightPadding;
let icon = this._items[this._selectedIndex].actor;
let icon = this._items[this._selectedIndex];
let [posX, posY] = icon.get_transformed_position();
let thumbnailCenter = posX + icon.width / 2;
let [childMinWidth, childNaturalWidth] = this._thumbnails.actor.get_preferred_width(-1);
let [childMinWidth, childNaturalWidth] = this._thumbnails.get_preferred_width(-1);
childBox.x1 = Math.max(primary.x + leftPadding, Math.floor(thumbnailCenter - childNaturalWidth / 2));
if (childBox.x1 + childNaturalWidth > primary.x + primary.width - hPadding) {
let offset = childBox.x1 + childNaturalWidth - primary.width + hPadding;
childBox.x1 = Math.max(primary.x + leftPadding, childBox.x1 - offset - hPadding);
}
let spacing = this.actor.get_theme_node().get_length('spacing');
let spacing = this.get_theme_node().get_length('spacing');
childBox.x2 = childBox.x1 + childNaturalWidth;
if (childBox.x2 > primary.x + primary.width - rightPadding)
childBox.x2 = primary.x + primary.width - rightPadding;
childBox.y1 = this._switcherList.actor.allocation.y2 + spacing;
childBox.y1 = this._switcherList.allocation.y2 + spacing;
this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
let [childMinHeight, childNaturalHeight] = this._thumbnails.actor.get_preferred_height(-1);
let [childMinHeight, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._thumbnails.actor.allocate(childBox, flags);
this._thumbnails.allocate(childBox, flags);
}
},
......@@ -262,7 +263,7 @@ var AppSwitcherPopup = new Lang.Class({
_windowActivated(thumbnailList, n) {
let appIcon = this._items[this._selectedIndex];
Main.activateWindow(appIcon.cachedWindows[n]);
this.destroy();
this.fadeAndDestroy();
},
_windowEntered(thumbnailList, n) {
......@@ -367,7 +368,7 @@ var AppSwitcherPopup = new Lang.Class({
},
_destroyThumbnails() {
let thumbnailsActor = this._thumbnails.actor;
let thumbnailsActor = this._thumbnails;
Tweener.addTween(thumbnailsActor,
{ opacity: 0,
time: THUMBNAIL_FADE_TIME,
......@@ -387,19 +388,19 @@ var AppSwitcherPopup = new Lang.Class({
this._thumbnails.connect('item-activated', this._windowActivated.bind(this));
this._thumbnails.connect('item-entered', this._windowEntered.bind(this));
this._thumbnails.connect('item-removed', this._windowRemoved.bind(this));
this._thumbnails.actor.connect('destroy', () => {
this._thumbnails.connect('destroy', () => {
this._thumbnails = null;
this._thumbnailsFocused = false;
});
this.actor.add_actor(this._thumbnails.actor);
this.add_actor(this._thumbnails);
// Need to force an allocation so we can figure out whether we
// need to scroll when selecting
this._thumbnails.actor.get_allocation_box();
this._thumbnails.get_allocation_box();
this._thumbnails.actor.opacity = 0;
Tweener.addTween(this._thumbnails.actor,
this._thumbnails.opacity = 0;
Tweener.addTween(this._thumbnails,
{ opacity: 255,
time: THUMBNAIL_FADE_TIME,
transition: 'easeOutQuad',
......@@ -471,6 +472,21 @@ var CyclerHighlight = new Lang.Class({
}
});
// We don't show an actual popup, so just provide what SwitcherPopup
// expects instead of inheriting from SwitcherList
var CyclerList = new Lang.Class({
Name: 'CyclerList',
Extends: St.Widget,
Signals: { 'item-activated': { param_types: [GObject.TYPE_INT] },
'item-entered': { param_types: [GObject.TYPE_INT] },
'item-removed': { param_types: [GObject.TYPE_INT] },
'item-highlighted': { param_types: [GObject.TYPE_INT] } },
highlight(index, justOutline) {
this.emit('item-highlighted', index);
}
});
var CyclerPopup = new Lang.Class({
Name: 'CyclerPopup',
Extends: SwitcherPopup.SwitcherPopup,
......@@ -487,11 +503,10 @@ var CyclerPopup = new Lang.Class({
this._highlight = new CyclerHighlight();
global.window_group.add_actor(this._highlight.actor);
// We don't show an actual popup, so just provide what SwitcherPopup
// expects instead of inheriting from SwitcherList
this._switcherList = { actor: new St.Widget(),
highlight: this._highlightItem.bind(this),
connect() {} };
this._switcherList = new CyclerList();
this._switcherList.connect('item-highlighted', (list, index) => {
this._highlightItem(index);
});
},
_highlightItem(index, justOutline) {
......@@ -653,22 +668,32 @@ var WindowCyclerPopup = new Lang.Class({
var AppIcon = new Lang.Class({
Name: 'AppIcon',
Extends: St.BoxLayout,
_init(app) {
this.parent({ style_class: 'alt-tab-app',
vertical: true });
this.app = app;
this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
vertical: true });
this.icon = null;
this._iconBin = new St.Bin({ x_fill: true, y_fill: true });
this.actor.add(this._iconBin, { x_fill: false, y_fill: false } );
this.add(this._iconBin, { x_fill: false, y_fill: false } );
this.label = new St.Label({ text: this.app.get_name() });
this.actor.add(this.label, { x_fill: false });
this.add(this.label, { x_fill: false });
},
set_size(size) {
this.icon = this.app.create_icon_texture(size);
this._iconBin.child = this.icon;
this._iconBin.set_size(size, size);
},
vfunc_get_preferred_width(forHeight) {
let [minWidth, ] = this.parent(forHeight);
minWidth = Math.max(minWidth, forHeight);
return [minWidth, minWidth];
}
});
......@@ -707,11 +732,10 @@ var AppSwitcher = new Lang.Class({
}
this._curApp = -1;
this._iconSize = 0;
this._altTabPopup = altTabPopup;
this._mouseTimeOutId = 0;
this.actor.connect('destroy', this._onDestroy.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
},
_onDestroy() {
......@@ -738,17 +762,16 @@ var AppSwitcher = new Lang.Class({
// We just assume the whole screen here due to weirdness happing with the passed width
let primary = Main.layoutManager.primaryMonitor;
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
let availWidth = primary.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding();
let parentPadding = this.get_parent().get_theme_node().get_horizontal_padding();
let availWidth = primary.width - parentPadding - this.get_theme_node().get_horizontal_padding();
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let iconSizes = baseIconSizes.map(s => s * scaleFactor);
let iconSize = baseIconSizes[0];
if (this._items.length == 1) {
this._iconSize = baseIconSizes[0];
} else {
if (this._items.length > 1) {
for(let i = 0; i < baseIconSizes.length; i++) {
this._iconSize = baseIconSizes[i];
iconSize = baseIconSizes[i];
let height = iconSizes[i] + iconSpacing;
let w = height * this._items.length + totalSpacing;
if (w <= availWidth)
......@@ -756,32 +779,36 @@ var AppSwitcher = new Lang.Class({
}
}
this._iconSize = iconSize;
for(let i = 0; i < this.icons.length; i++) {
if (this.icons[i].icon != null)
break;
this.icons[i].set_size(this._iconSize);
this.icons[i].set_size(iconSize);
}
},
_getPreferredHeight(actor, forWidth, alloc) {
vfunc_get_preferred_height(forWidth) {
this._setIconSize();
this.parent(actor, forWidth, alloc);
return this.parent(forWidth);
},
_allocate(actor, box, flags) {
vfunc_allocate(box, flags) {
// Allocate the main list items
this.parent(actor, box, flags);
this.parent(box, flags);
let contentBox = this.get_theme_node().get_content_box(box);
let arrowHeight = Math.floor(this.actor.get_theme_node().get_padding(St.Side.BOTTOM) / 3);
let arrowHeight = Math.floor(this.get_theme_node().get_padding(St.Side.BOTTOM) / 3);
let arrowWidth = arrowHeight * 2;
// Now allocate each arrow underneath its item
let childBox = new Clutter.ActorBox();
for (let i = 0; i < this._items.length; i++) {
let itemBox = this._items[i].allocation;
childBox.x1 = Math.floor(itemBox.x1 + (itemBox.x2 - itemBox.x1 - arrowWidth) / 2);
childBox.x1 = contentBox.x1 + Math.floor(itemBox.x1 + (itemBox.x2 - itemBox.x1 - arrowWidth) / 2);
childBox.x2 = childBox.x1 + arrowWidth;
childBox.y1 = itemBox.y2 + arrowHeight;
childBox.y1 = contentBox.y1 + itemBox.y2 + arrowHeight;
childBox.y2 = childBox.y1 + arrowHeight;
this._arrows[i].allocate(childBox, flags);
}
......@@ -839,7 +866,7 @@ var AppSwitcher = new Lang.Class({
_addIcon(appIcon) {
this.icons.push(appIcon);
let item = this.addItem(appIcon.actor, appIcon.label);
let item = this.addItem(appIcon, appIcon.label);
appIcon._stateChangedId = appIcon.app.connect('notify::state', app => {
if (app.state != Shell.AppState.RUNNING)
......@@ -849,7 +876,7 @@ var AppSwitcher = new Lang.Class({
let n = this._arrows.length;
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
arrow.connect('repaint', () => { SwitcherPopup.drawArrow(arrow, St.Side.BOTTOM); });
this._list.add_actor(arrow);
this.add_actor(arrow);
this._arrows.push(arrow);
if (appIcon.cachedWindows.length == 1)
......@@ -907,21 +934,21 @@ var ThumbnailList = new Lang.Class({
}
this.actor.connect('destroy', this._onDestroy.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
},
addClones(availHeight) {
if (!this._thumbnailBins.length)
return;
let totalPadding = this._items[0].get_theme_node().get_horizontal_padding() + this._items[0].get_theme_node().get_vertical_padding();
totalPadding += this.actor.get_theme_node().get_horizontal_padding() + this.actor.get_theme_node().get_vertical_padding();
totalPadding += this.get_theme_node().get_horizontal_padding() + this.get_theme_node().get_vertical_padding();
let [labelMinHeight, labelNaturalHeight] = this._labels[0].get_preferred_height(-1);
let spacing = this._items[0].child.get_theme_node().get_length('spacing');
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let thumbnailSize = THUMBNAIL_DEFAULT_SIZE * scaleFactor;
availHeight = Math.min(availHeight - labelNaturalHeight - totalPadding - spacing, thumbnailSize);
let binHeight = availHeight + this._items[0].get_theme_node().get_vertical_padding() + this.actor.get_theme_node().get_vertical_padding() - spacing;
let binHeight = availHeight + this._items[0].get_theme_node().get_vertical_padding() + this.get_theme_node().get_vertical_padding() - spacing;
binHeight = Math.min(thumbnailSize, binHeight);
for (let i = 0; i < this._thumbnailBins.length; i++) {
......@@ -956,7 +983,7 @@ var ThumbnailList = new Lang.Class({
if (this._clones.length > 0)
this.highlight(SwitcherPopup.mod(index, this._clones.length));
else
this.actor.destroy();
this.destroy();
},
_onDestroy() {
......@@ -970,15 +997,17 @@ var ThumbnailList = new Lang.Class({
var WindowIcon = new Lang.Class({
Name: 'WindowIcon',
Extends: St.BoxLayout,
_init(window, mode) {
this.parent({ style_class: 'alt-tab-app',
vertical: true });
this.window = window;
this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
vertical: true });
this._icon = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this.actor.add(this._icon, { x_fill: false, y_fill: false } );
this.add(this._icon, { x_fill: false, y_fill: false } );
this.label = new St.Label({ text: window.get_title() });
let tracker = Shell.WindowTracker.get_default();
......@@ -1034,7 +1063,7 @@ var WindowList = new Lang.Class({
this._label = new St.Label({ x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER });
this.actor.add_actor(this._label);
this.add_actor(this._label);
this.windows = windows;
this.icons = [];
......@@ -1043,7 +1072,7 @@ var WindowList = new Lang.Class({
let win = windows[i];
let icon = new WindowIcon(win, mode);
this.addItem(icon.actor, icon.label);
this.addItem(icon, icon.label);
this.icons.push(icon);
icon._unmanagedSignalId = icon.window.connect('unmanaged', (window) => {
......@@ -1051,7 +1080,7 @@ var WindowList = new Lang.Class({
});
}
this.actor.connect('destroy', () => { this._onDestroy(); });
this.connect('destroy', this._onDestroy.bind(this));
},
_onDestroy() {
......@@ -1060,26 +1089,40 @@ var WindowList = new Lang.Class({
});
},
_getPreferredHeight(actor, forWidth, alloc) {
this.parent(actor, forWidth, alloc);
vfunc_get_preferred_height(forWidth) {
let [minHeight, natHeight] = this.parent(forWidth);
let spacing = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
let spacing = this.get_theme_node().get_padding(St.Side.BOTTOM);
let [labelMin, labelNat] = this._label.get_preferred_height(-1);
alloc.min_size += labelMin + spacing;
alloc.natural_size += labelNat + spacing;
minHeight += labelMin + spacing;
natHeight += labelNat + spacing;
return [minHeight, natHeight];
},
_allocateTop(actor, box, flags) {
vfunc_allocate(box, flags) {
let themeNode = this.get_theme_node();
let contentBox = themeNode.get_content_box(box);
let childBox = new Clutter.ActorBox();
childBox.x1 = box.x1;
childBox.x2 = box.x2;
childBox.y2 = box.y2;
childBox.x1 = contentBox.x1;
childBox.x2 = contentBox.x2;
childBox.y2 = contentBox.y2;
childBox.y1 = childBox.y2 - this._label.height;
this._label.allocate(childBox, flags);
let spacing = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
box.y2 -= this._label.height + spacing;
this.parent(actor, box, flags);
let totalLabelHeight = this._label.height + themeNode.get_padding(St.Side.BOTTOM)
childBox.x1 = box.x1;
childBox.x2 = box.x2;
childBox.y1 = box.y1;
childBox.y2 = box.y2 - totalLabelHeight;
this.parent(childBox, flags);
// Hooking up the parent vfunc will call this.set_allocation() with
// the height without the label height, so call it again with the
// correct size here.
this.set_allocation(box, flags);
},
highlight(index, justOutline) {
......
......@@ -126,17 +126,17 @@ var BaseAppView = new Lang.Class({
else
this._grid = new IconGrid.IconGrid(gridParams);
this._grid.connect('key-focus-in', (grid, actor) => {
this._keyFocusIn(actor);
this._grid.connect('child-focused', (grid, actor) => {
this._childFocused(actor);
});
// Standard hack for ClutterBinLayout
this._grid.actor.x_expand = true;
this._grid.x_expand = true;
this._items = {};
this._allItems = [];
},
_keyFocusIn(actor) {
_childFocused(actor) {
// Nothing by default
},
......@@ -203,7 +203,7 @@ var BaseAppView = new Lang.Class({
},
_doSpringAnimation(animationDirection) {
this._grid.actor.opacity = 255;
this._grid.opacity = 255;
this._grid.animateSpring(animationDirection,
Main.overview.getShowAppsButton());
},
......@@ -217,8 +217,8 @@ var BaseAppView = new Lang.Class({
}
if (animationDirection == IconGrid.AnimationDirection.IN) {
let id = this._grid.actor.connect('paint', () => {
this._grid.actor.disconnect(id);
let id = this._grid.connect('paint', () => {
this._grid.disconnect(id);
this._doSpringAnimation(animationDirection);
});
} else {
......@@ -228,7 +228,7 @@ var BaseAppView = new Lang.Class({
animateSwitch(animationDirection) {
Tweener.removeTweens(this.actor);
Tweener.removeTweens(this._grid.actor);
Tweener.removeTweens(this._grid);
let params = { time: VIEWS_SWITCH_TIME,
transition: 'easeOutQuad' };
......@@ -242,7 +242,7 @@ var BaseAppView = new Lang.Class({
params.onComplete = () => { this.actor.hide(); };
}
Tweener.addTween(this._grid.actor, params);
Tweener.addTween(this._grid, params);
}
});
Signals.addSignalMethods(BaseAppView.prototype);
......@@ -396,7 +396,7 @@ var AllView = new Lang.Class({
let box = new St.BoxLayout({ vertical: true });
this._grid.currentPage = 0;
this._stack.add_actor(this._grid.actor);
this._stack.add_actor(this._grid);
this._eventBlocker = new St.Widget({ x_expand: true, y_expand: true });
this._stack.add_actor(this._eventBlocker);
......@@ -717,7 +717,7 @@ var AllView = new Lang.Class({
});
},
_keyFocusIn(icon) {
_childFocused(icon) {
let itemPage = this._grid.getItemPage(icon);
this.goToPage(itemPage);
},
......@@ -745,7 +745,7 @@ var AllView = new Lang.Class({
box.y2 = height;
box = this.actor.get_theme_node().get_content_box(box);
box = this._scrollView.get_theme_node().get_content_box(box);
box = this._grid.actor.get_theme_node().get_content_box(box);
box = this._grid.get_theme_node().get_content_box(box);
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let oldNPages = this._grid.nPages();
......@@ -794,9 +794,9 @@ var FrequentView = new Lang.Class({
y_align: Clutter.ActorAlign.CENTER,
y_expand: true });
this._grid.actor.y_expand = true;
this._grid.y_expand = true;
this.actor.add_actor(this._grid.actor);
this.actor.add_actor(this._grid);
this.actor.add_actor(this._noFrequentAppsLabel);
this._noFrequentAppsLabel.hide();
......@@ -843,7 +843,7 @@ var FrequentView = new Lang.Class({
box.x2 = width;
box.y2 = height;
box = this.actor.get_theme_node().get_content_box(box);
box = this._grid.actor.get_theme_node().get_content_box(box);
box = this._grid.get_theme_node().get_content_box(box);
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
this._grid.adaptToSize(availWidth, availHeight);
......@@ -1141,12 +1141,12 @@ var FolderView = new Lang.Class({
this.parent(null, null);
// If it not expand, the parent doesn't take into account its preferred_width when allocating
// the second time it allocates, so we apply the "Standard hack for ClutterBinLayout"
this._grid.actor.x_expand = true;
this._grid.x_expand = true;
this.actor = new St.ScrollView({ overlay_scrollbars: true });
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
let scrollableContainer = new St.BoxLayout({ vertical: true, reactive: true });
scrollableContainer.add_actor(this._grid.actor);
scrollableContainer.add_actor(this._grid);
this.actor.add_actor(scrollableContainer);
let action = new Clutter.PanAction({ interpolate: true });
......@@ -1154,7 +1154,7 @@ var FolderView = new Lang.Class({
this.actor.add_action(action);
},
_keyFocusIn(actor) {
_childFocused(actor) {
Util.ensureActorVisibleInScrollView(this.actor, actor);
},
......@@ -1267,7 +1267,7 @@ var FolderIcon = new Lang.Class({
this._popupInvalidated = false;
this.icon = new IconGrid.BaseIcon('', { createIcon: this._createIcon.bind(this), setSizeManually: true });
this.actor.set_child(this.icon.actor);
this.actor.set_child(this.icon);
this.actor.label_actor = this.icon.label;
this.view = new FolderView();
......@@ -1369,7 +1369,7 @@ var FolderIcon = new Lang.Class({
_updatePopupSize() {
// StWidget delays style calculation until needed, make sure we use the correct values
this.view._grid.actor.ensure_style();
this.view._grid.ensure_style();
let offsetForEachSide = Math.ceil((this._popup.getOffset(St.Side.TOP) +
this._popup.getOffset(St.Side.BOTTOM) -
......@@ -1535,7 +1535,7 @@ var AppFolderPopup = new Lang.Class({
// is completed so we can animate the icons after as we like without
// showing them while boxpointer is animating.
this._view.actor.opacity = 0;
this._boxPointer.show(BoxPointer.PopupAnimation.FADE |
this._boxPointer.open(BoxPointer.PopupAnimation.FADE |
BoxPointer.PopupAnimation.SLIDE,
() => {
this._view.actor.opacity = 255;
......@@ -1551,8 +1551,8 @@ var AppFolderPopup = new Lang.Class({
this._grabHelper.ungrab({ actor: this.actor });
this._boxPointer.hide(BoxPointer.PopupAnimation.FADE |
BoxPointer.PopupAnimation.SLIDE);
this._boxPointer.close(BoxPointer.PopupAnimation.FADE |
BoxPointer.PopupAnimation.SLIDE);
this._isOpen = false;
this.emit('open-state-changed', false);
},
......@@ -1615,7 +1615,7 @@ var AppIcon = new Lang.Class({
iconParams['createIcon'] = this._createIcon.bind(this);
iconParams['setSizeManually'] = true;
this.icon = new IconGrid.BaseIcon(app.get_name(), iconParams);
this._iconContainer.add_child(this.icon.actor);
this._iconContainer.add_child(this.icon);
this.actor.label_actor = this.icon.label;
......
......@@ -34,25 +34,25 @@ var POPUP_ANIMATION_TIME = 0.15;
*/
var BoxPointer = new Lang.Class({
Name: 'BoxPointer',
Extends: St.Widget,
Signals: { 'arrow-side-changed': {} },
_init(arrowSide, binProperties) {
this.parent();
this.actor = this;
this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._arrowSide = arrowSide;
this._userArrowSide = arrowSide;
this._arrowOrigin = 0;
this._arrowActor = null;
this.actor = new St.Bin({ x_fill: true,
y_fill: true });
this._container = new Shell.GenericContainer();
this.actor.set_child(this._container);
this.actor.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._container.connect('get-preferred-width', this._getPreferredWidth.bind(this));
this._container.connect('get-preferred-height', this._getPreferredHeight.bind(this));
this._container.connect('allocate', this._allocate.bind(this));
this.bin = new St.Bin(binProperties);
this._container.add_actor(this.bin);
this.add_actor(this.bin);
this._border = new St.DrawingArea();
this._border.connect('repaint', this._drawBorder.bind(this));
this._container.add_actor(this._border);
this.add_actor(this._border);
this.bin.raise(this._border);
this._xOffset = 0;
this._yOffset = 0;
......@@ -69,19 +69,49 @@ var BoxPointer = new Lang.Class({
_muteInput() {
if (this._capturedEventId == 0)
this._capturedEventId = this.actor.connect('captured-event',
() => Clutter.EVENT_STOP);
this._capturedEventId = this.connect('captured-event',
() => Clutter.EVENT_STOP);
},
_unmuteInput() {
if (this._capturedEventId != 0) {
this.actor.disconnect(this._capturedEventId);
this.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
},
// BoxPointer.show() and BoxPointer.hide() are here for only compatibility
// purposes, and will be removed in 3.32.
show(animate, onComplete) {
let themeNode = this.actor.get_theme_node();
if (animate !== undefined) {
try {
throw new Error('BoxPointer.show() has been moved to BoxPointer.open(), this code will break in the future.');
} catch(e) {
logError(e);
this.open(animate, onComplete);
return;
}
}
this.visible = true;
},
hide(animate, onComplete) {
if (animate !== undefined) {
try {
throw new Error('BoxPointer.hide() has been moved to BoxPointer.close(), this code will break in the future.');
} catch(e) {
logError(e);
this.close(animate, onComplete);
return;
}
}
this.visible = false;
},
open(animate, onComplete) {
let themeNode = this.get_theme_node();
let rise = themeNode.get_length('-arrow-rise');
let animationTime = (animate & PopupAnimation.FULL) ? POPUP_ANIMATION_TIME : 0;
......@@ -90,7 +120,7 @@ var BoxPointer = new Lang.Class({
else
this.opacity = 255;
this.actor.show();
this.show();
if (animate & PopupAnimation.SLIDE) {
switch (this._arrowSide) {
......@@ -121,13 +151,13 @@ var BoxPointer = new Lang.Class({
time: animationTime });
},
hide(animate, onComplete) {
if (!this.actor.visible)
close(animate, onComplete) {
if (!this.visible)
return;
let xOffset = 0;
let yOffset = 0;
let themeNode = this.actor.get_theme_node();
let themeNode = this.get_theme_node();
let rise = themeNode.get_length('-arrow-rise');
let fade = (animate & PopupAnimation.FADE);
let animationTime = (animate & PopupAnimation.FULL) ? POPUP_ANIMATION_TIME : 0;
......@@ -158,7 +188,7 @@ var BoxPointer = new Lang.Class({
transition: 'linear',
time: animationTime,
onComplete: () => {
this.actor.hide();
this.hide();
this.opacity = 0;
this.xOffset = 0;
this.yOffset = 0;
......@@ -168,37 +198,48 @@ var BoxPointer = new Lang.Class({
});
},
_adjustAllocationForArrow(isWidth, alloc) {
let themeNode = this.actor.get_theme_node();
_adjustAllocationForArrow(isWidth, minSize, natSize) {
let themeNode = this.get_theme_node();
let borderWidth = themeNode.get_length('-arrow-border-width');
alloc.min_size += borderWidth * 2;
alloc.natural_size += borderWidth * 2;
minSize += borderWidth * 2;
natSize += borderWidth * 2;
if ((!isWidth && (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM))
|| (isWidth && (this._arrowSide == St.Side.LEFT || this._arrowSide == St.Side.RIGHT))) {
let rise = themeNode.get_length('-arrow-rise');
alloc.min_size += rise;
alloc.natural_size += rise;
minSize += rise;
natSize += rise;
}
return [minSize, natSize];
},
_getPreferredWidth(actor, forHeight, alloc) {
let [minInternalSize, natInternalSize] = this.bin.get_preferred_width(forHeight);
alloc.min_size = minInternalSize;
alloc.natural_size = natInternalSize;
this._adjustAllocationForArrow(true, alloc);
vfunc_get_preferred_width(forHeight) {
let themeNode = this.get_theme_node();
forHeight = themeNode.adjust_for_height(forHeight);
let width = this.bin.get_preferred_width(forHeight);
width = this._adjustAllocationForArrow(true, ...width);
return themeNode.adjust_preferred_width(...width);
},
_getPreferredHeight(actor, forWidth, alloc) {
let themeNode = this.actor.get_theme_node();
vfunc_get_preferred_height(forWidth) {
let themeNode = this.get_theme_node();
let borderWidth = themeNode.get_length('-arrow-border-width');
let [minSize, naturalSize] = this.bin.get_preferred_height(forWidth - 2 * borderWidth);
alloc.min_size = minSize;
alloc.natural_size = naturalSize;
this._adjustAllocationForArrow(false, alloc);
forWidth = themeNode.adjust_for_width(forWidth);
let height = this.bin.get_preferred_height(forWidth - 2 * borderWidth);
height = this._adjustAllocationForArrow(false, ...height);
return themeNode.adjust_preferred_height(...height);
},
_allocate(actor, box, flags) {
let themeNode = this.actor.get_theme_node();
vfunc_allocate(box, flags) {
this.set_allocation(box, flags);
let themeNode = this.get_theme_node();
box = themeNode.get_content_box(box);
let borderWidth = themeNode.get_length('-arrow-border-width');
let rise = themeNode.get_length('-arrow-rise');
let childBox = new Clutter.ActorBox();
......@@ -238,12 +279,12 @@ var BoxPointer = new Lang.Class({
},
_drawBorder(area) {
let themeNode = this.actor.get_theme_node();
let themeNode = this.get_theme_node();
if (this._arrowActor) {
let [sourceX, sourceY] = this._arrowActor.get_transformed_position();
let [sourceWidth, sourceHeight] = this._arrowActor.get_transformed_size();
let [absX, absY] = this.actor.get_transformed_position();
let [absX, absY] = this.get_transformed_position();
if (this._arrowSide == St.Side.TOP ||
this._arrowSide == St.Side.BOTTOM) {
......@@ -422,7 +463,7 @@ var BoxPointer = new Lang.Class({
setPosition(sourceActor, alignment) {
// We need to show it now to force an allocation,
// so that we can query the correct size.
this.actor.show();
this.show();
this._sourceActor = sourceActor;
this._arrowAlignment = alignment;
......@@ -450,13 +491,13 @@ var BoxPointer = new Lang.Class({
let sourceAllocation = Shell.util_get_transformed_allocation(sourceActor);
let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * this._sourceAlignment;
let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * this._sourceAlignment;
let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size();
let [minWidth, minHeight, natWidth, natHeight] = this.get_preferred_size();
// We also want to keep it onscreen, and separated from the
// edge by the same distance as the main part of the box is
// separated from its sourceActor
let monitor = Main.layoutManager.findMonitorForActor(sourceActor);
let themeNode = this.actor.get_theme_node();
let themeNode = this.get_theme_node();
let borderWidth = themeNode.get_length('-arrow-border-width');
let arrowBase = themeNode.get_length('-arrow-base');
let borderRadius = themeNode.get_length('-arrow-border-radius');
......@@ -542,7 +583,7 @@ var BoxPointer = new Lang.Class({
this.setArrowOrigin(arrowOrigin);
let parent = this.actor.get_parent();
let parent = this.get_parent();
let success, x, y;
while (!success) {
[success, x, y] = parent.transform_stage_point(resX, resY);
......@@ -581,16 +622,16 @@ var BoxPointer = new Lang.Class({
// allocation loops and warnings. Instead we do the positioning via
// the anchor point, which is independent of allocation, and leave
// x == y == 0.
this.actor.set_anchor_point(-(this._xPosition + this._xOffset),
-(this._yPosition + this._yOffset));
this.set_anchor_point(-(this._xPosition + this._xOffset),
-(this._yPosition + this._yOffset));
},
_calculateArrowSide(arrowSide) {
let sourceAllocation = Shell.util_get_transformed_allocation(this._sourceActor);
let [minWidth, minHeight, boxWidth, boxHeight] = this._container.get_preferred_size();
let [minWidth, minHeight, boxWidth, boxHeight] = this.get_preferred_size();
let monitorActor = this.sourceActor;
if (!monitorActor)
monitorActor = this.actor;
monitorActor = this;
let monitor = Main.layoutManager.findMonitorForActor(monitorActor);
switch (arrowSide) {
......@@ -625,7 +666,7 @@ var BoxPointer = new Lang.Class({
this._arrowSide = arrowSide;
this._reposition();
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._container.queue_relayout();
this.queue_relayout();
return false;
});
......@@ -651,14 +692,6 @@ var BoxPointer = new Lang.Class({
return this._yOffset;
},
set opacity(opacity) {
this.actor.opacity = opacity;
},
get opacity() {
return this.actor.opacity;
},
updateArrowSide(side) {
this._arrowSide = side;
this._border.queue_repaint();
......@@ -671,7 +704,6 @@ var BoxPointer = new Lang.Class({
},
getArrowHeight() {
return this.actor.get_theme_node().get_length('-arrow-rise');
return this.get_theme_node().get_length('-arrow-rise');
}
});
Signals.addSignalMethods(BoxPointer.prototype);
......@@ -125,10 +125,10 @@ var CtrlAltTabManager = new Lang.Class({
this._popup = new CtrlAltTabPopup(items);
this._popup.show(backward, binding, mask);
this._popup.actor.connect('destroy',
() => {
this._popup = null;
});
this._popup.connect('destroy',
() => {
this._popup = null;
});
}
},
......
......@@ -38,7 +38,10 @@ var DashItemContainer = new Lang.Class({
Extends: St.Widget,
_init() {
this.parent({ style_class: 'dash-item-container' });
this.parent({ style_class: 'dash-item-container',
pivot_point: new Clutter.Point({ x: .5, y: .5 }),
x_expand: true,
x_align: Clutter.ActorAlign.CENTER });
this._labelText = "";
this.label = new St.Label({ style_class: 'dash-label'});
......@@ -56,52 +59,20 @@ var DashItemContainer = new Lang.Class({
});
},
vfunc_allocate(box, flags) {
this.set_allocation(box, flags);
if (this.child == null)
return;
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] =
this.child.get_preferred_size();
let [childScaleX, childScaleY] = this.child.get_scale();
let childWidth = Math.min(natChildWidth * childScaleX, availWidth);
let childHeight = Math.min(natChildHeight * childScaleY, availHeight);
let childBox = new Clutter.ActorBox();
childBox.x1 = (availWidth - childWidth) / 2;
childBox.y1 = (availHeight - childHeight) / 2;
childBox.x2 = childBox.x1 + childWidth;
childBox.y2 = childBox.y1 + childHeight;
this.child.allocate(childBox, flags);
},
vfunc_get_preferred_height(forWidth) {
let themeNode = this.get_theme_node();
if (this.child == null)
return [0, 0];
forWidth = themeNode.adjust_for_width(forWidth);
let [minHeight, natHeight] = this.child.get_preferred_height(forWidth);
return themeNode.adjust_preferred_height(minHeight * this.child.scale_y,
natHeight * this.child.scale_y);
let [minHeight, natHeight] = this.parent(forWidth);
return themeNode.adjust_preferred_height(minHeight * this.scale_y,
natHeight * this.scale_y);
},
vfunc_get_preferred_width(forHeight) {
let themeNode = this.get_theme_node();
if (this.child == null)
return [0, 0];
forHeight = themeNode.adjust_for_height(forHeight);
let [minWidth, natWidth] = this.child.get_preferred_width(forHeight);
return themeNode.adjust_preferred_width(minWidth * this.child.scale_y,
natWidth * this.child.scale_y);
let [minWidth, natWidth] = this.parent(forHeight);
return themeNode.adjust_preferred_width(minWidth * this.scale_x,
natWidth * this.scale_x);
},
showLabel() {
......@@ -163,9 +134,8 @@ var DashItemContainer = new Lang.Class({
this.child = actor;
this.add_actor(this.child);
this.child.set_scale_with_gravity(this._childScale, this._childScale,
Clutter.Gravity.CENTER);
this.child.set_opacity(this._childOpacity);
this.set_scale(this._childScale, this._childScale);
this.set_opacity(this._childOpacity);
},
show(animate) {
......@@ -204,11 +174,7 @@ var DashItemContainer = new Lang.Class({
set childScale(scale) {
this._childScale = scale;
if (this.child == null)
return;
this.child.set_scale_with_gravity(scale, scale,
Clutter.Gravity.CENTER);
this.set_scale(scale, scale);
this.queue_relayout();
},
......@@ -219,10 +185,7 @@ var DashItemContainer = new Lang.Class({
set childOpacity(opacity) {
this._childOpacity = opacity;
if (this.child == null)
return;
this.child.set_opacity(opacity);
this.set_opacity(opacity);
this.queue_redraw();
},
......@@ -247,7 +210,7 @@ var ShowAppsIcon = new Lang.Class({
{ setSizeManually: true,
showLabel: false,
createIcon: this._createIcon.bind(this) });
this.toggleButton.add_actor(this.icon.actor);
this.toggleButton.add_actor(this.icon);
this.toggleButton._delegate = this;
this.setChild(this.toggleButton);
......@@ -643,10 +606,10 @@ var Dash = new Lang.Class({
// Enforce the current icon size during the size request
firstIcon.icon.ensure_style();
let [currentWidth, currentHeight] = firstIcon.icon.get_size();
firstIcon.icon.set_size(this.iconSize * scaleFactor, this.iconSize * scaleFactor);
let [, currentHeight] = firstIcon.icon.get_size();
firstIcon.icon.set_height(this.iconSize * scaleFactor);
[minHeight, natHeight] = firstButton.get_preferred_height(-1);
firstIcon.icon.set_size(currentWidth, currentHeight);
firstIcon.icon.set_height(currentHeight);
// Subtract icon padding and box spacing from the available height
availHeight -= iconChildren.length * (natHeight - this.iconSize * scaleFactor) +
......
......@@ -133,9 +133,9 @@ var CandidatePopup = new Lang.Class({
_init() {
this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP);
this._boxPointer.actor.visible = false;
this._boxPointer.actor.style_class = 'candidate-popup-boxpointer';
Main.layoutManager.addChrome(this._boxPointer.actor);
this._boxPointer.visible = false;
this._boxPointer.style_class = 'candidate-popup-boxpointer';
Main.layoutManager.addChrome(this._boxPointer);
let box = new St.BoxLayout({ style_class: 'candidate-popup-content',
vertical: true });
......@@ -272,7 +272,7 @@ var CandidatePopup = new Lang.Class({
this._updateVisibility();
});
panelService.connect('focus-out', ps => {
this._boxPointer.hide(BoxPointer.PopupAnimation.NONE);
this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
Main.keyboard.resetSuggestions();
});
},
......@@ -291,10 +291,10 @@ var CandidatePopup = new Lang.Class({
if (isVisible) {
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
this._boxPointer.show(BoxPointer.PopupAnimation.NONE);
this._boxPointer.open(BoxPointer.PopupAnimation.NONE);
this._boxPointer.actor.raise_top();
} else {
this._boxPointer.hide(BoxPointer.PopupAnimation.NONE);
this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
}
},
......
......@@ -36,6 +36,7 @@ var APPICON_ANIMATION_OUT_TIME = 0.25;
var BaseIcon = new Lang.Class({
Name: 'BaseIcon',
Extends: St.Bin,
_init(label, params) {
params = Params.parse(params, { createIcon: null,
......@@ -46,32 +47,26 @@ var BaseIcon = new Lang.Class({
if (params.showLabel)
styleClass += ' overview-icon-with-label';
this.actor = new St.Bin({ style_class: styleClass,
x_fill: true,
y_fill: true });
this.actor._delegate = this;
this.actor.connect('style-changed', this._onStyleChanged.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
this.parent({ style_class: styleClass,
x_fill: true,
y_fill: true });
this._spacing = 0;
this.actor = this;
this.connect('destroy', this._onDestroy.bind(this));
let box = new Shell.GenericContainer();
box.connect('allocate', this._allocate.bind(this));
box.connect('get-preferred-width',
this._getPreferredWidth.bind(this));
box.connect('get-preferred-height',
this._getPreferredHeight.bind(this));
this.actor.set_child(box);
this._box = new St.BoxLayout({ vertical: true });
this.set_child(this._box);
this.iconSize = ICON_SIZE;
this._iconBin = new St.Bin({ x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
box.add_actor(this._iconBin);
this._box.add_actor(this._iconBin);
if (params.showLabel) {
this.label = new St.Label({ text: label });
box.add_actor(this.label);
this._box.add_actor(this.label);
} else {
this.label = null;
}
......@@ -86,54 +81,9 @@ var BaseIcon = new Lang.Class({
this._iconThemeChangedId = cache.connect('icon-theme-changed', this._onIconThemeChanged.bind(this));
},
_allocate(actor, box, flags) {
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let iconSize = availHeight;
let [iconMinHeight, iconNatHeight] = this._iconBin.get_preferred_height(-1);
let [iconMinWidth, iconNatWidth] = this._iconBin.get_preferred_width(-1);
let preferredHeight = iconNatHeight;
let childBox = new Clutter.ActorBox();
if (this.label) {
let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(-1);
preferredHeight += this._spacing + labelNatHeight;
let labelHeight = availHeight >= preferredHeight ? labelNatHeight
: labelMinHeight;
iconSize -= this._spacing + labelHeight;
childBox.x1 = 0;
childBox.x2 = availWidth;
childBox.y1 = iconSize + this._spacing;
childBox.y2 = childBox.y1 + labelHeight;
this.label.allocate(childBox, flags);
}
childBox.x1 = Math.floor((availWidth - iconNatWidth) / 2);
childBox.y1