~ubuntu-branches/ubuntu/vivid/gnome-shell-extensions/vivid-proposed

« back to all changes in this revision

Viewing changes to .pc/02-Revert-all-remove-all-GSettings-usage.patch/extensions/dock/extension.js

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Josselin Mouette, Michael Biebl
  • Date: 2012-02-11 23:28:53 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120211232853-mc92yae3sgemtz7l
Tags: 3.2.3-1
[ Josselin Mouette ]
* gnome-shell-extensions.gsettings-override: enable the alternative 
  status menu by default. Closes: #648112.
* Use ${gnome:Version} to generate strict dependencies, it’s very 
  unlikely that extensions remain compatible after a major upgrade.

[ Michael Biebl ]
* Upload to unstable.

[ Josselin Mouette ]
* 01_status-menu_disable_accounts.patch: new patch. Drop the unusable
  advertisement for Google. It is already available in the control 
  center anyway.

[ Michael Biebl ]
* New upstream release.
* Drop patches which have been merged upstream:
  - debian/patches/upstream/*
  - debian/patches/fix-*
* Refresh 01_status-menu_disable_accounts.patch.
* Add 02-Revert-all-remove-all-GSettings-usage.patch: Use GSettings since we
  install the extensions system-wide.
* Use dh-autoreconf to generate the build system.
* Add 03-Revert-Remove-all-references-to-localedir-from-metad.patch: Use
  locales from system-wide location.

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 Pango = imports.gi.Pango;
 
5
const GLib = imports.gi.GLib;
 
6
const Gio = imports.gi.Gio;
 
7
const Gtk = imports.gi.Gtk;
 
8
const Shell = imports.gi.Shell;
 
9
const Lang = imports.lang;
 
10
const Signals = imports.signals;
 
11
const St = imports.gi.St;
 
12
const Mainloop = imports.mainloop;
 
13
 
 
14
const AppFavorites = imports.ui.appFavorites;
 
15
const DND = imports.ui.dnd;
 
16
const Main = imports.ui.main;
 
17
const Overview = imports.ui.overview;
 
18
const PopupMenu = imports.ui.popupMenu;
 
19
const Search = imports.ui.search;
 
20
const Tweener = imports.ui.tweener;
 
21
const Workspace = imports.ui.workspace;
 
22
const AppDisplay = imports.ui.appDisplay;
 
23
const AltTab = imports.ui.altTab;
 
24
 
 
25
const Gettext = imports.gettext.domain('gnome-shell-extensions');
 
26
const _ = Gettext.gettext;
 
27
 
 
28
//hide
 
29
//const autohide_animation_time = 0.3;
 
30
 
 
31
// Keep enums in sync with GSettings schemas
 
32
const PositionMode = {
 
33
    LEFT: 0,
 
34
    RIGHT: 1
 
35
};
 
36
 
 
37
const AutoHideEffect = {
 
38
    RESIZE: 0,
 
39
    RESCALE: 1,
 
40
    MOVE: 2
 
41
};
 
42
 
 
43
// Settings
 
44
const DOCK_POSITION = PositionMode.RIGHT;
 
45
const DOCK_SIZE = 48;
 
46
const DOCK_AUTOHIDE = true;
 
47
const DOCK_EFFECTHIDE = AutoHideEffect.MOVE;
 
48
const DOCK_AUTOHIDE_ANIMATION_TIME = 0.3;
 
49
// Do not change anything below this line (it is intentionally duplicate to keep in
 
50
// sync with master branch)
 
51
 
 
52
let position = PositionMode.RIGHT;
 
53
let dockicon_size = 48;
 
54
let hideable = true;
 
55
let hideDock = true;
 
56
let hideEffect = AutoHideEffect.RESIZE;
 
57
let autohide_animation_time = 0.3;
 
58
const DND_RAISE_APP_TIMEOUT = 500;
 
59
 
 
60
/*************************************************************************************/
 
61
/**** start resize's Dock functions                                  *****************/
 
62
/*************************************************************************************/
 
