Compare commits
	
		
			82 Commits
		
	
	
		
			3.35.2
			...
			gnome-3-34
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f6ace7a325 | ||
| 
						 | 
					c38196dd85 | ||
| 
						 | 
					059af4c4cd | ||
| 
						 | 
					aba60dcac8 | ||
| 
						 | 
					3d7ee7856f | ||
| 
						 | 
					0a50b6ea01 | ||
| 
						 | 
					c5dd9a9341 | ||
| 
						 | 
					2756806f84 | ||
| 
						 | 
					bb9c286e3f | ||
| 
						 | 
					cf2ab505a0 | ||
| 
						 | 
					b7389b328c | ||
| 
						 | 
					99d948559b | ||
| 
						 | 
					f21a0ff458 | ||
| 
						 | 
					ec852ab265 | ||
| 
						 | 
					a8bb7c0a2a | ||
| 
						 | 
					8a8c6e2f23 | ||
| 
						 | 
					f7fe7bc676 | ||
| 
						 | 
					a35f9a5226 | ||
| 
						 | 
					fb74394d58 | ||
| 
						 | 
					9f7b1bd677 | ||
| 
						 | 
					afd2ce2353 | ||
| 
						 | 
					61fccf188a | ||
| 
						 | 
					5043e6d6bd | ||
| 
						 | 
					7be1729cde | ||
| 
						 | 
					f92cb46b02 | ||
| 
						 | 
					56902542c7 | ||
| 
						 | 
					523eea4527 | ||
| 
						 | 
					a7b0e96304 | ||
| 
						 | 
					bb24df2f9d | ||
| 
						 | 
					9150cbca3e | ||
| 
						 | 
					35bb67bb2f | ||
| 
						 | 
					d4c2f9d0ef | ||
| 
						 | 
					e211c68a5c | ||
| 
						 | 
					af95883807 | ||
| 
						 | 
					91f41105d5 | ||
| 
						 | 
					45fa520cca | ||
| 
						 | 
					334762ee9e | ||
| 
						 | 
					88e3dfa104 | ||
| 
						 | 
					4b89314813 | ||
| 
						 | 
					a9fa4cc49e | ||
| 
						 | 
					9476c9c4ca | ||
| 
						 | 
					24df43d579 | ||
| 
						 | 
					363336e4a1 | ||
| 
						 | 
					070c784412 | ||
| 
						 | 
					455eb67a49 | ||
| 
						 | 
					23cc59f52a | ||
| 
						 | 
					19bb459a57 | ||
| 
						 | 
					48477443fa | ||
| 
						 | 
					40b2fbf465 | ||
| 
						 | 
					7800bd2158 | ||
| 
						 | 
					d4f07410a1 | ||
| 
						 | 
					64b62de5df | ||
| 
						 | 
					9b0d42309b | ||
| 
						 | 
					cf249ab870 | ||
| 
						 | 
					c752682ab9 | ||
| 
						 | 
					a6e4ef862c | ||
| 
						 | 
					8d2365b7b9 | ||
| 
						 | 
					03219f745d | ||
| 
						 | 
					7d34dee77f | ||
| 
						 | 
					f0e59ea088 | ||
| 
						 | 
					f8a90f6583 | ||
| 
						 | 
					aa1d297bdf | ||
| 
						 | 
					b88f7d0655 | ||
| 
						 | 
					59daa4192c | ||
| 
						 | 
					d08cd1f523 | ||
| 
						 | 
					a85cddada0 | ||
| 
						 | 
					ae8568a2e0 | ||
| 
						 | 
					4a3ca40c48 | ||
| 
						 | 
					e257be64d0 | ||
| 
						 | 
					96ac00b53c | ||
| 
						 | 
					7e8884a601 | ||
| 
						 | 
					ef726bf313 | ||
| 
						 | 
					a43c22e3af | ||
| 
						 | 
					22b6a09cd7 | ||
| 
						 | 
					65110968c5 | ||
| 
						 | 
					d142f59478 | ||
| 
						 | 
					c1ecd304e7 | ||
| 
						 | 
					750c5acd30 | ||
| 
						 | 
					246150d8b6 | ||
| 
						 | 
					072a9a4842 | ||
| 
						 | 
					7149da3f4f | ||
| 
						 | 
					6c2a82258e | 
@@ -1,6 +1,5 @@
 | 
			
		||||
#!/usr/bin/bash
 | 
			
		||||
 | 
			
		||||
shell_branch=$(git describe --contains --all HEAD)
 | 
			
		||||
mutter_target=
 | 
			
		||||
 | 
			
		||||
git clone https://gitlab.gnome.org/GNOME/mutter.git
 | 
			
		||||
