~ubuntu-branches/ubuntu/saucy/gnome-shell-extensions/saucy

« back to all changes in this revision

Viewing changes to extensions/alternate-tab/workspaceIcons.js

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-08-17 21:07:02 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120817210702-q3vk64mg17sj21ei
Tags: 3.5.5-0ubuntu1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 
2
 
 
3
const Clutter = imports.gi.Clutter;
 
4
const Gdk = imports.gi.Gdk;
 
5
const Gio = imports.gi.Gio;
 
6
const Gtk = imports.gi.Gtk;
 
7
const Lang = imports.lang;
 
8
const Mainloop = imports.mainloop;
 
9
const Meta = imports.gi.Meta;
 
10
const Shell = imports.gi.Shell;
 
11
const St = imports.gi.St;
 
12
 
 
13
const AltTab = imports.ui.altTab;
 
14
const Main = imports.ui.main;
 
15
const ModalDialog = imports.ui.modalDialog;
 
16
const Tweener = imports.ui.tweener;
 
17
const WindowManager = imports.ui.windowManager;
 
18
 
 
19
const Gettext = imports.gettext.domain('gnome-shell-extensions');
 
20
const _ = Gettext.gettext;
 
21
const N_ = function(e) { return e };
 
22
 
 
23
const SETTINGS_HIGHLIGHT_SELECTED_KEY = 'highlight-selected';
 
24
 
 
25
const AltTabPopupWorkspaceIcons = new Lang.Class({
 
26
    Name: 'AlternateTab.AltTabPopupWorkspaceIcons',
 
27
    Extends: AltTab.AltTabPopup,
 
28
 
 
29
    _init: function(settings) {
 
30
        this.parent();
 
31
 
 
32
        this._settings = settings;
 
33
    },
 
34
 
 
35
    _windowActivated : function(thumbnailList, n) { },
 
36
 
 
37
    show : function(backward, binding, mask) {
 
38
        let appSys = Shell.AppSystem.get_default();
 
39
        let apps = appSys.get_running ();
 
40
 
 
41
        if (!apps.length)
 
42
            return false;
 
43
 
 
44
        if (!Main.pushModal(this.actor)) {
 
45
            // Probably someone else has a pointer grab, try again with keyboard only
 
46
            if (!Main.pushModal(this.actor, global.get_current_time(), Meta.ModalOptions.POINTER_ALREADY_GRABBED)) {
 
47
                return false;
 
48
            }
 
49
        }
 
50
        this._haveModal = true;
 
51
        this._modifierMask = AltTab.primaryModifier(mask);
 
52
 
 
53
        this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
 
54
        this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
 
55
 
 
56
        this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside));
 
57
        this.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
 
58
 
 
59
        this._appSwitcher = new WindowSwitcher(apps, this);
 
60
        this.actor.add_actor(this._appSwitcher.actor);
 
61
        this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated));
 
62
        this._appSwitcher.connect('item-entered', Lang.bind(this, this._appEntered));
 
63
 
 
64
        this._appIcons = this._appSwitcher.icons;
 
65
 
 
66
        // Need to force an allocation so we can figure out whether we
 
67
        // need to scroll when selecting
 
68
        this.actor.opacity = 0;
 
69
        this.actor.show();
 
70
        this.actor.get_allocation_box();
 
71
 
 
72
        this._highlight_selected = this._settings.get_boolean(SETTINGS_HIGHLIGHT_SELECTED_KEY);
 
73
 
 
74
        // Make the initial selection
 
75
        if (binding == 'switch_group') {
 
76
            //see AltTab.AltTabPopup.show function
 
77
            //cached windows are always of length one, so select first app and the window
 
78
            //the direction doesn't matter, so ignore backward
 
79
            this._select(0, 0);
 
80
        } else if (binding == 'switch_group_backward') {
 
81
            this._select(0, 0);
 
82
        } else if (binding == 'switch_windows_backward') {
 
83
            this._select(this._appIcons.length - 1);
 
84
        } else if (this._appIcons.length == 1) {
 
85
            this._select(0);
 
86
        } else if (backward) {
 
87
            this._select(this._appIcons.length - 1);
 
88
        } else {
 
89
            this._select(1);
 
90
        }
 