63
function hideDock_size () {
 
64
    if (hideable){
 
65
       let monitor = Main.layoutManager.primaryMonitor
 
66
       let position_x = monitor.x;
 
67
       let height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
 
68
       let width = this._item_size + 4*this._spacing;
 
69
 
 
70
       Tweener.addTween(this,{
 
71
              _item_size: 1,
 
72
              time: autohide_animation_time,
 
73
              transition: 'easeOutQuad',
 
74
              onUpdate: function () {
 
75
                   height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
 
76
                   width = this._item_size + 4*this._spacing;
 
77
                   switch (position) {
 
78
                       case PositionMode.LEFT:
 
79
                              position_x=monitor.x-2*this._spacing;
 
80
                              break;
 
81
                       case PositionMode.RIGHT:
 
82
                       default:
 
83
                              position_x = monitor.x + (monitor.width-1-this._item_size-2*this._spacing);
 
84
                   }
 
85
                   this.actor.set_position (position_x,monitor.y+(monitor.height-height)/2);
 
86
                   this.actor.set_size(width,height);
 
87
              },
 
88
       });
 
89
       hideDock=true;
 
90
    }
 
91
}
 
92
 
 
93
function showDock_size () {
 
94
     let monitor = Main.layoutManager.primaryMonitor;
 
95
     let height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
 
96
     let width = this._item_size + 4*this._spacing;
 
97
     let position_x = monitor.x;
 
98
 
 
99
     Tweener.addTween(this,{
 
100
             _item_size: dockicon_size,
 
101
             time: autohide_animation_time,
 
102
             transition: 'easeOutQuad',
 
103
             onUpdate: function () {
 
104
                height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
 
105
                width = this._item_size + 4*this._spacing;
 
106
                switch (position) {
 
107
                   case PositionMode.LEFT:
 
108
                      position_x=monitor.x-2*this._spacing;
 
109
                      break;
 
110
                   case PositionMode.RIGHT:
 
111
                   default:
 
112
                      position_x=monitor.x + (monitor.width-this._item_size-2*this._spacing);
 
113
                }
 
114
                this.actor.set_position (position_x, monitor.y+(monitor.height-height)/2);
 
115
                this.actor.set_size(width,height);
 
116
             }
 
117
     });
 
118
     hideDock=false;
 
119
}
 
120
 
 
121
function initShowDock_size () {
 
122
        this._item_size=1;
 
123
        this._showDock();
 
124
}
 
125
 
 
126
function showEffectAddItem_size () {
 
127
        let primary = Main.layoutManager.primaryMonitor;
 
128
        let height = (this._nicons)*(this._item_size + this._spacing) + 2*this._spacing;
 
129
        let width = this._item_size + 4*this._spacing;
 
130
 
 
131
        Tweener.addTween(this.actor, {
 
132
                y: primary.y + (primary.height-height)/2,
 
133
                height: height,
 
134
                width: width,
 
135
                time: autohide_animation_time,
 
136
                transition: 'easeOutQuad'
 
137
        });
 
138
}
 
139
 
 
140
/**************************************************************************************/
 
141
/**** start rescale's Dock functions                                  *****************/
 
142
/**************************************************************************************/
 
143
function hideDock_scale () {
 
144
       this._item_size = dockicon_size;
 
145
       let monitor = Main.layoutManager.primaryMonitor;
 
146
       let cornerX = 0;
 
147
       let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
 
148
       let width = this._item_size + 4*this._spacing;
 
149
 
 
150
       switch (position) {
 
151
            case PositionMode.LEFT:
 
152
                cornerX=monitor.x;
 
153
                break;
 
154
            case PositionMode.RIGHT:
 
155
            default:
 
156
                cornerX = monitor.x + monitor.width-1;
 
157
        }
 
158
 
 
159
        if (hideable) {
 
160
               Tweener.addTween(this.actor,{
 
161
                       y: monitor.y + (monitor.height-height)/2,
 
162
                       x: cornerX,
 
163
                       height:height,
 
164
                       width: width,
 
165
                       scale_x: 0.025,
 
166
                       time: autohide_animation_time,
 
167
                       transition: 'easeOutQuad'
 
168
                     });
 
169
               hideDock=true;
 
170
        }
 
171
}
 
172
 
 
173
function showDock_scale () {
 
174
        this._item_size = dockicon_size;
 
175
        let monitor = Main.layoutManager.primaryMonitor;
 
176
        let position_x = monitor.x;
 
177
        let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
 
178
        let width = this._item_size + 4*this._spacing;
 
179
 
 
180
        switch (position) {
 
181
            case PositionMode.LEFT:
 
182
                position_x=monitor.x-2*this._spacing;
 
183
                break;
 
184
            case PositionMode.RIGHT:
 
185
            default:
 
186
                 position_x=monitor.x + (monitor.width-this._item_size-2*this._spacing);
 
187
        }
 
188
        Tweener.addTween(this.actor, {
 
189
                y: monitor.y + (monitor.height-height)/2,
 
190
                x: monitor.x + position_x,
 
191
                height: height,
 
192
                width: width,
 
193
                scale_x: 1,
 
194
                time: autohide_animation_time,
 
195
                transition: 'easeOutQuad'
 
196
        });
 
197
        hideDock=false;
 
198
}
 
