~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/native-window-placement/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; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
 
2
// import just everything from workspace.js:
 
3
const Clutter = imports.gi.Clutter;
 
4
const Gio = imports.gi.Gio;
 
5
const Lang = imports.lang;
 
6
const Mainloop = imports.mainloop;
 
7
const Meta = imports.gi.Meta;
 
8
const Pango = imports.gi.Pango;
 
9
const Shell = imports.gi.Shell;
 
10
const St = imports.gi.St;
 
11
const Signals = imports.signals;
 
12
 
 
13
const DND = imports.ui.dnd;
 
14
const Lightbox = imports.ui.lightbox;
 
15
const Main = imports.ui.main;
 
16
const Overview = imports.ui.overview;
 
17
const Panel = imports.ui.panel;
 
18
const Tweener = imports.ui.tweener;
 
19
 
 
20
const Workspace = imports.ui.workspace;
 
21
const WindowPositionFlags = Workspace.WindowPositionFlags;
 
22
 
 
23
const WindowPlacementStrategy = {
 
24
    NATURAL: 0,
 
25
    GRID: 1,
 
26
};
 
27
 
 
28
/* Begin user settings */
 
29
const PLACEMENT_STRATEGY = WindowPlacementStrategy.NATURAL;
 
30
const USE_MORE_SCREEN = true;
 
31
const WINDOW_CAPTIONS_ON_TOP = true;
 
32
/* End user settings - do not change anything below this line */
 
33
 
 
34
// testing settings for natural window placement strategy:
 
35
const WINDOW_PLACEMENT_NATURAL_FILLGAPS = true;                     // enlarge windows at the end to fill gaps         // not implemented yet
 
36
const WINDOW_PLACEMENT_NATURAL_GRID_FALLBACK = true;                // fallback to grid mode if all windows have the same size and positions.     // not implemented yet
 
37
const WINDOW_PLACEMENT_NATURAL_ACCURACY = 20;                       // accuracy of window translate moves  (KDE-default: 20)
 
38
const WINDOW_PLACEMENT_NATURAL_GAPS = 5;                            // half of the minimum gap between windows
 
39
const WINDOW_PLACEMENT_NATURAL_MAX_TRANSLATIONS = 5000;             // safety limit for preventing endless loop if something is wrong in the algorithm
 
40
 
 
41
const PLACE_WINDOW_CAPTIONS_ON_TOP = true;                          // place window titles in overview on top of windows with overlap parameter
 
42
 
 
43
function injectToFunction(parent, name, func) {
 
44
    let origin = parent[name];
 
45
    parent[name] = function() {
 
46
        let ret;
 
47
        ret = origin.apply(this, arguments);
 
48
        if (ret === undefined)
 
49
            ret = func.apply(this, arguments);
 
50
        return ret;
 
51
    }
 
52
}
 
53
const WORKSPACE_BORDER_GAP = 10;                                    // gap between the workspace area and the workspace selector
 
54
 
 
55
function Rect(x, y, width, height) {
 
56
    [this.x, this.y, this.width, this.height] = arguments;
 
57
}
 
58
 
 
59
Rect.prototype = {
 
60
    /**
 
61
     * used in _calculateWindowTransformationsNatural to replace Meta.Rectangle that is too slow.
 
62
     */
 
63
 
 
64
    copy: function() {
 
65
        return new Rect(this.x, this.y, this.width, this.height);
 
66
    },
 
67
 
 
68
    union: function(rect2) {
 
69
        let dest = this.copy();
 
70
        if (rect2.x < dest.x)
 
71
          {
 
72
            dest.width += dest.x - rect2.x;
 
73
            dest.x = rect2.x;
 
74
          }
 
75
        if (rect2.y < dest.y)
 
76
          {
 
77
            dest.height += dest.y - rect2.y;
 
78
            dest.y = rect2.y;
 
79
          }
 
80
        if (rect2.x + rect2.width > dest.x + dest.width)
 
81
          dest.width = rect2.x + rect2.width - dest.x;
 
82
        if (rect2.y + rect2.height > dest.y + dest.height)
 
83
          dest.height = rect2.y + rect2.height - dest.y;
 
84
 
 
85
        return dest;
 
86
    },
 
87
 
 
88
    adjusted: function(dx, dy, dx2, dy2) {
 
89
        let dest = this.copy();
 
90
        dest.x += dx;
 
91
        dest.y += dy;
 
92
        dest.width += -dx + dx2;
 
93
        dest.height += -dy + dy2;
 
94
        return dest;
 
95
    },
 
96
 
 
97
    overlap: function(rect2) {
 
98
        return !((this.x + this.width    <= rect2.x) ||
 
99
                 (rect2.x + rect2.width  <= this.x) ||
 
100
                 (this.y + this.height   <= rect2.y) ||
 
101
                 (rect2.y + rect2.height <= this.y));
 
102
    },
 
103
 
 
104
    center: function() {
 
105
        return [this.x + this.width / 2, this.y + this.height / 2];
 
106
    },
 
107
 
 
108
    translate: function(dx, dy) {
 
109
        this.x += dx;
 
110
        this.y += dy;
 
111
    }
 
112
};
 