91
 
 
92
 
 
93
        // There's a race condition; if the user released Alt before
 
94
        // we got the grab, then we won't be notified. (See
 
95
        // https://bugzilla.gnome.org/show_bug.cgi?id=596695 for
 
96
        // details.) So we check now. (Have to do this after updating
 
97
        // selection.)
 
98
        let [x, y, mods] = global.get_pointer();
 
99
        if (!(mods & this._modifierMask)) {
 
100
            this._finish();
 
101
            return false;
 
102
        }
 
103
 
 
104
        // We delay showing the popup so that fast Alt+Tab users aren't
 
105
        // disturbed by the popup briefly flashing.
 
106
        this._initialDelayTimeoutId = Mainloop.timeout_add(AltTab.POPUP_DELAY_TIMEOUT,
 
107
                                                           Lang.bind(this, function () {
 
108
                                                               this.actor.opacity = 255;
 
109
                                                               this._initialDelayTimeoutId = 0;
 
110
                                                           }));
 
111
 
 
112
        return true;
 
113
    },
 
114
 
 
115
    _select : function(app, window, forceAppFocus) {
 
116
        if (app != this._currentApp || window == null) {
 
117
            if (this._thumbnails)
 
118
                this._destroyThumbnails();
 
119
        }
 
120
 
 
121
        if (this._thumbnailTimeoutId != 0) {
 
122
            Mainloop.source_remove(this._thumbnailTimeoutId);
 
123
            this._thumbnailTimeoutId = 0;
 
124
        }
 
125
 
 
126
        this._thumbnailsFocused = (window != null) && !forceAppFocus;
 
127
 
 
128
        this._currentApp = app;
 
129
        this._currentWindow = window ? window : -1;
 
130
        this._appSwitcher.highlight(app, this._thumbnailsFocused);
 
131
 
 
132
        if (window != null) {
 
133
            if (!this._thumbnails)
 
134
                this._createThumbnails();
 
135
            this._currentWindow = window;
 
136
            this._thumbnails.highlight(window, forceAppFocus);
 
137
        } else if (this._appIcons[this._currentApp].cachedWindows.length > 1 &&
 
138
                   !forceAppFocus) {
 
139
            this._thumbnailTimeoutId = Mainloop.timeout_add (
 
140
                AltTab.THUMBNAIL_POPUP_TIME,
 
141
                Lang.bind(this, this._timeoutPopupThumbnails));
 
142
        }
 
143
        if (this._highlight_selected) {
 
144
            let current_app = this._appIcons[this._currentApp];
 
145
            Main.activateWindow(current_app.cachedWindows[0]);
 
146
        }
 
147
    },
 
148
 
 
149
    _finish : function() {
 
150
        let app = this._appIcons[this._currentApp];
 
151
        if (!app)
 
152
            return;
 
153
 
 
154
        /*
 
155
         * We've to restore the original Z-depth and order of all windows.
 
156
         *
 
157
         * Gnome-shell doesn't give an option to change Z-depth without
 
158
         * messing the window's user_time.
 
159
         *
 
160
         * Pointless if the popup wasn't showed.
 
161
         */
 
162
        if (this._highlight_selected && this.actor.opacity == 255) {
 
163
            for (let i = this._appIcons.length - 2; i >= 0; i--) {
 
164
                let app_walker = this._appIcons[i];
 
165
                Main.activateWindow(app_walker.cachedWindows[0], global.get_current_time() - i - 1);
 
166
            }
 
167
        }
 
168
 
 
169
        Main.activateWindow(app.cachedWindows[0]);
 
170
        this.destroy();
 
171
    }
 
172
 
 
173
});
 