199
 
 
200
function initShowDock_scale () {
 
201
        let primary = Main.layoutManager.primaryMonitor;
 
202
        let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
 
203
        let width = this._item_size + 4*this._spacing;
 
204
 
 
205
        this.actor.set_scale (0,0);
 
206
        this.actor.set_size (width,height);
 
207
 
 
208
        // set the position of the dock
 
209
        switch (position) {
 
210
                case PositionMode.LEFT:
 
211
                   this.actor.x = 0;
 
212
                   // effect of creation of the dock
 
213
                   Tweener.addTween(this.actor, {
 
214
                       x: primary.x-2*this._spacing,
 
215
                       y: primary.y + (primary.height-height)/2,
 
216
                       time: autohide_animation_time * 3,
 
217
                       transition: 'easeOutQuad'
 
218
                   });
 
219
                   break;
 
220
                case PositionMode.RIGHT:
 
221
                   default:
 
222
                   this.actor.x = primary.width-1;
 
223
                   // effect of creation of the dock
 
224
                   Tweener.addTween(this.actor, {
 
225
                      x: primary.x + primary.width-this._item_size- 2*this._spacing,
 
226
                      y: primary.y + (primary.height-height)/2,
 
227
                      time: autohide_animation_time * 3,
 
228
                      transition: 'easeOutQuad'
 
229
                   });
 
230
        }
 
231
        Tweener.addTween(this.actor,{
 
232
           scale_x: 1,
 
233
           scale_y: 1,
 
234
           time: autohide_animation_time * 3,
 
235
           transition: 'easeOutQuad'
 
236
        });
 
237
        hideDock=false;
 
238
}
 
239
 
 
240
function showEffectAddItem_scale () {
 
241
        let monitor = Main.layoutManager.primaryMonitor;
 
242
        let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
 
243
        let width = this._item_size + 4*this._spacing;
 
244
 
 
245
        Tweener.addTween(this.actor, {
 
246
                y: monitor.y + (monitor.height-height)/2,
 
247
                height: height,
 
248
                width: width,
 
249
                time: autohide_animation_time,
 
250
                transition: 'easeOutQuad'
 
251
        });
 
252
}
 
253
 
 
254
/**************************************************************************************/
 
255
/**** start move Dock functions                                       *****************/
 
256
/**************************************************************************************/
 
257
function hideDock_move () {
 
258
       this._item_size = dockicon_size;
 
259
       let monitor = Main.layoutManager.primaryMonitor;
 
260
       let cornerX = 0;
 
261
       let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
 
262
       let width = this._item_size + 4*this._spacing;
 
263
 
 
264
       switch (position) {
 
265
            case PositionMode.LEFT:
 
266
                cornerX= monitor.x - width + this._spacing;
 
267
                break;
 
268
            case PositionMode.RIGHT:
 
269
            default:
 
270
                cornerX = monitor.x + monitor.width - this._spacing;
 
271
        }
 
272
 
 
273
        if (hideable) {
 
274
               Tweener.addTween(this.actor,{
 
275
                       x: cornerX,
 
276
                       y: monitor.y + (monitor.height - height)/2,
 
277
                       width: width,
 
278
                       height: height,
 
279
                       time: autohide_animation_time,
 
280
                       transition: 'easeOutQuad'
 
281
                     });
 
282
               hideDock=true;
 
283
        }
 
284
}
 
285
 
 
286
function showDock_move () {
 
287
        this._item_size = dockicon_size;
 
288
        let monitor = Main.layoutManager.primaryMonitor;
 
289
        let position_x = monitor.x;
 
290
        let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
 
291
        let width = this._item_size + 4*this._spacing;
 
292
 
 
293
        switch (position) {
 
294
            case PositionMode.LEFT:
 
295
                position_x=monitor.x - 2*this._spacing;
 
296
                break;
 
297
            case PositionMode.RIGHT:
 
298
            default:
 
299
                 position_x=monitor.x + (monitor.width-this._item_size-2*this._spacing);
 
300
        }
 
301
        Tweener.addTween(this.actor, {
 
302
                x: position_x,
 
303
                y: monitor.y + (monitor.height - height)/2,
 
304
                width: width,
 
305
                height: height,
 
306
                time: autohide_animation_time,
 
307
                transition: 'easeOutQuad'
 
308
        });
 
309
        hideDock=false;
 
310
}
 