113
 
 
114
let winInjections, workspaceInjections, connectedSignals;
 
115
 
 
116
function resetState() {
 
117
    winInjections = { };
 
118
    workspaceInjections = { };
 
119
    workViewInjections = { };
 
120
    connectedSignals = [ ];
 
121
}
 
122
 
 
123
function enable() {
 
124
    resetState();
 
125
 
 
126
    let placementStrategy = PLACEMENT_STRATEGY;
 
127
    let useMoreScreen = USE_MORE_SCREEN;
 
128
 
 
129
    /**
 
130
     * _calculateWindowTransformationsNatural:
 
131
     * @clones: Array of #MetaWindow
 
132
     *
 
133
     * Returns clones with matching target coordinates and scales to arrange windows in a natural way that no overlap exists and relative window size is preserved.
 
134
     * This function is almost a 1:1 copy of the function
 
135
     * PresentWindowsEffect::calculateWindowTransformationsNatural() from KDE, see:
 
136
     * https://projects.kde.org/projects/kde/kdebase/kde-workspace/repository/revisions/master/entry/kwin/effects/presentwindows/presentwindows.cpp
 
137
     */
 
138
    Workspace.Workspace.prototype._calculateWindowTransformationsNatural = function(clones) {
 
139
        // As we are using pseudo-random movement (See "slot") we need to make sure the list
 
140
        // is always sorted the same way no matter which window is currently active.
 
141
        clones = clones.sort(function (win1, win2) {
 
142
            return win2.metaWindow.get_stable_sequence() - win1.metaWindow.get_stable_sequence();
 
143
        });
 
144
 
 
145
        // Put a gap on the right edge of the workspace to separe it from the workspace selector
 
146
        let x_gap = WORKSPACE_BORDER_GAP;
 
147
        let y_gap = WORKSPACE_BORDER_GAP * this._height / this._width
 
148
        let area = new Rect(this._x, this._y, this._width - x_gap, this._height - y_gap);
 
149
 
 
150
        let bounds = area.copy();
 
151
 
 
152
        let direction = 0;
 
153
        let directions = [];
 
154
        let rects = [];
 
155
        for (let i = 0; i < clones.length; i++) {
 
156
            // save rectangles into 4-dimensional arrays representing two corners of the rectangular: [left_x, top_y, right_x, bottom_y]
 
157
            let rect = clones[i].metaWindow.get_outer_rect();
 
158
            rects[i] = new Rect(rect.x, rect.y, rect.width, rect.height);
 
159
            bounds = bounds.union(rects[i]);
 
160
 
 
161
            // This is used when the window is on the edge of the screen to try to use as much screen real estate as possible.
 
162
            directions[i] = direction;
 
163
            direction++;
 
164
            if (direction == 4) {
 
165
                direction = 0;
 
166
            }
 
167
        }
 
168
 
 
169
        let loop_counter = 0;
 
170
        let overlap;
 
171
        do {
 
172
            overlap = false;
 
173
            for (let i = 0; i < rects.length; i++) {
 
174
                for (let j = 0; j < rects.length; j++) {
 
175
                    if (i != j && rects[i].adjusted(-WINDOW_PLACEMENT_NATURAL_GAPS, -WINDOW_PLACEMENT_NATURAL_GAPS,
 
176
                                                    WINDOW_PLACEMENT_NATURAL_GAPS, WINDOW_PLACEMENT_NATURAL_GAPS).overlap(
 
177
                                                     rects[j].adjusted(-WINDOW_PLACEMENT_NATURAL_GAPS, -WINDOW_PLACEMENT_NATURAL_GAPS,
 
178
                                                                       WINDOW_PLACEMENT_NATURAL_GAPS, WINDOW_PLACEMENT_NATURAL_GAPS))) {
 
179
                        loop_counter++;
 
180
                        overlap = true;
 
181
 
 
182
                        // TODO: something like a Point2D would be nicer here:
 
183
 
 
184
                        // Determine pushing direction
 
185
                        let i_center = rects[i].center();
 
186
                        let j_center = rects[j].center();
 
187
                        let diff = [j_center[0] - i_center[0], j_center[1] - i_center[1]];
 
188
 
 
189
                        // Prevent dividing by zero and non-movement
 
190
                        if (diff[0] == 0 && diff[1] == 0)
 
191
                            diff[0] = 1;
 
192
                        // Try to keep screen/workspace aspect ratio
 
193
                        if ( bounds.height / bounds.width > area.height / area.width )
 
194
                            diff[0] *= 2;
 
195
                        else
 
196
                            diff[1] *= 2;
 
197
 
 
198
                        // Approximate a vector of between 10px and 20px in magnitude in the same direction
 
199
                        let length = Math.sqrt(diff[0] * diff[0] + diff[1] * diff[1]);
 
200
                        diff[0] = diff[0] * WINDOW_PLACEMENT_NATURAL_ACCURACY / length;
 
201
                        diff[1] = diff[1] * WINDOW_PLACEMENT_NATURAL_ACCURACY / length;
 
202
 
 
203
                        // Move both windows apart
 
204
                        rects[i].translate(-diff[0], -diff[1]);
 
205
                        rects[j].translate(diff[0], diff[1]);
 
206
 
 
207
 
 
208
                        if (useMoreScreen) {
 
209
                            // Try to keep the bounding rect the same aspect as the screen so that more
 
210
                            // screen real estate is utilised. We do this by splitting the screen into nine
 
211
                            // equal sections, if the window center is in any of the corner sections pull the
 
212
                            // window towards the outer corner. If it is in any of the other edge sections
 
213
                            // alternate between each corner on that edge. We don't want to determine it
 
214
                            // randomly as it will not produce consistant locations when using the filter.
 
215
                            // Only move one window so we don't cause large amounts of unnecessary zooming
 
216
                            // in some situations. We need to do this even when expanding later just in case
 
217
                            // all windows are the same size.
 
218
                            // (We are using an old bounding rect for this, hopefully it doesn't matter)
 
219
                            let xSection = Math.round((rects[i].x - bounds.x) / (bounds.width / 3));
 
220
                            let ySection = Math.round((rects[i].y - bounds.y) / (bounds.height / 3));
 
221
 
 
222
                            let i_center = rects[i].center();
 
223
                            diff[0] = 0;
 
224
                            diff[1] = 0;
 
225
                            if (xSection != 1 || ySection != 1) { // Remove this if you want the center to pull as well
 
226
                                if (xSection == 1)
 
227
                                    xSection = (directions[i] / 2 ? 2 : 0);
 
228
                                if (ySection == 1)
 
229
                                    ySection = (directions[i] % 2 ? 2 : 0);
 
230
                            }
 
231
                            if (xSection == 0 && ySection == 0) {
 
232
                                diff[0] = bounds.x - i_center[0];
 
233
                                diff[1] = bounds.y - i_center[1];
 
234
                            }
 
235
                            if (xSection == 2 && ySection == 0) {
 
236
                                diff[0] = bounds.x + bounds.width - i_center[0];
 
237
                                diff[1] = bounds.y - i_center[1];
 
238
                            }
 
239
                            if (xSection == 2 && ySection == 2) {
 
240
                                diff[0] = bounds.x + bounds.width - i_center[0];
 
241
                                diff[1] = bounds.y + bounds.height - i_center[1];
 
242
                            }
 
243
                            if (xSection == 0 && ySection == 2) {
 
244
                                diff[0] = bounds.x - i_center[0];
 
245
                                diff[1] = bounds.y + bounds.height - i_center[1];
 
246
                            }
 
247
                            if (diff[0] != 0 || diff[1] != 0) {
 
248
                                let length = Math.sqrt(diff[0]*diff[0] + diff[1]*diff[1]);
 
249
                                diff[0] *= WINDOW_PLACEMENT_NATURAL_ACCURACY / length / 2;   // /2 to make it less influencing than the normal center-move above
 
250
                                diff[1] *= WINDOW_PLACEMENT_NATURAL_ACCURACY / length / 2;
 
251
                                rects[i].translate(diff[0], diff[1]);
 
252
                            }
 
253
                        }
 
254
 
 
255
                        // Update bounding rect
 
256
                        bounds = bounds.union(rects[i]);
 
257
                        bounds = bounds.union(rects[j]);
 
258
                    }
 
259
                }
 
260
            }
 
261
        } while (overlap && loop_counter < WINDOW_PLACEMENT_NATURAL_MAX_TRANSLATIONS);
 
262
 
 
263
        // Work out scaling by getting the most top-left and most bottom-right window coords.
 
264
        let scale;
 
265
        scale = Math.min(area.width / bounds.width,
 
266
                         area.height / bounds.height,
 
267
                         1.0);
 
268
 
 
269
        // Make bounding rect fill the screen size for later steps
 
270
        bounds.x = bounds.x - (area.width - bounds.width * scale) / 2;
 
271
        bounds.y = bounds.y - (area.height - bounds.height * scale) / 2;
 
272
        bounds.width = area.width / scale;
 
273
        bounds.height = area.height / scale;
 
274
 
 
275
        // Move all windows back onto the screen and set their scale
 
276
        for (let i = 0; i < rects.length; i++) {
 
277
            rects[i].translate(-bounds.x, -bounds.y);
 
278
        }
 
279
 
 
280
        // TODO: Implement the KDE part "Try to fill the gaps by enlarging windows if they have the space" here. (If this is wanted)
 
281
 
 
282
        // rescale to workspace
 
283
        let scales = [];
 
284
 
 
285
        let buttonOuterHeight, captionHeight;
 
286
        let buttonOuterWidth = 0;
 
287
 
 
288
        let targets = [];
 
289
        for (let i = 0; i < rects.length; i++) {
 
290
            rects[i].x = rects[i].x * scale + this._x;
 
291
            rects[i].y = rects[i].y * scale + this._y;
 
292
 
 
293
            targets[i] = [rects[i].x, rects[i].y, scale];
 
294
        }
 
295
 
 
296
        return [clones, targets];
 
297
    }
 
298
    workspaceInjections['_calculateWindowTransformationsNatural'] = undefined;
 
299
 
 
300
    /**
 
301
     * _calculateWindowTransformationsGrid:
 
302
     * @clones: Array of #MetaWindow
 
303
     *
 
304
     * Returns clones with matching target coordinates and scales to arrange windows in a grid.
 
305
     */
 
306
    Workspace.Workspace.prototype._calculateWindowTransformationsGrid = function(clones) {
 
307
        let slots = this._computeAllWindowSlots(clones.length);
 
308
        clones = this._orderWindowsByMotionAndStartup(clones, slots);
 
309
        let targets = [];
 
310
 
 
311
        for (let i = 0; i < clones.length; i++) {
 
312
            targets[i] = this._computeWindowLayout(clones[i].metaWindow, slots[i]);
 
313
        }
 
314
 
 
315
        return [clones, targets];
 
316
    }
 
317
    workspaceInjections['_calculateWindowTransformationsGrid'] = undefined;
 
318
 
 
319
    /**
 
320
     * positionWindows:
 
321
     * @flags:
 
322
     *  INITIAL - this is the initial positioning of the windows.
 
323
     *  ANIMATE - Indicates that we need animate changing position.
 
324
     */
 
325
    workspaceInjections['positionWindows'] = Workspace.Workspace.prototype.positionWindows;
 
326
    Workspace.Workspace.prototype.positionWindows = function(flags) {
 
327
        if (this._repositionWindowsId > 0) {
 
328
            Mainloop.source_remove(this._repositionWindowsId);
 
329
            this._repositionWindowsId = 0;
 
330
        }
 
331
 
 
332
        let clones = this._windows.slice();
 
333
        if (this._reservedSlot)
 
334
            clones.push(this._reservedSlot);
 
335
 
 
336
        let initialPositioning = flags & WindowPositionFlags.INITIAL;
 
337
        let animate = flags & WindowPositionFlags.ANIMATE;
 
338
 
 
339
        // Start the animations
 
340
        let targets = [];
 
341
        let scales = [];
 
342
 
 
343
        switch (placementStrategy) {
 
344
        case WindowPlacementStrategy.NATURAL:
 
345
            [clones, targets] = this._calculateWindowTransformationsNatural(clones);
 
346
            break;
 
347
        default:
 
348
            log ('Invalid window placement strategy');
 
349
            placementStrategy = WindowPlacementStrategy.GRID;
 
350
        case WindowPlacementStrategy.GRID:
 
351
            [clones, targets] = this._calculateWindowTransformationsGrid(clones);
 
352
            break;
 
353
        }
 
354
 
 
355
        let currentWorkspace = global.screen.get_active_workspace();
 
356
        let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
 
357
 
 
358
        for (let i = 0; i < clones.length; i++) {
 
359
            let clone = clones[i];
 
360
            let [x, y , scale] = targets[i];
 
361
            let metaWindow = clone.metaWindow;
 
362
            let mainIndex = this._lookupIndex(metaWindow);
 
363
            let overlay = this._windowOverlays[mainIndex];
 
364
 
 
365
            // Positioning a window currently being dragged must be avoided;
 
366
            // we'll just leave a blank spot in the layout for it.
 
367
            if (clone.inDrag)
 
368
                continue;
 
369
 
 
370
            if (overlay)
 
371
                overlay.hide();
 
372
            if (animate && isOnCurrentWorkspace) {
 
373
                if (!metaWindow.showing_on_its_workspace()) {
 
374
                    /* Hidden windows should fade in and grow
 
375
                     * therefore we need to resize them now so they
 
376
                     * can be scaled up later */
 
377
                    if (initialPositioning) {
 
378
                        clone.actor.opacity = 0;
 
379
                        clone.actor.scale_x = 0;
 
380
                        clone.actor.scale_y = 0;
 
381
                        clone.actor.x = x;
 
382
                        clone.actor.y = y;
 
383
                    }
 
384
 
 
385
                    // Make the window slightly transparent to indicate it's hidden
 
386
                    Tweener.addTween(clone.actor,
 
387
                                     { opacity: 255,
 
388
                                       time: Overview.ANIMATION_TIME,
 
389
                                       transition: 'easeInQuad'
 
390
                                     });
 
391
                }
 
392
 
 
393
                Tweener.addTween(clone.actor,
 
394
                                 { x: x,
 
395
                                   y: y,
 
396
                                   scale_x: scale,
 
397
                                   scale_y: scale,
 
398
                                   time: Overview.ANIMATION_TIME,
 
399
                                   transition: 'easeOutQuad',
 
400
                                   onComplete: Lang.bind(this, function() {
 
401
                                       this._showWindowOverlay(clone, overlay, true);
 
402
                                   })
 
403
                                 });
 
404
            } else {
 
405
                clone.actor.set_position(x, y);
 
406
                clone.actor.set_scale(scale, scale);
 
407
                this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
 
408
            }
 
409
        }
 
410
    }
 
411
 
 
412
    /// position window titles on top of windows in overlay ////
 
413
    if (WINDOW_CAPTIONS_ON_TOP)  {
 
414
        winInjections['_init'] = Workspace.WindowOverlay.prototype._init;
 
415
        Workspace.WindowOverlay.prototype._init = function(windowClone, parentActor) {
 
416
            let metaWindow = windowClone.metaWindow;
 
417
 
 
418
            this._windowClone = windowClone;
 
419
            this._parentActor = parentActor;
 
420
            this._hidden = false;
 
421
 
 
422
            let title = new St.Label({ style_class: 'window-caption',
 
423
                                       text: metaWindow.title });
 
424
            title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
 
425
            title._spacing = 0;
 
426
            title._overlap = 0;
 
427
 
 
428
            this._updateCaptionId = metaWindow.connect('notify::title', Lang.bind(this, function(w) {
 
429
                this.title.text = w.title;
 
430
            }));
 
431
 
 
432
            let button = new St.Button({ style_class: 'window-close' });
 
433
            button._overlap = 0;
 
434
 
 
435
            this._idleToggleCloseId = 0;
 
436
            button.connect('clicked', Lang.bind(this, this._closeWindow));
 
437
 
 
438
            windowClone.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 
439
            windowClone.actor.connect('enter-event', Lang.bind(this, this._onEnter));
 
440
            windowClone.actor.connect('leave-event', Lang.bind(this, this._onLeave));
 
441
 
 
442
            this._windowAddedId = 0;
 
443
            windowClone.connect('zoom-start', Lang.bind(this, this.hide));
 
444
            windowClone.connect('zoom-end', Lang.bind(this, this.show));
 
445
 
 
446
            button.hide();
 
447
 
 
448
            this.title = title;
 
449
            this.closeButton = button;
 
450
 
 
451
            parentActor.add_actor(this.title);
 
452
            parentActor.add_actor(this.closeButton);
 
453
            title.connect('style-changed', Lang.bind(this, this._onStyleChanged));
 
454
            button.connect('style-changed', Lang.bind(this, this._onStyleChanged));
 
455
 
 
456
            // force a style change if we are already on a stage - otherwise
 
457
            // the signal will be emitted normally when we are added
 
458
            if (parentActor.get_stage())
 
459
                this._onStyleChanged();
 
460
        },
 
461
 
 
462
        winInjections['chromeHeights'] = Workspace.WindowOverlay.prototype.chromeHeights;
 
463
        Workspace.WindowOverlay.prototype.chromeHeights = function () {
 
464
            return [Math.max( this.closeButton.height - this.closeButton._overlap, this.title.height - this.title._overlap),
 
465
                    0];
 
466
        },
 
467
 
 
468
        winInjections['updatePositions'] = Workspace.WindowOverlay.prototype.updatePositions;
 
469
        Workspace.WindowOverlay.prototype.updatePositions = function(cloneX, cloneY, cloneWidth, cloneHeight) {
 
470
            let button = this.closeButton;
 
471
            let title = this.title;
 
472
 
 
473
            let buttonX;
 
474
            let buttonY = cloneY - (button.height - button._overlap);
 
475
            if (St.Widget.get_default_direction() == St.TextDirection.RTL)
 
476
                buttonX = cloneX - (button.width - button._overlap);
 
477
            else
 
478
                buttonX = cloneX + (cloneWidth - button._overlap);
 
479
 
 
480
            button.set_position(Math.floor(buttonX), Math.floor(buttonY));
 
481
 
 
482
            if (!title.fullWidth)
 
483
                title.fullWidth = title.width;
 
484
            title.width = Math.min(title.fullWidth, cloneWidth);
 
485
 
 
486
            let titleX = cloneX + (cloneWidth - title.width) / 2;
 
487
            let titleY = cloneY - title.height + title._overlap;
 
488
            title.set_position(Math.floor(titleX), Math.floor(titleY));
 
489
        },
 
490
 
 
491
        winInjections['_onStyleChanged'] = Workspace.WindowOverlay.prototype._onStyleChanged;
 
492
        Workspace.WindowOverlay.prototype._onStyleChanged = function() {
 
493
            let titleNode = this.title.get_theme_node();
 
494
            this.title._spacing = titleNode.get_length('-shell-caption-spacing');
 
495
            this.title._overlap = titleNode.get_length('-shell-caption-overlap');
 
496
 
 
497
            let closeNode = this.closeButton.get_theme_node();
 
498
            this.closeButton._overlap = closeNode.get_length('-shell-close-overlap');
 
499
 
 
500
            this._parentActor.queue_relayout();
 
501
        }
 
502
    }
 
503
}
 
504
 
 
505
function removeInjection(object, injection, name) {
 
506
    if (injection[name] === undefined)
 
507
        delete object[name];
 
508
    else
 
509
        object[name] = injection[name];
 
510
}
 
511
 
 
512
function disable() {
 
513
    for (i in workspaceInjections)
 
514
        removeInjection(Workspace.Workspace.prototype, workspaceInjections, i);
 
515
    for (i in winInjections)
 
516
        removeInjection(Workspace.WindowOverlay.prototype, winInjections, i);
 
517
 
 
518
    for each (i in connectedSignals)
 
519
        i.obj.disconnect(i.id);
 
520
 
 
521
    global.stage.queue_relayout();
 
522
    resetState();
 
523
}
 
524
 
 
525
function init() {
 
526
    /* do nothing */
 
527
}