Compare commits
	
		
			89 Commits
		
	
	
		
			wip/carlos
			...
			cherry-pic
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 1045b35c8b | ||
|   | 24cdcc56da | ||
|   | 1b28cdfbf4 | ||
|   | a73294312f | ||
|   | 5e7a7e31a1 | ||
|   | 8111286463 | ||
|   | 06c6ecc15b | ||
|   | 36f9dcd2bd | ||
|   | 219118e633 | ||
|   | 1e929357e0 | ||
|   | e7463e38ca | ||
|   | 420c1cbfd1 | ||
|   | d53bd98532 | ||
|   | 128a501b9a | ||
|   | b29e243fec | ||
|   | fa2ddcc52f | ||
|   | fbf194f6a1 | ||
|   | 5610a2435d | ||
|   | a5b36fc7f4 | ||
|   | 923d80bba8 | ||
|   | 9e196d2765 | ||
|   | 94897492be | ||
|   | 6baf82eb83 | ||
|   | 65d27aaa43 | ||
|   | 176aaa4a97 | ||
|   | 5ae5811155 | ||
|   | e027af9548 | ||
|   | 73649a0d6a | ||
|   | 7dbcd26619 | ||
|   | f30ec4a4c8 | ||
|   | c04289853f | ||
|   | b72b773d87 | ||
|   | da7cd2807f | ||
|   | 20373ba64e | ||
|   | 025f6eb68e | ||
|   | dc5df5c4c9 | ||
|   | 81db908339 | ||
|   | 706a2259b8 | ||
|   | e94af71430 | ||
|   | a662e7bb87 | ||
|   | 0b82388c49 | ||
|   | b359b937e9 | ||
|   | 98fb7c33f2 | ||
|   | 4dfc2e0fd1 | ||
|   | 9152d3a286 | ||
|   | ba33a05dd2 | ||
|   | ddb309815c | ||
|   | 6a796675bd | ||
|   | d08497414f | ||
|   | 82886b7ee8 | ||
|   | dca43c7b24 | ||
|   | af50a7829f | ||
|   | 67cb02d46a | ||
|   | 721ce54037 | ||
|   | 445eed40a7 | ||
|   | fddd122956 | ||
|   | df1b46eee2 | ||
|   | bf318df7f3 | ||
|   | 2a2f3c981e | ||
|   | 8e5eab0498 | ||
|   | 6ed21e1ce0 | ||
|   | 9c51c87d8c | ||
|   | db2245d60b | ||
|   | f26cc3ac23 | ||
|   | 02c5b4b947 | ||
|   | df57829ea1 | ||
|   | da96408098 | ||
|   | 4b2e0247af | ||
|   | 2c617e5a3a | ||
|   | 4ff7e84c51 | ||
|   | 9f76b6e4a2 | ||
|   | 0ac0f7e85b | ||
|   | 73b00ff1a7 | ||
|   | a52597ac5b | ||
|   | 9a2597f80b | ||
|   | e1ed4b25e1 | ||
|   | c70b18764b | ||
|   | 4398516520 | ||
|   | 220514d10e | ||
|   | 18312d9ccd | ||
|   | 234b1441e4 | ||
|   | e909db5848 | ||
|   | 702338bc7d | ||
|   | 7c9dbc66d9 | ||
|   | 0d031dc20f | ||
|   | b476e851b7 | ||
|   | a27be6a540 | ||
|   | 4b6a57fabe | ||
|   | 92758890bb | 
							
								
								
									
										28
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								NEWS
									
									
									
									
									
								
							| @@ -1,3 +1,31 @@ | ||||