311
 
 
312
function initShowDock_move () {
 
313
    this._showDock();
 
314
}
 
315
 
 
316
function showEffectAddItem_move () {
 
317
        let monitor = Main.layoutManager.primaryMonitor;
 
318
        let height = this._nicons*(this._item_size + this._spacing) + 2*this._spacing;
 
319
        let width = this._item_size + 4*this._spacing;
 
320
 
 
321
        Tweener.addTween(this.actor, {
 
322
                y: monitor.y + (monitor.height-height)/2,
 
323
                height: height,
 
324
                width: width,
 
325
                time: autohide_animation_time,
 
326
                transition: 'easeOutQuad'
 
327
        });
 
328
}
 
329
 
 
330
function Dock() {
 
331
    this._init();
 
332
}
 
333
 
 
334
Dock.prototype = {
 
335
    _init : function() {
 
336
        this._placeholderText = null;
 
337
        this._menus = [];
 
338
        this._menuDisplays = [];
 
339
 
 
340
        this._favorites = [];
 
341
 
 
342
        // Load Settings
 
343
        position = DOCK_POSITION;
 
344
        dockicon_size = DOCK_SIZE;
 
345
        hideDock = hideable = DOCK_AUTOHIDE;
 
346
        hideEffect = DOCK_EFFECTHIDE;
 
347
        autohide_animation_time = DOCK_AUTOHIDE_ANIMATION_TIME;
 
348
 
 
349
        this._spacing = 4;
 
350
        this._item_size = dockicon_size;
 
351
        this._nicons = 0;
 
352
        this._selectFunctionsHide ();
 
353
 
 
354
        this.actor = new St.BoxLayout({ name: 'dock', vertical: true, reactive: true });
 
355
 
 
356
        this._grid = new Shell.GenericContainer();
 
357
        this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
 
358
        this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
 
359
 
 
360
        this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
 
361
        this._grid.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
 
362
        this._grid.connect('allocate', Lang.bind(this, this._allocate));
 
363
 
 
364
        this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
 
365
 
 
366
        this._tracker = Shell.WindowTracker.get_default();
 
367
        this._appSystem = Shell.AppSystem.get_default();
 
368
 
 
369
        this._installedChangedId = this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
 
370
        this._appFavoritesChangedId = AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._queueRedisplay));
 
371
        this._appStateChangedId = this._appSystem.connect('app-state-changed', Lang.bind(this, this._queueRedisplay));
 
372
 
 
373
        this._overviewShowingId = Main.overview.connect('showing', Lang.bind(this, function() {
 
374
            this.actor.hide();
 
375
        }));
 
376
        this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this, function() {
 
377
            this.actor.show();
 
378
        }));
 
379
        Main.layoutManager.addChrome(this.actor);
 
380
 
 
381
        this._leave_event = this.actor.connect('leave-event', Lang.bind(this, this._hideDock));
 
382
        this._enter_event = this.actor.connect('enter-event', Lang.bind(this, this._showDock));
 
383
 
 
384
        this._hideDock();
 
385
    },
 
386
 
 
387
    destroy: function() {
 
388
        if (this._installedChangedId) {
 
389
            this._appSystem.disconnect(this._installedChangedId);
 
390
            this._installedChangedId = 0;
 
391
        }
 
392
 
 
393
        if (this._appFavoritesChangedId) {
 
394
            AppFavorites.getAppFavorites().disconnect(this._appFavoritesChangedId);
 
395
            this._appFavoritesChangedId = 0;
 
396
        }
 
397
 
 
398
        if (this._appStateChangedId) {
 
399
            this._appSystem.disconnect(this._appStateChangedId);
 
400
            this._appStateChangedId = 0;
 
401
        }
 
402
 
 
403
        if (this._overviewShowingId) {
 
404
            Main.overview.disconnect(this._overviewShowingId);
 
405
            this._overviewShowingId = 0;
 
406
        }
 
407
 
 
408
        if (this._overviewHiddenId) {
 
409
            Main.overview.disconnect(this._overviewHiddenId);
 
410
            this._overviewHiddenId = 0;
 
411
        }
 
412
 
 
413
        this.actor.destroy();
 
414
 
 
415
        // Break reference cycles
 
416
        this._appSystem = null;
 
417
        this._tracker = null;
 
418
    },
 