@@ -26,8 +25,7 @@ if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ -z "$mutter_target" ]; then
 | 
			
		||||
  mutter_target=$(git branch -r -l origin/$shell_branch)
 | 
			
		||||
  mutter_target=${mutter_target:-$(git branch -r -l ${shell_branch#remotes/})}
 | 
			
		||||
  mutter_target=$(git branch -r -l origin/$CI_COMMIT_REF_NAME)
 | 
			
		||||
  mutter_target=${mutter_target:-origin/master}
 | 
			
		||||
  echo Using $mutter_target instead
 | 
			
		||||
fi
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										75
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								NEWS
									
									
									
									
									
								
							@@ -1,3 +1,78 @@
 | 
			
		||||
3.34.5
 | 
			
		||||
======
 | 
			
		||||
* Leave overview when locking the screen [Jonas D.; !1043]
 | 
			
		||||
* Avoid IO on the main thread [Christian; !1050]
 | 
			
		||||
* Fix OSK layout fallback for unsupported variants [Florian; #2471]
 | 
			
		||||
* Fix high-contrast/symbolic icon mix-up [Florian; #2414]
 | 
			
		||||
* Misc. bug fixes and cleanups [Jonas Å., Florian; !1032, #2386]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Jonas Dreßler, Christian Hergert, Florian Müllner, Jwtiyar Nariman,
 | 
			
		||||
  Jonas Ådahl
 | 
			
		||||
 | 
			
		||||
Translators:
 | 
			
		||||
  Jwtiyar Nariman [ckb]
 | 
			
		||||
 | 
			
		||||
3.34.4
 | 
			
		||||
======
 | 
			
		||||
* Switch screen-recorder back to VP8 [Björn; #256]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Björn Daase
 | 
			
		||||
 | 
			
		||||
Translators:
 | 
			
		||||
  Jor Teron [mjw], Dušan Kazik [sk]
 | 
			
		||||
 | 
			
		||||
3.34.3
 | 
			
		||||
======
 | 
			
		||||
* polkitAgent: Fix confirming via keyboard when password-less [Jonas; #2066]
 | 
			
		||||
* Misc. bug fixes and cleanups [Florian; !906]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Jonas Dreßler, Florian Müllner
 | 
			
		||||
 | 
			
		||||
3.34.2
 | 
			
		||||
======
 | 
			
		||||
* Fix unredirection after cancelled animations [Florian; #1788]
 | 
			
		||||
* Use cached coordinates for window sorting in overview [Andrew; !763]
 | 
			
		||||
* Include shadow in window screenshots [Robert; !762]
 | 
			
		||||
* Use correct timezones for events [Milan, Florian; !806, #1895]
 | 
			
		||||
* Adjust style of system menu action buttons [monday; !802]
 | 
			
		||||
* Fix windows getting stuck on screen if closed while animating [Florian; !815]
 | 
			
		||||
* Hide stopped spinner in top bar [Joonas; !834]
 | 
			
		||||
* Reuse existing icons when updating the app picker grid [Georges; !841]
 | 
			
		||||
* Fix not-responding dialog size when using geometry scaling [Jonas; !783]
 | 
			
		||||
* Fix battery icon glitch in "100% but charging" case [Philip; !814]
 | 
			
		||||
* Update window titles in app menu [Florian; #1830]
 | 
			
		||||
* Improve modifier-less keyboard navigation of switcher popups [Florian; #1883]
 | 
			
		||||
* Use better OSK layout fallback for unsupported variants [Florian; #1907]
 | 
			
		||||
* Fix creating app folders with no pre-existing folders [Jonas; #1652]
 | 
			
		||||
* Improve DND page switching in app picker [Florian, Jonas; #1693]
 | 
			
		||||
* Show polkit confirmation dialog for users with no password [Joaquim; !829]
 | 
			
		||||
* Fix interacting with applications when magnifier is enabled [Jonas; !754]
 | 
			
		||||
* Tweak styling of notifications/media constrols [Joonas; !855, !865]
 | 
			
		||||
* Fix disable command of gnome-extensions tool [Florian; #1946]
 | 
			
		||||
* Enable clean session shutdown after gnome-shell failure [Benjamin; !858]
 | 
			
		||||
* Also remove scaled keys when texture cache is cleared [Daniel; !567]
 | 
			
		||||
* Don't show overflow indicator in switchers that fit screen [Florian; #1834]
 | 
			
		||||
* Place launched applications into a systemd scope [Benjamin; !863]
 | 
			
		||||
* Fix weather forecasts for automatic location when Weather is not sandboxed
 | 
			
		||||
  [Florian; #1823]
 | 
			
		||||
* Dismiss switcher popups when a system modal dialogs opens [Florian; #1536]
 | 
			
		||||
* Misc. bug fixes and cleanups [Marco, Philip, Florian, cunidev, Jonas, Joonas;
 | 
			
		||||
  !758, !749, !777, !811, #1884, !823, !840, !782, !847, #1836, !852, !851,
 | 
			
		||||
  !788, #1916, !866, !884]
 | 
			
		||||
 | 
			
		||||
Contributors:
 | 
			
		||||
  Marco Trevisan (Treviño), Benjamin Berg, Philip Chimento, Milan Crha,
 | 
			
		||||
  Jonas Dreßler, Joonas Henriksson, Robert Mader, Daniel García Moreno,
 | 
			
		||||
  Florian Müllner, Georges Basile Stavracas Neto, Joaquim Rocha, Andrew Watson,
 | 
			
		||||
  cunidev, monday
 | 
			
		||||
 | 
			
		||||
Translators:
 | 
			
		||||
  Stas Solovey [ru], Ricardo Silva Veloso [pt_BR], Yi-Jyun Pan [zh_TW],
 | 
			
		||||
  Umarzuki Bin Mochlis Moktar [ms]
 | 
			
		||||
 | 
			
		||||
3.34.1
 | 
			
		||||
======
 | 
			
		||||
* Fix "Frequent" view icons disappearing on hover [Jonas D.; #1502]
 | 
			
		||||
 
 | 
			
		||||
@@ -30,3 +30,6 @@
 | 
			
		||||
 | 
			
		||||
/* Define if fdwalk is available in libc */
 | 
			
		||||
#mesondefine HAVE_FDWALK
 | 
			
		||||
 | 
			
		||||
/* Define if we have gnome-desktop systemd utils */
 | 
			
		||||
#mesondefine HAVE_GNOME_SYSTEMD
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,12 @@
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Disable GNOME Shell extensions after failure
 | 
			
		||||
# Note that this unit must not conflict with anything, and must
 | 
			
		||||
# be able to run in parallel with the gnome-session-shutdown.target.
 | 
			
		||||
DefaultDependencies=no
 | 
			
		||||
 | 
			
		||||
# Only disable extensions for a short period of time after login.
 | 
			
		||||
# This means we err on the side of failing the first login after a broken
 | 
			
		||||
# extension was installed.
 | 
			
		||||
Requisite=gnome-session-stable.timer
 | 
			
		||||
# We want to disable extensions only if gnome-shell has flagged the extensions
 | 
			
		||||
# to be a likely cause of trouble.
 | 
			
		||||
ConditionPathExists=%t/gnome-shell-disable-extensions
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
 
 | 
			
		||||
@@ -1061,9 +1061,9 @@ StScrollBar {
 | 
			
		||||
      }
 | 
			
		||||
      .calendar-today {
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
        //color: lighten($fg_color,10%);
 | 
			
		||||
        //background-color: darken($bg_color,5%);
 | 
			
		||||
        border: 1px solid $_bubble_borders_color;
 | 
			
		||||
        color: lighten($fg_color,5%);
 | 
			
		||||
        background-color: darken($bg_color,5%);
 | 
			
		||||
        // border: 1px solid lighten($_bubble_borders_color,20%);
 | 
			
		||||
      }
 | 
			
		||||
      .calendar-day-with-events {
 | 
			
		||||
        color: lighten($fg_color,10%);
 | 
			
		||||
@@ -1153,14 +1153,21 @@ StScrollBar {
 | 
			
		||||
            padding: 10px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .message-close-button {
 | 
			
		||||
            color: lighten($fg_color, 15%);
 | 
			
		||||
            &:hover { color: if($variant=='light', lighten($fg_color, 30%), darken($fg_color, 10%)); }
 | 
			
		||||
            &:active { color: if($variant=='light', lighten($fg_color, 40%), darken($fg_color, 20%)); }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .message-media-control {
 | 
			
		||||
            padding: 12px;
 | 
			
		||||
            color: lighten($fg_color, 15%);
 | 
			
		||||
 | 
			
		||||
            &:last-child:ltr { padding-right: 18px; }
 | 
			
		||||
            &:last-child:rtl { padding-left: 18px; }
 | 
			
		||||
            &:hover { color: $fg_color; }
 | 
			
		||||
            &:insensitive { color: darken($fg_color,40%); }
 | 
			
		||||
            &:hover { color: if($variant=='light', lighten($fg_color, 30%), darken($fg_color, 10%)); }
 | 
			
		||||
            &:active { color: if($variant=='light', lighten($fg_color, 40%), darken($fg_color, 20%)); }
 | 
			
		||||
            &:insensitive { color: if($variant=='light', lighten($fg_color, 50%), darken($fg_color, 40%)); }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .media-message-cover-icon {
 | 
			
		||||
@@ -1209,12 +1216,11 @@ StScrollBar {
 | 
			
		||||
    &:hover, &:focus {
 | 
			
		||||
      background-color: $_hover_bg_color;
 | 
			
		||||
      color: $fg_color;
 | 
			
		||||
      border: none;
 | 
			
		||||
      padding: 14px;
 | 
			
		||||
    }
 | 
			
		||||
    &:active { 
 | 
			
		||||
      background-color: $selected_bg_color;
 | 
			
		||||
      color: $selected_fg_color;
 | 
			
		||||
      border-color: $selected_borders_color;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > StIcon { icon-size: 16px; }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,5 @@ var LOCALEDIR = '@datadir@/locale';
 | 
			
		||||
/* other standard directories */
 | 
			
		||||
var LIBEXECDIR = '@libexecdir@';
 | 
			
		||||
var PKGDATADIR = '@datadir@/@PACKAGE_NAME@';
 | 
			
		||||
var VPNDIR = '@vpndir@';
 | 
			
		||||
/* g-i package versions */
 | 
			
		||||
var LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@'
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,15 @@ var IntrospectService = class {
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
        this._syncRunningApplications();
 | 
			
		||||
 | 
			
		||||
        this._whitelistMap = new Map();
 | 
			
		||||
        APP_WHITELIST.forEach(appName => {
 | 
			
		||||
            Gio.DBus.watch_name(Gio.BusType.SESSION,
 | 
			
		||||
                appName,
 | 
			
		||||
                Gio.BusNameWatcherFlags.NONE,
 | 
			
		||||
                (conn, name, owner) => this._whitelistMap.set(name, owner),
 | 
			
		||||
                (conn, name) => this._whitelistMap.delete(name));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _isStandaloneApp(app) {
 | 
			
		||||
@@ -51,7 +60,7 @@ var IntrospectService = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _isSenderWhitelisted(sender) {
 | 
			
		||||
        return APP_WHITELIST.includes(sender);
 | 
			
		||||
        return [...this._whitelistMap.values()].includes(sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _getSandboxedAppId(app) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ jsconf.set10('HAVE_BLUETOOTH', bt_dep.found())
 | 
			
		||||
jsconf.set10('HAVE_NETWORKMANAGER', have_networkmanager)
 | 
			
		||||
jsconf.set('datadir', datadir)
 | 
			
		||||
jsconf.set('libexecdir', libexecdir)
 | 
			
		||||
jsconf.set('vpndir', vpndir)
 | 
			
		||||
 | 
			
		||||
config_js = configure_file(
 | 
			
		||||
  input: 'config.js.in',
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
            formatTime, formatTimeSpan, createTimeLabel, insertSorted,
 | 
			
		||||
            makeCloseButton, ensureActorVisibleInScrollView */
 | 
			
		||||
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi;
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, Shell, St, GnomeDesktop } = imports.gi;
 | 
			
		||||
const Gettext = imports.gettext;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
@@ -127,6 +127,14 @@ function trySpawn(argv) {
 | 
			
		||||
            throw err;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Async call, we don't need the reply though
 | 
			
		||||
    try {
 | 
			
		||||
        GnomeDesktop.start_systemd_scope(argv[0], pid, null, null, null, () => {});
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        // Ignore error; it likely means GnomeDesktop is too old
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Dummy child watch; we don't want to double-fork internally
 | 
			
		||||
    // because then we lose the parent-child relationship, which
 | 
			
		||||
    // can break polkit.  See https://bugzilla.redhat.com//show_bug.cgi?id=819275
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ var WeatherClient = class {
 | 
			
		||||
        this._gclueStarting = false;
 | 
			
		||||
        this._gclueLocationChangedId = 0;
 | 
			
		||||
 | 
			
		||||
        this._needsAuth = true;
 | 
			
		||||
        this._weatherAuthorized = false;
 | 
			
		||||
        this._permStore = new PermissionStore.PermissionStore((proxy, error) => {
 | 
			
		||||
            if (error) {
 | 
			
		||||
@@ -142,7 +143,7 @@ var WeatherClient = class {
 | 
			
		||||
    get _useAutoLocation() {
 | 
			
		||||
        return this._autoLocationRequested &&
 | 
			
		||||
               this._locationSettings.get_boolean('enabled') &&
 | 
			
		||||
               this._weatherAuthorized;
 | 
			
		||||
               (!this._needsAuth || this._weatherAuthorized);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onWeatherProxyReady(o, res) {
 | 
			
		||||
@@ -175,6 +176,13 @@ var WeatherClient = class {
 | 
			
		||||
 | 
			
		||||
        if (hadApp !== haveApp)
 | 
			
		||||
            this.emit('changed');
 | 
			
		||||
 | 
			
		||||
        let neededAuth = this._needsAuth;
 | 
			
		||||
        this._needsAuth = this._weatherApp === null ||
 | 
			
		||||
                          this._weatherApp.app_info.has_key('X-Flatpak');
 | 
			
		||||
 | 
			
		||||
        if (neededAuth !== this._needsAuth)
 | 
			
		||||
            this._updateAutoLocation();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _loadInfo() {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,8 @@
 | 
			
		||||
 | 
			
		||||
const { Clutter, GLib, Gio, St } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
var ANIMATED_ICON_UPDATE_TIMEOUT = 16;
 | 
			
		||||
var SPINNER_ANIMATION_TIME = 300;
 | 
			
		||||
var SPINNER_ANIMATION_DELAY = 1000;
 | 
			
		||||
@@ -131,12 +133,22 @@ var AnimatedIcon = class extends Animation {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var Spinner = class extends AnimatedIcon {
 | 
			
		||||
    constructor(size, animate = false) {
 | 
			
		||||
    constructor(size, params) {
 | 
			
		||||
        // Compatibility with older callers
 | 
			
		||||
        if (params === true || params === false)
 | 
			
		||||
            params = { animate: params };
 | 
			
		||||
 | 
			
		||||
        params = Params.parse(params, {
 | 
			
		||||
            animate: false,
 | 
			
		||||
            hideOnStop: false,
 | 
			
		||||
        });
 | 
			
		||||
        let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg');
 | 
			
		||||
        super(file, size);
 | 
			
		||||
 | 
			
		||||
        this.actor.opacity = 0;
 | 
			
		||||
        this._animate = animate;
 | 
			
		||||
        this._animate = params.animate;
 | 
			
		||||
        this._hideOnStop = params.hideOnStop;
 | 
			
		||||
        this.actor.visible = !this._hideOnStop;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
@@ -146,6 +158,7 @@ var Spinner = class extends AnimatedIcon {
 | 
			
		||||
 | 
			
		||||
    play() {
 | 
			
		||||
        this.actor.remove_all_transitions();
 | 
			
		||||
        this.actor.show();
 | 
			
		||||
 | 
			
		||||
        if (this._animate) {
 | 
			
		||||
            super.play();
 | 
			
		||||
@@ -169,11 +182,18 @@ var Spinner = class extends AnimatedIcon {
 | 
			
		||||
                opacity: 0,
 | 
			
		||||
                duration: SPINNER_ANIMATION_TIME,
 | 
			
		||||
                mode: Clutter.AnimationMode.LINEAR,
 | 
			
		||||
                onComplete: () => super.stop()
 | 
			
		||||
                onComplete: () => {
 | 
			
		||||
                    super.stop();
 | 
			
		||||
                    if (this._hideOnStop)
 | 
			
		||||
                        this.actor.hide();
 | 
			
		||||
                },
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            this.actor.opacity = 0;
 | 
			
		||||
            super.stop();
 | 
			
		||||
 | 
			
		||||
            if (this._hideOnStop)
 | 
			
		||||
                this.actor.hide();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,9 @@ var PAGE_SWITCH_TIME = 300;
 | 
			
		||||
var APP_ICON_SCALE_IN_TIME = 500;
 | 
			
		||||
var APP_ICON_SCALE_IN_DELAY = 700;
 | 
			
		||||
 | 
			
		||||
const OVERSHOOT_THRESHOLD = 20;
 | 
			
		||||
const OVERSHOOT_TIMEOUT = 1000;
 | 
			
		||||
 | 
			
		||||
const SWITCHEROO_BUS_NAME = 'net.hadess.SwitcherooControl';
 | 
			
		||||
const SWITCHEROO_OBJECT_PATH = '/net/hadess/SwitcherooControl';
 | 
			
		||||
 | 
			
		||||
@@ -97,7 +100,10 @@ function _findBestFolderName(apps) {
 | 
			
		||||
    let commonCategories = [];
 | 
			
		||||
 | 
			
		||||
    appInfos.reduce((categories, appInfo) => {
 | 
			
		||||
        for (let category of appInfo.get_categories().split(';')) {
 | 
			
		||||
        const appCategories = appInfo.get_categories();
 | 
			
		||||
        if (!appCategories)
 | 
			
		||||
            return categories;
 | 
			
		||||
        for (let category of appCategories.split(';')) {
 | 
			
		||||
            if (!(category in categoryCounter))
 | 
			
		||||
                categoryCounter[category] = 0;
 | 
			
		||||
 | 
			
		||||
@@ -173,10 +179,11 @@ class BaseAppView {
 | 
			
		||||
        // Remove old app icons
 | 
			
		||||
        removedApps.forEach(icon => {
 | 
			
		||||
            let iconIndex = this._allItems.indexOf(icon);
 | 
			
		||||
            let id = icon.id;
 | 
			
		||||
 | 
			
		||||
            this._allItems.splice(iconIndex, 1);
 | 
			
		||||
            this._grid.removeItem(icon);
 | 
			
		||||
            delete this._items[icon.id];
 | 
			
		||||
            icon.actor.destroy();
 | 
			
		||||
            delete this._items[id];
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Add new app icons
 | 
			
		||||
@@ -308,7 +315,12 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
 | 
			
		||||
        this._grid.currentPage = 0;
 | 
			
		||||
        this._stack.add_actor(this._grid);
 | 
			
		||||
        this._eventBlocker = new St.Widget({ x_expand: true, y_expand: true });
 | 
			
		||||
        this._eventBlocker = new St.Widget({
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            y_expand: true,
 | 
			
		||||
            reactive: true,
 | 
			
		||||
            visible: false,
 | 
			
		||||
        });
 | 
			
		||||
        this._stack.add_actor(this._eventBlocker);
 | 
			
		||||
 | 
			
		||||
        box.add_actor(this._stack);
 | 
			
		||||
@@ -335,12 +347,16 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
        });
 | 
			
		||||
        this._eventBlocker.add_action(this._clickAction);
 | 
			
		||||
 | 
			
		||||
        this._currentPopup = null;
 | 
			
		||||
        this._displayingPopup = false;
 | 
			
		||||
        this._currentPopupDestroyId = 0;
 | 
			
		||||
 | 
			
		||||
        this._availWidth = 0;
 | 
			
		||||
        this._availHeight = 0;
 | 
			
		||||
 | 
			
		||||
        this._lastOvershootY = -1;
 | 
			
		||||
        this._lastOvershootTimeoutId = 0;
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('hidden', () => this.goToPage(0));
 | 
			
		||||
        this._grid.connect('space-opened', () => {
 | 
			
		||||
            let fadeEffect = this._scrollView.get_effect('fade');
 | 
			
		||||
@@ -377,8 +393,6 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
 | 
			
		||||
        Main.overview.connect('item-drag-begin', this._onDragBegin.bind(this));
 | 
			
		||||
        Main.overview.connect('item-drag-end', this._onDragEnd.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._nEventBlockerInhibits = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _redisplay() {
 | 
			
		||||
@@ -425,7 +439,7 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _loadApps() {
 | 
			
		||||
        let newApps = [];
 | 
			
		||||
        let appIcons = [];
 | 
			
		||||
        this._appInfoList = Shell.AppSystem.get_default().get_installed().filter(appInfo => {
 | 
			
		||||
            try {
 | 
			
		||||
                (appInfo.get_id()); // catch invalid file encodings
 | 
			
		||||
@@ -450,7 +464,7 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
                icon.connect('name-changed', this._itemNameChanged.bind(this));
 | 
			
		||||
                icon.connect('apps-changed', this._redisplay.bind(this));
 | 
			
		||||
            }
 | 
			
		||||
            newApps.push(icon);
 | 
			
		||||
            appIcons.push(icon);
 | 
			
		||||
            this.folderIcons.push(icon);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@@ -463,14 +477,19 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
        let favoritesWritable = global.settings.is_writable('favorite-apps');
 | 
			
		||||
 | 
			
		||||
        apps.forEach(appId => {
 | 
			
		||||
            let app = appSys.lookup_app(appId);
 | 
			
		||||
            let icon = this._items[appId];
 | 
			
		||||
            if (!icon) {
 | 
			
		||||
                let app = appSys.lookup_app(appId);
 | 
			
		||||
 | 
			
		||||
            let icon = new AppIcon(app,
 | 
			
		||||
                                   { isDraggable: favoritesWritable });
 | 
			
		||||
            newApps.push(icon);
 | 
			
		||||
                icon = new AppIcon(app, {
 | 
			
		||||
                    isDraggable: favoritesWritable,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            appIcons.push(icon);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return newApps;
 | 
			
		||||
        return appIcons;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Overridden from BaseAppView
 | 
			
		||||
@@ -648,7 +667,7 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
    addFolderPopup(popup) {
 | 
			
		||||
        this._stack.add_actor(popup.actor);
 | 
			
		||||
        popup.connect('open-state-changed', (popup, isOpen) => {
 | 
			
		||||
            this._eventBlocker.reactive = isOpen;
 | 
			
		||||
            this._eventBlocker.visible = isOpen;
 | 
			
		||||
 | 
			
		||||
            if (this._currentPopup) {
 | 
			
		||||
                this._currentPopup.actor.disconnect(this._currentPopupDestroyId);
 | 
			
		||||
@@ -662,7 +681,7 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
                this._currentPopupDestroyId = popup.actor.connect('destroy', () => {
 | 
			
		||||
                    this._currentPopup = null;
 | 
			
		||||
                    this._currentPopupDestroyId = 0;
 | 
			
		||||
                    this._eventBlocker.reactive = false;
 | 
			
		||||
                    this._eventBlocker.visible = false;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            this._updateIconOpacities(isOpen);
 | 
			
		||||
@@ -730,29 +749,58 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
            this.folderIcons[i].adaptToSize(availWidth, availHeight);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _resetOvershoot() {
 | 
			
		||||
        if (this._lastOvershootTimeoutId)
 | 
			
		||||
            GLib.source_remove(this._lastOvershootTimeoutId);
 | 
			
		||||
        this._lastOvershootTimeoutId = 0;
 | 
			
		||||
        this._lastOvershootY = -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _handleDragOvershoot(dragEvent) {
 | 
			
		||||
        let [, gridY] = this.actor.get_transformed_position();
 | 
			
		||||
        let [, gridHeight] = this.actor.get_transformed_size();
 | 
			
		||||
        let gridBottom = gridY + gridHeight;
 | 
			
		||||
 | 
			
		||||
        // Within the grid boundaries, or already animating
 | 
			
		||||
        if (dragEvent.y > gridY && dragEvent.y < gridBottom ||
 | 
			
		||||
            this._adjustment.get_transition('value') != null) {
 | 
			
		||||
        // Already animating
 | 
			
		||||
        if (this._adjustment.get_transition('value') !== null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // Within the grid boundaries
 | 
			
		||||
        if (dragEvent.y > gridY && dragEvent.y < gridBottom) {
 | 
			
		||||
            // Check whether we moved out the area of the last switch
 | 
			
		||||
            if (Math.abs(this._lastOvershootY - dragEvent.y) > OVERSHOOT_THRESHOLD)
 | 
			
		||||
                this._resetOvershoot();
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Moving above the grid
 | 
			
		||||
        // Still in the area of the previous page switch
 | 
			
		||||
        if (this._lastOvershootY >= 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let currentY = this._adjustment.value;
 | 
			
		||||
        if (dragEvent.y <= gridY && currentY > 0) {
 | 
			
		||||
            this.goToPage(this._grid.currentPage - 1);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Moving below the grid
 | 
			
		||||
        let maxY = this._adjustment.upper - this._adjustment.page_size;
 | 
			
		||||
        if (dragEvent.y >= gridBottom && currentY < maxY) {
 | 
			
		||||
 | 
			
		||||
        if (dragEvent.y <= gridY && currentY > 0)
 | 
			
		||||
            this.goToPage(this._grid.currentPage - 1);
 | 
			
		||||
        else if (dragEvent.y >= gridBottom && currentY < maxY)
 | 
			
		||||
            this.goToPage(this._grid.currentPage + 1);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            return; // don't go beyond first/last page
 | 
			
		||||
 | 
			
		||||
        this._lastOvershootY = dragEvent.y;
 | 
			
		||||
 | 
			
		||||
        if (this._lastOvershootTimeoutId > 0)
 | 
			
		||||
            GLib.source_remove(this._lastOvershootTimeoutId);
 | 
			
		||||
 | 
			
		||||
        this._lastOvershootTimeoutId =
 | 
			
		||||
            GLib.timeout_add(GLib.PRIORITY_DEFAULT, OVERSHOOT_TIMEOUT, () => {
 | 
			
		||||
                this._resetOvershoot();
 | 
			
		||||
                this._handleDragOvershoot(dragEvent);
 | 
			
		||||
                return GLib.SOURCE_REMOVE;
 | 
			
		||||
            });
 | 
			
		||||
        GLib.Source.set_name_by_id(this._lastOvershootTimeoutId,
 | 
			
		||||
            '[gnome-shell] this._lastOvershootTimeoutId');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDragBegin() {
 | 
			
		||||
@@ -760,6 +808,8 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
            dragMotion: this._onDragMotion.bind(this)
 | 
			
		||||
        };
 | 
			
		||||
        DND.addDragMonitor(this._dragMonitor);
 | 
			
		||||
 | 
			
		||||
        this._eventBlocker.visible = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDragMotion(dragEvent) {
 | 
			
		||||
@@ -782,6 +832,9 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
            DND.removeDragMonitor(this._dragMonitor);
 | 
			
		||||
            this._dragMonitor = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._eventBlocker.visible = this._currentPopup !== null;
 | 
			
		||||
        this._resetOvershoot();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _canAccept(source) {
 | 
			
		||||
@@ -815,19 +868,6 @@ var AllView = class AllView extends BaseAppView {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inhibitEventBlocker() {
 | 
			
		||||
        this._nEventBlockerInhibits++;
 | 
			
		||||
        this._eventBlocker.visible = this._nEventBlockerInhibits == 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uninhibitEventBlocker() {
 | 
			
		||||
        if (this._nEventBlockerInhibits === 0)
 | 
			
		||||
            throw new Error('Not inhibited');
 | 
			
		||||
 | 
			
		||||
        this._nEventBlockerInhibits--;
 | 
			
		||||
        this._eventBlocker.visible = this._nEventBlockerInhibits == 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createFolder(apps) {
 | 
			
		||||
        let newFolderId = GLib.uuid_string_random();
 | 
			
		||||
 | 
			
		||||
@@ -918,8 +958,12 @@ var FrequentView = class FrequentView extends BaseAppView {
 | 
			
		||||
        for (let i = 0; i < mostUsed.length; i++) {
 | 
			
		||||
            if (!mostUsed[i].get_app_info().should_show())
 | 
			
		||||
                continue;
 | 
			
		||||
            let appIcon = new AppIcon(mostUsed[i],
 | 
			
		||||
                                      { isDraggable: favoritesWritable });
 | 
			
		||||
            let appIcon = this._items[mostUsed[i].get_id()];
 | 
			
		||||
            if (!appIcon) {
 | 
			
		||||
                appIcon = new AppIcon(mostUsed[i], {
 | 
			
		||||
                    isDraggable: favoritesWritable,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            apps.push(appIcon);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1349,7 +1393,10 @@ var FolderView = class FolderView extends BaseAppView {
 | 
			
		||||
            if (apps.some(appIcon => appIcon.id == appId))
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            let icon = new AppIcon(app);
 | 
			
		||||
            let icon = this._items[appId];
 | 
			
		||||
            if (!icon)
 | 
			
		||||
                icon = new AppIcon(app);
 | 
			
		||||
 | 
			
		||||
            apps.push(icon);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -1387,15 +1434,15 @@ var FolderView = class FolderView extends BaseAppView {
 | 
			
		||||
        // Remove the folder if this is the last app icon; otherwise,
 | 
			
		||||
        // just remove the icon
 | 
			
		||||
        if (folderApps.length == 0) {
 | 
			
		||||
            let settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders' });
 | 
			
		||||
            let folders = settings.get_strv('folder-children');
 | 
			
		||||
            folders.splice(folders.indexOf(this._id), 1);
 | 
			
		||||
            settings.set_strv('folder-children', folders);
 | 
			
		||||
 | 
			
		||||
            // Resetting all keys deletes the relocatable schema
 | 
			
		||||
            let keys = this._folder.settings_schema.list_keys();
 | 
			
		||||
            for (let key of keys)
 | 
			
		||||
                this._folder.reset(key);
 | 
			
		||||
 | 
			
		||||
            let settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders' });
 | 
			
		||||
            let folders = settings.get_strv('folder-children');
 | 
			
		||||
            folders.splice(folders.indexOf(this._id), 1);
 | 
			
		||||
            settings.set_strv('folder-children', folders);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._folder.set_strv('apps', folderApps);
 | 
			
		||||
        }
 | 
			
		||||
@@ -1487,8 +1534,6 @@ var FolderIcon = class FolderIcon {
 | 
			
		||||
            dragMotion: this._onDragMotion.bind(this),
 | 
			
		||||
        };
 | 
			
		||||
        DND.addDragMonitor(this._dragMonitor);
 | 
			
		||||
 | 
			
		||||
        this._parentView.inhibitEventBlocker();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDragMotion(dragEvent) {
 | 
			
		||||
@@ -1504,7 +1549,6 @@ var FolderIcon = class FolderIcon {
 | 
			
		||||
 | 
			
		||||
    _onDragEnd() {
 | 
			
		||||
        this.actor.remove_style_pseudo_class('drop');
 | 
			
		||||
        this._parentView.uninhibitEventBlocker();
 | 
			
		||||
        DND.removeDragMonitor(this._dragMonitor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1994,17 +2038,10 @@ var AppIcon = class AppIcon {
 | 
			
		||||
                                     x_fill: true,
 | 
			
		||||
                                     y_fill: true });
 | 
			
		||||
 | 
			
		||||
        this._dot = new St.Widget({ style_class: 'app-well-app-running-dot',
 | 
			
		||||
                                    layout_manager: new Clutter.BinLayout(),
 | 
			
		||||
                                    x_expand: true, y_expand: true,
 | 
			
		||||
                                    x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
                                    y_align: Clutter.ActorAlign.END });
 | 
			
		||||
 | 
			
		||||
        this._iconContainer = new St.Widget({ layout_manager: new Clutter.BinLayout(),
 | 
			
		||||
                                              x_expand: true, y_expand: true });
 | 
			
		||||
 | 
			
		||||
        this.actor.set_child(this._iconContainer);
 | 
			
		||||
        this._iconContainer.add_child(this._dot);
 | 
			
		||||
 | 
			
		||||
        this.actor._delegate = this;
 | 
			
		||||
 | 
			
		||||
@@ -2021,6 +2058,16 @@ var AppIcon = class AppIcon {
 | 
			
		||||
        this.icon = new IconGrid.BaseIcon(app.get_name(), iconParams);
 | 
			
		||||
        this._iconContainer.add_child(this.icon);
 | 
			
		||||
 | 
			
		||||
        this._dot = new St.Widget({
 | 
			
		||||
            style_class: 'app-well-app-running-dot',
 | 
			
		||||
            layout_manager: new Clutter.BinLayout(),
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            y_expand: true,
 | 
			
		||||
            x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
            y_align: Clutter.ActorAlign.END,
 | 
			
		||||
        });
 | 
			
		||||
        this._iconContainer.add_child(this._dot);
 | 
			
		||||
 | 
			
		||||
        this.actor.label_actor = this.icon.label;
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('leave-event', this._onLeaveEvent.bind(this));
 | 
			
		||||
@@ -2051,6 +2098,7 @@ var AppIcon = class AppIcon {
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._dragMonitor = null;
 | 
			
		||||
        this._itemDragBeginId = Main.overview.connect(
 | 
			
		||||
            'item-drag-begin', this._onDragBegin.bind(this));
 | 
			
		||||
        this._itemDragEndId = Main.overview.connect(
 | 
			
		||||
@@ -2075,6 +2123,12 @@ var AppIcon = class AppIcon {
 | 
			
		||||
        }
 | 
			
		||||
        if (this._stateChangedId > 0)
 | 
			
		||||
            this.app.disconnect(this._stateChangedId);
 | 
			
		||||
 | 
			
		||||
        if (this._dragMonitor) {
 | 
			
		||||
            DND.removeDragMonitor(this._dragMonitor);
 | 
			
		||||
            this._dragMonitor = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._draggable) {
 | 
			
		||||
            if (this._dragging)
 | 
			
		||||
                Main.overview.endItemDrag(this);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported CloseDialog */
 | 
			
		||||
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, Meta, Shell } = imports.gi;
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
 | 
			
		||||
 | 
			
		||||
const Dialog = imports.ui.dialog;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
@@ -46,6 +46,18 @@ var CloseDialog = GObject.registerClass({
 | 
			
		||||
        return new Dialog.MessageDialogContent({ icon, title, subtitle });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _updateScale() {
 | 
			
		||||
        // Since this is a child of MetaWindowActor (which, for Wayland clients,
 | 
			
		||||
        // applies the geometry scale factor to its children itself, see
 | 
			
		||||
        // meta_window_actor_set_geometry_scale()), make sure we don't apply
 | 
			
		||||
        // the factor twice in the end.
 | 
			
		||||
        if (this._window.get_client_type() !== Meta.WindowClientType.WAYLAND)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let { scaleFactor } = St.ThemeContext.get_for_stage(global.stage);
 | 
			
		||||
        this._dialog.set_scale(1 / scaleFactor, 1 / scaleFactor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _initDialog() {
 | 
			
		||||
        if (this._dialog)
 | 
			
		||||
            return;
 | 
			
		||||
@@ -64,6 +76,11 @@ var CloseDialog = GObject.registerClass({
 | 
			
		||||
                                 key: Clutter.Escape });
 | 
			
		||||
 | 
			
		||||
        global.focus_manager.add_group(this._dialog);
 | 
			
		||||
 | 
			
		||||
        let themeContext = St.ThemeContext.get_for_stage(global.stage);
 | 
			
		||||
        themeContext.connect('notify::scale-factor', this._updateScale.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._updateScale();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _addWindowEffect() {
 | 
			
		||||
@@ -145,10 +162,10 @@ var CloseDialog = GObject.registerClass({
 | 
			
		||||
        this._addWindowEffect();
 | 
			
		||||
        this._initDialog();
 | 
			
		||||
 | 
			
		||||
        this._dialog.scale_y = 0;
 | 
			
		||||
        this._dialog.set_pivot_point(0.5, 0.5);
 | 
			
		||||
        this._dialog._dialog.scale_y = 0;
 | 
			
		||||
        this._dialog._dialog.set_pivot_point(0.5, 0.5);
 | 
			
		||||
 | 
			
		||||
        this._dialog.ease({
 | 
			
		||||
        this._dialog._dialog.ease({
 | 
			
		||||
            scale_y: 1,
 | 
			
		||||
            mode: Clutter.AnimationMode.LINEAR,
 | 
			
		||||
            duration: DIALOG_TRANSITION_TIME,
 | 
			
		||||
@@ -175,7 +192,8 @@ var CloseDialog = GObject.registerClass({
 | 
			
		||||
        this._dialog = null;
 | 
			
		||||
        this._removeWindowEffect();
 | 
			
		||||
 | 
			
		||||
        dialog.ease({
 | 
			
		||||
        dialog.makeInactive();
 | 
			
		||||
        dialog._dialog.ease({
 | 
			
		||||
            scale_y: 0,
 | 
			
		||||
            mode: Clutter.AnimationMode.LINEAR,
 | 
			
		||||
            duration: DIALOG_TRANSITION_TIME,
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,9 @@ class KeyringDialog extends ModalDialog.ModalDialog {
 | 
			
		||||
            ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
 | 
			
		||||
            this._passwordEntry.clutter_text.connect('activate', this._onPasswordActivate.bind(this));
 | 
			
		||||
 | 
			
		||||
            this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
 | 
			
		||||
            this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
 | 
			
		||||
                animate: true,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (rtl) {
 | 
			
		||||
                layout.attach(this._workSpinner.actor, 0, row, 1, 1);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,15 @@
 | 
			
		||||
const { Clutter, Gio, GLib, GObject, NM, Pango, Shell, St } = imports.gi;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const Config = imports.misc.config;
 | 
			
		||||
const Dialog = imports.ui.dialog;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
 | 
			
		||||
Gio._promisify(Shell.NetworkAgent.prototype,
 | 
			
		||||
    'search_vpn_plugin', 'search_vpn_plugin_finish');
 | 
			
		||||
 | 
			
		||||
const VPN_UI_GROUP = 'VPN Plugin UI';
 | 
			
		||||
 | 
			
		||||
var NetworkSecretDialog = GObject.registerClass(
 | 
			
		||||
@@ -622,14 +624,6 @@ var NetworkAgent = class {
 | 
			
		||||
        this._vpnRequests = { };
 | 
			
		||||
        this._notifications = { };
 | 
			
		||||
 | 
			
		||||
        this._pluginDir = Gio.file_new_for_path(Config.VPNDIR);
 | 
			
		||||
        try {
 | 
			
		||||
            let monitor = this._pluginDir.monitor(Gio.FileMonitorFlags.NONE, null);
 | 
			
		||||
            monitor.connect('changed', () => (this._vpnCacheBuilt = false));
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log(`Failed to create monitor for VPN plugin dir: ${e.message}`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._native.connect('new-request', this._newRequest.bind(this));
 | 
			
		||||
        this._native.connect('cancel-request', this._cancelRequest.bind(this));
 | 
			
		||||
 | 
			
		||||
@@ -769,13 +763,11 @@ var NetworkAgent = class {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _vpnRequest(requestId, connection, hints, flags) {
 | 
			
		||||
    async _vpnRequest(requestId, connection, hints, flags) {
 | 
			
		||||
        let vpnSetting = connection.get_setting_vpn();
 | 
			
		||||
        let serviceType = vpnSetting.service_type;
 | 
			
		||||
 | 
			
		||||
        this._buildVPNServiceCache();
 | 
			
		||||
 | 
			
		||||
        let binary = this._vpnBinaries[serviceType];
 | 
			
		||||
        let binary = await this._findAuthBinary(serviceType);
 | 
			
		||||
        if (!binary) {
 | 
			
		||||
            log('Invalid VPN service type (cannot find authentication binary)');
 | 
			
		||||
 | 
			
		||||
@@ -791,36 +783,30 @@ var NetworkAgent = class {
 | 
			
		||||
        this._vpnRequests[requestId] = vpnRequest;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _buildVPNServiceCache() {
 | 
			
		||||
        if (this._vpnCacheBuilt)
 | 
			
		||||
            return;
 | 
			
		||||
    async _findAuthBinary(serviceType) {
 | 
			
		||||
        let plugin;
 | 
			
		||||
 | 
			
		||||
        this._vpnCacheBuilt = true;
 | 
			
		||||
        this._vpnBinaries = { };
 | 
			
		||||
        try {
 | 
			
		||||
            plugin = await this._native.search_vpn_plugin(serviceType);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            logError(e);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        NM.VpnPluginInfo.list_load().forEach(plugin => {
 | 
			
		||||
            let service = plugin.get_service();
 | 
			
		||||
            let fileName = plugin.get_auth_dialog();
 | 
			
		||||
            let supportsHints = plugin.supports_hints();
 | 
			
		||||
            let externalUIMode = false;
 | 
			
		||||
        const fileName = plugin.get_auth_dialog();
 | 
			
		||||
        if (!GLib.file_test(fileName, GLib.FileTest.IS_EXECUTABLE)) {
 | 
			
		||||
            log('VPN plugin at %s is not executable'.format(fileName));
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            let prop = plugin.lookup_property('GNOME', 'supports-external-ui-mode');
 | 
			
		||||
            if (prop) {
 | 
			
		||||
                prop = prop.trim().toLowerCase();
 | 
			
		||||
                externalUIMode = ['true', 'yes', 'on', '1'].includes(prop);
 | 
			
		||||
            }
 | 
			
		||||
        const prop = plugin.lookup_property('GNOME', 'supports-external-ui-mode');
 | 
			
		||||
        const trimmedProp = prop ? prop.trim().toLowerCase() : '';
 | 
			
		||||
 | 
			
		||||
            if (GLib.file_test(fileName, GLib.FileTest.IS_EXECUTABLE)) {
 | 
			
		||||
                let binary = { fileName, externalUIMode, supportsHints };
 | 
			
		||||
                this._vpnBinaries[service] = binary;
 | 
			
		||||
 | 
			
		||||
                plugin.get_aliases().forEach(alias => {
 | 
			
		||||
                    this._vpnBinaries[alias] = binary;
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                log('VPN plugin at %s is not executable'.format(fileName));
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        return {
 | 
			
		||||
            fileName,
 | 
			
		||||
            supportsHints: plugin.supports_hints(),
 | 
			
		||||
            externalUIMode: ['true', 'yes', 'on', '1'].includes(trimmedProp),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
var Component = NetworkAgent;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,11 @@ const ModalDialog = imports.ui.modalDialog;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const UserWidget = imports.ui.userWidget;
 | 
			
		||||
 | 
			
		||||
const DialogMode = {
 | 
			
		||||
    AUTH: 0,
 | 
			
		||||
    CONFIRM: 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var DIALOG_ICON_SIZE = 48;
 | 
			
		||||
 | 
			
		||||
var WORK_SPINNER_ICON_SIZE = 16;
 | 
			
		||||
@@ -51,47 +56,32 @@ var AuthenticationDialog = GObject.registerClass({
 | 
			
		||||
            userName = userNames[0];
 | 
			
		||||
 | 
			
		||||
        this._user = AccountsService.UserManager.get_default().get_user(userName);
 | 
			
		||||
        let userRealName = this._user.get_real_name();
 | 
			
		||||
        this._userLoadedId = this._user.connect('notify::is_loaded',
 | 
			
		||||
                                                this._onUserChanged.bind(this));
 | 
			
		||||
        this._userChangedId = this._user.connect('changed',
 | 
			
		||||
                                                 this._onUserChanged.bind(this));
 | 
			
		||||
 | 
			
		||||
        // Special case 'root'
 | 
			
		||||
        let userIsRoot = false;
 | 
			
		||||
        if (userName == 'root') {
 | 
			
		||||
            userIsRoot = true;
 | 
			
		||||
            userRealName = _("Administrator");
 | 
			
		||||
        }
 | 
			
		||||
        let userBox = new St.BoxLayout({
 | 
			
		||||
            style_class: 'polkit-dialog-user-layout',
 | 
			
		||||
            vertical: false,
 | 
			
		||||
        });
 | 
			
		||||
        content.messageBox.add(userBox);
 | 
			
		||||
 | 
			
		||||
        if (userIsRoot) {
 | 
			
		||||
            let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-root-label',
 | 
			
		||||
                                            text: userRealName }));
 | 
			
		||||
            content.messageBox.add(userLabel, { x_fill: false,
 | 
			
		||||
                                                x_align: St.Align.START });
 | 
			
		||||
        } else {
 | 
			
		||||
            let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
 | 
			
		||||
                                             vertical: false });
 | 
			
		||||
            content.messageBox.add(userBox);
 | 
			
		||||
            this._userAvatar = new UserWidget.Avatar(this._user,
 | 
			
		||||
                                                     { iconSize: DIALOG_ICON_SIZE,
 | 
			
		||||
                                                       styleClass: 'polkit-dialog-user-icon' });
 | 
			
		||||
            this._userAvatar.actor.hide();
 | 
			
		||||
            userBox.add(this._userAvatar.actor,
 | 
			
		||||
                        { x_fill: true,
 | 
			
		||||
                          y_fill: false,
 | 
			
		||||
                          x_align: St.Align.END,
 | 
			
		||||
                          y_align: St.Align.START });
 | 
			
		||||
            let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-label',
 | 
			
		||||
                                            text: userRealName }));
 | 
			
		||||
            userBox.add(userLabel,
 | 
			
		||||
                        { x_fill: true,
 | 
			
		||||
                          y_fill: false,
 | 
			
		||||
                          x_align: St.Align.END,
 | 
			
		||||
                          y_align: St.Align.MIDDLE });
 | 
			
		||||
        }
 | 
			
		||||
        this._userAvatar = new UserWidget.Avatar(this._user, {
 | 
			
		||||
            iconSize: DIALOG_ICON_SIZE,
 | 
			
		||||
            styleClass: 'polkit-dialog-user-icon',
 | 
			
		||||
        });
 | 
			
		||||
        this._userAvatar.actor.hide();
 | 
			
		||||
        userBox.add_child(this._userAvatar.actor);
 | 
			
		||||
 | 
			
		||||
        this._onUserChanged();
 | 
			
		||||
        this._userLabel = new St.Label({
 | 
			
		||||
            style_class: userName === 'root'
 | 
			
		||||
                ? 'polkit-dialog-user-root-label'
 | 
			
		||||
                : 'polkit-dialog-user-label',
 | 
			
		||||
            x_expand: true,
 | 
			
		||||
            y_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (userName === 'root')
 | 
			
		||||
            this._userLabel.text = _('Administrator');
 | 
			
		||||
 | 
			
		||||
        userBox.add_child(this._userLabel);
 | 
			
		||||
 | 
			
		||||
        this._passwordBox = new St.BoxLayout({ vertical: false, style_class: 'prompt-dialog-password-box' });
 | 
			
		||||
        content.messageBox.add(this._passwordBox);
 | 
			
		||||
@@ -105,10 +95,11 @@ var AuthenticationDialog = GObject.registerClass({
 | 
			
		||||
        this._passwordBox.add(this._passwordEntry,
 | 
			
		||||
                              { expand: true });
 | 
			
		||||
 | 
			
		||||
        this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
 | 
			
		||||
        this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
 | 
			
		||||
            animate: true,
 | 
			
		||||
        });
 | 
			
		||||
        this._passwordBox.add(this._workSpinner.actor);
 | 
			
		||||
 | 
			
		||||
        this.setInitialKeyFocus(this._passwordEntry);
 | 
			
		||||
        this._passwordBox.hide();
 | 
			
		||||
 | 
			
		||||
        this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' });
 | 
			
		||||
@@ -144,8 +135,16 @@ var AuthenticationDialog = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        this._doneEmitted = false;
 | 
			
		||||
 | 
			
		||||
        this._mode = -1;
 | 
			
		||||
 | 
			
		||||
        this._identityToAuth = Polkit.UnixUser.new_for_name(userName);
 | 
			
		||||
        this._cookie = cookie;
 | 
			
		||||
 | 
			
		||||
        this._userLoadedId = this._user.connect('notify::is-loaded',
 | 
			
		||||
            this._onUserChanged.bind(this));
 | 
			
		||||
        this._userChangedId = this._user.connect('changed',
 | 
			
		||||
            this._onUserChanged.bind(this));
 | 
			
		||||
        this._onUserChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _setWorking(working) {
 | 
			
		||||
@@ -155,8 +154,9 @@ var AuthenticationDialog = GObject.registerClass({
 | 
			
		||||
            this._workSpinner.stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    performAuthentication() {
 | 
			
		||||
    _initiateSession() {
 | 
			
		||||
        this._destroySession();
 | 
			
		||||
 | 
			
		||||
        this._session = new PolkitAgent.Session({ identity: this._identityToAuth,
 | 
			
		||||
                                                  cookie: this._cookie });
 | 
			
		||||
        this._sessionCompletedId = this._session.connect('completed', this._onSessionCompleted.bind(this));
 | 
			
		||||
@@ -216,7 +216,10 @@ var AuthenticationDialog = GObject.registerClass({
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onAuthenticateButtonPressed() {
 | 
			
		||||
        this._onEntryActivate();
 | 
			
		||||
        if (this._mode === DialogMode.CONFIRM)
 | 
			
		||||
            this._initiateSession();
 | 
			
		||||
        else
 | 
			
		||||
            this._onEntryActivate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onSessionCompleted(session, gainedAuthorization) {
 | 
			
		||||
@@ -247,7 +250,7 @@ var AuthenticationDialog = GObject.registerClass({
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Try and authenticate again */
 | 
			
		||||
            this.performAuthentication();
 | 
			
		||||
            this._initiateSession();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -265,9 +268,10 @@ var AuthenticationDialog = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        this._passwordBox.show();
 | 
			
		||||
        this._passwordEntry.set_text('');
 | 
			
		||||
        this._passwordEntry.grab_key_focus();
 | 
			
		||||
        this._updateSensitivity(true);
 | 
			
		||||
 | 
			
		||||
        this._ensureOpen();
 | 
			
		||||
        this._passwordEntry.grab_key_focus();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onSessionShowError(session, text) {
 | 
			
		||||
@@ -303,10 +307,40 @@ var AuthenticationDialog = GObject.registerClass({
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onUserChanged() {
 | 
			
		||||
        if (this._user.is_loaded && this._userAvatar) {
 | 
			
		||||
        if (!this._user.is_loaded)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let userName = this._user.get_user_name();
 | 
			
		||||
        let realName = this._user.get_real_name();
 | 
			
		||||
 | 
			
		||||
        if (userName !== 'root') {
 | 
			
		||||
            this._userLabel.set_text(realName);
 | 
			
		||||
 | 
			
		||||
            this._userAvatar.update();
 | 
			
		||||
            this._userAvatar.actor.show();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._user.get_password_mode() === AccountsService.UserPasswordMode.NONE) {
 | 
			
		||||
            if (this._mode === DialogMode.CONFIRM)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            this._mode = DialogMode.CONFIRM;
 | 
			
		||||
            this._destroySession();
 | 
			
		||||
 | 
			
		||||
            this._okButton.reactive = true;
 | 
			
		||||
 | 
			
		||||
            /* We normally open the dialog when we get a "request" signal, but
 | 
			
		||||
             * since in this case initiating a session would perform the
 | 
			
		||||
             * authentication, only open the dialog and initiate the session
 | 
			
		||||
             * when the user confirmed. */
 | 
			
		||||
            this._ensureOpen();
 | 
			
		||||
        } else {
 | 
			
		||||
            if (this._mode === DialogMode.AUTH)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            this._mode = DialogMode.AUTH;
 | 
			
		||||
            this._initiateSession();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cancel() {
 | 
			
		||||
@@ -369,19 +403,7 @@ var AuthenticationAgent = class {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._currentDialog = new AuthenticationDialog(actionId, message, cookie, userNames);
 | 
			
		||||
 | 
			
		||||
        // We actually don't want to open the dialog until we know for
 | 
			
		||||
        // sure that we're going to interact with the user. For
 | 
			
		||||
        // example, if the password for the identity to auth is blank
 | 
			
		||||
        // (which it will be on a live CD) then there will be no
 | 
			
		||||
        // conversation at all... of course, we don't *know* that
 | 
			
		||||
        // until we actually try it.
 | 
			
		||||
        //
 | 
			
		||||
        // See https://bugzilla.gnome.org/show_bug.cgi?id=643062 for more
 | 
			
		||||
        // discussion.
 | 
			
		||||
 | 
			
		||||
        this._currentDialog.connect('done', this._onDialogDone.bind(this));
 | 
			
		||||
        this._currentDialog.performAuthentication();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onCancel(_nativeAgent) {
 | 
			
		||||
 
 | 
			
		||||
@@ -51,10 +51,16 @@ class Dialog extends St.Widget {
 | 
			
		||||
                           y_align: St.Align.START });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
    makeInactive() {
 | 
			
		||||
        if (this._eventId != 0)
 | 
			
		||||
            this._parentActor.disconnect(this._eventId);
 | 
			
		||||
        this._eventId = 0;
 | 
			
		||||
 | 
			
		||||
        this.buttonLayout.get_children().forEach(c => c.set_reactive(false));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
        this.makeInactive();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _modalEventHandler(actor, event) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							@@ -573,11 +573,15 @@ var _Draggable = class _Draggable {
 | 
			
		||||
        while (target) {
 | 
			
		||||
            if (target._delegate && target._delegate.acceptDrop) {
 | 
			
		||||
                let [r_, targX, targY] = target.transform_stage_point(dropX, dropY);
 | 
			
		||||
                if (target._delegate.acceptDrop(this.actor._delegate,
 | 
			
		||||
                                                this._dragActor,
 | 
			
		||||
                                                targX,
 | 
			
		||||
                                                targY,
 | 
			
		||||
                                                event.get_time())) {
 | 
			
		||||
                let accepted = false;
 | 
			
		||||
                try {
 | 
			
		||||
                    accepted = target._delegate.acceptDrop(this.actor._delegate,
 | 
			
		||||
                        this._dragActor, targX, targY, event.get_time());
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    // On error, skip this target
 | 
			
		||||
                    logError(e, "Skipping drag target");
 | 
			
		||||
                }
 | 
			
		||||
                if (accepted) {
 | 
			
		||||
                    // If it accepted the drop without taking the actor,
 | 
			
		||||
                    // handle it ourselves.
 | 
			
		||||
                    if (this._dragActor && this._dragActor.get_parent() == Main.uiGroup) {
 | 
			
		||||
 
 | 
			
		||||
@@ -109,8 +109,6 @@ function _easeActor(actor, params) {
 | 
			
		||||
        actor.set_easing_mode(params.mode);
 | 
			
		||||
    delete params.mode;
 | 
			
		||||
 | 
			
		||||
    Meta.disable_unredirect_for_display(global.display);
 | 
			
		||||
 | 
			
		||||
    let cleanup = () => Meta.enable_unredirect_for_display(global.display);
 | 
			
		||||
    let callback = _makeEaseCallback(params, cleanup);
 | 
			
		||||
 | 
			
		||||
@@ -124,6 +122,11 @@ function _easeActor(actor, params) {
 | 
			
		||||
    let transition = animatedProps.map(p => actor.get_transition(p))
 | 
			
		||||
        .find(t => t !== null);
 | 
			
		||||
 | 
			
		||||
    if (transition && transition.delay)
 | 
			
		||||
        transition.connect('started', () => Meta.disable_unredirect_for_display(global.display));
 | 
			
		||||
    else
 | 
			
		||||
        Meta.disable_unredirect_for_display(global.display);
 | 
			
		||||
 | 
			
		||||
    if (transition)
 | 
			
		||||
        transition.connect('stopped', (t, finished) => callback(finished));
 | 
			
		||||
    else
 | 
			
		||||
@@ -145,8 +148,6 @@ function _easeActorProperty(actor, propName, target, params) {
 | 
			
		||||
    if (actor instanceof Clutter.Actor && !actor.mapped)
 | 
			
		||||
        duration = 0;
 | 
			
		||||
 | 
			
		||||
    Meta.disable_unredirect_for_display(global.display);
 | 
			
		||||
 | 
			
		||||
    let cleanup = () => Meta.enable_unredirect_for_display(global.display);
 | 
			
		||||
    let callback = _makeEaseCallback(params, cleanup);
 | 
			
		||||
 | 
			
		||||
@@ -157,6 +158,7 @@ function _easeActorProperty(actor, propName, target, params) {
 | 
			
		||||
        let [obj, prop] = _getPropertyTarget(actor, propName);
 | 
			
		||||
        obj[prop] = target;
 | 
			
		||||
 | 
			
		||||
        Meta.disable_unredirect_for_display(global.display);
 | 
			
		||||
        callback(true);
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
@@ -172,6 +174,11 @@ function _easeActorProperty(actor, propName, target, params) {
 | 
			
		||||
 | 
			
		||||
    transition.set_to(target);
 | 
			
		||||
 | 
			
		||||
    if (transition.delay)
 | 
			
		||||
        transition.connect('started', () => Meta.disable_unredirect_for_display(global.display));
 | 
			
		||||
    else
 | 
			
		||||
        Meta.disable_unredirect_for_display(global.display);
 | 
			
		||||
 | 
			
		||||
    transition.connect('stopped', (t, finished) => callback(finished));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 | 
			
		||||
/* exported init connect disconnect */
 | 
			
		||||
 | 
			
		||||
const { Gio, St } = imports.gi;
 | 
			
		||||
const { GLib, Gio, St } = imports.gi;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const ExtensionUtils = imports.misc.extensionUtils;
 | 
			
		||||
@@ -28,6 +28,23 @@ var ExtensionManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    init() {
 | 
			
		||||
        // The following file should exist for a period of time when extensions
 | 
			
		||||
        // are enabled after start. If it exists, then the systemd unit will
 | 
			
		||||
        // disable extensions should gnome-shell crash.
 | 
			
		||||
        // Should the file already exist from a previous login, then this is OK.
 | 
			
		||||
        let disableFilename = GLib.build_filenamev([GLib.get_user_runtime_dir(), 'gnome-shell-disable-extensions']);
 | 
			
		||||
        let disableFile = Gio.File.new_for_path(disableFilename);
 | 
			
		||||
        try {
 | 
			
		||||
            disableFile.create(Gio.FileCreateFlags.REPLACE_DESTINATION, null);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            log(`Failed to create file ${disableFilename}: ${e.message}`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 60, () => {
 | 
			
		||||
            FileUtils.deleteGFile(disableFile);
 | 
			
		||||
            return GLib.SOURCE_REMOVE;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._sessionUpdated();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -466,10 +466,17 @@ Signals.addSignalMethods(Key.prototype);
 | 
			
		||||
 | 
			
		||||
var KeyboardModel = class {
 | 
			
		||||
    constructor(groupName) {
 | 
			
		||||
        try {
 | 
			
		||||
            this._model = this._loadModel(groupName);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            this._model = this._loadModel('us');
 | 
			
		||||
        let names = [groupName];
 | 
			
		||||
        if (groupName.includes('+'))
 | 
			
		||||
            names.push(groupName.replace(/\+.*/, ''));
 | 
			
		||||
        names.push('us');
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < names.length; i++) {
 | 
			
		||||
            try {
 | 
			
		||||
                this._model = this._loadModel(names[i]);
 | 
			
		||||
                break;
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -887,7 +894,7 @@ var EmojiSelection = class EmojiSelection {
 | 
			
		||||
        this._emojiPager.connect('emoji', (pager, str) => {
 | 
			
		||||
            this.emit('emoji-selected', str);
 | 
			
		||||
        });
 | 
			
		||||
        this.actor.add(this._emojiPager.actor, { expand: true });
 | 
			
		||||
        this.actor.add(this._emojiPager, { expand: true });
 | 
			
		||||
 | 
			
		||||
        this._pageIndicator = new PageIndicators.PageIndicators(false);
 | 
			
		||||
        this.actor.add(this._pageIndicator, { expand: true, x_fill: false, y_fill: false });
 | 
			
		||||
 
 | 
			
		||||
@@ -189,6 +189,7 @@ var LayoutManager = GObject.registerClass({
 | 
			
		||||
               'startup-complete': {},
 | 
			
		||||
               'startup-prepared': {},
 | 
			
		||||
               'monitors-changed': {},
 | 
			
		||||
               'system-modal-opened': {},
 | 
			
		||||
               'keyboard-visible-changed': { param_types: [GObject.TYPE_BOOLEAN] } },
 | 
			
		||||
}, class LayoutManager extends GObject.Object {
 | 
			
		||||
    _init() {
 | 
			
		||||
 
 | 
			
		||||
@@ -127,6 +127,8 @@ var Magnifier = class Magnifier {
 | 
			
		||||
     * Show the system mouse pointer.
 | 
			
		||||
     */
 | 
			
		||||
    showSystemCursor() {
 | 
			
		||||
        if (this._cursorTracker.set_keep_focus_while_hidden)
 | 
			
		||||
            this._cursorTracker.set_keep_focus_while_hidden(false);
 | 
			
		||||
        this._cursorTracker.set_pointer_visible(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -135,6 +137,8 @@ var Magnifier = class Magnifier {
 | 
			
		||||
     * Hide the system mouse pointer.
 | 
			
		||||
     */
 | 
			
		||||
    hideSystemCursor() {
 | 
			
		||||
        if (this._cursorTracker.set_keep_focus_while_hidden)
 | 
			
		||||
            this._cursorTracker.set_keep_focus_while_hidden(true);
 | 
			
		||||
        this._cursorTracker.set_pointer_visible(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -169,7 +173,7 @@ var Magnifier = class Magnifier {
 | 
			
		||||
        // Make sure system mouse pointer is shown when all zoom regions are
 | 
			
		||||
        // invisible.
 | 
			
		||||
        if (!activate)
 | 
			
		||||
            this._cursorTracker.set_pointer_visible(true);
 | 
			
		||||
            this.showSystemCursor();
 | 
			
		||||
 | 
			
		||||
        // Notify interested parties of this change
 | 
			
		||||
        this.emit('active-changed', activate);
 | 
			
		||||
 
 | 
			
		||||
@@ -333,7 +333,10 @@ var Message = class Message {
 | 
			
		||||
 | 
			
		||||
        let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic',
 | 
			
		||||
                                      icon_size: 16 });
 | 
			
		||||
        this._closeButton = new St.Button({ child: closeIcon, opacity: 0 });
 | 
			
		||||
        this._closeButton = new St.Button({
 | 
			
		||||
            style_class: 'message-close-button',
 | 
			
		||||
            child: closeIcon, opacity: 0,
 | 
			
		||||
        });
 | 
			
		||||
        titleBox.add_actor(this._closeButton);
 | 
			
		||||
 | 
			
		||||
        this._bodyStack = new St.Widget({ x_expand: true });
 | 
			
		||||
 
 | 
			
		||||
@@ -216,6 +216,8 @@ var ModalDialog = GObject.registerClass({
 | 
			
		||||
        if (!Main.pushModal(this, params))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.emit('system-modal-opened');
 | 
			
		||||
 | 
			
		||||
        this._hasModal = true;
 | 
			
		||||
        if (this._savedKeyFocus) {
 | 
			
		||||
            this._savedKeyFocus.grab_key_focus();
 | 
			
		||||
 
 | 
			
		||||
@@ -199,7 +199,11 @@ var Overview = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sessionUpdated() {
 | 
			
		||||
        this.isDummy = !Main.sessionMode.hasOverview;
 | 
			
		||||
        const { hasOverview } = Main.sessionMode;
 | 
			
		||||
        if (!hasOverview)
 | 
			
		||||
            this.hide();
 | 
			
		||||
 | 
			
		||||
        this.isDummy = !hasOverview;
 | 
			
		||||
        this._createOverview();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -170,9 +170,13 @@ class AppMenu extends PopupMenu.PopupMenu {
 | 
			
		||||
        let windows = this._app.get_windows();
 | 
			
		||||
        windows.forEach(window => {
 | 
			
		||||
            let title = window.title || this._app.get_name();
 | 
			
		||||
            this._windowSection.addAction(title, event => {
 | 
			
		||||
            let item = this._windowSection.addAction(title, event => {
 | 
			
		||||
                Main.activateWindow(window, event.get_time());
 | 
			
		||||
            });
 | 
			
		||||
            let id = window.connect('notify::title', () => {
 | 
			
		||||
                item.label.text = window.title || this._app.get_name();
 | 
			
		||||
            });
 | 
			
		||||
            item.connect('destroy', () => window.disconnect(id));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -234,7 +238,10 @@ var AppMenuButton = GObject.registerClass({
 | 
			
		||||
        this._overviewHidingId = Main.overview.connect('hiding', this._sync.bind(this));
 | 
			
		||||
        this._overviewShowingId = Main.overview.connect('showing', this._sync.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._spinner = new Animation.Spinner(PANEL_ICON_SIZE, true);
 | 
			
		||||
        this._spinner = new Animation.Spinner(PANEL_ICON_SIZE, {
 | 
			
		||||
            animate: true,
 | 
			
		||||
            hideOnStop: true,
 | 
			
		||||
        });
 | 
			
		||||
        this._container.add_actor(this._spinner.actor);
 | 
			
		||||
 | 
			
		||||
        let menu = new AppMenu(this);
 | 
			
		||||
 
 | 
			
		||||
@@ -804,6 +804,7 @@ var PopupMenu = class extends PopupMenuBase {
 | 
			
		||||
            this._keyPressId = this.sourceActor.connect('key-press-event',
 | 
			
		||||
                                                        this._onKeyPress.bind(this));
 | 
			
		||||
 | 
			
		||||
        this._systemModalOpenedId = 0;
 | 
			
		||||
        this._openedSubMenu = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -878,6 +879,11 @@ var PopupMenu = class extends PopupMenuBase {
 | 
			
		||||
        if (this.isEmpty())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (!this._systemModalOpenedId) {
 | 
			
		||||
            this._systemModalOpenedId =
 | 
			
		||||
                Main.layoutManager.connect('system-modal-opened', () => this.close());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.isOpen = true;
 | 
			
		||||
 | 
			
		||||
        this._boxPointer.setPosition(this.sourceActor, this._arrowAlignment);
 | 
			
		||||
@@ -908,6 +914,11 @@ var PopupMenu = class extends PopupMenuBase {
 | 
			
		||||
    destroy() {
 | 
			
		||||
        if (this._keyPressId)
 | 
			
		||||
            this.sourceActor.disconnect(this._keyPressId);
 | 
			
		||||
 | 
			
		||||
        if (this._systemModalOpenedId)
 | 
			
		||||
            Main.layoutManager.disconnect(this._systemModalOpenedId);
 | 
			
		||||
        this._systemModalOpenedId = 0;
 | 
			
		||||
 | 
			
		||||
        super.destroy();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,8 @@ const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const ShellDBus = imports.ui.shellDBus;
 | 
			
		||||
const SmartcardManager = imports.misc.smartcardManager;
 | 
			
		||||
 | 
			
		||||
const { adjustAnimationTime } = imports.ui.environment;
 | 
			
		||||
 | 
			
		||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
 | 
			
		||||
const LOCK_ENABLED_KEY = 'lock-enabled';
 | 
			
		||||
const LOCK_DELAY_KEY = 'lock-delay';
 | 
			
		||||
@@ -51,11 +53,17 @@ var Clock = class {
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'screen-shield-clock',
 | 
			
		||||
                                        vertical: true });
 | 
			
		||||
 | 
			
		||||
        this._time = new St.Label({ style_class: 'screen-shield-clock-time' });
 | 
			
		||||
        this._date = new St.Label({ style_class: 'screen-shield-clock-date' });
 | 
			
		||||
        this._time = new St.Label({
 | 
			
		||||
            style_class: 'screen-shield-clock-time',
 | 
			
		||||
            x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
        });
 | 
			
		||||
        this._date = new St.Label({
 | 
			
		||||
            style_class: 'screen-shield-clock-date',
 | 
			
		||||
            x_align: Clutter.ActorAlign.CENTER,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.actor.add(this._time, { x_align: St.Align.MIDDLE });
 | 
			
		||||
        this.actor.add(this._date, { x_align: St.Align.MIDDLE });
 | 
			
		||||
        this.actor.add_child(this._time);
 | 
			
		||||
        this.actor.add_child(this._date);
 | 
			
		||||
 | 
			
		||||
        this._wallClock = new GnomeDesktop.WallClock({ time_only: true });
 | 
			
		||||
        this._wallClock.connect('notify::clock', this._updateClock.bind(this));
 | 
			
		||||
@@ -91,7 +99,7 @@ var NotificationsBox = class {
 | 
			
		||||
                                                   style_class: 'screen-shield-notifications-container' });
 | 
			
		||||
        this._scrollView.add_actor(this._notificationBox);
 | 
			
		||||
 | 
			
		||||
        this.actor.add(this._scrollView, { x_fill: true, x_align: St.Align.START });
 | 
			
		||||
        this.actor.add_child(this._scrollView);
 | 
			
		||||
 | 
			
		||||
        this._sources = new Map();
 | 
			
		||||
        Main.messageTray.getSources().forEach(source => {
 | 
			
		||||
@@ -132,10 +140,10 @@ var NotificationsBox = class {
 | 
			
		||||
 | 
			
		||||
    _makeNotificationSource(source, box) {
 | 
			
		||||
        let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
 | 
			
		||||
        box.add(sourceActor, { y_fill: true });
 | 
			
		||||
        box.add_child(sourceActor);
 | 
			
		||||
 | 
			
		||||
        let textBox = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        box.add(textBox, { y_fill: false, y_align: St.Align.START });
 | 
			
		||||
        box.add_child(textBox);
 | 
			
		||||
 | 
			
		||||
        let title = new St.Label({ text: source.title,
 | 
			
		||||
                                   style_class: 'screen-shield-notification-label' });
 | 
			
		||||
@@ -158,7 +166,7 @@ var NotificationsBox = class {
 | 
			
		||||
        box.add(sourceBin);
 | 
			
		||||
 | 
			
		||||
        let textBox = new St.BoxLayout({ vertical: true });
 | 
			
		||||
        box.add(textBox, { y_fill: false, y_align: St.Align.START });
 | 
			
		||||
        box.add_child(textBox);
 | 
			
		||||
 | 
			
		||||
        let title = new St.Label({ text: source.title,
 | 
			
		||||
                                   style_class: 'screen-shield-notification-label' });
 | 
			
		||||
@@ -220,7 +228,7 @@ var NotificationsBox = class {
 | 
			
		||||
        obj.sourceBox = new St.BoxLayout({ style_class: 'screen-shield-notification-source',
 | 
			
		||||
                                           x_expand: true });
 | 
			
		||||
        this._showSource(source, obj, obj.sourceBox);
 | 
			
		||||
        this._notificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
 | 
			
		||||
        this._notificationBox.add_child(obj.sourceBox);
 | 
			
		||||
 | 
			
		||||
        obj.sourceCountChangedId = source.connect('count-updated', source => {
 | 
			
		||||
            this._countChanged(source, obj);
 | 
			
		||||
@@ -832,7 +840,7 @@ var ScreenShield = class {
 | 
			
		||||
 | 
			
		||||
        if (shouldLock) {
 | 
			
		||||
            let lockTimeout = Math.max(
 | 
			
		||||
                STANDARD_FADE_TIME,
 | 
			
		||||
                adjustAnimationTime(STANDARD_FADE_TIME),
 | 
			
		||||
                this._settings.get_uint(LOCK_DELAY_KEY) * 1000);
 | 
			
		||||
            this._lockTimeoutId = GLib.timeout_add(
 | 
			
		||||
                GLib.PRIORITY_DEFAULT,
 | 
			
		||||
@@ -1131,16 +1139,13 @@ var ScreenShield = class {
 | 
			
		||||
                                                         vertical: true,
 | 
			
		||||
                                                         style_class: 'screen-shield-contents-box' });
 | 
			
		||||
        this._clock = new Clock();
 | 
			
		||||
        this._lockScreenContentsBox.add(this._clock.actor, { x_fill: true,
 | 
			
		||||
                                                             y_fill: true });
 | 
			
		||||
        this._lockScreenContentsBox.add_child(this._clock.actor);
 | 
			
		||||
 | 
			
		||||
        this._lockScreenContents.add_actor(this._lockScreenContentsBox);
 | 
			
		||||
 | 
			
		||||
        this._notificationsBox = new NotificationsBox();
 | 
			
		||||
        this._wakeUpScreenId = this._notificationsBox.connect('wake-up-screen', this._wakeUpScreen.bind(this));
 | 
			
		||||
        this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
 | 
			
		||||
                                                                        y_fill: true,
 | 
			
		||||
                                                                        expand: true });
 | 
			
		||||
        this._lockScreenContentsBox.add_child(this._notificationsBox.actor);
 | 
			
		||||
 | 
			
		||||
        this._hasLockScreen = true;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -359,7 +359,9 @@ var ShellMountPasswordDialog = GObject.registerClass({
 | 
			
		||||
        this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
 | 
			
		||||
        ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
 | 
			
		||||
        this.setInitialKeyFocus(this._passwordEntry);
 | 
			
		||||
        this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
 | 
			
		||||
        this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
 | 
			
		||||
            animate: true,
 | 
			
		||||
        });
 | 
			
		||||
        this._passwordEntry.secondary_icon = this._workSpinner.actor;
 | 
			
		||||
 | 
			
		||||
        if (rtl) {
 | 
			
		||||
 
 | 
			
		||||
@@ -138,14 +138,14 @@ class ATIndicator extends PanelMenu.Button {
 | 
			
		||||
            interfaceSettings.is_writable(KEY_ICON_THEME),
 | 
			
		||||
            enabled => {
 | 
			
		||||
                if (enabled) {
 | 
			
		||||
                    interfaceSettings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
 | 
			
		||||
                    interfaceSettings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
 | 
			
		||||
                    interfaceSettings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
 | 
			
		||||
                } else if (!hasHC) {
 | 
			
		||||
                    interfaceSettings.set_string(KEY_GTK_THEME, gtkTheme);
 | 
			
		||||
                    interfaceSettings.set_string(KEY_ICON_THEME, iconTheme);
 | 
			
		||||
                    interfaceSettings.set_string(KEY_GTK_THEME, gtkTheme);
 | 
			
		||||
                } else {
 | 
			
		||||
                    interfaceSettings.reset(KEY_GTK_THEME);
 | 
			
		||||
                    interfaceSettings.reset(KEY_ICON_THEME);
 | 
			
		||||
                    interfaceSettings.reset(KEY_GTK_THEME);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -111,9 +111,12 @@ var Indicator = class extends PanelMenu.SystemIndicator {
 | 
			
		||||
        let chargingState = this._proxy.State == UPower.DeviceState.CHARGING
 | 
			
		||||
            ? '-charging' : '';
 | 
			
		||||
        let fillLevel = 10 * Math.floor(this._proxy.Percentage / 10);
 | 
			
		||||
        let icon = this._proxy.State == UPower.DeviceState.FULLY_CHARGED
 | 
			
		||||
            ? 'battery-level-100-charged-symbolic'
 | 
			
		||||
            : `battery-level-${fillLevel}${chargingState}-symbolic`;
 | 
			
		||||
        let icon;
 | 
			
		||||
        if (this._proxy.State == UPower.DeviceState.FULLY_CHARGED ||
 | 
			
		||||
            fillLevel === 100)
 | 
			
		||||
            icon = 'battery-level-100-charged-symbolic';
 | 
			
		||||
        else
 | 
			
		||||
            icon = `battery-level-${fillLevel}${chargingState}-symbolic`;
 | 
			
		||||
 | 
			
		||||
        // Make sure we fall back to fallback-icon-name and not GThemedIcon's
 | 
			
		||||
        // default fallbacks
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,9 @@ var SwitcherPopup = GObject.registerClass({
 | 
			
		||||
 | 
			
		||||
        Main.uiGroup.add_actor(this);
 | 
			
		||||
 | 
			
		||||
        this._systemModalOpenedId =
 | 
			
		||||
            Main.layoutManager.connect('system-modal-opened', () => this.destroy());
 | 
			
		||||
 | 
			
		||||
        this._haveModal = false;
 | 
			
		||||
        this._modifierMask = 0;
 | 
			
		||||
 | 
			
		||||
@@ -180,6 +183,14 @@ var SwitcherPopup = GObject.registerClass({
 | 
			
		||||
        if (keysym == Clutter.Escape || keysym == Clutter.Tab)
 | 
			
		||||
            this.fadeAndDestroy();
 | 
			
		||||
 | 
			
		||||
        // Allow to explicitly select the current item; this is particularly
 | 
			
		||||
        // useful for no-modifier popups
 | 
			
		||||
        if (keysym === Clutter.KEY_space ||
 | 
			
		||||
            keysym === Clutter.KEY_Return ||
 | 
			
		||||
            keysym === Clutter.KEY_KP_Enter ||
 | 
			
		||||
            keysym === Clutter.KEY_ISO_Enter)
 | 
			
		||||
            this._finish(event.get_time());
 | 
			
		||||
 | 
			
		||||
        return Clutter.EVENT_STOP;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -270,7 +281,7 @@ var SwitcherPopup = GObject.registerClass({
 | 
			
		||||
            GLib.PRIORITY_DEFAULT,
 | 
			
		||||
            NO_MODS_TIMEOUT,
 | 
			
		||||
            () => {
 | 
			
		||||
                this._finish(global.get_current_time());
 | 
			
		||||
                this._finish(global.display.get_current_time_roundtrip());
 | 
			
		||||
                this._noModsTimeoutId = 0;
 | 
			
		||||
                return GLib.SOURCE_REMOVE;
 | 
			
		||||
            });
 | 
			
		||||
@@ -304,6 +315,8 @@ var SwitcherPopup = GObject.registerClass({
 | 
			
		||||
    _onDestroy() {
 | 
			
		||||
        this._popModal();
 | 
			
		||||
 | 
			
		||||
        Main.layoutManager.disconnect(this._systemModalOpenedId);
 | 
			
		||||
 | 
			
		||||
        if (this._motionTimeoutId != 0)
 | 
			
		||||
            GLib.source_remove(this._motionTimeoutId);
 | 
			
		||||
        if (this._initialDelayTimeoutId != 0)
 | 
			
		||||
@@ -560,10 +573,10 @@ var SwitcherList = GObject.registerClass({
 | 
			
		||||
        let leftPadding = this.get_theme_node().get_padding(St.Side.LEFT);
 | 
			
		||||
        let rightPadding = this.get_theme_node().get_padding(St.Side.RIGHT);
 | 
			
		||||
 | 
			
		||||
        let [, natScrollViewWidth] = this._scrollView.get_preferred_width(height);
 | 
			
		||||
        let [minListWidth] = this._list.get_preferred_width(height);
 | 
			
		||||
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
        let scrollable = natScrollViewWidth > width;
 | 
			
		||||
        let scrollable = minListWidth > width;
 | 
			
		||||
 | 
			
		||||
        this._scrollView.allocate(contentBox, flags);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -700,16 +700,17 @@ var WindowManager = class {
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this._shellwm =  global.window_manager;
 | 
			
		||||
 | 
			
		||||
        this._minimizing = [];
 | 
			
		||||
        this._unminimizing = [];
 | 
			
		||||
        this._mapping = [];
 | 
			
		||||
        this._resizing = [];
 | 
			
		||||
        this._destroying = [];
 | 
			
		||||
        this._minimizing = new Set();
 | 
			
		||||
        this._unminimizing = new Set();
 | 
			
		||||
        this._mapping = new Set();
 | 
			
		||||
        this._resizing = new Set();
 | 
			
		||||
        this._resizePending = new Set();
 | 
			
		||||
        this._destroying = new Set();
 | 
			
		||||
        this._movingWindow = null;
 | 
			
		||||
 | 
			
		||||
        this._dimmedWindows = [];
 | 
			
		||||
 | 
			
		||||
        this._skippedActors = [];
 | 
			
		||||
        this._skippedActors = new Set();
 | 
			
		||||
 | 
			
		||||
        this._allowedKeybindings = {};
 | 
			
		||||
 | 
			
		||||
@@ -1257,7 +1258,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    skipNextEffect(actor) {
 | 
			
		||||
        this._skippedActors.push(actor);
 | 
			
		||||
        this._skippedActors.add(actor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setCustomKeybindingHandler(name, modes, handler) {
 | 
			
		||||
@@ -1286,7 +1287,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _shouldAnimateActor(actor, types) {
 | 
			
		||||
        if (this._removeEffect(this._skippedActors, actor))
 | 
			
		||||
        if (this._skippedActors.delete(actor))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (!this._shouldAnimate())
 | 
			
		||||
@@ -1299,15 +1300,6 @@ var WindowManager = class {
 | 
			
		||||
        return types.includes(type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _removeEffect(list, actor) {
 | 
			
		||||
        let idx = list.indexOf(actor);
 | 
			
		||||
        if (idx != -1) {
 | 
			
		||||
            list.splice(idx, 1);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _minimizeWindow(shellwm, actor) {
 | 
			
		||||
        let types = [Meta.WindowType.NORMAL,
 | 
			
		||||
                     Meta.WindowType.MODAL_DIALOG,
 | 
			
		||||
@@ -1319,7 +1311,7 @@ var WindowManager = class {
 | 
			
		||||
 | 
			
		||||
        actor.set_scale(1.0, 1.0);
 | 
			
		||||
 | 
			
		||||
        this._minimizing.push(actor);
 | 
			
		||||
        this._minimizing.add(actor);
 | 
			
		||||
 | 
			
		||||
        if (actor.meta_window.is_monitor_sized()) {
 | 
			
		||||
            actor.ease({
 | 
			
		||||
@@ -1373,7 +1365,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _minimizeWindowDone(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._minimizing, actor)) {
 | 
			
		||||
        if (this._minimizing.delete(actor)) {
 | 
			
		||||
            actor.remove_all_transitions();
 | 
			
		||||
            actor.set_scale(1.0, 1.0);
 | 
			
		||||
            actor.set_opacity(255);
 | 
			
		||||
@@ -1384,7 +1376,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _minimizeWindowOverwritten(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._minimizing, actor)) {
 | 
			
		||||
        if (this._minimizing.delete(actor)) {
 | 
			
		||||
            shellwm.completed_minimize(actor);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -1398,7 +1390,7 @@ var WindowManager = class {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._unminimizing.push(actor);
 | 
			
		||||
        this._unminimizing.add(actor);
 | 
			
		||||
 | 
			
		||||
        if (actor.meta_window.is_monitor_sized()) {
 | 
			
		||||
            actor.opacity = 0;
 | 
			
		||||
@@ -1455,7 +1447,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _unminimizeWindowDone(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._unminimizing, actor)) {
 | 
			
		||||
        if (this._unminimizing.delete(actor)) {
 | 
			
		||||
            actor.remove_all_transitions();
 | 
			
		||||
            actor.set_scale(1.0, 1.0);
 | 
			
		||||
            actor.set_opacity(255);
 | 
			
		||||
@@ -1466,7 +1458,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _unminimizeWindowOverwritten(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._unminimizing, actor)) {
 | 
			
		||||
        if (this._unminimizing.delete(actor)) {
 | 
			
		||||
            shellwm.completed_unminimize(actor);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -1501,6 +1493,7 @@ var WindowManager = class {
 | 
			
		||||
            this._clearAnimationInfo(actor);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._resizePending.add(actor);
 | 
			
		||||
        actor.__animationInfo = { clone: actorClone,
 | 
			
		||||
                                  oldRect: oldFrameRect,
 | 
			
		||||
                                  destroyId: destroyId };
 | 
			
		||||
@@ -1509,7 +1502,7 @@ var WindowManager = class {
 | 
			
		||||
    _sizeChangedWindow(shellwm, actor) {
 | 
			
		||||
        if (!actor.__animationInfo)
 | 
			
		||||
            return;
 | 
			
		||||
        if (this._resizing.includes(actor))
 | 
			
		||||
        if (this._resizing.has(actor))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let actorClone = actor.__animationInfo.clone;
 | 
			
		||||
@@ -1519,7 +1512,8 @@ var WindowManager = class {
 | 
			
		||||
        let scaleX = targetRect.width / sourceRect.width;
 | 
			
		||||
        let scaleY = targetRect.height / sourceRect.height;
 | 
			
		||||
 | 
			
		||||
        this._resizing.push(actor);
 | 
			
		||||
        this._resizePending.delete(actor);
 | 
			
		||||
        this._resizing.add(actor);
 | 
			
		||||
 | 
			
		||||
        // Now scale and fade out the clone
 | 
			
		||||
        actorClone.ease({
 | 
			
		||||
@@ -1572,7 +1566,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sizeChangeWindowDone(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._resizing, actor)) {
 | 
			
		||||
        if (this._resizing.delete(actor)) {
 | 
			
		||||
            actor.remove_all_transitions();
 | 
			
		||||
            actor.scale_x = 1.0;
 | 
			
		||||
            actor.scale_y = 1.0;
 | 
			
		||||
@@ -1580,10 +1574,13 @@ var WindowManager = class {
 | 
			
		||||
            actor.translation_y = 0;
 | 
			
		||||
            this._clearAnimationInfo(actor);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._resizePending.delete(actor))
 | 
			
		||||
            this._shellwm.completed_size_change(actor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _sizeChangeWindowOverwritten(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._resizing, actor))
 | 
			
		||||
        if (this._resizing.delete(actor))
 | 
			
		||||
            this._clearAnimationInfo(actor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1676,7 +1673,7 @@ var WindowManager = class {
 | 
			
		||||
            actor.scale_y = 0.05;
 | 
			
		||||
            actor.opacity = 0;
 | 
			
		||||
            actor.show();
 | 
			
		||||
            this._mapping.push(actor);
 | 
			
		||||
            this._mapping.add(actor);
 | 
			
		||||
 | 
			
		||||
            actor.ease({
 | 
			
		||||
                opacity: 255,
 | 
			
		||||
@@ -1698,7 +1695,7 @@ var WindowManager = class {
 | 
			
		||||
            actor.scale_y = 0;
 | 
			
		||||
            actor.opacity = 0;
 | 
			
		||||
            actor.show();
 | 
			
		||||
            this._mapping.push(actor);
 | 
			
		||||
            this._mapping.add(actor);
 | 
			
		||||
 | 
			
		||||
            actor.ease({
 | 
			
		||||
                opacity: 255,
 | 
			
		||||
@@ -1720,7 +1717,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _mapWindowDone(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._mapping, actor)) {
 | 
			
		||||
        if (this._mapping.delete(actor)) {
 | 
			
		||||
            actor.remove_all_transitions();
 | 
			
		||||
            actor.opacity = 255;
 | 
			
		||||
            actor.set_pivot_point(0, 0);
 | 
			
		||||
@@ -1733,7 +1730,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _mapWindowOverwrite(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._mapping, actor)) {
 | 
			
		||||
        if (this._mapping.delete(actor)) {
 | 
			
		||||
            shellwm.completed_map(actor);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -1763,7 +1760,7 @@ var WindowManager = class {
 | 
			
		||||
        switch (actor.meta_window.window_type) {
 | 
			
		||||
        case Meta.WindowType.NORMAL:
 | 
			
		||||
            actor.set_pivot_point(0.5, 0.5);
 | 
			
		||||
            this._destroying.push(actor);
 | 
			
		||||
            this._destroying.add(actor);
 | 
			
		||||
 | 
			
		||||
            actor.ease({
 | 
			
		||||
                opacity: 0,
 | 
			
		||||
@@ -1777,7 +1774,7 @@ var WindowManager = class {
 | 
			
		||||
        case Meta.WindowType.MODAL_DIALOG:
 | 
			
		||||
        case Meta.WindowType.DIALOG:
 | 
			
		||||
            actor.set_pivot_point(0.5, 0.5);
 | 
			
		||||
            this._destroying.push(actor);
 | 
			
		||||
            this._destroying.add(actor);
 | 
			
		||||
 | 
			
		||||
            if (window.is_attached_dialog()) {
 | 
			
		||||
                let parent = window.get_transient_for();
 | 
			
		||||
@@ -1800,7 +1797,7 @@ var WindowManager = class {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _destroyWindowDone(shellwm, actor) {
 | 
			
		||||
        if (this._removeEffect(this._destroying, actor)) {
 | 
			
		||||
        if (this._destroying.delete(actor)) {
 | 
			
		||||
            let parent = actor.get_meta_window().get_transient_for();
 | 
			
		||||
            if (parent && actor._parentDestroyId) {
 | 
			
		||||
                parent.disconnect(actor._parentDestroyId);
 | 
			
		||||
 
 | 
			
		||||
@@ -157,6 +157,8 @@ var WindowClone = GObject.registerClass({
 | 
			
		||||
        this.x = this._boundingBox.x;
 | 
			
		||||
        this.y = this._boundingBox.y;
 | 
			
		||||
 | 
			
		||||
        this._computeWindowCenter();
 | 
			
		||||
 | 
			
		||||
        let clickAction = new Clutter.ClickAction();
 | 
			
		||||
        clickAction.connect('clicked', this._onClicked.bind(this));
 | 
			
		||||
        clickAction.connect('long-press', this._onLongPress.bind(this));
 | 
			
		||||
@@ -299,6 +301,18 @@ var WindowClone = GObject.registerClass({
 | 
			
		||||
        this.layout_manager.boundingBox = rect;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get windowCenter() {
 | 
			
		||||
        return this._windowCenter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _computeWindowCenter() {
 | 
			
		||||
        let box = this.realWindow.get_allocation_box();
 | 
			
		||||
        this._windowCenter = new Clutter.Point({
 | 
			
		||||
            x: box.get_x() + box.get_width() / 2,
 | 
			
		||||
            y: box.get_y() + box.get_height() / 2,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Find the actor just below us, respecting reparenting done by DND code
 | 
			
		||||
    getActualStackAbove() {
 | 
			
		||||
        if (this._stackAbove == null)
 | 
			
		||||
@@ -1003,11 +1017,7 @@ var UnalignedLayoutStrategy = class extends LayoutStrategy {
 | 
			
		||||
    _sortRow(row) {
 | 
			
		||||
        // Sort windows horizontally to minimize travel distance.
 | 
			
		||||
        // This affects in what order the windows end up in a row.
 | 
			
		||||
        row.windows.sort((a, b) => {
 | 
			
		||||
            let aCenter = a.realWindow.x + a.realWindow.width / 2;
 | 
			
		||||
            let bCenter = b.realWindow.x + b.realWindow.width / 2;
 | 
			
		||||
            return aCenter - bCenter;
 | 
			
		||||
        });
 | 
			
		||||
        row.windows.sort((a, b) => a.windowCenter.x - b.windowCenter.x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    computeLayout(windows, layout) {
 | 
			
		||||
@@ -1026,11 +1036,7 @@ var UnalignedLayoutStrategy = class extends LayoutStrategy {
 | 
			
		||||
        // Sort windows vertically to minimize travel distance.
 | 
			
		||||
        // This affects what rows the windows get placed in.
 | 
			
		||||
        let sortedWindows = windows.slice();
 | 
			
		||||
        sortedWindows.sort((a, b) => {
 | 
			
		||||
            let aCenter = a.realWindow.y + a.realWindow.height / 2;
 | 
			
		||||
            let bCenter = b.realWindow.y + b.realWindow.height / 2;
 | 
			
		||||
            return aCenter - bCenter;
 | 
			
		||||
        });
 | 
			
		||||
        sortedWindows.sort((a, b) => a.windowCenter.y - b.windowCenter.y);
 | 
			
		||||
 | 
			
		||||
        let windowIdx = 0;
 | 
			
		||||
        for (let i = 0; i < numRows; i++) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								meson.build
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
			
		||||
project('gnome-shell', 'c',
 | 
			
		||||
  version: '3.34.1',
 | 
			
		||||
  version: '3.34.5',
 | 
			
		||||
  meson_version: '>= 0.47.0',
 | 
			
		||||
  license: 'GPLv2+'
 | 
			
		||||
)
 | 
			
		||||
@@ -31,6 +31,7 @@ polkit_req = '>= 0.100'
 | 
			
		||||
schemas_req = '>= 3.33.1'
 | 
			
		||||
startup_req = '>= 0.11'
 | 
			
		||||
ibus_req = '>= 1.5.2'
 | 
			
		||||
gnome_desktop_req = '>= 3.32'
 | 
			
		||||
 | 
			
		||||
bt_req = '>= 3.9.0'
 | 
			
		||||
gst_req = '>= 0.11.92'
 | 
			
		||||
@@ -97,6 +98,7 @@ startup_dep = dependency('libstartup-notification-1.0', version: startup_req)
 | 
			
		||||
ibus_dep = dependency('ibus-1.0', version: ibus_req)
 | 
			
		||||
x11_dep = dependency('x11')
 | 
			
		||||
schemas_dep = dependency('gsettings-desktop-schemas', version: schemas_req)
 | 
			
		||||
gnome_desktop_dep = dependency('gnome-desktop-3.0', version: gnome_desktop_req)
 | 
			
		||||
 | 
			
		||||
bt_dep = dependency('gnome-bluetooth-1.0', version: bt_req, required: false)
 | 
			
		||||
gst_dep = dependency('gstreamer-1.0', version: gst_req, required: false)
 | 
			
		||||
@@ -113,12 +115,8 @@ if get_option('networkmanager')
 | 
			
		||||
  nm_deps += dependency('libnm', version: nm_req)
 | 
			
		||||
  nm_deps += dependency('libsecret-1', version: secret_req)
 | 
			
		||||
 | 
			
		||||
  vpndir = nm_deps[0].get_pkgconfig_variable('vpnservicedir')
 | 
			
		||||
 | 
			
		||||
  have_networkmanager = true
 | 
			
		||||
else
 | 
			
		||||
  vpndir = prefix
 | 
			
		||||
 | 
			
		||||
  have_networkmanager = false
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
@@ -177,6 +175,11 @@ cdata.set('HAVE__NL_TIME_FIRST_WEEKDAY',
 | 
			
		||||
  cc.has_header_symbol('langinfo.h', '_NL_TIME_FIRST_WEEKDAY')
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# New API added in gnome-desktop3 3.34.2/3.35.2
 | 
			
		||||
cdata.set('HAVE_GNOME_SYSTEMD',
 | 
			
		||||
  cc.has_header('libgnome-desktop/gnome-systemd.h', dependencies: gnome_desktop_dep)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
cdata.set('HAVE_FDWALK',
 | 
			
		||||
          cc.has_function('fdwalk')
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ bn_IN
 | 
			
		||||
bs
 | 
			
		||||
ca
 | 
			
		||||
ca@valencia
 | 
			
		||||
ckb
 | 
			
		||||
cs
 | 
			
		||||
da
 | 
			
		||||
de
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										462
									
								
								po/pt_BR.po
									
									
									
									
									
								
							
							
						
						
									
										462
									
								
								po/pt_BR.po
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1403
									
								
								po/zh_TW.po
									
									
									
									
									
								
							
							
						
						
									
										1403
									
								
								po/zh_TW.po
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -105,7 +105,8 @@ typedef struct
 | 
			
		||||
} CollectAppointmentsData;
 | 
			
		||||
 | 
			
		||||
static time_t
 | 
			
		||||
get_time_from_property (ICalComponent         *icomp,
 | 
			
		||||
get_time_from_property (ECalClient            *cal,
 | 
			
		||||
                        ICalComponent         *icomp,
 | 
			
		||||
                        ICalPropertyKind       prop_kind,
 | 
			
		||||
                        ICalTime * (* get_prop_func) (ICalProperty *prop),
 | 
			
		||||
                        ICalTimezone          *default_zone)
 | 
			
		||||
@@ -124,12 +125,14 @@ get_time_from_property (ICalComponent         *icomp,
 | 
			
		||||
 | 
			
		||||
  param = i_cal_property_get_first_parameter (prop, I_CAL_TZID_PARAMETER);
 | 
			
		||||
  if (param)
 | 
			
		||||
    timezone = i_cal_timezone_get_builtin_timezone_from_tzid (i_cal_parameter_get_tzid (param));
 | 
			
		||||
    timezone = e_timezone_cache_get_timezone (E_TIMEZONE_CACHE (cal), i_cal_parameter_get_tzid (param));
 | 
			
		||||
  else if (i_cal_time_is_utc (itt))
 | 
			
		||||
    timezone = i_cal_timezone_get_utc_timezone ();
 | 
			
		||||
  else
 | 
			
		||||
    timezone = default_zone;
 | 
			
		||||
 | 
			
		||||
  i_cal_time_set_timezone (itt, timezone);
 | 
			
		||||
 | 
			
		||||
  retval = i_cal_time_as_timet_with_zone (itt, timezone);
 | 
			
		||||
 | 
			
		||||
  g_clear_object (¶m);
 | 
			
		||||
@@ -180,27 +183,32 @@ get_ical_description (ICalComponent *icomp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline time_t
 | 
			
		||||
get_ical_start_time (ICalComponent *icomp,
 | 
			
		||||
get_ical_start_time (ECalClient    *cal,
 | 
			
		||||
                     ICalComponent *icomp,
 | 
			
		||||
                     ICalTimezone  *default_zone)
 | 
			
		||||
{
 | 
			
		||||
  return get_time_from_property (icomp,
 | 
			
		||||
  return get_time_from_property (cal,
 | 
			
		||||
                                 icomp,
 | 
			
		||||
                                 I_CAL_DTSTART_PROPERTY,
 | 
			
		||||
                                 i_cal_property_get_dtstart,
 | 
			
		||||
                                 default_zone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline time_t
 | 
			
		||||
get_ical_end_time (ICalComponent *icomp,
 | 
			
		||||
get_ical_end_time (ECalClient    *cal,
 | 
			
		||||
                   ICalComponent *icomp,
 | 
			
		||||
                   ICalTimezone  *default_zone)
 | 
			
		||||
{
 | 
			
		||||
  return get_time_from_property (icomp,
 | 
			
		||||
  return get_time_from_property (cal,
 | 
			
		||||
                                 icomp,
 | 
			
		||||
                                 I_CAL_DTEND_PROPERTY,
 | 
			
		||||
                                 i_cal_property_get_dtend,
 | 
			
		||||
                                 default_zone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
get_ical_is_all_day (ICalComponent *icomp,
 | 
			
		||||
get_ical_is_all_day (ECalClient    *cal,
 | 
			
		||||
                     ICalComponent *icomp,
 | 
			
		||||
                     time_t         start_time,
 | 
			
		||||
                     ICalTimezone  *default_zone)
 | 
			
		||||
{
 | 
			
		||||
@@ -226,7 +234,7 @@ get_ical_is_all_day (ICalComponent *icomp,
 | 
			
		||||
      start_tm->tm_hour != 0)
 | 
			
		||||
    return FALSE;
 | 
			
		||||
 | 
			
		||||
  if ((end_time = get_ical_end_time (icomp, default_zone)))
 | 
			
		||||
  if ((end_time = get_ical_end_time (cal, icomp, default_zone)))
 | 
			
		||||
    return (end_time - start_time) % 86400 == 0;
 | 
			
		||||
 | 
			
		||||
  prop = i_cal_component_get_first_property (icomp, I_CAL_DURATION_PROPERTY);
 | 
			
		||||
@@ -244,20 +252,24 @@ get_ical_is_all_day (ICalComponent *icomp,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline time_t
 | 
			
		||||
get_ical_due_time (ICalComponent *icomp,
 | 
			
		||||
get_ical_due_time (ECalClient    *cal,
 | 
			
		||||
                   ICalComponent *icomp,
 | 
			
		||||
                   ICalTimezone  *default_zone)
 | 
			
		||||
{
 | 
			
		||||
  return get_time_from_property (icomp,
 | 
			
		||||
  return get_time_from_property (cal,
 | 
			
		||||
                                 icomp,
 | 
			
		||||
                                 I_CAL_DUE_PROPERTY,
 | 
			
		||||
                                 i_cal_property_get_due,
 | 
			
		||||
                                 default_zone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline time_t
 | 
			
		||||
get_ical_completed_time (ICalComponent *icomp,
 | 
			
		||||
get_ical_completed_time (ECalClient    *cal,
 | 
			
		||||
                         ICalComponent *icomp,
 | 
			
		||||
                         ICalTimezone  *default_zone)
 | 
			
		||||
{
 | 
			
		||||
  return get_time_from_property (icomp,
 | 
			
		||||
  return get_time_from_property (cal,
 | 
			
		||||
                                 icomp,
 | 
			
		||||
                                 I_CAL_COMPLETED_PROPERTY,
 | 
			
		||||
                                 i_cal_property_get_completed,
 | 
			
		||||
                                 default_zone);
 | 
			
		||||
@@ -411,9 +423,10 @@ calendar_appointment_init (CalendarAppointment  *appointment,
 | 
			
		||||
  appointment->summary      = get_ical_summary (icomp);
 | 
			
		||||
  appointment->description  = get_ical_description (icomp);
 | 
			
		||||
  appointment->color_string = get_source_color (cal);
 | 
			
		||||
  appointment->start_time   = get_ical_start_time (icomp, default_zone);
 | 
			
		||||
  appointment->end_time     = get_ical_end_time (icomp, default_zone);
 | 
			
		||||
  appointment->is_all_day   = get_ical_is_all_day (icomp,
 | 
			
		||||
  appointment->start_time   = get_ical_start_time (cal, icomp, default_zone);
 | 
			
		||||
  appointment->end_time     = get_ical_end_time (cal, icomp, default_zone);
 | 
			
		||||
  appointment->is_all_day   = get_ical_is_all_day (cal,
 | 
			
		||||
                                                   icomp,
 | 
			
		||||
                                                   appointment->start_time,
 | 
			
		||||
                                                   default_zone);
 | 
			
		||||
}
 | 
			
		||||
@@ -430,6 +443,18 @@ calendar_appointment_new (ICalComponent        *icomp,
 | 
			
		||||
  return appointment;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static time_t
 | 
			
		||||
timet_from_ical_time (ICalTime     *time,
 | 
			
		||||
                      ICalTimezone *default_zone)
 | 
			
		||||
{
 | 
			
		||||
  ICalTimezone *timezone = NULL;
 | 
			
		||||
 | 
			
		||||
  timezone = i_cal_time_get_timezone (time);
 | 
			
		||||
  if (timezone == NULL)
 | 
			
		||||
    timezone = default_zone;
 | 
			
		||||
  return i_cal_time_as_timet_with_zone (time, timezone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
generate_instances_cb (ICalComponent *icomp,
 | 
			
		||||
                       ICalTime *instance_start,
 | 
			
		||||
@@ -456,8 +481,8 @@ generate_instances_cb (ICalComponent *icomp,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  occurrence             = g_new0 (CalendarOccurrence, 1);
 | 
			
		||||
  occurrence->start_time = i_cal_time_as_timet_with_zone (instance_start, default_zone);
 | 
			
		||||
  occurrence->end_time   = i_cal_time_as_timet_with_zone (instance_end, default_zone);
 | 
			
		||||
  occurrence->start_time = timet_from_ical_time (instance_start, default_zone);
 | 
			
		||||
  occurrence->end_time   = timet_from_ical_time (instance_end, default_zone);
 | 
			
		||||
  occurrence->rid        = e_cal_util_component_get_recurid_as_string (icomp);
 | 
			
		||||
 | 
			
		||||
  appointment->occurrences = g_slist_append (appointment->occurrences, occurrence);
 | 
			
		||||
 
 | 
			
		||||
@@ -142,9 +142,10 @@ settings_list_remove (GSettings  *settings,
 | 
			
		||||
 | 
			
		||||
  n_values = g_strv_length (list);
 | 
			
		||||
  new_value = g_new0 (char *, n_values);
 | 
			
		||||
  for (i = 0, s = (const char **)list; i < n_values; i++, s++)
 | 
			
		||||
  i = 0;
 | 
			
		||||
  for (s = (const char **)list; *s != NULL; s++)
 | 
			
		||||
    if (!g_str_equal (*s, value))
 | 
			
		||||
      new_value[i] = g_strdup (*s);
 | 
			
		||||
      new_value[i++] = g_strdup (*s);
 | 
			
		||||
 | 
			
		||||
  g_settings_set_strv (settings, key, (const char **)new_value);
 | 
			
		||||
  g_settings_sync ();
 | 
			
		||||
 
 | 
			
		||||
@@ -192,7 +192,7 @@ libshell_no_gir_sources += dbus_generated
 | 
			
		||||
 | 
			
		||||
libshell = library('gnome-shell',
 | 
			
		||||
  sources: libshell_gir_sources + libshell_no_gir_sources,
 | 
			
		||||
  dependencies: gnome_shell_deps + [libshell_menu_dep, libst_dep, mutter_dep, m_dep],
 | 
			
		||||
  dependencies: gnome_shell_deps + [libshell_menu_dep, libst_dep, mutter_dep, gnome_desktop_dep, m_dep],
 | 
			
		||||
  include_directories: [conf_inc, st_inc, include_directories('tray')],
 | 
			
		||||
  c_args: gnome_shell_cflags,
 | 
			
		||||
  link_with: [libtray],
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,11 @@
 | 
			
		||||
#include <meta/meta-workspace-manager.h>
 | 
			
		||||
#include <meta/meta-x11-display.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_GNOME_SYSTEMD
 | 
			
		||||
#define GNOME_DESKTOP_USE_UNSTABLE_API
 | 
			
		||||
#include <libgnome-desktop/gnome-systemd.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Memory report bits */
 | 
			
		||||
#ifdef HAVE_MALLINFO
 | 
			
		||||
#include <malloc.h>
 | 
			
		||||
@@ -43,6 +48,7 @@
 | 
			
		||||
#include "shell-perf-log.h"
 | 
			
		||||
#include "shell-window-tracker.h"
 | 
			
		||||
#include "shell-wm.h"
 | 
			
		||||
#include "shell-util.h"
 | 
			
		||||
#include "st.h"
 | 
			
		||||
 | 
			
		||||
static ShellGlobal *the_object = NULL;
 | 
			
		||||
@@ -1308,6 +1314,32 @@ shell_global_get_current_time (ShellGlobal *global)
 | 
			
		||||
  return clutter_get_current_event_time ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_GNOME_SYSTEMD
 | 
			
		||||
static void
 | 
			
		||||
shell_global_app_launched_cb (GAppLaunchContext *context,
 | 
			
		||||
                              GAppInfo          *info,
 | 
			
		||||
                              GVariant          *platform_data,
 | 
			
		||||
                              gpointer           user_data)
 | 
			
		||||
{
 | 
			
		||||
  gint32 pid;
 | 
			
		||||
  const gchar *app_name;
 | 
			
		||||
 | 
			
		||||
  if (!g_variant_lookup (platform_data, "pid", "i", &pid))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  app_name = g_app_info_get_id (info);
 | 
			
		||||
  if (app_name == NULL)
 | 
			
		||||
    app_name = g_app_info_get_executable (info);
 | 
			
		||||
 | 
			
		||||
  /* Start async request; we don't care about the result */
 | 
			
		||||
  gnome_start_systemd_scope (app_name,
 | 
			
		||||
                             pid,
 | 
			
		||||
                             NULL,
 | 
			
		||||
                             NULL,
 | 
			
		||||
                             NULL, NULL, NULL);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * shell_global_create_app_launch_context:
 | 
			
		||||
 * @global: A #ShellGlobal
 | 
			
		||||
@@ -1343,6 +1375,13 @@ shell_global_create_app_launch_context (ShellGlobal *global,
 | 
			
		||||
 | 
			
		||||
  meta_launch_context_set_workspace (context, ws);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_GNOME_SYSTEMD
 | 
			
		||||
  g_signal_connect (context,
 | 
			
		||||
                    "launched",
 | 
			
		||||
                    G_CALLBACK (shell_global_app_launched_cb),
 | 
			
		||||
                    NULL);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  return (GAppLaunchContext *) context;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1515,6 +1554,55 @@ delete_variant_cb (GObject      *object,
 | 
			
		||||
  g_hash_table_remove (global->save_ops, object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
replace_contents_worker (GTask        *task,
 | 
			
		||||
                         gpointer      source_object,
 | 
			
		||||
                         gpointer      task_data,
 | 
			
		||||
                         GCancellable *cancellable)
 | 
			
		||||
{
 | 
			
		||||
  GFile *file = source_object;
 | 
			
		||||
  GBytes *bytes = task_data;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  const gchar *data;
 | 
			
		||||
  gsize len;
 | 
			
		||||
 | 
			
		||||
  data = g_bytes_get_data (bytes, &len);
 | 
			
		||||
 | 
			
		||||
  if (!g_file_replace_contents (file, data, len, NULL, FALSE,
 | 
			
		||||
                                G_FILE_CREATE_REPLACE_DESTINATION,
 | 
			
		||||
                                NULL, cancellable, &error))
 | 
			
		||||
    g_task_return_error (task, g_steal_pointer (&error));
 | 
			
		||||
  else
 | 
			
		||||
    g_task_return_boolean (task, TRUE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
replace_contents_async (GFile               *path,
 | 
			
		||||
                        GBytes              *bytes,
 | 
			
		||||
                        GCancellable        *cancellable,
 | 
			
		||||
                        GAsyncReadyCallback  callback,
 | 
			
		||||
                        gpointer             user_data)
 | 
			
		||||
{
 | 
			
		||||
  g_autoptr(GTask) task = NULL;
 | 
			
		||||
 | 
			
		||||
  g_assert (G_IS_FILE (path));
 | 
			
		||||
  g_assert (bytes != NULL);
 | 
			
		||||
  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 | 
			
		||||
 | 
			
		||||
  task = g_task_new (path, cancellable, callback, user_data);
 | 
			
		||||
  g_task_set_source_tag (task, replace_contents_async);
 | 
			
		||||
  g_task_set_task_data (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
 | 
			
		||||
  g_task_run_in_thread (task, replace_contents_worker);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
replace_contents_finish (GFile         *file,
 | 
			
		||||
                         GAsyncResult  *result,
 | 
			
		||||
                         GError       **error)
 | 
			
		||||
{
 | 
			
		||||
  return g_task_propagate_boolean (G_TASK (result), error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
replace_variant_cb (GObject      *object,
 | 
			
		||||
                    GAsyncResult *result,
 | 
			
		||||
@@ -1523,7 +1611,7 @@ replace_variant_cb (GObject      *object,
 | 
			
		||||
  ShellGlobal *global = user_data;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
 | 
			
		||||
  if (!g_file_replace_contents_finish (G_FILE (object), result, NULL, &error))
 | 
			
		||||
  if (!replace_contents_finish (G_FILE (object), result, &error))
 | 
			
		||||
    {
 | 
			
		||||
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 | 
			
		||||
        {
 | 
			
		||||
@@ -1559,12 +1647,19 @@ save_variant (ShellGlobal *global,
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      g_file_replace_contents_async (path,
 | 
			
		||||
                                     g_variant_get_data (variant),
 | 
			
		||||
                                     g_variant_get_size (variant),
 | 
			
		||||
                                     NULL, FALSE,
 | 
			
		||||
                                     G_FILE_CREATE_REPLACE_DESTINATION,
 | 
			
		||||
                                     cancellable, replace_variant_cb, global);
 | 
			
		||||
      g_autoptr(GBytes) bytes = NULL;
 | 
			
		||||
 | 
			
		||||
      bytes = g_bytes_new_with_free_func (g_variant_get_data (variant),
 | 
			
		||||
                                          g_variant_get_size (variant),
 | 
			
		||||
                                          (GDestroyNotify)g_variant_unref,
 | 
			
		||||
                                          g_variant_ref (variant));
 | 
			
		||||
      /* g_file_replace_contents_async() can potentially fsync() from the
 | 
			
		||||
       * calling thread when completing the asynchronous task. Instead, we
 | 
			
		||||
       * want to force that fsync() to a thread to avoid blocking the
 | 
			
		||||
       * compositor main loop. Using our own replace_contents_async()
 | 
			
		||||
       * simply executes the operation synchronously from a thread.
 | 
			
		||||
       */
 | 
			
		||||
      replace_contents_async (path, bytes, cancellable, replace_variant_cb, global);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  g_object_unref (path);
 | 
			
		||||
 
 | 
			
		||||
@@ -478,6 +478,63 @@ shell_network_agent_respond (ShellNetworkAgent         *self,
 | 
			
		||||
  g_hash_table_remove (priv->requests, request_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
search_vpn_plugin (GTask        *task,
 | 
			
		||||
                   gpointer      object,
 | 
			
		||||
                   gpointer      task_data,
 | 
			
		||||
                   GCancellable *cancellable)
 | 
			
		||||
{
 | 
			
		||||
  NMVpnPluginInfo *info = NULL;
 | 
			
		||||
  char *service = task_data;
 | 
			
		||||
 | 
			
		||||
  info = nm_vpn_plugin_info_new_search_file (NULL, service);
 | 
			
		||||
 | 
			
		||||
  if (info)
 | 
			
		||||
    {
 | 
			
		||||
      g_task_return_pointer (task, info, g_object_unref);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      g_task_return_new_error (task,
 | 
			
		||||
                               G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
 | 
			
		||||
                               "No plugin for %s", service);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
shell_network_agent_search_vpn_plugin (ShellNetworkAgent   *self,
 | 
			
		||||
                                       const char          *service,
 | 
			
		||||
                                       GAsyncReadyCallback  callback,
 | 
			
		||||
                                       gpointer             user_data)
 | 
			
		||||
{
 | 
			
		||||
  g_autoptr(GTask) task = NULL;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (SHELL_IS_NETWORK_AGENT (self));
 | 
			
		||||
  g_return_if_fail (service != NULL);
 | 
			
		||||
 | 
			
		||||
  task = g_task_new (self, NULL, callback, user_data);
 | 
			
		||||
  g_task_set_source_tag (task, shell_network_agent_search_vpn_plugin);
 | 
			
		||||
  g_task_set_task_data (task, g_strdup (service), g_free);
 | 
			
		||||
 | 
			
		||||
  g_task_run_in_thread (task, search_vpn_plugin);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * shell_network_agent_search_vpn_plugin_finish:
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: (nullable) (transfer full): The found plugin or %NULL
 | 
			
		||||
 */
 | 
			
		||||
NMVpnPluginInfo *
 | 
			
		||||
shell_network_agent_search_vpn_plugin_finish (ShellNetworkAgent  *self,
 | 
			
		||||
                                              GAsyncResult       *result,
 | 
			
		||||
                                              GError            **error)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (SHELL_IS_NETWORK_AGENT (self), NULL);
 | 
			
		||||
  g_return_val_if_fail (G_IS_TASK (result), NULL);
 | 
			
		||||
 | 
			
		||||
  return g_task_propagate_pointer (G_TASK (result), error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
shell_network_agent_cancel_get_secrets (NMSecretAgentOld *agent,
 | 
			
		||||
                                        const gchar      *connection_path,
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,14 @@ void               shell_network_agent_respond      (ShellNetworkAgent *self,
 | 
			
		||||
                                                     gchar             *request_id,
 | 
			
		||||
                                                     ShellNetworkAgentResponse response);
 | 
			
		||||
 | 
			
		||||
void               shell_network_agent_search_vpn_plugin (ShellNetworkAgent   *self,
 | 
			
		||||
                                                          const char          *service,
 | 
			
		||||
                                                          GAsyncReadyCallback  callback,
 | 
			
		||||
                                                          gpointer             user_data);
 | 
			
		||||
NMVpnPluginInfo   *shell_network_agent_search_vpn_plugin_finish (ShellNetworkAgent  *self,
 | 
			
		||||
                                                                 GAsyncResult       *result,
 | 
			
		||||
                                                                 GError            **error);
 | 
			
		||||
 | 
			
		||||
/* If these are kept in sync with nm-applet, secrets will be shared */
 | 
			
		||||
#define SHELL_KEYRING_UUID_TAG "connection-uuid"
 | 
			
		||||
#define SHELL_KEYRING_SN_TAG "setting-name"
 | 
			
		||||
 
 | 
			
		||||
@@ -146,7 +146,7 @@ G_DEFINE_TYPE(ShellRecorder, shell_recorder, G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
/* The default pipeline.
 | 
			
		||||
 */
 | 
			
		||||
#define DEFAULT_PIPELINE "vp9enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux"
 | 
			
		||||
#define DEFAULT_PIPELINE "vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux"
 | 
			
		||||
 | 
			
		||||
/* If we can find the amount of memory on the machine, we use half
 | 
			
		||||
 * of that for memory_target, otherwise, we use this value, in kB.
 | 
			
		||||
@@ -1479,7 +1479,7 @@ shell_recorder_set_draw_cursor (ShellRecorder *recorder,
 | 
			
		||||
 * might be used to send the output to an icecast server
 | 
			
		||||
 * via shout2send or similar.
 | 
			
		||||
 *
 | 
			
		||||
 * The default value is 'vp9enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux'
 | 
			
		||||
 * The default value is 'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux'
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
shell_recorder_set_pipeline (ShellRecorder *recorder,
 | 
			
		||||
 
 | 
			
		||||
@@ -457,7 +457,6 @@ grab_window_screenshot (ClutterActor *stage,
 | 
			
		||||
  ClutterActor *window_actor;
 | 
			
		||||
  gfloat actor_x, actor_y;
 | 
			
		||||
  MetaRectangle rect;
 | 
			
		||||
  cairo_rectangle_int_t clip;
 | 
			
		||||
 | 
			
		||||
  window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
 | 
			
		||||
  clutter_actor_get_position (window_actor, &actor_x, &actor_y);
 | 
			
		||||
@@ -467,16 +466,10 @@ grab_window_screenshot (ClutterActor *stage,
 | 
			
		||||
  if (!priv->include_frame)
 | 
			
		||||
    meta_window_frame_rect_to_client_rect (window, &rect, &rect);
 | 
			
		||||
 | 
			
		||||
  priv->screenshot_area.x = rect.x;
 | 
			
		||||
  priv->screenshot_area.y = rect.y;
 | 
			
		||||
  clip.x = rect.x - (gint) actor_x;
 | 
			
		||||
  clip.y = rect.y - (gint) actor_y;
 | 
			
		||||
 | 
			
		||||
  clip.width = priv->screenshot_area.width = rect.width;
 | 
			
		||||
  clip.height = priv->screenshot_area.height = rect.height;
 | 
			
		||||
  priv->screenshot_area = rect;
 | 
			
		||||
 | 
			
		||||
  priv->image = meta_window_actor_get_image (META_WINDOW_ACTOR (window_actor),
 | 
			
		||||
                                             &clip);
 | 
			
		||||
                                             NULL);
 | 
			
		||||
  priv->datetime = g_date_time_new_now_local ();
 | 
			
		||||
 | 
			
		||||
  if (priv->include_cursor)
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,8 @@ struct _StTextureCachePrivate
 | 
			
		||||
  GHashTable *keyed_cache; /* char * -> ClutterImage* */
 | 
			
		||||
  GHashTable *keyed_surface_cache; /* char * -> cairo_surface_t* */
 | 
			
		||||
 | 
			
		||||
  GHashTable *used_scales; /* Set: double */
 | 
			
		||||
 | 
			
		||||
  /* Presently this is used to de-duplicate requests for GIcons and async URIs. */
 | 
			
		||||
  GHashTable *outstanding_requests; /* char * -> AsyncTextureLoadData * */
 | 
			
		||||
 | 
			
		||||
@@ -181,6 +183,7 @@ st_texture_cache_init (StTextureCache *self)
 | 
			
		||||
                                                           g_str_equal,
 | 
			
		||||
                                                           g_free,
 | 
			
		||||
                                                           (GDestroyNotify) cairo_surface_destroy);
 | 
			
		||||
  self->priv->used_scales = g_hash_table_new (g_double_hash, g_double_equal);
 | 
			
		||||
  self->priv->outstanding_requests = g_hash_table_new_full (g_str_hash, g_str_equal,
 | 
			
		||||
                                                            g_free, NULL);
 | 
			
		||||
  self->priv->file_monitors = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
 | 
			
		||||
@@ -199,6 +202,7 @@ st_texture_cache_dispose (GObject *object)
 | 
			
		||||
 | 
			
		||||
  g_clear_pointer (&self->priv->keyed_cache, g_hash_table_destroy);
 | 
			
		||||
  g_clear_pointer (&self->priv->keyed_surface_cache, g_hash_table_destroy);
 | 
			
		||||
  g_clear_pointer (&self->priv->used_scales, g_hash_table_destroy);
 | 
			
		||||
  g_clear_pointer (&self->priv->outstanding_requests, g_hash_table_destroy);
 | 
			
		||||
  g_clear_pointer (&self->priv->file_monitors, g_hash_table_destroy);
 | 
			
		||||
 | 
			
		||||
@@ -1062,6 +1066,22 @@ load_from_pixbuf (GdkPixbuf *pixbuf,
 | 
			
		||||
  return actor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
hash_table_remove_with_scales (GHashTable *hash,
 | 
			
		||||
                               GList      *scales,
 | 
			
		||||
                               const char *base_key)
 | 
			
		||||
{
 | 
			
		||||
  GList *l;
 | 
			
		||||
 | 
			
		||||
  for (l = scales; l; l = l->next)
 | 
			
		||||
    {
 | 
			
		||||
      double scale = *((double *)l->data);
 | 
			
		||||
      g_autofree char *key = NULL;
 | 
			
		||||
      key = g_strdup_printf ("%s%f", base_key, scale);
 | 
			
		||||
      g_hash_table_remove (hash, key);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
file_changed_cb (GFileMonitor      *monitor,
 | 
			
		||||
                 GFile             *file,
 | 
			
		||||
@@ -1072,18 +1092,22 @@ file_changed_cb (GFileMonitor      *monitor,
 | 
			
		||||
  StTextureCache *cache = user_data;
 | 
			
		||||
  char *key;
 | 
			
		||||
  guint file_hash;
 | 
			
		||||
  g_autoptr (GList) scales = NULL;
 | 
			
		||||
 | 
			
		||||
  if (event_type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  file_hash = g_file_hash (file);
 | 
			
		||||
  scales = g_hash_table_get_keys (cache->priv->used_scales);
 | 
			
		||||
 | 
			
		||||
  key = g_strdup_printf (CACHE_PREFIX_FILE "%u", file_hash);
 | 
			
		||||
  g_hash_table_remove (cache->priv->keyed_cache, key);
 | 
			
		||||
  hash_table_remove_with_scales (cache->priv->keyed_cache, scales, key);
 | 
			
		||||
  g_free (key);
 | 
			
		||||
 | 
			
		||||
  key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", file_hash);
 | 
			
		||||
  g_hash_table_remove (cache->priv->keyed_surface_cache, key);
 | 
			
		||||
  hash_table_remove_with_scales (cache->priv->keyed_surface_cache, scales, key);
 | 
			
		||||
  g_free (key);
 | 
			
		||||
 | 
			
		||||
  g_signal_emit (cache, signals[TEXTURE_FILE_CHANGED], 0, file);
 | 
			
		||||
@@ -1418,7 +1442,10 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache,
 | 
			
		||||
        goto out;
 | 
			
		||||
 | 
			
		||||
      if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
 | 
			
		||||
        g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), image);
 | 
			
		||||
        {
 | 
			
		||||
          g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), image);
 | 
			
		||||
          g_hash_table_insert (cache->priv->used_scales, &resource_scale, &resource_scale);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Because the texture is loaded synchronously, we won't call
 | 
			
		||||
@@ -1467,6 +1494,7 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache        *cache,
 | 
			
		||||
          cairo_surface_reference (surface);
 | 
			
		||||
          g_hash_table_insert (cache->priv->keyed_surface_cache,
 | 
			
		||||
                               g_strdup (key), surface);
 | 
			
		||||
          g_hash_table_insert (cache->priv->used_scales, &resource_scale, &resource_scale);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
 
 | 
			
		||||
 Submodule subprojects/gvc updated: 0e1b4bdafc...ec5cf3e0de
									
								
							
		Reference in New Issue
	
	Block a user