![Dan Winship](/assets/img/avatar_default.png)
The menu is needed by the app switcher as well as the overview, so make it slightly more generic and move the code to appIcon. Also add support for drawing the menu either to the right of or below the icon. https://bugzilla.gnome.org/show_bug.cgi?id=590563
549 lines
21 KiB
JavaScript
549 lines
21 KiB
JavaScript
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
|
const Big = imports.gi.Big;
|
|
const Clutter = imports.gi.Clutter;
|
|
const GLib = imports.gi.GLib;
|
|
const Lang = imports.lang;
|
|
const Mainloop = imports.mainloop;
|
|
const Pango = imports.gi.Pango;
|
|
const Shell = imports.gi.Shell;
|
|
const Signals = imports.signals;
|
|
const Gettext = imports.gettext.domain('gnome-shell');
|
|
const _ = Gettext.gettext;
|
|
|
|
const GenericDisplay = imports.ui.genericDisplay;
|
|
const Main = imports.ui.main;
|
|
const Workspaces = imports.ui.workspaces;
|
|
|
|
const GLOW_COLOR = new Clutter.Color();
|
|
GLOW_COLOR.from_pixel(0x4f6ba4ff);
|
|
const GLOW_PADDING_HORIZONTAL = 3;
|
|
const GLOW_PADDING_VERTICAL = 3;
|
|
|
|
const APPICON_ICON_SIZE = 48;
|
|
|
|
const APPICON_PADDING = 1;
|
|
const APPICON_BORDER_WIDTH = 1;
|
|
const APPICON_CORNER_RADIUS = 4;
|
|
|
|
const APPICON_MENU_POPUP_TIMEOUT_MS = 600;
|
|
|
|
const APPICON_BORDER_COLOR = new Clutter.Color();
|
|
APPICON_BORDER_COLOR.from_pixel(0x787878ff);
|
|
const APPICON_MENU_BACKGROUND_COLOR = new Clutter.Color();
|
|
APPICON_MENU_BACKGROUND_COLOR.from_pixel(0x292929ff);
|
|
const APPICON_MENU_FONT = 'Sans 14px';
|
|
const APPICON_MENU_COLOR = new Clutter.Color();
|
|
APPICON_MENU_COLOR.from_pixel(0xffffffff);
|
|
const APPICON_MENU_SELECTED_COLOR = new Clutter.Color();
|
|
APPICON_MENU_SELECTED_COLOR.from_pixel(0x005b97ff);
|
|
const APPICON_MENU_SEPARATOR_COLOR = new Clutter.Color();
|
|
APPICON_MENU_SEPARATOR_COLOR.from_pixel(0x787878ff);
|
|
const APPICON_MENU_BORDER_WIDTH = 1;
|
|
const APPICON_MENU_ARROW_SIZE = 12;
|
|
const APPICON_MENU_CORNER_RADIUS = 4;
|
|
const APPICON_MENU_PADDING = 4;
|
|
|
|
const TRANSPARENT_COLOR = new Clutter.Color();
|
|
TRANSPARENT_COLOR.from_pixel(0x00000000);
|
|
|
|
const MenuType = { NONE: 0, ON_RIGHT: 1, BELOW: 2 };
|
|
|
|
function AppIcon(appInfo, menuType) {
|
|
this._init(appInfo, menuType || MenuType.NONE);
|
|
}
|
|
|
|
AppIcon.prototype = {
|
|
_init : function(appInfo, menuType) {
|
|
this.appInfo = appInfo;
|
|
this._menuType = menuType;
|
|
|
|
this.actor = new Shell.ButtonBox({ orientation: Big.BoxOrientation.VERTICAL,
|
|
border: APPICON_BORDER_WIDTH,
|
|
corner_radius: APPICON_CORNER_RADIUS,
|
|
padding: APPICON_PADDING,
|
|
reactive: true });
|
|
this.actor._delegate = this;
|
|
|
|
if (menuType != MenuType.NONE) {
|
|
this.windows = Shell.AppMonitor.get_default().get_windows_for_app(appInfo.get_id());
|
|
for (let i = 0; i < this.windows.length; i++) {
|
|
this.windows[i].connect('notify::user-time', Lang.bind(this, this._resortWindows));
|
|
}
|
|
this._resortWindows();
|
|
|
|
this.actor.connect('button-press-event', Lang.bind(this, this._updateMenuOnButtonPress));
|
|
this.actor.connect('notify::hover', Lang.bind(this, this._updateMenuOnHoverChanged));
|
|
this.actor.connect('activate', Lang.bind(this, this._updateMenuOnActivate));
|
|
|
|
this._menuTimeoutId = 0;
|
|
this._menu = null;
|
|
} else
|
|
this.windows = [];
|
|
|
|
let iconBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
|
x_align: Big.BoxAlignment.CENTER,
|
|
y_align: Big.BoxAlignment.CENTER,
|
|
width: APPICON_ICON_SIZE,
|
|
height: APPICON_ICON_SIZE });
|
|
this.icon = appInfo.create_icon_texture(APPICON_ICON_SIZE);
|
|
iconBox.append(this.icon, Big.BoxPackFlags.NONE);
|
|
|
|
this.actor.append(iconBox, Big.BoxPackFlags.EXPAND);
|
|
|
|
let nameBox = new Shell.GenericContainer();
|
|
nameBox.connect('get-preferred-width', Lang.bind(this, this._nameBoxGetPreferredWidth));
|
|
nameBox.connect('get-preferred-height', Lang.bind(this, this._nameBoxGetPreferredHeight));
|
|
nameBox.connect('allocate', Lang.bind(this, this._nameBoxAllocate));
|
|
this._nameBox = nameBox;
|
|
|
|
this._name = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
|
font_name: "Sans 12px",
|
|
line_alignment: Pango.Alignment.CENTER,
|
|
ellipsize: Pango.EllipsizeMode.END,
|
|
text: appInfo.get_name() });
|
|
nameBox.add_actor(this._name);
|
|
this._glowBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
|
|
let glowPath = GLib.filename_to_uri(global.imagedir + 'app-well-glow.png', '');
|
|
for (let i = 0; i < this.windows.length && i < 3; i++) {
|
|
let glow = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
|
glowPath, -1, -1);
|
|
glow.keep_aspect_ratio = false;
|
|
this._glowBox.append(glow, Big.BoxPackFlags.EXPAND);
|
|
}
|
|
this._nameBox.add_actor(this._glowBox);
|
|
this._glowBox.lower(this._name);
|
|
this.actor.append(nameBox, Big.BoxPackFlags.NONE);
|
|
},
|
|
|
|
_nameBoxGetPreferredWidth: function (nameBox, forHeight, alloc) {
|
|
let [min, natural] = this._name.get_preferred_width(forHeight);
|
|
alloc.min_size = min + GLOW_PADDING_HORIZONTAL * 2;
|
|
alloc.natural_size = natural + GLOW_PADDING_HORIZONTAL * 2;
|
|
},
|
|
|
|
_nameBoxGetPreferredHeight: function (nameBox, forWidth, alloc) {
|
|
let [min, natural] = this._name.get_preferred_height(forWidth);
|
|
alloc.min_size = min + GLOW_PADDING_VERTICAL * 2;
|
|
alloc.natural_size = natural + GLOW_PADDING_VERTICAL * 2;
|
|
},
|
|
|
|
_nameBoxAllocate: function (nameBox, box, flags) {
|
|
let childBox = new Clutter.ActorBox();
|
|
let [minWidth, naturalWidth] = this._name.get_preferred_width(-1);
|
|
let [minHeight, naturalHeight] = this._name.get_preferred_height(-1);
|
|
let availWidth = box.x2 - box.x1;
|
|
let availHeight = box.y2 - box.y1;
|
|
let targetWidth = availWidth;
|
|
let xPadding = 0;
|
|
if (naturalWidth < availWidth) {
|
|
xPadding = Math.floor((availWidth - naturalWidth) / 2);
|
|
}
|
|
childBox.x1 = xPadding;
|
|
childBox.x2 = availWidth - xPadding;
|
|
childBox.y1 = GLOW_PADDING_VERTICAL;
|
|
childBox.y2 = availHeight - GLOW_PADDING_VERTICAL;
|
|
this._name.allocate(childBox, flags);
|
|
|
|
// Now the glow
|
|
if (this._glowBox != null) {
|
|
let glowPaddingHoriz = Math.max(0, xPadding - GLOW_PADDING_HORIZONTAL);
|
|
glowPaddingHoriz = Math.max(GLOW_PADDING_HORIZONTAL, glowPaddingHoriz);
|
|
childBox.x1 = glowPaddingHoriz;
|
|
childBox.x2 = availWidth - glowPaddingHoriz;
|
|
childBox.y1 = 0;
|
|
childBox.y2 = availHeight;
|
|
this._glowBox.allocate(childBox, flags);
|
|
}
|
|
},
|
|
|
|
_resortWindows: function() {
|
|
this.windows.sort(function (a, b) {
|
|
let timeA = a.get_user_time();
|
|
let timeB = b.get_user_time();
|
|
if (timeA == timeB)
|
|
return 0;
|
|
else if (timeA > timeB)
|
|
return -1;
|
|
return 1;
|
|
});
|
|
},
|
|
|
|
// AppIcon itself is not a draggable, but if you want to make
|
|
// a subclass of it draggable, you can use this method to create
|
|
// a drag actor
|
|
createDragActor: function() {
|
|
return this.appInfo.create_icon_texture(APPICON_ICON_SIZE);
|
|
},
|
|
|
|
setHighlight: function(highlight) {
|
|
if (highlight) {
|
|
this.actor.border_color = APPICON_BORDER_COLOR;
|
|
} else {
|
|
this.actor.border_color = TRANSPARENT_COLOR;
|
|
}
|
|
},
|
|
|
|
_updateMenuOnActivate: function(actor, event) {
|
|
if (this._menuTimeoutId != 0) {
|
|
Mainloop.source_remove(this._menuTimeoutId);
|
|
this._menuTimeoutId = 0;
|
|
}
|
|
this.emit('activate');
|
|
return false;
|
|
},
|
|
|
|
_updateMenuOnHoverChanged: function() {
|
|
if (!this.actor.hover && this._menuTimeoutId != 0) {
|
|
Mainloop.source_remove(this._menuTimeoutId);
|
|
this._menuTimeoutId = 0;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
_updateMenuOnButtonPress: function(actor, event) {
|
|
if (this._menuTimeoutId != 0)
|
|
Mainloop.source_remove(this._menuTimeoutId);
|
|
this._menuTimeoutId = Mainloop.timeout_add(APPICON_MENU_POPUP_TIMEOUT_MS,
|
|
Lang.bind(this, this._popupMenu));
|
|
return false;
|
|
},
|
|
|
|
_popupMenu: function() {
|
|
this._menuTimeoutId = 0;
|
|
|
|
this.actor.fake_release();
|
|
|
|
if (!this._menu) {
|
|
this._menu = new AppIconMenu(this, this._menuType);
|
|
this._menu.connect('highlight-window', Lang.bind(this, function (menu, window) {
|
|
this.highlightWindow(window);
|
|
}));
|
|
this._menu.connect('activate-window', Lang.bind(this, function (menu, window) {
|
|
this.activateWindow(window);
|
|
}));
|
|
this._menu.connect('popup', Lang.bind(this, function (menu, isPoppedUp) {
|
|
if (isPoppedUp)
|
|
this.menuPoppedUp();
|
|
else
|
|
this.menuPoppedDown();
|
|
}));
|
|
}
|
|
|
|
this._menu.popup();
|
|
|
|
return false;
|
|
},
|
|
|
|
// Default implementations; AppDisplay.RunningWellItem overrides these
|
|
highlightWindow: function(window) {
|
|
this.emit('highlight-window', window);
|
|
},
|
|
|
|
activateWindow: function(window) {
|
|
this.emit('activate-window', window);
|
|
},
|
|
|
|
menuPoppedUp: function() {},
|
|
menuPoppedDown: function() {}
|
|
};
|
|
|
|
Signals.addSignalMethods(AppIcon.prototype);
|
|
|
|
function AppIconMenu(source, type) {
|
|
this._init(source, type);
|
|
}
|
|
|
|
AppIconMenu.prototype = {
|
|
_init: function(source, type) {
|
|
this._source = source;
|
|
this._type = type;
|
|
|
|
this.actor = new Shell.GenericContainer({ reactive: true });
|
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
|
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
|
|
|
this._windowContainer = new Shell.Menu({ orientation: Big.BoxOrientation.VERTICAL,
|
|
border_color: APPICON_BORDER_COLOR,
|
|
border: APPICON_MENU_BORDER_WIDTH,
|
|
background_color: APPICON_MENU_BACKGROUND_COLOR,
|
|
padding: 4,
|
|
corner_radius: APPICON_MENU_CORNER_RADIUS,
|
|
width: Main.overview._dash.actor.width * 0.75 });
|
|
this._windowContainer.connect('unselected', Lang.bind(this, this._onItemUnselected));
|
|
this._windowContainer.connect('selected', Lang.bind(this, this._onItemSelected));
|
|
this._windowContainer.connect('cancelled', Lang.bind(this, this._onWindowSelectionCancelled));
|
|
this._windowContainer.connect('activate', Lang.bind(this, this._onItemActivate));
|
|
this.actor.add_actor(this._windowContainer);
|
|
|
|
// Stay popped up on release over application icon
|
|
this._windowContainer.set_persistent_source(this._source.actor);
|
|
|
|
// Intercept events while the menu has the pointer grab to do window-related effects
|
|
this._windowContainer.connect('enter-event', Lang.bind(this, this._onMenuEnter));
|
|
this._windowContainer.connect('leave-event', Lang.bind(this, this._onMenuLeave));
|
|
this._windowContainer.connect('button-release-event', Lang.bind(this, this._onMenuButtonRelease));
|
|
|
|
this._arrow = new Shell.DrawingArea();
|
|
this._arrow.connect('redraw', Lang.bind(this, function (area, texture) {
|
|
Shell.draw_box_pointer(texture,
|
|
this._type == MenuType.ON_RIGHT ? Clutter.Gravity.WEST : Clutter.Gravity.NORTH,
|
|
APPICON_BORDER_COLOR,
|
|
APPICON_MENU_BACKGROUND_COLOR);
|
|
}));
|
|
this.actor.add_actor(this._arrow);
|
|
|
|
// Chain our visibility and lifecycle to that of the source
|
|
source.actor.connect('notify::mapped', Lang.bind(this, function () {
|
|
if (!source.actor.mapped)
|
|
this._windowContainer.popdown();
|
|
}));
|
|
source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
|
|
|
|
global.stage.add_actor(this.actor);
|
|
},
|
|
|
|
_getPreferredWidth: function(actor, forHeight, alloc) {
|
|
let [min, natural] = this._windowContainer.get_preferred_width(forHeight);
|
|
if (this._type == MenuType.ON_RIGHT) {
|
|
min += APPICON_MENU_ARROW_SIZE;
|
|
natural += APPICON_MENU_ARROW_SIZE;
|
|
}
|
|
alloc.min_size = min;
|
|
alloc.natural_size = natural;
|
|
},
|
|
|
|
_getPreferredHeight: function(actor, forWidth, alloc) {
|
|
let [min, natural] = this._windowContainer.get_preferred_height(forWidth);
|
|
if (this._type == MenuType.BELOW) {
|
|
min += APPICON_MENU_ARROW_SIZE;
|
|
natural += APPICON_MENU_ARROW_SIZE;
|
|
}
|
|
alloc.min_size = min;
|
|
alloc.natural_size = natural;
|
|
},
|
|
|
|
_allocate: function(actor, box, flags) {
|
|
let childBox = new Clutter.ActorBox();
|
|
|
|
let width = box.x2 - box.x1;
|
|
let height = box.y2 - box.y1;
|
|
|
|
if (this._type == MenuType.ON_RIGHT) {
|
|
childBox.x1 = 0;
|
|
childBox.x2 = APPICON_MENU_ARROW_SIZE;
|
|
childBox.y1 = Math.floor((height / 2) - (APPICON_MENU_ARROW_SIZE / 2));
|
|
childBox.y2 = childBox.y1 + APPICON_MENU_ARROW_SIZE;
|
|
this._arrow.allocate(childBox, flags);
|
|
|
|
childBox.x1 = APPICON_MENU_ARROW_SIZE - APPICON_MENU_BORDER_WIDTH;
|
|
childBox.x2 = width;
|
|
childBox.y1 = 0;
|
|
childBox.y2 = height;
|
|
this._windowContainer.allocate(childBox, flags);
|
|
} else /* MenuType.BELOW */ {
|
|
childBox.x1 = Math.floor((width / 2) - (APPICON_MENU_ARROW_SIZE / 2));
|
|
childBox.x2 = childBox.x1 + APPICON_MENU_ARROW_SIZE;
|
|
childBox.y1 = 0;
|
|
childBox.y2 = APPICON_MENU_ARROW_SIZE;
|
|
this._arrow.allocate(childBox, flags);
|
|
|
|
childBox.x1 = 0;
|
|
childBox.x2 = width;
|
|
childBox.y1 = APPICON_MENU_ARROW_SIZE - APPICON_MENU_BORDER_WIDTH;
|
|
childBox.y2 = height;
|
|
this._windowContainer.allocate(childBox, flags);
|
|
}
|
|
},
|
|
|
|
_redisplay: function() {
|
|
this._windowContainer.remove_all();
|
|
|
|
let windows = this._source.windows;
|
|
|
|
this._windowContainer.show();
|
|
|
|
let iconsDiffer = false;
|
|
let texCache = Shell.TextureCache.get_default();
|
|
let firstIcon = windows[0].mini_icon;
|
|
for (let i = 1; i < windows.length; i++) {
|
|
if (!texCache.pixbuf_equal(windows[i].mini_icon, firstIcon)) {
|
|
iconsDiffer = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
let activeWorkspace = global.screen.get_active_workspace();
|
|
|
|
let currentWorkspaceWindows = windows.filter(function (w) {
|
|
return w.get_workspace() == activeWorkspace;
|
|
});
|
|
let otherWorkspaceWindows = windows.filter(function (w) {
|
|
return w.get_workspace() != activeWorkspace;
|
|
});
|
|
|
|
this._appendWindows(currentWorkspaceWindows, iconsDiffer);
|
|
if (currentWorkspaceWindows.length > 0 && otherWorkspaceWindows.length > 0) {
|
|
this._appendSeparator();
|
|
}
|
|
this._appendWindows(otherWorkspaceWindows, iconsDiffer);
|
|
|
|
this._appendSeparator();
|
|
|
|
this._newWindowMenuItem = this._appendMenuItem(null, _("New Window"));
|
|
},
|
|
|
|
_appendSeparator: function () {
|
|
let box = new Big.Box({ padding_top: 2, padding_bottom: 2 });
|
|
box.append(new Clutter.Rectangle({ height: 1,
|
|
color: APPICON_MENU_SEPARATOR_COLOR }),
|
|
Big.BoxPackFlags.EXPAND);
|
|
this._windowContainer.append_separator(box, Big.BoxPackFlags.NONE);
|
|
},
|
|
|
|
_appendMenuItem: function(iconTexture, labelText) {
|
|
/* Use padding here rather than spacing in the box above so that
|
|
* we have a larger reactive area.
|
|
*/
|
|
let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
|
padding_top: 4,
|
|
padding_bottom: 4,
|
|
spacing: 4,
|
|
reactive: true });
|
|
let vCenter;
|
|
if (iconTexture != null) {
|
|
vCenter = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
|
vCenter.append(iconTexture, Big.BoxPackFlags.NONE);
|
|
box.append(vCenter, Big.BoxPackFlags.NONE);
|
|
}
|
|
vCenter = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
|
let label = new Clutter.Text({ text: labelText,
|
|
font_name: APPICON_MENU_FONT,
|
|
ellipsize: Pango.EllipsizeMode.END,
|
|
color: APPICON_MENU_COLOR });
|
|
vCenter.append(label, Big.BoxPackFlags.NONE);
|
|
box.append(vCenter, Big.BoxPackFlags.NONE);
|
|
this._windowContainer.append(box, Big.BoxPackFlags.NONE);
|
|
return box;
|
|
},
|
|
|
|
_appendWindows: function (windows, iconsDiffer) {
|
|
for (let i = 0; i < windows.length; i++) {
|
|
let metaWindow = windows[i];
|
|
|
|
let icon = null;
|
|
if (iconsDiffer) {
|
|
icon = Shell.TextureCache.get_default().bind_pixbuf_property(metaWindow, "mini-icon");
|
|
}
|
|
let box = this._appendMenuItem(icon, metaWindow.title);
|
|
box._window = metaWindow;
|
|
}
|
|
},
|
|
|
|
popup: function() {
|
|
let [stageX, stageY] = this._source.actor.get_transformed_position();
|
|
let [stageWidth, stageHeight] = this._source.actor.get_transformed_size();
|
|
|
|
this._redisplay();
|
|
|
|
this._windowContainer.popup(0, Clutter.get_current_event_time());
|
|
|
|
this.emit('popup', true);
|
|
|
|
let x, y;
|
|
if (this._type == MenuType.ON_RIGHT) {
|
|
x = Math.floor(stageX + stageWidth);
|
|
y = Math.floor(stageY + (stageHeight / 2) - (this.actor.height / 2));
|
|
} else {
|
|
x = Math.floor(stageX + (stageWidth / 2) - (this.actor.width / 2));
|
|
y = Math.floor(stageY + stageHeight);
|
|
}
|
|
|
|
this.actor.set_position(x, y);
|
|
this.actor.show();
|
|
},
|
|
|
|
_findMetaWindowForActor: function (actor) {
|
|
if (actor._delegate instanceof Workspaces.WindowClone)
|
|
return actor._delegate.metaWindow;
|
|
else if (actor.get_meta_window)
|
|
return actor.get_meta_window();
|
|
return null;
|
|
},
|
|
|
|
// This function is called while the menu has a pointer grab; what we want
|
|
// to do is see if the mouse was released over a window representation
|
|
_onMenuButtonRelease: function (actor, event) {
|
|
let metaWindow = this._findMetaWindowForActor(event.get_source());
|
|
if (metaWindow) {
|
|
this.emit('activate-window', metaWindow);
|
|
}
|
|
},
|
|
|
|
_lookupMenuItemForWindow: function (metaWindow) {
|
|
let children = this._windowContainer.get_children();
|
|
for (let i = 0; i < children.length; i++) {
|
|
let child = children[i];
|
|
let menuMetaWindow = child._window;
|
|
if (menuMetaWindow == metaWindow)
|
|
return child;
|
|
}
|
|
return null;
|
|
},
|
|
|
|
// Called while menu has a pointer grab
|
|
_onMenuEnter: function (actor, event) {
|
|
let metaWindow = this._findMetaWindowForActor(event.get_source());
|
|
if (metaWindow) {
|
|
let menu = this._lookupMenuItemForWindow(metaWindow);
|
|
menu.background_color = APPICON_MENU_SELECTED_COLOR;
|
|
this.emit('highlight-window', metaWindow);
|
|
}
|
|
},
|
|
|
|
// Called while menu has a pointer grab
|
|
_onMenuLeave: function (actor, event) {
|
|
let metaWindow = this._findMetaWindowForActor(event.get_source());
|
|
if (metaWindow) {
|
|
let menu = this._lookupMenuItemForWindow(metaWindow);
|
|
menu.background_color = TRANSPARENT_COLOR;
|
|
this.emit('highlight-window', null);
|
|
}
|
|
},
|
|
|
|
_onItemUnselected: function (actor, child) {
|
|
child.background_color = TRANSPARENT_COLOR;
|
|
if (child._window) {
|
|
this.emit('highlight-window', null);
|
|
}
|
|
},
|
|
|
|
_onItemSelected: function (actor, child) {
|
|
child.background_color = APPICON_MENU_SELECTED_COLOR;
|
|
if (child._window) {
|
|
this.emit('highlight-window', child._window);
|
|
}
|
|
},
|
|
|
|
_onItemActivate: function (actor, child) {
|
|
if (child._window) {
|
|
let metaWindow = child._window;
|
|
this.emit('activate-window', metaWindow);
|
|
} else if (child == this._newWindowMenuItem) {
|
|
this._source.appInfo.launch();
|
|
this.emit('activate-window', null);
|
|
}
|
|
this.emit('popup', false);
|
|
this.actor.hide();
|
|
},
|
|
|
|
_onWindowSelectionCancelled: function () {
|
|
this.emit('highlight-window', null);
|
|
this.emit('popup', false);
|
|
this.actor.hide();
|
|
}
|
|
};
|
|
|
|
Signals.addSignalMethods(AppIconMenu.prototype);
|