419
 
 
420
    // fuctions hide
 
421
    _restoreHideDock: function(){
 
422
        hideable = DOCK_AUTOHIDE;
 
423
    },
 
424
 
 
425
    _disableHideDock: function (){
 
426
        hideable = false;
 
427
    },
 
428
 
 
429
    _selectFunctionsHide: function () {
 
430
        switch (hideEffect) {
 
431
        case AutoHideEffect.RESCALE:
 
432
            this._hideDock = hideDock_scale;
 
433
            this._showDock = showDock_scale;
 
434
            this._initShowDock = initShowDock_scale;
 
435
            this._showEffectAddItem = showEffectAddItem_scale;
 
436
            break;
 
437
        case AutoHideEffect.MOVE:
 
438
            this._hideDock = hideDock_move;
 
439
            this._showDock = showDock_move;
 
440
            this._initShowDock = initShowDock_move;
 
441
            this._showEffectAddItem = showEffectAddItem_move;
 
442
            break;
 
443
        case AutoHideEffect.RESIZE:
 
444
        default:
 
445
            this._hideDock = hideDock_size;
 
446
            this._showDock = showDock_size;
 
447
            this._initShowDock = initShowDock_size;
 
448
            this._showEffectAddItem = showEffectAddItem_size;
 
449
        }
 
450
    },
 
451
 
 
452
    _appIdListToHash: function(apps) {
 
453
        let ids = {};
 
454
        for (let i = 0; i < apps.length; i++)
 
455
            ids[apps[i].get_id()] = apps[i];
 
456
        return ids;
 
457
    },
 
458
 
 
459
    _queueRedisplay: function () {
 
460
        Main.queueDeferredWork(this._workId);
 
461
    },
 
462
 
 
463
    _redisplay: function () {
 
464
        this.removeAll();
 
465
 
 
466
        let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
 
467
 
 
468
        let running = this._appSystem.get_running();
 
469
        let runningIds = this._appIdListToHash(running);
 
470
 
 
471
        let icons = 0;
 
472
 
 
473
        let nFavorites = 0;
 
474
        for (let id in favorites) {
 
475
            let app = favorites[id];
 
476
            let display = new DockIcon(app,this);
 
477
            this.addItem(display.actor);
 
478
            nFavorites++;
 
479
            icons++;
 
480
        }
 
481
 
 
482
        for (let i = 0; i < running.length; i++) {
 
483
            let app = running[i];
 
484
            if (app.get_id() in favorites)
 
485
                continue;
 
486
            let display = new DockIcon(app,this);
 
487
            icons++;
 
488
            this.addItem(display.actor);
 
489
        }
 
490
        this._nicons=icons;
 
491
 
 
492
        if (this._placeholderText) {
 
493
            this._placeholderText.destroy();
 
494
            this._placeholderText = null;
 
495
        }
 
496
 
 
497
        if (running.length == 0 && nFavorites == 0) {
 
498
            this._placeholderText = new St.Label({ text: _("Drag here to add favorites") });
 
499
            this.actor.add_actor(this._placeholderText);
 
500
        }
 
501
 
 
502
        let primary = Main.layoutManager.primaryMonitor;
 
503
        let height = (icons)*(this._item_size + this._spacing) + 2*this._spacing;
 
504
        let width = this._item_size + 4*this._spacing;
 
505
 
 
506
        if (this.actor.y != primary.y) {
 
507
                if (hideable && hideDock) {
 
508
                        this._hideDock();
 
509
                } else {
 
510
                   if (dockicon_size == this._item_size) {
 
511
                        // only add/delete icon
 
512
                        this._showEffectAddItem ();
 
513
                    } else {
 
514
                        // change size icon
 
515
                        this._showDock ();
 
516
                    }
 
517
                }
 
518
        } else {
 
519
                // effect of creation
 
520
                this._initShowDock ();
 
521
        }
 
522
    },
 
523
 
 
524
    _getPreferredWidth: function (grid, forHeight, alloc) {
 
525
        alloc.min_size = this._item_size;
 
526
        alloc.natural_size = this._item_size + this._spacing;
 
527
    },
 
528
 
 
529
    _getPreferredHeight: function (grid, forWidth, alloc) {
 
530
        let children = this._grid.get_children();
 
531
        let nRows = children.length;
 
532
        let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
 
533
        let height = nRows * this._item_size + totalSpacing;
 
534
        alloc.min_size = height;
 
535
        alloc.natural_size = height;
 
536
    },
 