174
 
 
175
const AppIcon = new Lang.Class({
 
176
    Name: 'AlternateTab.AppIcon',
 
177
    Extends: AltTab.AppIcon,
 
178
 
 
179
    _init: function(app, window) {
 
180
        this.app = app;
 
181
 
 
182
        this.cachedWindows = [];
 
183
        this.cachedWindows.push(window);
 
184
 
 
185
        this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
 
186
                                         vertical: true });
 
187
        this.icon = null;
 
188
        this._iconBin = new St.Bin({ x_fill: true, y_fill: true });
 
189
 
 
190
        this.actor.add(this._iconBin, { x_fill: false, y_fill: false } );
 
191
 
 
192
        let title = window.get_title();
 
193
        if (title) {
 
194
            this.label = new St.Label({ text: title });
 
195
            let bin = new St.Bin({ x_align: St.Align.MIDDLE });
 
196
            bin.add_actor(this.label);
 
197
            this.actor.add(bin);
 
198
        }
 
199
        else {
 
200
            this.label = new St.Label({ text: this.app.get_name() });
 
201
            this.actor.add(this.label, { x_fill: false });
 
202
        }
 
203
    }
 
204
});
 
205
 
 
206
const WindowSwitcher = new Lang.Class({
 
207
    Name: 'AlternateTab.WindowSwitcher',
 
208
    Extends: AltTab.AppSwitcher,
 
209
 
 
210
    _init : function(apps, altTabPopup) {
 
211
        // Horrible HACK!
 
212
        // We inherit from AltTab.AppSwitcher, but only chain up to
 
213
        // AltTab.SwitcherList._init, to bypass AltTab.AppSwitcher._init
 
214
        AltTab.SwitcherList.prototype._init.call(this, true);
 
215
 
 
216
        // Construct the AppIcons, sort by time, add to the popup
 
217
        let activeWorkspace = global.screen.get_active_workspace();
 
218
        let workspaceIcons = [];
 
219
        let otherIcons = [];
 
220
        for (let i = 0; i < apps.length; i++) {
 
221
            // Cache the window list now; we don't handle dynamic changes here,
 
222
            // and we don't want to be continually retrieving it
 
223
            let windows = apps[i].get_windows();
 
224
 
 
225
            for(let j = 0; j < windows.length; j++) {
 
226
                let appIcon = new AppIcon(apps[i], windows[j]);
 
227
                if (this._isWindowOnWorkspace(windows[j], activeWorkspace)) {
 
228
                  workspaceIcons.push(appIcon);
 
229
                }
 
230
                else {
 
231
                  otherIcons.push(appIcon);
 
232
                }
 
233
            }
 
234
        }
 
235
 
 
236
        workspaceIcons.sort(Lang.bind(this, this._sortAppIcon));
 
237
        otherIcons.sort(Lang.bind(this, this._sortAppIcon));
 
238
 
 
239
        if(otherIcons.length > 0) {
 
240
            let mostRecentOtherIcon = otherIcons[0];
 
241
            otherIcons = [];
 
242
            otherIcons.push(mostRecentOtherIcon);
 
243
        }
 
244
 
 
245
        this.icons = [];
 
246
        this._arrows = [];
 
247
        for (let i = 0; i < workspaceIcons.length; i++)
 
248
            this._addIcon(workspaceIcons[i]);
 
249
        if (workspaceIcons.length > 0 && otherIcons.length > 0)
 
250
            this.addSeparator();
 
251
        for (let i = 0; i < otherIcons.length; i++)
 
252
            this._addIcon(otherIcons[i]);
 
253
 
 
254
        this._curApp = -1;
 
255
        this._iconSize = 0;
 
256
        this._altTabPopup = altTabPopup;
 
257
        this._mouseTimeOutId = 0;
 
258
    },
 
259
 
 
260
 
 
261
    _isWindowOnWorkspace: function(w, workspace) {
 
262
            if (w.get_workspace() == workspace)
 
263
                return true;
 
264
        return false;
 
265
    },
 
266
 
 
267
    _sortAppIcon : function(appIcon1, appIcon2) {
 
268
        let t1 = appIcon1.cachedWindows[0].get_user_time();
 
269
        let t2 = appIcon2.cachedWindows[0].get_user_time();
 
270
        if (t2 > t1) return 1;
 
271
        else return -1;
 
272
    }
 
273
});
 
274