| 3.28.3 | ||||
| ====== | ||||
| * Fix lagging pointer when zoomed [Daniel; #682013] | ||||
| * Fix "Clear All" for calendar events [Florian; #325] | ||||
| * Misc. bug fixes [Florian, Mario, Marco; #136, #214, #788931, #791233] | ||||
|  | ||||
| Contributors: | ||||
|   Carlos Garnacho, Florian Müllner, Mario Sanchez Prada, Joe Rabinoff, | ||||
|   Didier Roche, Marco Trevisan (Treviño), Daniel van Vugt | ||||
|  | ||||
| Translators: | ||||
|   Pieter Schalk Schoeman [af], Gun Chleoc [gd] | ||||
|  | ||||
| 3.28.2 | ||||
| ====== | ||||
| * Fix lock-up on cancelling polkit dialog [Florian; #221] | ||||
| * Guard against untimely keyboard map changes [Carlos; #240] | ||||
| * Fix blurriness of OSD under some resolutions [Silvère; #782011] | ||||
| * Fix icons in search provider results [Florian; #249] | ||||
| * Misc. bug fixes [Marco, Florian; #792687, #781471] | ||||
|  | ||||
| Contributors: | ||||
|   Carlos Garnacho, Silvère Latchurié, Florian Müllner, Mario Sanchez Prada, | ||||
|   Ray Strode, Marco Trevisan (Treviño) | ||||
|  | ||||
| Translators: | ||||
|   Stas Solovey [ru], Rafael Fontenelle [pt_BR] | ||||
|  | ||||
| 3.28.1 | ||||
| ====== | ||||
| * Fix compose characters in shell entries [Carlos; #115] | ||||
|   | ||||
| @@ -242,11 +242,11 @@ var AuthPrompt = new Lang.Class({ | ||||
|         this.emit('prompted'); | ||||
|     }, | ||||
|  | ||||
|     _onVerificationFailed() { | ||||
|     _onVerificationFailed(userVerifier, canRetry) { | ||||
|         this._queryingService = null; | ||||
|         this.clear(); | ||||
|  | ||||
|         this.updateSensitivity(true); | ||||
|         this.updateSensitivity(canRetry); | ||||
|         this.setActorInDefaultButtonWell(null); | ||||
|         this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; | ||||
|     }, | ||||
| @@ -439,6 +439,7 @@ var AuthPrompt = new Lang.Class({ | ||||
|         this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; | ||||
|         this.cancelButton.reactive = true; | ||||
|         this.nextButton.label = _("Next"); | ||||
|         this._preemptiveAnswer = null; | ||||
|  | ||||
|         if (this._userVerifier) | ||||
|             this._userVerifier.cancel(); | ||||
|   | ||||
| @@ -534,12 +534,13 @@ var ShellUserVerifier = new Lang.Class({ | ||||
|     _verificationFailed(retry) { | ||||
|         // For Not Listed / enterprise logins, immediately reset | ||||
|         // the dialog | ||||
|         // Otherwise, we allow ALLOWED_FAILURES attempts. After that, we | ||||
|         // go back to the welcome screen. | ||||
|         // Otherwise, when in login mode we allow ALLOWED_FAILURES attempts. | ||||
|         // After that, we go back to the welcome screen. | ||||
|  | ||||
|         this._failCounter++; | ||||
|         let canRetry = retry && this._userName && | ||||
|             this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY); | ||||
|             (this._reauthOnly || | ||||
|              this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY)); | ||||
|  | ||||
|         if (canRetry) { | ||||
|             if (!this.hasPendingMessages) { | ||||
| @@ -562,7 +563,7 @@ var ShellUserVerifier = new Lang.Class({ | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this.emit('verification-failed'); | ||||
|         this.emit('verification-failed', canRetry); | ||||
|     }, | ||||
|  | ||||
|     _onConversationStopped(client, serviceName) { | ||||
|   | ||||
| @@ -115,6 +115,11 @@ var IBusManager = new Lang.Class({ | ||||
|                                                          object_path: IBus.PATH_PANEL }); | ||||
|             this._candidatePopup.setPanelService(this._panelService); | ||||
|             this._panelService.connect('update-property', this._updateProperty.bind(this)); | ||||
|             this._panelService.connect('set-cursor-location', (ps, x, y, w, h) => { | ||||
|                 let cursorLocation = { x, y, width: w, height: h }; | ||||
|                 this.emit('set-cursor-location', cursorLocation); | ||||
|             }); | ||||
|  | ||||
|             try { | ||||
|                 // IBus versions older than 1.5.10 have a bug which | ||||
|                 // causes spurious set-content-type emissions when | ||||
| @@ -200,7 +205,7 @@ var IBusManager = new Lang.Class({ | ||||
|         } | ||||
|  | ||||
|         this._ibus.set_global_engine_async(id, this._MAX_INPUT_SOURCE_ACTIVATION_TIME, | ||||
|                                            null, callback); | ||||
|                                            null, callback || null); | ||||
|     }, | ||||
|  | ||||
|     preloadEngines(ids) { | ||||
|   | ||||
| @@ -89,6 +89,8 @@ var KeyboardManager = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     setUserLayouts(ids) { | ||||
|         let currentId = this._current ? this._current.id : null; | ||||
|         let currentGroupIndex = this._current ? this._current.groupIndex : null; | ||||
|         this._current = null; | ||||
|         this._layoutInfos = {}; | ||||
|  | ||||
| @@ -115,6 +117,9 @@ var KeyboardManager = new Lang.Class({ | ||||
|             info.group = group; | ||||
|             info.groupIndex = groupIndex; | ||||
|  | ||||
|             if (currentId == id && currentGroupIndex == groupIndex) | ||||
|                 this._current = info; | ||||
|  | ||||
|             i += 1; | ||||
|         } | ||||
|     }, | ||||
|   | ||||
| @@ -236,11 +236,12 @@ var ObjectManager = new Lang.Class({ | ||||
|     _onNameVanished() { | ||||
|         let objectPaths = Object.keys(this._objects); | ||||
|         for (let i = 0; i < objectPaths.length; i++) { | ||||
|             let object = this._objects[objectPaths]; | ||||
|             let objectPath = objectPaths[i]; | ||||
|             let object = this._objects[objectPath]; | ||||
|  | ||||
|             let interfaceNames = Object.keys(object); | ||||
|             for (let j = 0; i < interfaceNames.length; i++) { | ||||
|                 let interfaceName = interfaceNames[i]; | ||||
|             for (let j = 0; j < interfaceNames.length; j++) { | ||||
|                 let interfaceName = interfaceNames[j]; | ||||
|  | ||||
|                 if (object[interfaceName]) | ||||
|                     this._removeInterface(objectPath, interfaceName); | ||||
|   | ||||
| @@ -802,6 +802,8 @@ var NotificationMessage = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     _onDestroy() { | ||||
|         this.parent(); | ||||
|  | ||||
|         if (this._updatedId) | ||||
|             this.notification.disconnect(this._updatedId); | ||||
|         this._updatedId = 0; | ||||
| @@ -821,6 +823,8 @@ var EventsSection = new Lang.Class({ | ||||
|         this._desktopSettings.connect('changed', this._reloadEvents.bind(this)); | ||||
|         this._eventSource = new EmptyEventSource(); | ||||
|  | ||||
|         this._messageById = new Map(); | ||||
|  | ||||
|         this.parent(); | ||||
|  | ||||
|         this._title = new St.Button({ style_class: 'events-section-title', | ||||
| @@ -875,20 +879,32 @@ var EventsSection = new Lang.Class({ | ||||
|  | ||||
|         this._reloading = true; | ||||
|  | ||||
|         this._list.destroy_all_children(); | ||||
|  | ||||
|         let periodBegin = _getBeginningOfDay(this._date); | ||||
|         let periodEnd = _getEndOfDay(this._date); | ||||
|         let events = this._eventSource.getEvents(periodBegin, periodEnd); | ||||
|  | ||||
|         let ids = events.map(e => e.id); | ||||
|         this._messageById.forEach((message, id) => { | ||||
|             if (ids.includes(id)) | ||||
|                 return; | ||||
|             this._messageById.delete(id); | ||||
|             this.removeMessage(message); | ||||
|         }); | ||||
|  | ||||
|         for (let i = 0; i < events.length; i++) { | ||||
|             let event = events[i]; | ||||
|  | ||||
|             let message = new EventMessage(event, this._date); | ||||
|             message.connect('close', () => { | ||||
|                 this._ignoreEvent(event); | ||||
|             }); | ||||
|             this.addMessage(message, false); | ||||
|             let message = this._messageById.get(event.id); | ||||
|             if (!message) { | ||||
|                 message = new EventMessage(event, this._date); | ||||
|                 message.connect('close', () => { | ||||
|                     this._ignoreEvent(event); | ||||
|                 }); | ||||
|                 this._messageById.set(event.id, message); | ||||
|                 this.addMessage(message, false); | ||||
|             } else { | ||||
|                 this.moveMessage(message, i, false); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         this._reloading = false; | ||||
|   | ||||
| @@ -210,6 +210,10 @@ var AutomountManager = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     _onVolumeRemoved(monitor, volume) { | ||||
|         if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) { | ||||
|             Mainloop.source_remove(volume._allowAutorunExpireId); | ||||
|             delete volume._allowAutorunExpireId; | ||||
|         } | ||||
|         this._volumeQueue =  | ||||
|             this._volumeQueue.filter(element => (element != volume)); | ||||
|     }, | ||||
| @@ -234,8 +238,10 @@ var AutomountManager = new Lang.Class({ | ||||
|     _allowAutorunExpire(volume) { | ||||
|         let id = Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, () => { | ||||
|             volume.allowAutorun = false; | ||||
|             delete volume._allowAutorunExpireId; | ||||
|             return GLib.SOURCE_REMOVE; | ||||
|         }); | ||||
|         volume._allowAutorunExpireId = id; | ||||
|         GLib.Source.set_name_by_id(id, '[gnome-shell] volume.allowAutorun'); | ||||
|     } | ||||
| }); | ||||
|   | ||||
| @@ -655,7 +655,7 @@ var NetworkAgent = new Lang.Class({ | ||||
|         switch (connectionType) { | ||||
|         case '802-11-wireless': | ||||
|             let wirelessSetting = connection.get_setting_wireless(); | ||||
|             let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid()); | ||||
|             let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data()); | ||||
|             title = _("Authentication required by wireless network"); | ||||
|             body = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid); | ||||
|             break; | ||||
|   | ||||
| @@ -201,7 +201,9 @@ var AuthenticationDialog = new Lang.Class({ | ||||
|     close(timestamp) { | ||||
|         this.parent(timestamp); | ||||
|  | ||||
|         Main.sessionMode.disconnect(this._sessionUpdatedId); | ||||
|         if (this._sessionUpdatedId) | ||||
|             Main.sessionMode.disconnect(this._sessionUpdatedId); | ||||
|         this._sessionUpdatedId = 0; | ||||
|     }, | ||||
|  | ||||
|     _ensureOpen() { | ||||
|   | ||||
| @@ -52,6 +52,8 @@ var DashItemContainer = new Lang.Class({ | ||||
|         this.animatingOut = false; | ||||
|  | ||||
|         this.connect('destroy', () => { | ||||
|             if (this.child != null) | ||||
|                 this.child.destroy(); | ||||
|             this.label.destroy(); | ||||
|         }); | ||||
|     }, | ||||
|   | ||||
							
								
								
									
										22
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								js/ui/dnd.js
									
									
									
									
									
								
							| @@ -396,10 +396,15 @@ var _Draggable = new Lang.Class({ | ||||
|         return true; | ||||
|     }, | ||||
|  | ||||
|     _pickTargetActor() { | ||||
|         return this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL, | ||||
|                                                             this._dragX, this._dragY); | ||||
|     }, | ||||
|  | ||||
|     _updateDragHover() { | ||||
|         this._updateHoverId = 0; | ||||
|         let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL, | ||||
|                                                                   this._dragX, this._dragY); | ||||
|         let target = this._pickTargetActor(); | ||||
|  | ||||
|         let dragEvent = { | ||||
|             x: this._dragX, | ||||
|             y: this._dragY, | ||||
| @@ -407,6 +412,18 @@ var _Draggable = new Lang.Class({ | ||||
|             source: this.actor._delegate, | ||||
|             targetActor: target | ||||
|         }; | ||||
|  | ||||
|         let targetActorDestroyHandlerId; | ||||
|         let handleTargetActorDestroyClosure; | ||||
|         handleTargetActorDestroyClosure = () => { | ||||
|             target = this._pickTargetActor(); | ||||
|             dragEvent.targetActor = target; | ||||
|             targetActorDestroyHandlerId = | ||||
|                 target.connect('destroy', handleTargetActorDestroyClosure); | ||||
|         }; | ||||
|         targetActorDestroyHandlerId = | ||||
|             target.connect('destroy', handleTargetActorDestroyClosure); | ||||
|  | ||||
|         for (let i = 0; i < dragMonitors.length; i++) { | ||||
|             let motionFunc = dragMonitors[i].dragMotion; | ||||
|             if (motionFunc) { | ||||
| @@ -417,6 +434,7 @@ var _Draggable = new Lang.Class({ | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         dragEvent.targetActor.disconnect(targetActorDestroyHandlerId); | ||||
|  | ||||
|         while (target) { | ||||
|             if (target._delegate && target._delegate.handleDragOver) { | ||||
|   | ||||
| @@ -760,7 +760,7 @@ var EndSessionDialog = new Lang.Class({ | ||||
|         let updatePrepared = this._pkOfflineProxy.UpdatePrepared; | ||||
|         let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed; | ||||
|  | ||||
|         _setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText); | ||||
|         _setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || ''); | ||||
|         this._checkBox.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed); | ||||
|         this._checkBox.actor.checked = (updatePrepared && updateTriggered); | ||||
|  | ||||
|   | ||||
| @@ -76,6 +76,7 @@ function disableExtension(uuid) { | ||||
|     if (extension.stylesheet) { | ||||
|         let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); | ||||
|         theme.unload_stylesheet(extension.stylesheet); | ||||
|         delete extension.stylesheet; | ||||
|     } | ||||
|  | ||||
|     try { | ||||
| @@ -115,13 +116,18 @@ function enableExtension(uuid) { | ||||
|     extensionOrder.push(uuid); | ||||
|  | ||||
|     let stylesheetNames = [global.session_mode + '.css', 'stylesheet.css']; | ||||
|     let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); | ||||
|     for (let i = 0; i < stylesheetNames.length; i++) { | ||||
|         let stylesheetFile = extension.dir.get_child(stylesheetNames[i]); | ||||
|         if (stylesheetFile.query_exists(null)) { | ||||
|             let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); | ||||
|         try { | ||||
|             let stylesheetFile = extension.dir.get_child(stylesheetNames[i]); | ||||
|             theme.load_stylesheet(stylesheetFile); | ||||
|             extension.stylesheet = stylesheetFile; | ||||
|             break; | ||||
|         } catch (e) { | ||||
|             if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) | ||||
|                 continue; // not an error | ||||
|             log(`Failed to load stylesheet for extension ${uuid}: ${e.message}`); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -131,6 +137,10 @@ function enableExtension(uuid) { | ||||
|         _signals.emit('extension-state-changed', extension); | ||||
|         return; | ||||
|     } catch(e) { | ||||
|         if (extension.stylesheet) { | ||||
|             theme.unload_stylesheet(extension.stylesheet); | ||||
|             delete extension.stylesheet; | ||||
|         } | ||||
|         logExtensionError(uuid, e); | ||||
|         return; | ||||
|     } | ||||
|   | ||||
| @@ -418,6 +418,11 @@ var IconGrid = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     _animationDone() { | ||||
|         this._clonesAnimating.forEach(clone => { | ||||
|             clone.source.reactive = true; | ||||
|             clone.source.opacity = 255; | ||||
|             clone.destroy(); | ||||
|         }); | ||||
|         this._clonesAnimating = []; | ||||
|         this.emit('animation-done'); | ||||
|     }, | ||||
| @@ -538,10 +543,6 @@ var IconGrid = new Lang.Class({ | ||||
|                                    onComplete: () => { | ||||
|                                        if (isLastItem) | ||||
|                                            this._animationDone(); | ||||
|  | ||||
|                                        actor.opacity = 255; | ||||
|                                        actor.reactive = true; | ||||
|                                        actorClone.destroy(); | ||||
|                                    }}; | ||||
|                 fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM, | ||||
|                                transition: 'easeInOutQuad', | ||||
| @@ -562,12 +563,8 @@ var IconGrid = new Lang.Class({ | ||||
|                                    scale_x: scaleX, | ||||
|                                    scale_y: scaleY, | ||||
|                                    onComplete: () => { | ||||
|                                        if (isLastItem) { | ||||
|                                        if (isLastItem) | ||||
|                                            this._animationDone(); | ||||
|                                            this._restoreItemsOpacity(); | ||||
|                                        } | ||||
|                                        actor.reactive = true; | ||||
|                                        actorClone.destroy(); | ||||
|                                    }}; | ||||
|                 fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM, | ||||
|                                transition: 'easeInOutQuad', | ||||
| @@ -581,12 +578,6 @@ var IconGrid = new Lang.Class({ | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _restoreItemsOpacity() { | ||||
|         for (let index = 0; index < this._items.length; index++) { | ||||
|             this._items[index].actor.opacity = 255; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _getAllocatedChildSizeAndSpacing(child) { | ||||
|         let [,, natWidth, natHeight] = child.get_preferred_size(); | ||||
|         let width = Math.min(this._getHItemSize(), natWidth); | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- | ||||
|  | ||||
| const FocusCaretTracker = imports.ui.focusCaretTracker; | ||||
| const Atspi = imports.gi.Atspi; | ||||
| const Clutter = imports.gi.Clutter; | ||||
| const Gdk = imports.gi.Gdk; | ||||
| @@ -13,6 +12,7 @@ const Signals = imports.signals; | ||||
| const St = imports.gi.St; | ||||
| const InputSourceManager = imports.ui.status.keyboard; | ||||
|  | ||||
| const IBusManager = imports.misc.ibusManager; | ||||
| const BoxPointer = imports.ui.boxpointer; | ||||
| const Layout = imports.ui.layout; | ||||
| const Main = imports.ui.main; | ||||
| @@ -261,6 +261,7 @@ var Key = new Lang.Class({ | ||||
|         this._extended_keyboard = null; | ||||
|         this._pressTimeoutId = 0; | ||||
|         this._capturedPress = false; | ||||
|  | ||||
|         this._capturedEventId = 0; | ||||
|         this._unmapId = 0; | ||||
|         this._longPress = false; | ||||
| @@ -484,6 +485,79 @@ var KeyboardModel = new Lang.Class({ | ||||
|     } | ||||
| }); | ||||
|  | ||||
| var FocusTracker = new Lang.Class({ | ||||
|     Name: 'FocusTracker', | ||||
|  | ||||
|     _init() { | ||||
|         this._currentWindow = null; | ||||
|         this._currentWindowPositionId = 0; | ||||
|  | ||||
|         global.screen.get_display().connect('notify::focus-window', () => { | ||||
|             this._setCurrentWindow(global.screen.get_display().focus_window); | ||||
|             this.emit('window-changed', this._currentWindow); | ||||
|         }); | ||||
|  | ||||
|         /* Valid for wayland clients */ | ||||
|         Main.inputMethod.connect('cursor-location-changed', (o, rect) => { | ||||
|             let newRect = { x: rect.get_x(), y: rect.get_y(), width: rect.get_width(), height: rect.get_height() }; | ||||
|             this._setCurrentRect(newRect); | ||||
|         }); | ||||
|  | ||||
|         this._ibusManager = IBusManager.getIBusManager(); | ||||
|         this._ibusManager.connect('set-cursor-location', (manager, rect) => { | ||||
|             /* Valid for X11 clients only */ | ||||
|             if (Main.inputMethod.currentFocus) | ||||
|                 return; | ||||
|  | ||||
|             this._setCurrentRect(rect); | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     get currentWindow() { | ||||
|         return this._currentWindow; | ||||
|     }, | ||||
|  | ||||
|     _setCurrentWindow(window) { | ||||
|         if (this._currentWindow) | ||||
|             this._currentWindow.disconnect(this._currentWindowPositionId); | ||||
|  | ||||
|         this._currentWindow = window; | ||||
|         if (window) { | ||||
|             this._currentWindowPositionId = this._currentWindow.connect('position-changed', () => { | ||||
|                 if (global.display.get_grab_op() == Meta.GrabOp.NONE) | ||||
|                     this.emit('position-changed'); | ||||
|                 else | ||||
|                     this.emit('reset'); | ||||
|             }); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _setCurrentRect(rect) { | ||||
|         if (this._currentWindow) { | ||||
|             let frameRect = this._currentWindow.get_frame_rect(); | ||||
|             rect.x -= frameRect.x; | ||||
|             rect.y -= frameRect.y; | ||||
|         } | ||||
|  | ||||
|         this._rect = rect; | ||||
|         this.emit('position-changed'); | ||||
|     }, | ||||
|  | ||||
|     getCurrentRect() { | ||||
|         let rect = { x: this._rect.x, y: this._rect.y, | ||||
|                      width: this._rect.width, height: this._rect.height }; | ||||
|  | ||||
|         if (this._currentWindow) { | ||||
|             let frameRect = this._currentWindow.get_frame_rect(); | ||||
|             rect.x += frameRect.x; | ||||
|             rect.y += frameRect.y; | ||||
|         } | ||||
|  | ||||
|         return rect; | ||||
|     } | ||||
| }); | ||||
| Signals.addSignalMethods(FocusTracker.prototype); | ||||
|  | ||||
| var Keyboard = new Lang.Class({ | ||||
|     Name: 'Keyboard', | ||||
|  | ||||
| @@ -491,15 +565,10 @@ var Keyboard = new Lang.Class({ | ||||
|         this.actor = null; | ||||
|         this._focusInExtendedKeys = false; | ||||
|  | ||||
|         this._focusCaretTracker = new FocusCaretTracker.FocusCaretTracker(); | ||||
|         this._focusCaretTracker.connect('focus-changed', this._onFocusChanged.bind(this)); | ||||
|         this._focusCaretTracker.connect('caret-moved', this._onCaretMoved.bind(this)); | ||||
|         this._languagePopup = null; | ||||
|         this._currentAccessible = null; | ||||
|         this._caretTrackingEnabled = false; | ||||
|         this._updateCaretPositionId = 0; | ||||
|         this._currentFocusWindow = null; | ||||
|         this._originalWindowY = null; | ||||
|         this._animFocusedWindow = null; | ||||
|         this._delayedAnimFocusWindow = null; | ||||
|  | ||||
|         this._enableKeyboard = false; // a11y settings value | ||||
|         this._enabled = false; // enabled state (by setting or device type) | ||||
| @@ -510,6 +579,14 @@ var Keyboard = new Lang.Class({ | ||||
|         this._lastDeviceId = null; | ||||
|         this._suggestions = null; | ||||
|  | ||||
|         this._focusTracker = new FocusTracker(); | ||||
|         this._focusTracker.connect('position-changed', this._onFocusPositionChanged.bind(this)); | ||||
|         this._focusTracker.connect('reset', () => { | ||||
|             this._delayedAnimFocusWindow = null; | ||||
|             this._animFocusedWindow = null; | ||||
|             this._oskFocusWindow = null; | ||||
|         }); | ||||
|  | ||||
|         Meta.get_backend().connect('last-device-changed',  | ||||
|             (backend, deviceId) => { | ||||
|                 let manager = Clutter.DeviceManager.get_default(); | ||||
| @@ -532,102 +609,15 @@ var Keyboard = new Lang.Class({ | ||||
|         this._keyboardRestingId = 0; | ||||
|  | ||||
|         Main.layoutManager.connect('monitors-changed', this._relayout.bind(this)); | ||||
|         //Main.inputMethod.connect('cursor-location-changed', (o, rect) => { | ||||
|         //    if (this._keyboardVisible) { | ||||
|         //        let currentWindow = global.screen.get_display().focus_window; | ||||
|         //        this.setCursorLocation(currentWindow, rect.get_x(), rect.get_y(), | ||||
|         //                               rect.get_width(), rect.get_height()); | ||||
|         //    } | ||||
|         //}); | ||||
|     }, | ||||
|  | ||||
|     get visible() { | ||||
|         return this._keyboardVisible; | ||||
|     }, | ||||
|  | ||||
|     _setCaretTrackerEnabled(enabled) { | ||||
|         if (this._caretTrackingEnabled == enabled) | ||||
|             return; | ||||
|  | ||||
|         this._caretTrackingEnabled = enabled; | ||||
|  | ||||
|         if (enabled) { | ||||
|             this._focusCaretTracker.registerFocusListener(); | ||||
|             this._focusCaretTracker.registerCaretListener(); | ||||
|         } else { | ||||
|             this._focusCaretTracker.deregisterFocusListener(); | ||||
|             this._focusCaretTracker.deregisterCaretListener(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _updateCaretPosition(accessible) { | ||||
|         if (this._updateCaretPositionId) | ||||
|             GLib.source_remove(this._updateCaretPositionId); | ||||
|         if (!this._keyboardRequested) | ||||
|             return; | ||||
|         this._updateCaretPositionId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { | ||||
|             this._updateCaretPositionId = 0; | ||||
|  | ||||
|             let currentWindow = global.screen.get_display().focus_window; | ||||
|             if (!currentWindow) { | ||||
|                 this.setCursorLocation(null); | ||||
|                 return GLib.SOURCE_REMOVE; | ||||
|             } | ||||
|  | ||||
|             let windowRect = currentWindow.get_frame_rect(); | ||||
|             let text = accessible.get_text_iface(); | ||||
|             let component = accessible.get_component_iface(); | ||||
|  | ||||
|             try { | ||||
|                 let caretOffset = text.get_caret_offset(); | ||||
|                 let caretRect = text.get_character_extents(caretOffset, Atspi.CoordType.WINDOW); | ||||
|                 let focusRect = component.get_extents(Atspi.CoordType.WINDOW); | ||||
|  | ||||
|                 if (caretRect.width == 0 && caretRect.height == 0) | ||||
|                     caretRect = focusRect; | ||||
|  | ||||
|                 this.setCursorLocation(currentWindow, caretRect.x, caretRect.y, caretRect.width, caretRect.height); | ||||
|             } catch (e) { | ||||
|                 log('Error updating caret position for OSK: ' + e.message); | ||||
|             } | ||||
|  | ||||
|             return GLib.SOURCE_REMOVE; | ||||
|         }); | ||||
|  | ||||
|         GLib.Source.set_name_by_id(this._updateCaretPositionId, '[gnome-shell] this._updateCaretPosition'); | ||||
|     }, | ||||
|  | ||||
|     _focusIsTextEntry(accessible) { | ||||
|         try { | ||||
|             let role = accessible.get_role(); | ||||
|             let stateSet = accessible.get_state_set(); | ||||
|             return stateSet.contains(Atspi.StateType.EDITABLE) || role == Atspi.Role.TERMINAL; | ||||
|         } catch (e) { | ||||
|             log('Error determining accessible role: ' + e.message); | ||||
|             return false; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onFocusChanged(caretTracker, event) { | ||||
|         let accessible = event.source; | ||||
|         if (!this._focusIsTextEntry(accessible)) | ||||
|             return; | ||||
|  | ||||
|         let focused = event.detail1 != 0; | ||||
|         if (focused) { | ||||
|             this._currentAccessible = accessible; | ||||
|             this._updateCaretPosition(accessible); | ||||
|             this.show(Main.layoutManager.focusIndex); | ||||
|         } else if (this._currentAccessible == accessible) { | ||||
|             this._currentAccessible = null; | ||||
|             this.hide(); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     _onCaretMoved(caretTracker, event) { | ||||
|         let accessible = event.source; | ||||
|         if (this._currentAccessible == accessible) | ||||
|             this._updateCaretPosition(accessible); | ||||
|     _onFocusPositionChanged(focusTracker) { | ||||
|         let rect = focusTracker.getCurrentRect(); | ||||
|         this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height); | ||||
|     }, | ||||
|  | ||||
|     _lastDeviceIsTouchscreen() { | ||||
| @@ -650,8 +640,6 @@ var Keyboard = new Lang.Class({ | ||||
|         if (!this._enabled && !this._keyboardController) | ||||
|             return; | ||||
|  | ||||
|         this._setCaretTrackerEnabled(this._enabled); | ||||
|  | ||||
|         if (this._enabled && !this._keyboardController) | ||||
|             this._setupKeyboard(); | ||||
|         else if (!this._enabled) | ||||
| @@ -936,9 +924,11 @@ var Keyboard = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     _relayout() { | ||||
|         if (this.actor == null) | ||||
|             return; | ||||
|         let monitor = Main.layoutManager.keyboardMonitor; | ||||
|  | ||||
|         if (this.actor == null || monitor == null) | ||||
|             return; | ||||
|  | ||||
|         let maxHeight = monitor.height / 3; | ||||
|         this.actor.width = monitor.width; | ||||
|         this.actor.height = maxHeight; | ||||
| @@ -1027,11 +1017,14 @@ var Keyboard = new Lang.Class({ | ||||
|         if (!this._keyboardRequested) | ||||
|             return; | ||||
|  | ||||
|         if (this._currentAccessible) | ||||
|             this._updateCaretPosition(this._currentAccessible); | ||||
|         Main.layoutManager.keyboardIndex = monitor; | ||||
|         this._relayout(); | ||||
|         Main.layoutManager.showKeyboard(); | ||||
|  | ||||
|         if (this._delayedAnimFocusWindow) { | ||||
|             this._setAnimationWindow(this._delayedAnimFocusWindow); | ||||
|             this._delayedAnimFocusWindow = null; | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     hide() { | ||||
| @@ -1102,8 +1095,9 @@ var Keyboard = new Lang.Class({ | ||||
|         window.move_frame(true, frameRect.x, frameRect.y); | ||||
|     }, | ||||
|  | ||||
|     _animateWindow(window, show, deltaY) { | ||||
|     _animateWindow(window, show) { | ||||
|         let windowActor = window.get_compositor_private(); | ||||
|         let deltaY = Main.layoutManager.keyboardBox.height; | ||||
|         if (!windowActor) | ||||
|             return; | ||||
|  | ||||
| @@ -1124,35 +1118,39 @@ var Keyboard = new Lang.Class({ | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     setCursorLocation(window, x, y , w, h) { | ||||
|         if (window == this._oskFocusWindow) | ||||
|     _setAnimationWindow(window) { | ||||
|         if (this._animFocusedWindow == window) | ||||
|             return; | ||||
|  | ||||
|         if (this._oskFocusWindow) { | ||||
|             let display = global.screen.get_display(); | ||||
|         if (this._animFocusedWindow) | ||||
|             this._animateWindow(this._animFocusedWindow, false); | ||||
|         if (window) | ||||
|             this._animateWindow(window, true); | ||||
|  | ||||
|             if (display.get_grab_op() == Meta.GrabOp.NONE || | ||||
|                 display.get_focus_window() != this._oskFocusWindow) | ||||
|                 this._animateWindow(this._oskFocusWindow, false, this._oskFocusWindowDelta); | ||||
|         this._animFocusedWindow = window; | ||||
|     }, | ||||
|  | ||||
|             this._oskFocusWindow = null; | ||||
|             this._oskFocusWindowDelta = null; | ||||
|         } | ||||
|     setCursorLocation(window, x, y , w, h) { | ||||
|         let monitor = Main.layoutManager.keyboardMonitor; | ||||
|  | ||||
|         if (window) { | ||||
|             let monitor = Main.layoutManager.keyboardMonitor; | ||||
|         if (window && monitor) { | ||||
|             let keyboardHeight = Main.layoutManager.keyboardBox.height; | ||||
|             let frameRect = window.get_frame_rect(); | ||||
|             let windowActor = window.get_compositor_private(); | ||||
|             let delta = 0; | ||||
|             let focusObscured = false; | ||||
|  | ||||
|             if (frameRect.y + y + h >= monitor.height - keyboardHeight) | ||||
|                 delta = keyboardHeight; | ||||
|  | ||||
|             this._animateWindow(window, true, delta); | ||||
|             this._oskFocusWindow = window; | ||||
|             this._oskFocusWindowDelta = delta; | ||||
|             if (y + h >= monitor.y + monitor.height - keyboardHeight) { | ||||
|                 if (this._keyboardVisible) | ||||
|                     this._setAnimationWindow(window); | ||||
|                 else | ||||
|                     this._delayedAnimFocusWindow = window; | ||||
|             } else if (y < keyboardHeight) { | ||||
|                 this._delayedAnimFocusWindow = null; | ||||
|                 this._setAnimationWindow(null); | ||||
|             } | ||||
|         } else { | ||||
|             this._setAnimationWindow(null); | ||||
|         } | ||||
|  | ||||
|         this._oskFocusWindow = window; | ||||
|     }, | ||||
| }); | ||||
|  | ||||
|   | ||||
| @@ -203,6 +203,7 @@ var LayoutManager = new Lang.Class({ | ||||
|  | ||||
|         // Set up stage hierarchy to group all UI actors under one container. | ||||
|         this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' }); | ||||
|         this.uiGroup.set_flags(Clutter.ActorFlags.NO_LAYOUT); | ||||
|         this.uiGroup.connect('allocate', (actor, box, flags) => { | ||||
|             let children = actor.get_children(); | ||||
|             for (let i = 0; i < children.length; i++) | ||||
| @@ -557,6 +558,8 @@ var LayoutManager = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     get focusMonitor() { | ||||
|         if (this.focusIndex < 0) | ||||
|             return null; | ||||
|         return this.monitors[this.focusIndex]; | ||||
|     }, | ||||
|  | ||||
|   | ||||
| @@ -19,7 +19,6 @@ const MagnifierDBus = imports.ui.magnifierDBus; | ||||
| const Params = imports.misc.params; | ||||
| const PointerWatcher = imports.ui.pointerWatcher; | ||||
|  | ||||
| var MOUSE_POLL_FREQUENCY = 50; | ||||
| var CROSSHAIRS_CLIP_SIZE = [100, 100]; | ||||
| var NO_CHANGE = 0.0; | ||||
|  | ||||
| @@ -152,8 +151,10 @@ var Magnifier = new Lang.Class({ | ||||
|      * Turn on mouse tracking, if not already doing so. | ||||
|      */ | ||||
|     startTrackingMouse() { | ||||
|         if (!this._pointerWatch) | ||||
|             this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(MOUSE_POLL_FREQUENCY, this.scrollToMousePos.bind(this)); | ||||
|         if (!this._pointerWatch) { | ||||
|             let interval = 1000 / Clutter.get_default_frame_rate(); | ||||
|             this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(interval, this.scrollToMousePos.bind(this)); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -256,6 +256,14 @@ function _getStylesheet(name) { | ||||
|     if (stylesheet.query_exists(null)) | ||||
|         return stylesheet; | ||||
|  | ||||
|     let dataDirs = GLib.get_system_data_dirs(); | ||||
|     for (let i = 0; i < dataDirs.length; i++) { | ||||
|         let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'theme', name]); | ||||
|         let stylesheet = Gio.file_new_for_path(path); | ||||
|         if (stylesheet.query_exists(null)) | ||||
|             return stylesheet; | ||||
|     } | ||||
|  | ||||
|     stylesheet = Gio.File.new_for_path(global.datadir + '/theme/' + name); | ||||
|     if (stylesheet.query_exists(null)) | ||||
|         return stylesheet; | ||||
| @@ -335,6 +343,9 @@ function loadTheme() { | ||||
|     let theme = new St.Theme ({ application_stylesheet: _cssStylesheet, | ||||
|                                 default_stylesheet: _defaultCssStylesheet }); | ||||
|  | ||||
|     if (theme.default_stylesheet == null) | ||||
|         throw new Error("No valid stylesheet found for '%s'".format(sessionMode.stylesheetName)); | ||||
|  | ||||
|     if (previousTheme) { | ||||
|         let customStylesheets = previousTheme.get_custom_stylesheets(); | ||||
|  | ||||
|   | ||||
| @@ -362,7 +362,8 @@ var Message = new Lang.Class({ | ||||
|         this.setBody(body); | ||||
|  | ||||
|         this._closeButton.connect('clicked', this.close.bind(this)); | ||||
|         this.actor.connect('notify::hover', this._sync.bind(this)); | ||||
|         let actorHoverId = this.actor.connect('notify::hover', this._sync.bind(this)); | ||||
|         this._closeButton.connect('destroy', this.actor.disconnect.bind(this.actor, actorHoverId)); | ||||
|         this.actor.connect('clicked', this._onClicked.bind(this)); | ||||
|         this.actor.connect('destroy', this._onDestroy.bind(this)); | ||||
|         this._sync(); | ||||
|   | ||||
| @@ -1320,6 +1320,7 @@ var MessageTray = new Lang.Class({ | ||||
|         this._bannerBin.y = -this._banner.actor.height; | ||||
|         this.actor.show(); | ||||
|  | ||||
|         Meta.disable_unredirect_for_display(global.display); | ||||
|         this._updateShowingNotification(); | ||||
|  | ||||
|         let [x, y, mods] = global.get_pointer(); | ||||
| @@ -1457,6 +1458,7 @@ var MessageTray = new Lang.Class({ | ||||
|  | ||||
|         this._pointerInNotification = false; | ||||
|         this._notificationRemoved = false; | ||||
|         Meta.enable_unredirect_for_display(global.display); | ||||
|  | ||||
|         this._banner.actor.destroy(); | ||||
|         this._banner = null; | ||||
|   | ||||
| @@ -117,10 +117,8 @@ var FdoNotificationDaemon = new Lang.Class({ | ||||
|                  bitsPerSample, nChannels, data] = hints['image-data']; | ||||
|             return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha, | ||||
|                                                       bitsPerSample, width, height, rowStride); | ||||
|         } else if (hints['image-path']) { | ||||
|             return new Gio.FileIcon({ file: Gio.File.new_for_path(hints['image-path']) }); | ||||
|         } | ||||
|         return null; | ||||
|         return this._iconForNotificationData(hints['image-path']); | ||||
|     }, | ||||
|  | ||||
|     _fallbackIconForNotificationData(hints) { | ||||
|   | ||||
| @@ -108,15 +108,30 @@ var OsdWindow = new Lang.Class({ | ||||
|         this._hideTimeoutId = 0; | ||||
|         this._reset(); | ||||
|  | ||||
|         Main.layoutManager.connect('monitors-changed', | ||||
|                                    this._relayout.bind(this)); | ||||
|         this.actor.connect('destroy', this._onDestroy.bind(this)); | ||||
|  | ||||
|         this._monitorsChangedId = | ||||
|             Main.layoutManager.connect('monitors-changed', | ||||
|                                        this._relayout.bind(this)); | ||||
|         let themeContext = St.ThemeContext.get_for_stage(global.stage); | ||||
|         themeContext.connect('notify::scale-factor', | ||||
|                              this._relayout.bind(this)); | ||||
|         this._scaleChangedId = | ||||
|             themeContext.connect('notify::scale-factor', | ||||
|                                  this._relayout.bind(this)); | ||||
|         this._relayout(); | ||||
|         Main.uiGroup.add_child(this.actor); | ||||
|     }, | ||||
|  | ||||
|     _onDestroy() { | ||||
|         if (this._monitorsChangedId) | ||||
|             Main.layoutManager.disconnect(this._monitorsChangedId); | ||||
|         this._monitorsChangedId = 0; | ||||
|  | ||||
|         let themeContext = St.ThemeContext.get_for_stage(global.stage); | ||||
|         if (this._scaleChangedId) | ||||
|             themeContext.disconnect(this._scaleChangedId); | ||||
|         this._scaleChangedId = 0; | ||||
|     }, | ||||
|  | ||||
|     setIcon(icon) { | ||||
|         this._icon.gicon = icon; | ||||
|     }, | ||||
| @@ -204,7 +219,7 @@ var OsdWindow = new Lang.Class({ | ||||
|  | ||||
|         let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; | ||||
|         this._icon.icon_size = popupSize / (2 * scaleFactor); | ||||
|         this._box.translation_y = monitor.height / 4; | ||||
|         this._box.translation_y = Math.round(monitor.height / 4); | ||||
|         this._boxConstraint.minSize = popupSize; | ||||
|     } | ||||
| }); | ||||
|   | ||||
| @@ -393,10 +393,8 @@ var Overview = new Lang.Class({ | ||||
|         if (!Main.layoutManager.primaryMonitor) | ||||
|             return; | ||||
|  | ||||
|         let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex); | ||||
|  | ||||
|         this._coverPane.set_position(0, workArea.y); | ||||
|         this._coverPane.set_size(workArea.width, workArea.height); | ||||
|         this._coverPane.set_position(0, 0); | ||||
|         this._coverPane.set_size(global.screen_width, global.screen_height); | ||||
|  | ||||
|         this._updateBackgrounds(); | ||||
|     }, | ||||
|   | ||||
| @@ -284,6 +284,11 @@ var ThumbnailsSlider = new Lang.Class({ | ||||
|         return child.get_theme_node().get_length('visible-width'); | ||||
|     }, | ||||
|  | ||||
|     _onDragEnd() { | ||||
|         this.actor.sync_hover(); | ||||
|         this.parent(); | ||||
|     }, | ||||
|  | ||||
|     _getSlide() { | ||||
|         if (!this._visible) | ||||
|             return 0; | ||||
|   | ||||
| @@ -796,6 +796,7 @@ var Panel = new Lang.Class({ | ||||
|         this.actor.connect('get-preferred-height', this._getPreferredHeight.bind(this)); | ||||
|         this.actor.connect('allocate', this._allocate.bind(this)); | ||||
|         this.actor.connect('button-press-event', this._onButtonPress.bind(this)); | ||||
|         this.actor.connect('touch-event', this._onButtonPress.bind(this)); | ||||
|         this.actor.connect('key-press-event', this._onKeyPress.bind(this)); | ||||
|  | ||||
|         Main.overview.connect('showing', () => { | ||||
| @@ -939,8 +940,13 @@ var Panel = new Lang.Class({ | ||||
|         if (event.get_source() != actor) | ||||
|             return Clutter.EVENT_PROPAGATE; | ||||
|  | ||||
|         let button = event.get_button(); | ||||
|         if (button != 1) | ||||
|         let type = event.type(); | ||||
|         let isPress = type == Clutter.EventType.BUTTON_PRESS; | ||||
|         if (!isPress && type != Clutter.EventType.TOUCH_BEGIN) | ||||
|             return Clutter.EVENT_PROPAGATE; | ||||
|  | ||||
|         let button = isPress ? event.get_button() : -1; | ||||
|         if (isPress && button != 1) | ||||
|             return Clutter.EVENT_PROPAGATE; | ||||
|  | ||||
|         let focusWindow = global.display.focus_window; | ||||
| @@ -1079,6 +1085,7 @@ var Panel = new Lang.Class({ | ||||
|         let windows = activeWorkspace.list_windows().filter(metaWindow => { | ||||
|             return metaWindow.is_on_primary_monitor() && | ||||
|                    metaWindow.showing_on_its_workspace() && | ||||
|                    !metaWindow.is_hidden() && | ||||
|                    metaWindow.get_window_type() != Meta.WindowType.DESKTOP; | ||||
|         }); | ||||
|  | ||||
|   | ||||
| @@ -141,8 +141,17 @@ var PopupBaseMenuItem = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     _onKeyPressEvent(actor, event) { | ||||
|         let symbol = event.get_key_symbol(); | ||||
|         let state = event.get_state(); | ||||
|  | ||||
|         // if user has a modifier down (except capslock) | ||||
|         // then don't handle the key press here | ||||
|         state &= ~Clutter.ModifierType.LOCK_MASK; | ||||
|         state &= Clutter.ModifierType.MODIFIER_MASK; | ||||
|  | ||||
|         if (state) | ||||
|             return Clutter.EVENT_PROPAGATE; | ||||
|  | ||||
|         let symbol = event.get_key_symbol(); | ||||
|         if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) { | ||||
|             this.activate(event); | ||||
|             return Clutter.EVENT_STOP; | ||||
| @@ -394,8 +403,9 @@ var PopupImageMenuItem = new Lang.Class({ | ||||
|     _init(text, icon, params) { | ||||
|         this.parent(params); | ||||
|  | ||||
|         this._icon = new St.Icon({ style_class: 'popup-menu-icon' }); | ||||
|         this.actor.add_child(this._icon, { align: St.Align.END }); | ||||
|         this._icon = new St.Icon({ style_class: 'popup-menu-icon', | ||||
|                                    x_align: Clutter.ActorAlign.END }); | ||||
|         this.actor.add_child(this._icon); | ||||
|         this.label = new St.Label({ text: text }); | ||||
|         this.actor.add_child(this.label); | ||||
|         this.actor.label_actor = this.label; | ||||
|   | ||||
| @@ -295,7 +295,7 @@ var RemoteSearchProvider = new Lang.Class({ | ||||
|                                name: metas[i]['name'], | ||||
|                                description: metas[i]['description'], | ||||
|                                createIcon: size => { | ||||
|                                    this.createIcon(size, metas[i]); | ||||
|                                    return this.createIcon(size, metas[i]); | ||||
|                                }, | ||||
|                                clipboardText: metas[i]['clipboardText'] }); | ||||
|         } | ||||
|   | ||||
| @@ -114,18 +114,16 @@ var RunDialog = new Lang.Class({ | ||||
|  | ||||
|         this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY, | ||||
|                                                      entry: this._entryText }); | ||||
|         this._entryText.connect('activate', (o) => { | ||||
|             this.popModal(); | ||||
|             this._run(o.get_text(), | ||||
|                       Clutter.get_current_event().get_state() & Clutter.ModifierType.CONTROL_MASK); | ||||
|             if (!this._commandError || | ||||
|                 !this.pushModal()) | ||||
|                 this.close(); | ||||
|         }); | ||||
|         this._entryText.connect('key-press-event', (o, e) => { | ||||
|             let symbol = e.get_key_symbol(); | ||||
|             if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) { | ||||
|                 this.popModal(); | ||||
|                 this._run(o.get_text(), | ||||
|                           e.get_state() & Clutter.ModifierType.CONTROL_MASK); | ||||
|                 if (!this._commandError || | ||||
|                     !this.pushModal()) | ||||
|                     this.close(); | ||||
|  | ||||
|                 return Clutter.EVENT_STOP; | ||||
|             } | ||||
|             if (symbol == Clutter.Tab) { | ||||
|                 let text = o.get_text(); | ||||
|                 let prefix; | ||||
|   | ||||
| @@ -192,6 +192,7 @@ var SearchResultsBase = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     clear() { | ||||
|         this._cancellable.cancel(); | ||||
|         for (let resultId in this._resultDisplays) | ||||
|             this._resultDisplays[resultId].actor.destroy(); | ||||
|         this._resultDisplays = {}; | ||||
| @@ -225,6 +226,12 @@ var SearchResultsBase = new Lang.Class({ | ||||
|             this._cancellable.reset(); | ||||
|  | ||||
|             this.provider.getResultMetas(metasNeeded, metas => { | ||||
|                 if (this._cancellable.is_cancelled()) { | ||||
|                     if (metas.length > 0) | ||||
|                         log(`Search provider ${this.provider.id} returned results after the request was canceled`); | ||||
|                     callback(false); | ||||
|                     return; | ||||
|                 } | ||||
|                 if (metas.length != metasNeeded.length) { | ||||
|                     log('Wrong number of result metas returned by search provider ' + this.provider.id + | ||||
|                         ': expected ' + metasNeeded.length + ' but got ' + metas.length); | ||||
|   | ||||
| @@ -360,11 +360,14 @@ var InputSourceManager = new Lang.Class({ | ||||
|         this._settings.connect('per-window-changed', this._sourcesPerWindowChanged.bind(this)); | ||||
|         this._sourcesPerWindowChanged(); | ||||
|         this._disableIBus = false; | ||||
|         this._reloading = false; | ||||
|     }, | ||||
|  | ||||
|     reload() { | ||||
|         this._reloading = true; | ||||
|         this._keyboardManager.setKeyboardOptions(this._settings.keyboardOptions); | ||||
|         this._inputSourcesChanged(); | ||||
|         this._reloading = false; | ||||
|     }, | ||||
|  | ||||
|     _ibusReadyCallback(im, ready) { | ||||
| @@ -458,7 +461,15 @@ var InputSourceManager = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     activateInputSource(is, interactive) { | ||||
|         KeyboardManager.holdKeyboard(); | ||||
|         // The focus changes during holdKeyboard/releaseKeyboard may trick | ||||
|         // the client into hiding UI containing the currently focused entry. | ||||
|         // So holdKeyboard/releaseKeyboard are not called when | ||||
|         // 'set-content-type' signal is received. | ||||
|         // E.g. Focusing on a password entry in a popup in Xorg Firefox | ||||
|         // will emit 'set-content-type' signal. | ||||
|         // https://gitlab.gnome.org/GNOME/gnome-shell/issues/391 | ||||
|         if (!this._reloading) | ||||
|             KeyboardManager.holdKeyboard(); | ||||
|         this._keyboardManager.apply(is.xkbId); | ||||
|  | ||||
|         // All the "xkb:..." IBus engines simply "echo" back symbols, | ||||
| @@ -473,7 +484,10 @@ var InputSourceManager = new Lang.Class({ | ||||
|         else | ||||
|             engine = 'xkb:us::eng'; | ||||
|  | ||||
|         this._ibusManager.setEngine(engine, KeyboardManager.releaseKeyboard); | ||||
|         if (!this._reloading) | ||||
|             this._ibusManager.setEngine(engine, KeyboardManager.releaseKeyboard); | ||||
|         else | ||||
|             this._ibusManager.setEngine(engine); | ||||
|         this._currentInputSourceChanged(is); | ||||
|  | ||||
|         if (interactive) | ||||
|   | ||||
| @@ -419,12 +419,14 @@ var NMConnectionDevice = new Lang.Class({ | ||||
|         this._deactivateItem.actor.visible = this._device.state > NM.DeviceState.DISCONNECTED; | ||||
|  | ||||
|         if (this._activeConnection == null) { | ||||
|             this._activeConnection = this._device.active_connection; | ||||
|  | ||||
|             if (this._activeConnection) { | ||||
|                 ensureActiveConnectionProps(this._activeConnection, this._client); | ||||
|                 let item = this._connectionItems.get(this._activeConnection.connection.get_uuid()); | ||||
|                 item.setActiveConnection(this._activeConnection); | ||||
|             let activeConnection = this._device.active_connection; | ||||
|             if (activeConnection && activeConnection.connection) { | ||||
|                 let item = this._connectionItems.get(activeConnection.connection.get_uuid()); | ||||
|                 if (item) { | ||||
|                     this._activeConnection = activeConnection; | ||||
|                     ensureActiveConnectionProps(this._activeConnection, this._client); | ||||
|                     item.setActiveConnection(this._activeConnection); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -1944,6 +1946,7 @@ var NMApplet = new Lang.Class({ | ||||
|         this.indicators.visible = this._client.nm_running; | ||||
|         this.menu.actor.visible = this._client.networking_enabled; | ||||
|  | ||||
|         this._updateIcon(); | ||||
|         this._syncConnectivity(); | ||||
|     }, | ||||
|  | ||||
|   | ||||
| @@ -58,6 +58,9 @@ var AltSwitcher = new Lang.Class({ | ||||
|             childToShow = this._standard; | ||||
|         } else if (this._alternate.visible) { | ||||
|             childToShow = this._alternate; | ||||
|         } else { | ||||
|             this.actor.hide(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         let childShown = this.actor.get_child(); | ||||
| @@ -79,7 +82,7 @@ var AltSwitcher = new Lang.Class({ | ||||
|             global.sync_pointer(); | ||||
|         } | ||||
|  | ||||
|         this.actor.visible = (childToShow != null); | ||||
|         this.actor.show(); | ||||
|     }, | ||||
|  | ||||
|     _onDestroy() { | ||||
|   | ||||
| @@ -311,6 +311,7 @@ var ViewSelector = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     hide() { | ||||
|         this.reset(); | ||||
|         this._workspacesDisplay.hide(); | ||||
|     }, | ||||
|  | ||||
| @@ -459,7 +460,11 @@ var ViewSelector = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     reset() { | ||||
|         global.stage.set_key_focus(null); | ||||
|         // Don't drop the key focus on Clutter's side if anything but the | ||||
|         // overview has pushed a modal (e.g. system modals when activated using | ||||
|         // the overview). | ||||
|         if (Main.modalCount <= 1) | ||||
|             global.stage.set_key_focus(null); | ||||
|  | ||||
|         this._entry.text = ''; | ||||
|  | ||||
|   | ||||
| @@ -24,7 +24,7 @@ const EdgeDragAction = imports.ui.edgeDragAction; | ||||
| const CloseDialog = imports.ui.closeDialog; | ||||
| const SwitchMonitor = imports.ui.switchMonitor; | ||||
|  | ||||
| const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings'; | ||||
| var SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings'; | ||||
| var MINIMIZE_WINDOW_ANIMATION_TIME = 0.2; | ||||
| var SHOW_WINDOW_ANIMATION_TIME = 0.15; | ||||
| var DIALOG_SHOW_WINDOW_ANIMATION_TIME = 0.1; | ||||
| @@ -627,8 +627,8 @@ var AppSwitchAction = new Lang.Class({ | ||||
|  | ||||
|         if (this.get_n_current_points() == 3) { | ||||
|             for (let i = 0; i < this.get_n_current_points(); i++) { | ||||
|                 [startX, startY] = this.get_press_coords(i); | ||||
|                 [x, y] = this.get_motion_coords(i); | ||||
|                 let [startX, startY] = this.get_press_coords(i); | ||||
|                 let [x, y] = this.get_motion_coords(i); | ||||
|  | ||||
|                 if (Math.abs(x - startX) > MOTION_THRESHOLD || | ||||
|                     Math.abs(y - startY) > MOTION_THRESHOLD) | ||||
| @@ -1173,6 +1173,10 @@ var WindowManager = new Lang.Class({ | ||||
|                 yScale = geom.height / actor.height; | ||||
|             } else { | ||||
|                 let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()]; | ||||
|                 if (!monitor) { | ||||
|                     this._minimizeWindowDone(); | ||||
|                     return; | ||||
|                 } | ||||
|                 xDest = monitor.x; | ||||
|                 yDest = monitor.y; | ||||
|                 if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) | ||||
| @@ -1248,6 +1252,11 @@ var WindowManager = new Lang.Class({ | ||||
|                                 geom.height / actor.height); | ||||
|             } else { | ||||
|                 let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()]; | ||||
|                 if (!monitor) { | ||||
|                     actor.show(); | ||||
|                     this._unminimizeWindowDone(); | ||||
|                     return; | ||||
|                 } | ||||
|                 actor.set_position(monitor.x, monitor.y); | ||||
|                 if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) | ||||
|                     actor.x += monitor.width; | ||||
|   | ||||
| @@ -128,11 +128,10 @@ var WindowMenu = new Lang.Class({ | ||||
|  | ||||
|         let screen = global.screen; | ||||
|         let nMonitors = screen.get_n_monitors(); | ||||
|         if (nMonitors > 1) { | ||||
|         let monitorIndex = window.get_monitor(); | ||||
|         if (nMonitors > 1 && monitorIndex >= 0) { | ||||
|             this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); | ||||
|  | ||||
|             let monitorIndex = window.get_monitor(); | ||||
|  | ||||
|             let dir = Meta.ScreenDirection.UP; | ||||
|             let upMonitorIndex = | ||||
|                 screen.get_monitor_neighbor_index(monitorIndex, dir); | ||||
|   | ||||
| @@ -137,8 +137,10 @@ var WindowClone = new Lang.Class({ | ||||
|         this._dragSlot = [0, 0, 0, 0]; | ||||
|         this._stackAbove = null; | ||||
|  | ||||
|         this._windowClone._updateId = this.metaWindow.connect('size-changed', | ||||
|             this._onRealWindowSizeChanged.bind(this)); | ||||
|         this._windowClone._sizeChangedId = this.metaWindow.connect('size-changed', | ||||
|             this._onMetaWindowSizeChanged.bind(this)); | ||||
|         this._windowClone._posChangedId = this.metaWindow.connect('position-changed', | ||||
|             this._computeBoundingBox.bind(this)); | ||||
|         this._windowClone._destroyId = | ||||
|             this.realWindow.connect('destroy', () => { | ||||
|                 // First destroy the clone and then destroy everything | ||||
| @@ -206,8 +208,7 @@ var WindowClone = new Lang.Class({ | ||||
|  | ||||
|     addAttachedDialog(win) { | ||||
|         this._doAddAttachedDialog(win, win.get_compositor_private()); | ||||
|         this._computeBoundingBox(); | ||||
|         this.emit('size-changed'); | ||||
|         this._onMetaWindowSizeChanged(); | ||||
|     }, | ||||
|  | ||||
|     hasAttachedDialogs() { | ||||
| @@ -216,15 +217,14 @@ var WindowClone = new Lang.Class({ | ||||
|  | ||||
|     _doAddAttachedDialog(metaWin, realWin) { | ||||
|         let clone = new Clutter.Clone({ source: realWin }); | ||||
|         clone._updateId = metaWin.connect('size-changed', () => { | ||||
|             this._computeBoundingBox(); | ||||
|             this.emit('size-changed'); | ||||
|         }); | ||||
|         clone._sizeChangedId = metaWin.connect('size-changed', | ||||
|             this._onMetaWindowSizeChanged.bind(this)); | ||||
|         clone._posChangedId = metaWin.connect('position-changed', | ||||
|             this._onMetaWindowSizeChanged.bind(this)); | ||||
|         clone._destroyId = realWin.connect('destroy', () => { | ||||
|             clone.destroy(); | ||||
|  | ||||
|             this._computeBoundingBox(); | ||||
|             this.emit('size-changed'); | ||||
|             this._onMetaWindowSizeChanged(); | ||||
|         }); | ||||
|         this.actor.add_child(clone); | ||||
|     }, | ||||
| @@ -321,12 +321,13 @@ var WindowClone = new Lang.Class({ | ||||
|             else | ||||
|                 realWindow = child.source; | ||||
|  | ||||
|             realWindow.meta_window.disconnect(child._updateId); | ||||
|             realWindow.meta_window.disconnect(child._sizeChangedId); | ||||
|             realWindow.meta_window.disconnect(child._posChangedId); | ||||
|             realWindow.disconnect(child._destroyId); | ||||
|         }); | ||||
|     }, | ||||
|  | ||||
|     _onRealWindowSizeChanged() { | ||||
|     _onMetaWindowSizeChanged() { | ||||
|         this._computeBoundingBox(); | ||||
|         this.emit('size-changed'); | ||||
|     }, | ||||
| @@ -469,7 +470,6 @@ var WindowOverlay = new Lang.Class({ | ||||
|         this._windowAddedId = 0; | ||||
|  | ||||
|         button.hide(); | ||||
|         title.hide(); | ||||
|  | ||||
|         this.title = title; | ||||
|         this.closeButton = button; | ||||
| @@ -544,12 +544,10 @@ var WindowOverlay = new Lang.Class({ | ||||
|         let titleX = cloneX + (cloneWidth - title.width) / 2; | ||||
|         let titleY = cloneY + cloneHeight - (title.height - this.borderSize) / 2; | ||||
|  | ||||
|         if (animate) { | ||||
|             this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY), title.width); | ||||
|         } else { | ||||
|             title.width = title.width; | ||||
|         if (animate) | ||||
|             this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY)); | ||||
|         else | ||||
|             title.set_position(Math.floor(titleX), Math.floor(titleY)); | ||||
|         } | ||||
|  | ||||
|         let borderX = cloneX - this.borderSize; | ||||
|         let borderY = cloneY - this.borderSize; | ||||
| @@ -568,10 +566,12 @@ var WindowOverlay = new Lang.Class({ | ||||
|     _animateOverlayActor(actor, x, y, width, height) { | ||||
|         let params = { x: x, | ||||
|                        y: y, | ||||
|                        width: width, | ||||
|                        time: Overview.ANIMATION_TIME, | ||||
|                        transition: 'easeOutQuad' }; | ||||
|  | ||||
|         if (width !== undefined) | ||||
|             params.width = width; | ||||
|  | ||||
|         if (height !== undefined) | ||||
|             params.height = height; | ||||
|  | ||||
| @@ -1431,34 +1431,26 @@ var Workspace = new Lang.Class({ | ||||
|     _doRemoveWindow(metaWin) { | ||||
|         let win = metaWin.get_compositor_private(); | ||||
|  | ||||
|         // find the position of the window in our list | ||||
|         let index = this._lookupIndex (metaWin); | ||||
|         let clone = this._removeWindowClone(metaWin); | ||||
|  | ||||
|         if (index == -1) | ||||
|             return; | ||||
|  | ||||
|         let clone = this._windows[index]; | ||||
|  | ||||
|         this._windows.splice(index, 1); | ||||
|         this._windowOverlays.splice(index, 1); | ||||
|  | ||||
|         // If metaWin.get_compositor_private() returned non-NULL, that | ||||
|         // means the window still exists (and is just being moved to | ||||
|         // another workspace or something), so set its overviewHint | ||||
|         // accordingly. (If it returned NULL, then the window is being | ||||
|         // destroyed; we'd like to animate this, but it's too late at | ||||
|         // this point.) | ||||
|         if (win) { | ||||
|             let [stageX, stageY] = clone.actor.get_transformed_position(); | ||||
|             let [stageWidth, stageHeight] = clone.actor.get_transformed_size(); | ||||
|             win._overviewHint = { | ||||
|                 x: stageX, | ||||
|                 y: stageY, | ||||
|                 scale: stageWidth / clone.actor.width | ||||
|             }; | ||||
|         if (clone) { | ||||
|             // If metaWin.get_compositor_private() returned non-NULL, that | ||||
|             // means the window still exists (and is just being moved to | ||||
|             // another workspace or something), so set its overviewHint | ||||
|             // accordingly. (If it returned NULL, then the window is being | ||||
|             // destroyed; we'd like to animate this, but it's too late at | ||||
|             // this point.) | ||||
|             if (win) { | ||||
|                 let [stageX, stageY] = clone.actor.get_transformed_position(); | ||||
|                 let [stageWidth, stageHeight] = clone.actor.get_transformed_size(); | ||||
|                 win._overviewHint = { | ||||
|                     x: stageX, | ||||
|                     y: stageY, | ||||
|                     scale: stageWidth / clone.actor.width | ||||
|                 }; | ||||
|             } | ||||
|             clone.destroy(); | ||||
|         } | ||||
|         clone.destroy(); | ||||
|  | ||||
|  | ||||
|         // We need to reposition the windows; to avoid shuffling windows | ||||
|         // around while the user is interacting with the workspace, we delay | ||||
| @@ -1514,7 +1506,7 @@ var Workspace = new Lang.Class({ | ||||
|             if (metaWin.is_attached_dialog()) { | ||||
|                 let parent = metaWin.get_transient_for(); | ||||
|                 while (parent.is_attached_dialog()) | ||||
|                     parent = metaWin.get_transient_for(); | ||||
|                     parent = parent.get_transient_for(); | ||||
|  | ||||
|                 let idx = this._lookupIndex (parent); | ||||
|                 if (idx < 0) { | ||||
| @@ -1848,6 +1840,9 @@ var Workspace = new Lang.Class({ | ||||
|         clone.connect('size-changed', () => { | ||||
|             this._recalculateWindowPositions(WindowPositionFlags.NONE); | ||||
|         }); | ||||
|         clone.actor.connect('destroy', () => { | ||||
|             this._removeWindowClone(clone.metaWindow); | ||||
|         }); | ||||
|  | ||||
|         this.actor.add_actor(clone.actor); | ||||
|  | ||||
| @@ -1869,6 +1864,17 @@ var Workspace = new Lang.Class({ | ||||
|         return [clone, overlay]; | ||||
|     }, | ||||
|  | ||||
|     _removeWindowClone(metaWin) { | ||||
|         // find the position of the window in our list | ||||
|         let index = this._lookupIndex (metaWin); | ||||
|  | ||||
|         if (index == -1) | ||||
|             return null; | ||||
|  | ||||
|         this._windowOverlays.splice(index, 1); | ||||
|         return this._windows.splice(index, 1).pop(); | ||||
|     }, | ||||
|  | ||||
|     _onShowOverlayClose(windowOverlay) { | ||||
|         for (let i = 0; i < this._windowOverlays.length; i++) { | ||||
|             let overlay = this._windowOverlays[i]; | ||||
|   | ||||
| @@ -31,7 +31,7 @@ var WORKSPACE_CUT_SIZE = 10; | ||||
|  | ||||
| var WORKSPACE_KEEP_ALIVE_TIME = 100; | ||||
|  | ||||
| const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides'; | ||||
| var OVERRIDE_SCHEMA = 'org.gnome.shell.overrides'; | ||||
|  | ||||
| /* A layout manager that requests size only for primary_actor, but then allocates | ||||
|    all using a fixed layout */ | ||||
| @@ -68,7 +68,7 @@ var WindowClone = new Lang.Class({ | ||||
|         this.realWindow = realWindow; | ||||
|         this.metaWindow = realWindow.meta_window; | ||||
|  | ||||
|         this.clone._updateId = this.metaWindow.connect('position-changed', | ||||
|         this.clone._updateId = this.realWindow.connect('notify::position', | ||||
|                                                        this._onPositionChanged.bind(this)); | ||||
|         this.clone._destroyId = this.realWindow.connect('destroy', () => { | ||||
|             // First destroy the clone and then destroy everything | ||||
| @@ -153,7 +153,7 @@ var WindowClone = new Lang.Class({ | ||||
|         let clone = new Clutter.Clone({ source: realDialog }); | ||||
|         this._updateDialogPosition(realDialog, clone); | ||||
|  | ||||
|         clone._updateId = metaDialog.connect('position-changed', dialog => { | ||||
|         clone._updateId = realDialog.connect('notify::position', dialog => { | ||||
|             this._updateDialogPosition(dialog, clone); | ||||
|         }); | ||||
|         clone._destroyId = realDialog.connect('destroy', () => { | ||||
| @@ -171,7 +171,6 @@ var WindowClone = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     _onPositionChanged() { | ||||
|         let rect = this.metaWindow.get_frame_rect(); | ||||
|         this.actor.set_position(this.realWindow.x, this.realWindow.y); | ||||
|     }, | ||||
|  | ||||
| @@ -179,7 +178,7 @@ var WindowClone = new Lang.Class({ | ||||
|         this.actor.get_children().forEach(child => { | ||||
|             let realWindow = child.source; | ||||
|  | ||||
|             realWindow.meta_window.disconnect(child._updateId); | ||||
|             realWindow.disconnect(child._updateId); | ||||
|             realWindow.disconnect(child._destroyId); | ||||
|         }); | ||||
|     }, | ||||
| @@ -241,7 +240,7 @@ var WindowClone = new Lang.Class({ | ||||
| Signals.addSignalMethods(WindowClone.prototype); | ||||
|  | ||||
|  | ||||
| const ThumbnailState = { | ||||
| var ThumbnailState = { | ||||
|     NEW   :         0, | ||||
|     ANIMATING_IN :  1, | ||||
|     NORMAL:         2, | ||||
| @@ -275,8 +274,8 @@ var WorkspaceThumbnail = new Lang.Class({ | ||||
|  | ||||
|         this._createBackground(); | ||||
|  | ||||
|         let monitor = Main.layoutManager.primaryMonitor; | ||||
|         this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height); | ||||
|         let workArea = Main.layoutManager.getWorkAreaForMonitor(this.monitorIndex); | ||||
|         this.setPorthole(workArea.x, workArea.y, workArea.width, workArea.height); | ||||
|  | ||||
|         let windows = global.get_window_actors().filter(actor => { | ||||
|             let win = actor.meta_window; | ||||
| @@ -321,8 +320,6 @@ var WorkspaceThumbnail = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     setPorthole(x, y, width, height) { | ||||
|         this._portholeX = x; | ||||
|         this._portholeY = y; | ||||
|         this.actor.set_size(width, height); | ||||
|         this._contents.set_position(-x, -y); | ||||
|     }, | ||||
| @@ -374,18 +371,9 @@ var WorkspaceThumbnail = new Lang.Class({ | ||||
|     }, | ||||
|  | ||||
|     _doRemoveWindow(metaWin) { | ||||
|         let win = metaWin.get_compositor_private(); | ||||
|  | ||||
|         // find the position of the window in our list | ||||
|         let index = this._lookupIndex (metaWin); | ||||
|  | ||||
|         if (index == -1) | ||||
|             return; | ||||
|  | ||||
|         let clone = this._windows[index]; | ||||
|         this._windows.splice(index, 1); | ||||
|  | ||||
|         clone.destroy(); | ||||
|         let clone = this._removeWindowClone(metaWin); | ||||
|         if (clone) | ||||
|             clone.destroy(); | ||||
|     }, | ||||
|  | ||||
|     _doAddWindow(metaWin) { | ||||
| @@ -428,7 +416,7 @@ var WorkspaceThumbnail = new Lang.Class({ | ||||
|         } else if (metaWin.is_attached_dialog()) { | ||||
|             let parent = metaWin.get_transient_for(); | ||||
|             while (parent.is_attached_dialog()) | ||||
|                 parent = metaWin.get_transient_for(); | ||||
|                 parent = parent.get_transient_for(); | ||||
|  | ||||
|             let idx = this._lookupIndex (parent); | ||||
|             if (idx < 0) { | ||||
| @@ -537,6 +525,9 @@ var WorkspaceThumbnail = new Lang.Class({ | ||||
|         clone.connect('drag-end', () => { | ||||
|             Main.overview.endWindowDrag(clone.metaWindow); | ||||
|         }); | ||||
|         clone.actor.connect('destroy', () => { | ||||
|             this._removeWindowClone(clone.metaWindow); | ||||
|         }); | ||||
|         this._contents.add_actor(clone.actor); | ||||
|  | ||||
|         if (this._windows.length == 0) | ||||
| @@ -549,6 +540,16 @@ var WorkspaceThumbnail = new Lang.Class({ | ||||
|         return clone; | ||||
|     }, | ||||
|  | ||||
|     _removeWindowClone(metaWin) { | ||||
|         // find the position of the window in our list | ||||
|         let index = this._lookupIndex (metaWin); | ||||
|  | ||||
|         if (index == -1) | ||||
|             return null; | ||||
|  | ||||
|         return this._windows.splice(index, 1).pop(); | ||||
|     }, | ||||
|  | ||||
|     activate(time) { | ||||
|         if (this.state > ThumbnailState.NORMAL) | ||||
|             return; | ||||
| @@ -1159,7 +1160,7 @@ var ThumbnailsBox = new Lang.Class({ | ||||
|     // The "porthole" is the portion of the screen that we show in the | ||||
|     // workspaces | ||||
|     _ensurePorthole() { | ||||
|         if (!Main.layoutManager.primaryMonitor) | ||||
|         if (!Main.layoutManager.primaryMonitor || !Main.overview.visible) | ||||
|             return false; | ||||
|  | ||||
|         if (!this._porthole) | ||||
|   | ||||
| @@ -470,6 +470,7 @@ var WorkspacesDisplay = new Lang.Class({ | ||||
|         this._switchWorkspaceNotifyId = 0; | ||||
|  | ||||
|         this._notifyOpacityId = 0; | ||||
|         this._restackedNotifyId = 0; | ||||
|         this._scrollEventId = 0; | ||||
|         this._keyPressEventId = 0; | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| project('gnome-shell', 'c', | ||||
|   version: '3.28.1', | ||||
|   version: '3.28.3', | ||||
|   meson_version: '>= 0.42.0', | ||||
|   license: 'GPLv2+' | ||||
| ) | ||||
|   | ||||
							
								
								
									
										2
									
								
								po/cs.po
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								po/cs.po
									
									
									
									
									
								
							| @@ -1064,7 +1064,7 @@ msgstr "Načítá se…" | ||||
| #: js/ui/dateMenu.js:321 | ||||
| #, javascript-format | ||||
| msgid "Feels like %s." | ||||
| msgstr "Pocitově jako %s." | ||||
| msgstr "Pocitová teplota %s." | ||||
|  | ||||
| #: js/ui/dateMenu.js:324 | ||||
| msgid "Go online for weather information" | ||||
|   | ||||
							
								
								
									
										46
									
								
								po/pt_BR.po
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								po/pt_BR.po
									
									
									
									
									
								
							| @@ -15,22 +15,22 @@ | ||||
| # Georges Basile Stavracas Neto <georges.stavracas@gmail.com>, 2014. | ||||
| # Felipe Braga <fbobraga@gmail.com>, 2015. | ||||
| # Artur de Aquino Morais <artur.morais93@outlook.com>, 2016. | ||||
| # Rafael Fontenelle <rafaelff@gnome.org>, 2013-2017. | ||||
| # Rafael Fontenelle <rafaelff@gnome.org>, 2013-2018. | ||||
| # Enrico Nicoletto <liverig@gmail.com>, 2013-2018. | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: gnome-shell\n" | ||||
| "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n" | ||||
| "POT-Creation-Date: 2018-03-16 21:34+0000\n" | ||||
| "PO-Revision-Date: 2018-02-09 21:52-0200\n" | ||||
| "Last-Translator: Enrico Nicoletto <liverig@gmail.com>\n" | ||||
| "POT-Creation-Date: 2018-04-13 18:31+0000\n" | ||||
| "PO-Revision-Date: 2018-05-02 15:45-0200\n" | ||||
| "Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n" | ||||
| "Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n" | ||||
| "Language: pt_BR\n" | ||||
| "MIME-Version: 1.0\n" | ||||
| "Content-Type: text/plain; charset=UTF-8\n" | ||||
| "Content-Transfer-Encoding: 8bit\n" | ||||
| "Plural-Forms: nplurals=2; plural=(n > 1);\n" | ||||
| "X-Generator: Poedit 2.0.6\n" | ||||
| "X-Generator: Virtaal 1.0.0-beta1\n" | ||||
| "X-Project-Style: gnome\n" | ||||
|  | ||||
| #: data/50-gnome-shell-system.xml:6 | ||||
| @@ -356,7 +356,7 @@ msgid "There was an error loading the preferences dialog for %s:" | ||||
| msgstr "Ocorreu um erro ao carregar o dialogo de preferências para %s:" | ||||
|  | ||||
| #: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71 | ||||
| #: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:148 | ||||
| #: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:153 | ||||
| #: js/ui/endSessionDialog.js:482 js/ui/extensionDownloader.js:197 | ||||
| #: js/ui/shellMountOperation.js:343 js/ui/status/network.js:919 | ||||
| msgid "Cancel" | ||||
| @@ -642,7 +642,7 @@ msgstr "Negar acesso" | ||||
|  | ||||
| #: js/ui/accessDialog.js:64 js/ui/status/location.js:396 | ||||
| msgid "Grant Access" | ||||
| msgstr "Garantir acesso" | ||||
| msgstr "Conceder acesso" | ||||
|  | ||||
| #: js/ui/appDisplay.js:793 | ||||
| msgid "Frequently used applications will appear here" | ||||
| @@ -676,12 +676,12 @@ msgstr "Adicionar aos favoritos" | ||||
| msgid "Show Details" | ||||
| msgstr "Mostrar detalhes" | ||||
|  | ||||
| #: js/ui/appFavorites.js:138 | ||||
| #: js/ui/appFavorites.js:140 | ||||
| #, javascript-format | ||||
| msgid "%s has been added to your favorites." | ||||
| msgstr "%s foi adicionado aos seus favoritos." | ||||
|  | ||||
| #: js/ui/appFavorites.js:172 | ||||
| #: js/ui/appFavorites.js:174 | ||||
| #, javascript-format | ||||
| msgid "%s has been removed from your favorites." | ||||
| msgstr "%s foi removido dos seus favoritos." | ||||
| @@ -876,7 +876,7 @@ msgstr "Unidade externa desconectada" | ||||
| msgid "Open with %s" | ||||
| msgstr "Abrir com %s" | ||||
|  | ||||
| #: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:284 | ||||
| #: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:295 | ||||
| msgid "Password:" | ||||
| msgstr "Senha:" | ||||
|  | ||||
| @@ -964,15 +964,15 @@ msgstr "Uma senha é necessária para se conectar a “%s”." | ||||
| msgid "Network Manager" | ||||
| msgstr "Gerenciador de rede" | ||||
|  | ||||
| #: js/ui/components/polkitAgent.js:43 | ||||
| #: js/ui/components/polkitAgent.js:48 | ||||
| msgid "Authentication Required" | ||||
| msgstr "Autenticação necessária" | ||||
|  | ||||
| #: js/ui/components/polkitAgent.js:71 | ||||
| #: js/ui/components/polkitAgent.js:76 | ||||
| msgid "Administrator" | ||||
| msgstr "Administrador" | ||||
|  | ||||
| #: js/ui/components/polkitAgent.js:151 | ||||
| #: js/ui/components/polkitAgent.js:156 | ||||
| msgid "Authenticate" | ||||
| msgstr "Autenticação" | ||||
|  | ||||
| @@ -980,7 +980,7 @@ msgstr "Autenticação" | ||||
| #. * requested authentication was not gained; this can happen | ||||
| #. * because of an authentication error (like invalid password), | ||||
| #. * for instance. | ||||
| #: js/ui/components/polkitAgent.js:270 js/ui/shellMountOperation.js:327 | ||||
| #: js/ui/components/polkitAgent.js:281 js/ui/shellMountOperation.js:327 | ||||
| msgid "Sorry, that didn’t work. Please try again." | ||||
| msgstr "Desculpe, isto não funcionou. Por favor, tente novamente." | ||||
|  | ||||
| @@ -1028,7 +1028,7 @@ msgstr "Adicionar relógios mundiais…" | ||||
| msgid "World Clocks" | ||||
| msgstr "Relógios mundiais" | ||||
|  | ||||
| #: js/ui/dateMenu.js:225 | ||||
| #: js/ui/dateMenu.js:227 | ||||
| msgid "Weather" | ||||
| msgstr "Meteorologia" | ||||
|  | ||||
| @@ -1036,7 +1036,7 @@ msgstr "Meteorologia" | ||||
| #. libgweather for the possible condition strings. If at all | ||||
| #. possible, the sentence should match the grammatical case etc. of | ||||
| #. the inserted conditions. | ||||
| #: js/ui/dateMenu.js:289 | ||||
| #: js/ui/dateMenu.js:291 | ||||
| #, javascript-format | ||||
| msgid "%s all day." | ||||
| msgstr "%s por todo o dia." | ||||
| @@ -1045,7 +1045,7 @@ msgstr "%s por todo o dia." | ||||
| #. libgweather for the possible condition strings. If at all | ||||
| #. possible, the sentence should match the grammatical case etc. of | ||||
| #. the inserted conditions. | ||||
| #: js/ui/dateMenu.js:295 | ||||
| #: js/ui/dateMenu.js:297 | ||||
| #, javascript-format | ||||
| msgid "%s, then %s later." | ||||
| msgstr "%s, depois %s mais tarde." | ||||
| @@ -1054,30 +1054,30 @@ msgstr "%s, depois %s mais tarde." | ||||
| #. libgweather for the possible condition strings. If at all | ||||
| #. possible, the sentence should match the grammatical case etc. of | ||||
| #. the inserted conditions. | ||||
| #: js/ui/dateMenu.js:301 | ||||
| #: js/ui/dateMenu.js:303 | ||||
| #, javascript-format | ||||
| msgid "%s, then %s, followed by %s later." | ||||
| msgstr "%s, depois %s, seguido de %s mais tarde." | ||||
|  | ||||
| #: js/ui/dateMenu.js:312 | ||||
| #: js/ui/dateMenu.js:314 | ||||
| msgid "Select a location…" | ||||
| msgstr "Selecione uma localização…" | ||||
|  | ||||
| #: js/ui/dateMenu.js:315 | ||||
| #: js/ui/dateMenu.js:317 | ||||
| msgid "Loading…" | ||||
| msgstr "Carregando…" | ||||
|  | ||||
| #. Translators: %s is a temperature with unit, e.g. "23℃" | ||||
| #: js/ui/dateMenu.js:321 | ||||
| #: js/ui/dateMenu.js:323 | ||||
| #, javascript-format | ||||
| msgid "Feels like %s." | ||||
| msgstr "Sensação térmica de %s." | ||||
|  | ||||
| #: js/ui/dateMenu.js:324 | ||||
| #: js/ui/dateMenu.js:326 | ||||
| msgid "Go online for weather information" | ||||
| msgstr "Conecte-se à internet para obter as informações meteorológicas" | ||||
|  | ||||
| #: js/ui/dateMenu.js:326 | ||||
| #: js/ui/dateMenu.js:328 | ||||
| msgid "Weather information is currently unavailable" | ||||
| msgstr "No momento as informações meteorológicas não estão disponíveis" | ||||
|  | ||||
|   | ||||
							
								
								
									
										40
									
								
								po/ru.po
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								po/ru.po
									
									
									
									
									
								
							| @@ -18,8 +18,8 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: gnome-shell\n" | ||||
| "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n" | ||||
| "POT-Creation-Date: 2018-04-12 11:47+0000\n" | ||||
| "PO-Revision-Date: 2018-04-12 16:48+0300\n" | ||||
| "POT-Creation-Date: 2018-04-13 18:31+0000\n" | ||||
| "PO-Revision-Date: 2018-04-19 23:31+0300\n" | ||||
| "Last-Translator: Stas Solovey <whats_up@tut.by>\n" | ||||
| "Language-Team: Русский <gnome-cyr@gnome.org>\n" | ||||
| "Language: ru\n" | ||||
| @@ -344,7 +344,7 @@ msgid "There was an error loading the preferences dialog for %s:" | ||||
| msgstr "Возникла ошибка загрузки диалогового окна параметров для %s:" | ||||
|  | ||||
| #: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71 | ||||
| #: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:149 | ||||
| #: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:153 | ||||
| #: js/ui/endSessionDialog.js:482 js/ui/extensionDownloader.js:197 | ||||
| #: js/ui/shellMountOperation.js:343 js/ui/status/network.js:919 | ||||
| msgid "Cancel" | ||||
| @@ -563,7 +563,6 @@ msgstr "Вчера, %H∶%M" | ||||
| msgid "%A, %H∶%M" | ||||
| msgstr "%A, %H∶%M" | ||||
|  | ||||
| # fix даты "11 мар., 20:35" | ||||
| #. Translators: this is the month name and day number | ||||
| #. followed by a time string in 24h format. | ||||
| #. i.e. "May 25, 14:30" | ||||
| @@ -572,7 +571,6 @@ msgstr "%A, %H∶%M" | ||||
| msgid "%B %d, %H∶%M" | ||||
| msgstr "%-d %B, %H∶%M" | ||||
|  | ||||
| # fix даты | ||||
| #. Translators: this is the month name, day number, year | ||||
| #. number followed by a time string in 24h format. | ||||
| #. i.e. "May 25 2012, 14:30" | ||||
| @@ -581,7 +579,6 @@ msgstr "%-d %B, %H∶%M" | ||||
| msgid "%B %d %Y, %H∶%M" | ||||
| msgstr "%-d %B %Y, %H∶%M" | ||||
|  | ||||
| # по всей видимости разрабы коммент перепутали c "Translators: Time in 12h format" | ||||
| #. Translators: Time in 12h format | ||||
| #: js/misc/util.js:257 | ||||
| msgid "%l∶%M %p" | ||||
| @@ -823,7 +820,6 @@ msgctxt "calendar heading" | ||||
| msgid "%A, %B %d" | ||||
| msgstr "%A, %-d %B" | ||||
|  | ||||
| # fix для даты в календаре и на экране блокировки | ||||
| #: js/ui/calendar.js:868 | ||||
| msgctxt "calendar heading" | ||||
| msgid "%A, %B %d, %Y" | ||||
| @@ -876,7 +872,7 @@ msgstr "Внешний диск отключён" | ||||
| msgid "Open with %s" | ||||
| msgstr "Открыть с помощью %s" | ||||
|  | ||||
| #: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:285 | ||||
| #: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:295 | ||||
| msgid "Password:" | ||||
| msgstr "Пароль:" | ||||
|  | ||||
| @@ -963,15 +959,15 @@ msgstr "Для подключения к «%s» требуется пароль. | ||||
| msgid "Network Manager" | ||||
| msgstr "Диспетчер сети" | ||||
|  | ||||
| #: js/ui/components/polkitAgent.js:44 | ||||
| #: js/ui/components/polkitAgent.js:48 | ||||
| msgid "Authentication Required" | ||||
| msgstr "Требуется подтверждение подлинности" | ||||
|  | ||||
| #: js/ui/components/polkitAgent.js:72 | ||||
| #: js/ui/components/polkitAgent.js:76 | ||||
| msgid "Administrator" | ||||
| msgstr "Администратор" | ||||
|  | ||||
| #: js/ui/components/polkitAgent.js:152 | ||||
| #: js/ui/components/polkitAgent.js:156 | ||||
| msgid "Authenticate" | ||||
| msgstr "Подтвердить" | ||||
|  | ||||
| @@ -979,7 +975,7 @@ msgstr "Подтвердить" | ||||
| #. * requested authentication was not gained; this can happen | ||||
| #. * because of an authentication error (like invalid password), | ||||
| #. * for instance. | ||||
| #: js/ui/components/polkitAgent.js:271 js/ui/shellMountOperation.js:327 | ||||
| #: js/ui/components/polkitAgent.js:281 js/ui/shellMountOperation.js:327 | ||||
| msgid "Sorry, that didn’t work. Please try again." | ||||
| msgstr "Не удалось подтвердить подлинность. Попробуйте снова." | ||||
|  | ||||
| @@ -1004,7 +1000,6 @@ msgstr "Показать приложения" | ||||
| msgid "Dash" | ||||
| msgstr "Панель приложений" | ||||
|  | ||||
| # fix для даты в календаре и на экране блокировки | ||||
| #. Translators: This is the date format to use when the calendar popup is | ||||
| #. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM"). | ||||
| #. | ||||
| @@ -1012,7 +1007,6 @@ msgstr "Панель приложений" | ||||
| msgid "%B %e %Y" | ||||
| msgstr "%-d %B %Y" | ||||
|  | ||||
| # fix для даты в календаре и на экране блокировки | ||||
| #. Translators: This is the accessible name of the date button shown | ||||
| #. * below the time in the shell; it should combine the weekday and the | ||||
| #. * date, e.g. "Tuesday February 17 2015". | ||||
| @@ -1029,7 +1023,7 @@ msgstr "Добавить мировые часы…" | ||||
| msgid "World Clocks" | ||||
| msgstr "Мировые часы" | ||||
|  | ||||
| #: js/ui/dateMenu.js:225 | ||||
| #: js/ui/dateMenu.js:227 | ||||
| msgid "Weather" | ||||
| msgstr "Погода" | ||||
|  | ||||
| @@ -1037,7 +1031,7 @@ msgstr "Погода" | ||||
| #. libgweather for the possible condition strings. If at all | ||||
| #. possible, the sentence should match the grammatical case etc. of | ||||
| #. the inserted conditions. | ||||
| #: js/ui/dateMenu.js:289 | ||||
| #: js/ui/dateMenu.js:291 | ||||
| #, javascript-format | ||||
| msgid "%s all day." | ||||
| msgstr "%s весь день." | ||||
| @@ -1046,7 +1040,7 @@ msgstr "%s весь день." | ||||
| #. libgweather for the possible condition strings. If at all | ||||
| #. possible, the sentence should match the grammatical case etc. of | ||||
| #. the inserted conditions. | ||||
| #: js/ui/dateMenu.js:295 | ||||
| #: js/ui/dateMenu.js:297 | ||||
| #, javascript-format | ||||
| msgid "%s, then %s later." | ||||
| msgstr "%s, затем позднее %s." | ||||
| @@ -1055,30 +1049,30 @@ msgstr "%s, затем позднее %s." | ||||
| #. libgweather for the possible condition strings. If at all | ||||
| #. possible, the sentence should match the grammatical case etc. of | ||||
| #. the inserted conditions. | ||||
| #: js/ui/dateMenu.js:301 | ||||
| #: js/ui/dateMenu.js:303 | ||||
| #, javascript-format | ||||
| msgid "%s, then %s, followed by %s later." | ||||
| msgstr "%s, затем %s, позже %s." | ||||
|  | ||||
| #: js/ui/dateMenu.js:312 | ||||
| #: js/ui/dateMenu.js:314 | ||||
| msgid "Select a location…" | ||||
| msgstr "Выберите местоположение…" | ||||
|  | ||||
| #: js/ui/dateMenu.js:315 | ||||
| #: js/ui/dateMenu.js:317 | ||||
| msgid "Loading…" | ||||
| msgstr "Загрузка…" | ||||
|  | ||||
| #. Translators: %s is a temperature with unit, e.g. "23℃" | ||||
| #: js/ui/dateMenu.js:321 | ||||
| #: js/ui/dateMenu.js:323 | ||||
| #, javascript-format | ||||
| msgid "Feels like %s." | ||||
| msgstr "Ощущается как %s." | ||||
|  | ||||
| #: js/ui/dateMenu.js:324 | ||||
| #: js/ui/dateMenu.js:326 | ||||
| msgid "Go online for weather information" | ||||
| msgstr "Подключите интернет для получения информации о погоде" | ||||
|  | ||||
| #: js/ui/dateMenu.js:326 | ||||
| #: js/ui/dateMenu.js:328 | ||||
| msgid "Weather information is currently unavailable" | ||||
| msgstr "Информация о погоде сейчас недоступна" | ||||
|  | ||||
|   | ||||
| @@ -142,7 +142,7 @@ libst_gir = gnome.generate_gir(libst, | ||||
|   sources: st_gir_sources, | ||||
|   nsversion: '1.0', | ||||
|   namespace: 'St', | ||||
|   includes: ['Clutter-' + mutter_api_version, 'Gtk-3.0'], | ||||
|   includes: ['Clutter-' + mutter_api_version, 'Cally-' + mutter_api_version, 'Gtk-3.0'], | ||||
|   dependencies: [mutter_dep], | ||||
|   include_directories: include_directories('..'), | ||||
|   extra_args: ['-DST_COMPILATION', '--quiet'], | ||||
|   | ||||
| @@ -177,15 +177,15 @@ st_bin_get_preferred_height (ClutterActor *self, | ||||
| } | ||||
|  | ||||
| static void | ||||
| st_bin_dispose (GObject *gobject) | ||||
| st_bin_destroy (ClutterActor *actor) | ||||
| { | ||||
|   StBinPrivate *priv = st_bin_get_instance_private (ST_BIN (gobject)); | ||||
|   StBinPrivate *priv = st_bin_get_instance_private (ST_BIN (actor)); | ||||
|  | ||||
|   if (priv->child) | ||||
|     clutter_actor_destroy (priv->child); | ||||
|   g_assert (priv->child == NULL); | ||||
|  | ||||
|   G_OBJECT_CLASS (st_bin_parent_class)->dispose (gobject); | ||||
|   CLUTTER_ACTOR_CLASS (st_bin_parent_class)->destroy (actor); | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -315,11 +315,11 @@ st_bin_class_init (StBinClass *klass) | ||||
|  | ||||
|   gobject_class->set_property = st_bin_set_property; | ||||
|   gobject_class->get_property = st_bin_get_property; | ||||
|   gobject_class->dispose = st_bin_dispose; | ||||
|  | ||||
|   actor_class->get_preferred_width = st_bin_get_preferred_width; | ||||
|   actor_class->get_preferred_height = st_bin_get_preferred_height; | ||||
|   actor_class->allocate = st_bin_allocate; | ||||
|   actor_class->destroy = st_bin_destroy; | ||||
|  | ||||
|   widget_class->popup_menu = st_bin_popup_menu; | ||||
|   widget_class->navigate_focus = st_bin_navigate_focus; | ||||
|   | ||||
| @@ -90,7 +90,7 @@ adjustment_value_notify_cb (StAdjustment *adjustment, | ||||
|                             GParamSpec   *pspec, | ||||
|                             StBoxLayout  *box) | ||||
| { | ||||
|   clutter_actor_queue_redraw (CLUTTER_ACTOR (box)); | ||||
|   clutter_actor_queue_relayout (CLUTTER_ACTOR (box)); | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -490,7 +490,7 @@ st_box_layout_get_paint_volume (ClutterActor       *actor, | ||||
|                                 ClutterPaintVolume *volume) | ||||
| { | ||||
|   StBoxLayout *self = ST_BOX_LAYOUT (actor); | ||||
|   gdouble x, y; | ||||
|   gdouble x, y, lower, upper; | ||||
|   StBoxLayoutPrivate *priv = self->priv; | ||||
|   StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); | ||||
|   ClutterActorBox allocation_box; | ||||
| @@ -505,13 +505,42 @@ st_box_layout_get_paint_volume (ClutterActor       *actor, | ||||
|    * our paint volume on that. */ | ||||
|   if (priv->hadjustment || priv->vadjustment) | ||||
|     { | ||||
|       gdouble width, height; | ||||
|  | ||||
|       clutter_actor_get_allocation_box (actor, &allocation_box); | ||||
|       st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); | ||||
|       origin.x = content_box.x1 - allocation_box.x1; | ||||
|       origin.y = content_box.y1 - allocation_box.y2; | ||||
|       origin.z = 0.f; | ||||
|       clutter_paint_volume_set_width (volume, content_box.x2 - content_box.x1); | ||||
|       clutter_paint_volume_set_height (volume, content_box.y2 - content_box.y1); | ||||
|  | ||||
|       if (priv->hadjustment) | ||||
|         { | ||||
|           g_object_get (priv->hadjustment, | ||||
|                         "lower", &lower, | ||||
|                         "upper", &upper, | ||||
|                         NULL); | ||||
|           width = upper - lower; | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           width = content_box.x2 - content_box.x1; | ||||
|         } | ||||
|  | ||||
|       if (priv->vadjustment) | ||||
|         { | ||||
|           g_object_get (priv->vadjustment, | ||||
|                         "lower", &lower, | ||||
|                         "upper", &upper, | ||||
|                         NULL); | ||||
|           height = upper - lower; | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           height = content_box.y2 - content_box.y1; | ||||
|         } | ||||
|  | ||||
|       clutter_paint_volume_set_width (volume, width); | ||||
|       clutter_paint_volume_set_height (volume, height); | ||||
|     } | ||||
|   else if (!CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->get_paint_volume (actor, volume)) | ||||
|     return FALSE; | ||||
|   | ||||
| @@ -248,14 +248,17 @@ st_button_touch_event (ClutterActor      *actor, | ||||
|   if (event->type == CLUTTER_TOUCH_BEGIN && !priv->press_sequence) | ||||
|     { | ||||
|       clutter_input_device_sequence_grab (device, sequence, actor); | ||||
|       st_button_press (button, device, 0, sequence); | ||||
|       if (!clutter_event_is_pointer_emulated ((ClutterEvent*) event)) | ||||
|         st_button_press (button, device, 0, sequence); | ||||
|       return CLUTTER_EVENT_STOP; | ||||
|     } | ||||
|   else if (event->type == CLUTTER_TOUCH_END && | ||||
|            priv->device == device && | ||||
|            priv->press_sequence == sequence) | ||||
|     { | ||||
|       st_button_release (button, device, mask, 0, sequence); | ||||
|       if (!clutter_event_is_pointer_emulated ((ClutterEvent*) event)) | ||||
|         st_button_release (button, device, mask, 0, sequence); | ||||
|  | ||||
|       clutter_input_device_sequence_ungrab (device, sequence); | ||||
|       return CLUTTER_EVENT_STOP; | ||||
|     } | ||||
|   | ||||
| @@ -906,6 +906,13 @@ st_entry_unmap (ClutterActor *actor) | ||||
|   CLUTTER_ACTOR_CLASS (st_entry_parent_class)->unmap (actor); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| st_entry_get_paint_volume (ClutterActor       *actor, | ||||
|                            ClutterPaintVolume *volume) | ||||
| { | ||||
|   return clutter_paint_volume_set_from_allocation (volume, actor); | ||||
| } | ||||
|  | ||||
| static void | ||||
| st_entry_class_init (StEntryClass *klass) | ||||
| { | ||||
| @@ -923,6 +930,7 @@ st_entry_class_init (StEntryClass *klass) | ||||
|   actor_class->allocate = st_entry_allocate; | ||||
|   actor_class->paint = st_entry_paint; | ||||
|   actor_class->unmap = st_entry_unmap; | ||||
|   actor_class->get_paint_volume = st_entry_get_paint_volume; | ||||
|  | ||||
|   actor_class->key_press_event = st_entry_key_press_event; | ||||
|   actor_class->key_focus_in = st_entry_key_focus_in; | ||||
| @@ -1287,10 +1295,10 @@ st_entry_get_input_hints (StEntry *entry) | ||||
|   return clutter_text_get_input_hints (CLUTTER_TEXT (priv->entry)); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| _st_entry_icon_press_cb (ClutterActor       *actor, | ||||
|                          ClutterButtonEvent *event, | ||||
|                          StEntry            *entry) | ||||
| static void | ||||
| _st_entry_icon_clicked_cb (ClutterClickAction *action, | ||||
|                            ClutterActor       *actor, | ||||
|                            StEntry            *entry) | ||||
| { | ||||
|   StEntryPrivate *priv = ST_ENTRY_PRIV (entry); | ||||
|  | ||||
| @@ -1298,8 +1306,6 @@ _st_entry_icon_press_cb (ClutterActor       *actor, | ||||
|     g_signal_emit (entry, entry_signals[PRIMARY_ICON_CLICKED], 0); | ||||
|   else | ||||
|     g_signal_emit (entry, entry_signals[SECONDARY_ICON_CLICKED], 0); | ||||
|  | ||||
|   return FALSE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -1309,21 +1315,24 @@ _st_entry_set_icon (StEntry       *entry, | ||||
| { | ||||
|   if (*icon) | ||||
|     { | ||||
|       g_signal_handlers_disconnect_by_func (*icon, | ||||
|                                             _st_entry_icon_press_cb, | ||||
|                                             entry); | ||||
|       clutter_actor_remove_action_by_name (*icon, "entry-icon-action"); | ||||
|       clutter_actor_remove_child (CLUTTER_ACTOR (entry), *icon); | ||||
|       *icon = NULL; | ||||
|     } | ||||
|  | ||||
|   if (new_icon) | ||||
|     { | ||||
|       ClutterAction *action; | ||||
|  | ||||
|       *icon = g_object_ref (new_icon); | ||||
|  | ||||
|       clutter_actor_set_reactive (*icon, TRUE); | ||||
|       clutter_actor_add_child (CLUTTER_ACTOR (entry), *icon); | ||||
|       g_signal_connect (*icon, "button-release-event", | ||||
|                         G_CALLBACK (_st_entry_icon_press_cb), entry); | ||||
|  | ||||
|       action = clutter_click_action_new (); | ||||
|       clutter_actor_add_action_with_name (*icon, "entry-icon-action", action); | ||||
|       g_signal_connect (action, "clicked", | ||||
|                         G_CALLBACK (_st_entry_icon_clicked_cb), entry); | ||||
|     } | ||||
|  | ||||
|   clutter_actor_queue_relayout (CLUTTER_ACTOR (entry)); | ||||
|   | ||||
| @@ -180,6 +180,7 @@ st_label_dispose (GObject   *object) | ||||
| { | ||||
|   StLabelPrivate *priv = ST_LABEL (object)->priv; | ||||
|  | ||||
|   priv->label = NULL; | ||||
|   g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref); | ||||
|  | ||||
|   G_OBJECT_CLASS (st_label_parent_class)->dispose (object); | ||||
|   | ||||
| @@ -304,6 +304,13 @@ st_scroll_view_pick (ClutterActor       *actor, | ||||
|     clutter_actor_paint (priv->vscroll); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| st_scroll_view_get_paint_volume (ClutterActor       *actor, | ||||
|                                  ClutterPaintVolume *volume) | ||||
| { | ||||
|   return clutter_paint_volume_set_from_allocation (volume, actor); | ||||
| } | ||||
|  | ||||
| static double | ||||
| get_scrollbar_width (StScrollView *scroll, | ||||
|                      gfloat        for_height) | ||||
| @@ -793,6 +800,7 @@ st_scroll_view_class_init (StScrollViewClass *klass) | ||||
|  | ||||
|   actor_class->paint = st_scroll_view_paint; | ||||
|   actor_class->pick = st_scroll_view_pick; | ||||
|   actor_class->get_paint_volume = st_scroll_view_get_paint_volume; | ||||
|   actor_class->get_preferred_width = st_scroll_view_get_preferred_width; | ||||
|   actor_class->get_preferred_height = st_scroll_view_get_preferred_height; | ||||
|   actor_class->allocate = st_scroll_view_allocate; | ||||
|   | ||||
| @@ -37,6 +37,7 @@ struct _StTextureCachePrivate | ||||
|  | ||||
|   /* Things that were loaded with a cache policy != NONE */ | ||||
|   GHashTable *keyed_cache; /* char * -> CoglTexture* */ | ||||
|   GHashTable *keyed_surface_cache; /* char * -> cairo_surface_t* */ | ||||
|  | ||||
|   /* Presently this is used to de-duplicate requests for GIcons and async URIs. */ | ||||
|   GHashTable *outstanding_requests; /* char * -> AsyncTextureLoadData * */ | ||||
| @@ -145,6 +146,10 @@ st_texture_cache_init (StTextureCache *self) | ||||
|  | ||||
|   self->priv->keyed_cache = g_hash_table_new_full (g_str_hash, g_str_equal, | ||||
|                                                    g_free, cogl_object_unref); | ||||
|   self->priv->keyed_surface_cache = g_hash_table_new_full (g_str_hash, | ||||
|                                                            g_str_equal, | ||||
|                                                            g_free, | ||||
|                                                            (GDestroyNotify) cairo_surface_destroy); | ||||
|   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, | ||||
| @@ -166,6 +171,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->outstanding_requests, g_hash_table_destroy); | ||||
|   g_clear_pointer (&self->priv->file_monitors, g_hash_table_destroy); | ||||
|  | ||||
| @@ -520,6 +526,8 @@ finish_texture_load (AsyncTextureLoadData *data, | ||||
|     goto out; | ||||
|  | ||||
|   texdata = pixbuf_to_cogl_texture (pixbuf); | ||||
|   if (!texdata) | ||||
|     goto out; | ||||
|  | ||||
|   if (data->policy != ST_TEXTURE_CACHE_POLICY_NONE) | ||||
|     { | ||||
| @@ -772,13 +780,13 @@ st_texture_cache_load (StTextureCache       *cache, | ||||
|   if (!texture) | ||||
|     { | ||||
|       texture = load (cache, key, data, error); | ||||
|       if (texture) | ||||
|       if (texture && policy == ST_TEXTURE_CACHE_POLICY_FOREVER) | ||||
|         g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), texture); | ||||
|       else | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|   cogl_object_ref (texture); | ||||
|   if (texture && policy == ST_TEXTURE_CACHE_POLICY_FOREVER) | ||||
|     cogl_object_ref (texture); | ||||
|  | ||||
|   return texture; | ||||
| } | ||||
|  | ||||
| @@ -976,7 +984,7 @@ file_changed_cb (GFileMonitor      *monitor, | ||||
|   char *key; | ||||
|   guint file_hash; | ||||
|  | ||||
|   if (event_type != G_FILE_MONITOR_EVENT_CHANGED) | ||||
|   if (event_type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) | ||||
|     return; | ||||
|  | ||||
|   file_hash = g_file_hash (file); | ||||
| @@ -986,7 +994,7 @@ file_changed_cb (GFileMonitor      *monitor, | ||||
|   g_free (key); | ||||
|  | ||||
|   key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", file_hash); | ||||
|   g_hash_table_remove (cache->priv->keyed_cache, key); | ||||
|   g_hash_table_remove (cache->priv->keyed_surface_cache, key); | ||||
|   g_free (key); | ||||
|  | ||||
|   g_signal_emit (cache, signals[TEXTURE_FILE_CHANGED], 0, file); | ||||
| @@ -1273,6 +1281,9 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache, | ||||
|       texdata = pixbuf_to_cogl_texture (pixbuf); | ||||
|       g_object_unref (pixbuf); | ||||
|  | ||||
|       if (!texdata) | ||||
|         goto out; | ||||
|  | ||||
|       if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER) | ||||
|         { | ||||
|           cogl_object_ref (texdata); | ||||
| @@ -1304,7 +1315,7 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache        *cache, | ||||
|  | ||||
|   key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", g_file_hash (file)); | ||||
|  | ||||
|   surface = g_hash_table_lookup (cache->priv->keyed_cache, key); | ||||
|   surface = g_hash_table_lookup (cache->priv->keyed_surface_cache, key); | ||||
|  | ||||
|   if (surface == NULL) | ||||
|     { | ||||
| @@ -1318,7 +1329,8 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache        *cache, | ||||
|       if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER) | ||||
|         { | ||||
|           cairo_surface_reference (surface); | ||||
|           g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), surface); | ||||
|           g_hash_table_insert (cache->priv->keyed_surface_cache, | ||||
|                                g_strdup (key), surface); | ||||
|         } | ||||
|     } | ||||
|   else | ||||
|   | ||||
| @@ -229,9 +229,9 @@ unpremultiply (ClutterColor *color) | ||||
| { | ||||
|   if (color->alpha != 0) | ||||
|     { | ||||
|       color->red = (color->red * 255 + 127) / color->alpha; | ||||
|       color->green = (color->green * 255 + 127) / color->alpha; | ||||
|       color->blue = (color->blue * 255 + 127) / color->alpha; | ||||
|       color->red = MIN((color->red * 255 + 127) / color->alpha, 255); | ||||
|       color->green = MIN((color->green * 255 + 127) / color->alpha, 255); | ||||
|       color->blue = MIN((color->blue * 255 + 127) / color->alpha, 255); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -402,7 +402,7 @@ st_theme_node_lookup_corner (StThemeNode    *node, | ||||
|     return COGL_INVALID_HANDLE; | ||||
|  | ||||
|   key = corner_to_string (&corner); | ||||
|   texture = st_texture_cache_load (cache, key, ST_TEXTURE_CACHE_POLICY_NONE, load_corner, &corner, NULL); | ||||
|   texture = st_texture_cache_load (cache, key, ST_TEXTURE_CACHE_POLICY_FOREVER, load_corner, &corner, NULL); | ||||
|  | ||||
|   if (texture) | ||||
|     { | ||||
| @@ -1414,6 +1414,32 @@ st_theme_node_load_background_image (StThemeNode *node) | ||||
|   return node->background_texture != COGL_INVALID_HANDLE; | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| st_theme_node_invalidate_resources_for_file (StThemeNode *node, | ||||
|                                              GFile       *file) | ||||
| { | ||||
|   StBorderImage *border_image; | ||||
|   gboolean changed = FALSE; | ||||
|   GFile *theme_file; | ||||
|  | ||||
|   theme_file = st_theme_node_get_background_image (node); | ||||
|   if ((theme_file != NULL) && g_file_equal (theme_file, file)) | ||||
|     { | ||||
|       st_theme_node_invalidate_background_image (node); | ||||
|       changed = TRUE; | ||||
|     } | ||||
|  | ||||
|   border_image = st_theme_node_get_border_image (node); | ||||
|   theme_file = border_image ? st_border_image_get_file (border_image) : NULL; | ||||
|   if ((theme_file != NULL) && g_file_equal (theme_file, file)) | ||||
|     { | ||||
|       st_theme_node_invalidate_border_image (node); | ||||
|       changed = TRUE; | ||||
|     } | ||||
|  | ||||
|   return changed; | ||||
| } | ||||
|  | ||||
| static void st_theme_node_prerender_shadow (StThemeNodePaintState *state); | ||||
|  | ||||
| static void | ||||
| @@ -2751,3 +2777,17 @@ st_theme_node_paint_state_invalidate (StThemeNodePaintState *state) | ||||
|   state->alloc_width = 0; | ||||
|   state->alloc_height = 0; | ||||
| } | ||||
|  | ||||
| gboolean | ||||
| st_theme_node_paint_state_invalidate_for_file (StThemeNodePaintState *state, | ||||
|                                                GFile                 *file) | ||||
| { | ||||
|   if (state->node != NULL && | ||||
|       st_theme_node_invalidate_resources_for_file (state->node, file)) | ||||
|     { | ||||
|       st_theme_node_paint_state_invalidate (state); | ||||
|       return TRUE; | ||||
|     } | ||||
|  | ||||
|   return FALSE; | ||||
| } | ||||
|   | ||||
| @@ -287,6 +287,9 @@ void st_theme_node_paint_state_free (StThemeNodePaintState *state); | ||||
| void st_theme_node_paint_state_copy (StThemeNodePaintState *state, | ||||
|                                      StThemeNodePaintState *other); | ||||
| void st_theme_node_paint_state_invalidate (StThemeNodePaintState *state); | ||||
| gboolean st_theme_node_paint_state_invalidate_for_file (StThemeNodePaintState *state, | ||||
|                                                         GFile                 *file); | ||||
|  | ||||
| void st_theme_node_paint_state_set_node (StThemeNodePaintState *state, | ||||
|                                          StThemeNode           *node); | ||||
|  | ||||
|   | ||||
| @@ -289,44 +289,17 @@ st_widget_texture_cache_changed (StTextureCache *cache, | ||||
| { | ||||
|   StWidget *actor = ST_WIDGET (user_data); | ||||
|   StWidgetPrivate *priv = st_widget_get_instance_private (actor); | ||||
|   StThemeNode *node = priv->theme_node; | ||||
|   StBorderImage *border_image; | ||||
|   gboolean changed = FALSE; | ||||
|   GFile *theme_file; | ||||
|   int i; | ||||
|  | ||||
|   if (node == NULL) | ||||
|     return; | ||||
|  | ||||
|   theme_file = st_theme_node_get_background_image (node); | ||||
|   if ((theme_file != NULL) && g_file_equal (theme_file, file)) | ||||
|   for (i = 0; i < G_N_ELEMENTS (priv->paint_states); i++) | ||||
|     { | ||||
|       st_theme_node_invalidate_background_image (node); | ||||
|       changed = TRUE; | ||||
|       StThemeNodePaintState *paint_state = &priv->paint_states[i]; | ||||
|       changed |= st_theme_node_paint_state_invalidate_for_file (paint_state, file); | ||||
|     } | ||||
|  | ||||
|   border_image = st_theme_node_get_border_image (node); | ||||
|   theme_file = border_image ? st_border_image_get_file (border_image) : NULL; | ||||
|   if ((theme_file != NULL) && g_file_equal (theme_file, file)) | ||||
|     { | ||||
|       st_theme_node_invalidate_border_image (node); | ||||
|       changed = TRUE; | ||||
|     } | ||||
|  | ||||
|   if (changed) | ||||
|     { | ||||
|       /* If we prerender the background / border, we need to update | ||||
|        * the paint state. We should probably implement a method to | ||||
|        * the theme node to determine this, but for now, just wipe | ||||
|        * the entire paint state. | ||||
|        * | ||||
|        * Use the existing state instead of a new one because it's | ||||
|        * assumed the rest of the state will stay the same. | ||||
|        */ | ||||
|       st_theme_node_paint_state_invalidate (current_paint_state (actor)); | ||||
|  | ||||
|       if (clutter_actor_is_mapped (CLUTTER_ACTOR (actor))) | ||||
|         clutter_actor_queue_redraw (CLUTTER_ACTOR (actor)); | ||||
|     } | ||||
|   if (changed && clutter_actor_is_mapped (CLUTTER_ACTOR (actor))) | ||||
|     clutter_actor_queue_redraw (CLUTTER_ACTOR (actor)); | ||||
| } | ||||
|  | ||||
| static void | ||||
|   | ||||
		Reference in New Issue
	
	Block a user