537
 
 
538
    _allocate: function (grid, box, flags) {
 
539
        let children = this._grid.get_children();
 
540
 
 
541
        let x = box.x1 + this._spacing;
 
542
        if (position == PositionMode.LEFT)
 
543
            x = box.x1 + 2*this._spacing;
 
544
        let y = box.y1 + this._spacing;
 
545
 
 
546
        for (let i = 0; i < children.length; i++) {
 
547
            let childBox = new Clutter.ActorBox();
 
548
            childBox.x1 = x;
 
549
            childBox.y1 = y;
 
550
            childBox.x2 = childBox.x1 + this._item_size;
 
551
            childBox.y2 = childBox.y1 + this._item_size;
 
552
            children[i].allocate(childBox, flags);
 
553
            y += this._item_size + this._spacing;
 
554
        }
 
555
    },
 
556
 
 
557
 
 
558
    _onStyleChanged: function() {
 
559
        let themeNode = this.actor.get_theme_node();
 
560
        let [success, len] = themeNode.get_length('spacing', false);
 
561
        if (success)
 
562
            this._spacing = len;
 
563
        [success, len] = themeNode.get_length('-shell-grid-item-size', false);
 
564
        if (success)
 
565
            this._item_size = len;
 
566
        this._grid.queue_relayout();
 
567
    },
 
568
 
 
569
    removeAll: function () {
 
570
        this._grid.get_children().forEach(Lang.bind(this, function (child) {
 
571
            child.destroy();
 
572
        }));
 
573
    },
 
574
 
 
575
    addItem: function(actor) {
 
576
        this._grid.add_actor(actor);
 
577
    }
 
578
};
 
579
Signals.addSignalMethods(Dock.prototype);
 
580
 
 
581
function DockIcon(app, dock) {
 
582
    this._init(app, dock);
 
583
}
 
584
 
 
585
DockIcon.prototype = {
 
586
    _init : function(app, dock) {
 
587
        this.app = app;
 
588
        this.actor = new St.Button({ style_class: 'dock-app',
 
589
                                     button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
 
590
                                     reactive: true,
 
591
                                     x_fill: true,
 
592
                                     y_fill: true });
 
593
        this.actor._delegate = this;
 
594
        this.actor.set_size(dockicon_size, dockicon_size);
 
595
 
 
596
        this._icon = this.app.create_icon_texture(dockicon_size);
 
597
        this.actor.set_child(this._icon);
 
598
 
 
599
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 
600
 
 
601
        this._menu = null;
 
602
        this._menuManager = new PopupMenu.PopupMenuManager(this);
 
603
 
 
604
        this._has_focus = false;
 
605
 
 
606
        let tracker = Shell.WindowTracker.get_default();
 
607
        tracker.connect('notify::focus-app', Lang.bind(this, this._onStateChanged));
 
608
 
 
609
        this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
 
610
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 
611
        this.actor.connect('notify::hover', Lang.bind(this, this._hoverChanged));
 
612
 
 
613
        this._menuTimeoutId = 0;
 
614
        this._stateChangedId = this.app.connect('notify::state',
 
615
                                                Lang.bind(this, this._onStateChanged));
 
616
        this._onStateChanged();
 
617
        this._dock=dock;
 
618
    },
 
619
 
 
620
    _onDestroy: function() {
 
621
        if (this._stateChangedId > 0)
 
622
            this.app.disconnect(this._stateChangedId);
 
623
        this._stateChangedId = 0;
 
624
        this._removeMenuTimeout();
 
625
    },
 
626
 
 
627
    _removeMenuTimeout: function() {
 
628
        if (this._menuTimeoutId > 0) {
 
629
            Mainloop.source_remove(this._menuTimeoutId);
 
630
            this._menuTimeoutId = 0;
 
631
        }
 
632
    },
 
633
 
 
634
    _hoverChanged: function(actor) {
 
635
        if (actor != this.actor)
 
636
            this._has_focus = false;
 
637
        else
 
638
            this._has_focus = true;
 
639
        return false;
 
640
    },
 
641
 
 
642
    _onStateChanged: function() {
 
643
        let tracker = Shell.WindowTracker.get_default();
 
644
        let focusedApp = tracker.focus_app;
 
645
        if (this.app.state != Shell.AppState.STOPPED) {
 
646
            this.actor.add_style_class_name('running');
 
647
            if (this.app == focusedApp) {
 
648
                this.actor.add_style_class_name('focused');
 
649
            } else {
 
650
                this.actor.remove_style_class_name('focused');
 
651
            }
 
652
        } else {
 
653
            this.actor.remove_style_class_name('focused');
 
654
            this.actor.remove_style_class_name('running');
 
655
        }
 
656
    },
 
657
 
 
658
    _onButtonPress: function(actor, event) {
 
659
        let button = event.get_button();
 
660
        if (button == 1) {
 
661
            this._removeMenuTimeout();
 
662
            this._menuTimeoutId = Mainloop.timeout_add(AppDisplay.MENU_POPUP_TIMEOUT, Lang.bind(this, function() {
 
663
                this.popupMenu();
 
664
            }));
 
665
        } else if (button == 3) {
 
666
            this.popupMenu();
 
667
        }
 
668
    },
 
669
 
 
670
    _onClicked: function(actor, button) {
 
671
        this._removeMenuTimeout();
 
672
 
 
673
        if (button == 1) {
 
674
            this._onActivate(Clutter.get_current_event());
 
675
        } else if (button == 2) {
 
676
            // Last workspace is always empty
 
677
            let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1);
 
678
            launchWorkspace.activate(global.get_current_time());
 
679
            this.emit('launching');
 
680
            this.app.open_new_window(-1);
 
681
        }
 
682
        return false;
 
683
    },
 
684
 
 
685
    getId: function() {
 
686
        return this.app.get_id();
 
687
    },
 
688
 
 
689
    popupMenu: function() {
 
690
        this._removeMenuTimeout();
 
691
        this.actor.fake_release();
 
692
 
 
693
        this._dock._disableHideDock();
 
694
 
 
695
        if (!this._menu) {
 
696
            this._menu = new DockIconMenu(this);
 
697
            this._menu.connect('activate-window', Lang.bind(this, function (menu, window) {
 
698
                this.activateWindow(window);
 
699
            }));
 
700
            this._menu.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) {
 
701
                if (!isPoppedUp){
 
702
                    //Restore value of autohidedock
 
703
                    this._dock._restoreHideDock();
 
704
                    this._dock._hideDock();
 
705
 
 
706
                    this._onMenuPoppedDown();
 
707
                }
 
708
            }));
 
709
 
 
710
            this._menuManager.addMenu(this._menu, true);
 
711
        }
 
712
 
 
713
        this._menu.popup();
 
714
 
 
715
        return false;
 
716
    },
 
717
 
 
718
    activateWindow: function(metaWindow) {
 
719
        if (metaWindow) {
 
720
            this._didActivateWindow = true;
 
721
            Main.activateWindow(metaWindow);
 
722
        }
 
723
    },
 
724
 
 
725
    setSelected: function (isSelected) {
 
726
        this._selected = isSelected;
 
727
        if (this._selected)
 
728
            this.actor.add_style_class_name('selected');
 
729
        else
 
730
            this.actor.remove_style_class_name('selected');
 
731
    },
 
732
 
 
733
    _onMenuPoppedDown: function() {
 
734
        this.actor.sync_hover();
 
735
    },
 
736
 
 
737
    _getRunning: function() {
 
738
        return this.app.state != Shell.AppState.STOPPED;
 
739
    },
 
740
 
 
741
    _onActivate: function (event) {
 
742
        this.emit('launching');
 
743
        let modifiers = Shell.get_event_state(event);
 
744
 
 
745
        if (modifiers & Clutter.ModifierType.CONTROL_MASK
 
746
            && this.app.state == Shell.AppState.RUNNING) {
 
747
            let current_workspace = global.screen.get_active_workspace().index();
 
748
            this.app.open_new_window(current_workspace);
 
749
        } else {
 
750
            let tracker = Shell.WindowTracker.get_default();
 
751
            let focusedApp = tracker.focus_app;
 
752
 
 
753
            if (this.app == focusedApp) {
 
754
                let windows = this.app.get_windows();
 
755
                let current_workspace = global.screen.get_active_workspace();
 
756
                for (let i = 0; i < windows.length; i++) {
 
757
                    let w = windows[i];
 
758
                    if (w.get_workspace() == current_workspace)
 
759
                        w.minimize();
 
760
                }
 
761
            } else {
 
762
                this.app.activate(-1);
 
763
            }
 
764
        }
 
765
        Main.overview.hide();
 
766
    },
 
767
 
 
768
    shellWorkspaceLaunch : function() {
 
769
        this.app.open_new_window();
 
770
    }
 
771
};
 
772
Signals.addSignalMethods(DockIcon.prototype);
 
773
 
 
774
function DockIconMenu(source) {
 
775
    this._init(source);
 
776
}
 
777
 
 
778
DockIconMenu.prototype = {
 
779
    __proto__: AppDisplay.AppIconMenu.prototype,
 
780
 
 
781
    _init: function(source) {
 
782
        switch (position) {
 
783
            case PositionMode.LEFT:
 
784
                PopupMenu.PopupMenu.prototype._init.call(this, source.actor, St.Align.MIDDLE, St.Side.LEFT, 0);
 
785
                break;
 
786
            case PositionMode.RIGHT:
 
787
            default:
 
788
                PopupMenu.PopupMenu.prototype._init.call(this, source.actor, St.Align.MIDDLE, St.Side.RIGHT, 0);
 
789
        }
 
790
 
 
791
        this._source = source;
 
792
 
 
793
        this.connect('activate', Lang.bind(this, this._onActivate));
 
794
 
 
795
        this.actor.add_style_class_name('dock-menu');
 
796
 
 
797
        // Chain our visibility and lifecycle to that of the source
 
798
        source.actor.connect('notify::mapped', Lang.bind(this, function () {
 
799
            if (!source.actor.mapped)
 
800
                this.close();
 
801
        }));
 
802
        source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
 
803
 
 
804
        Main.layoutManager.addChrome(this.actor);
 
805
    },
 
806
 
 
807
    _redisplay: function() {
 
808
        this.removeAll();
 
809
 
 
810
        let windows = this._source.app.get_windows();
 
811
 
 
812
        // Display the app windows menu items and the separator between windows
 
813
        // of the current desktop and other windows.
 
814
        let activeWorkspace = global.screen.get_active_workspace();
 
815
        let separatorShown = windows.length > 0 && windows[0].get_workspace() != activeWorkspace;
 
816
 
 
817
        for (let i = 0; i < windows.length; i++) {
 
818
            if (!separatorShown && windows[i].get_workspace() != activeWorkspace) {
 
819
                this._appendSeparator();
 
820
                separatorShown = true;
 
821
            }
 
822
            let item = this._appendMenuItem(windows[i].title);
 
823
            item._window = windows[i];
 
824
        }
 
825
 
 
826
        if (windows.length > 0)
 
827
            this._appendSeparator();
 
828
 
 
829
        let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
 
830
 
 
831
        this._newWindowMenuItem = windows.length > 0 ? this._appendMenuItem(_("New Window")) : null;
 
832
 
 
833
        this._quitAppMenuItem = windows.length >0 ? this._appendMenuItem(_("Quit Application")) : null;
 
834
 
 
835
        if (windows.length > 0)
 
836
            this._appendSeparator();
 
837
        this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ?
 
838
                                                            _("Remove from Favorites")
 
839
                                                            : _("Add to Favorites"));
 
840
 
 
841
        this._highlightedItem = null;
 
842
    },
 
843
 
 
844
    _onActivate: function (actor, child) {
 
845
        if (child._window) {
 
846
            let metaWindow = child._window;
 
847
            this.emit('activate-window', metaWindow);
 
848
        } else if (child == this._newWindowMenuItem) {
 
849
            let current_workspace = global.screen.get_active_workspace().index();
 
850
            this._source.app.open_new_window(current_workspace);
 
851
            this.emit('activate-window', null);
 
852
        } else if (child == this._quitAppMenuItem) {
 
853
            this._source.app.request_quit();
 
854
        } else if (child == this._toggleFavoriteMenuItem) {
 
855
            let favs = AppFavorites.getAppFavorites();
 
856
            let isFavorite = favs.isFavorite(this._source.app.get_id());
 
857
            if (isFavorite)
 
858
                favs.removeFavorite(this._source.app.get_id());
 
859
            else
 
860
                favs.addFavorite(this._source.app.get_id());
 
861
        }
 
862
        this.close();
 
863
    }
 
864
}
 
865
 
 
866
function init(extensionMeta) {
 
867
    imports.gettext.bindtextdomain('gnome-shell-extensions', GLib.build_filenamev([extensionMeta.path, 'locale']));
 
868
}
 
869
 
 
870
let dock;
 
871
 
 
872
function enable() {
 
873
    dock = new Dock();
 
874
}
 
875
 
 
876
function disable() {
 
877
    dock.destroy();
 
878
    dock = null;
 
879
}