diff --git a/data/org.cinnamon.gschema.xml b/data/org.cinnamon.gschema.xml index bfb8530a0f..38775311fb 100644 --- a/data/org.cinnamon.gschema.xml +++ b/data/org.cinnamon.gschema.xml @@ -429,6 +429,11 @@ Show all windows from all workspaces + + false + Warp mouse pointer to the new focused window + + false not used - lives in org.cinnamon.muffin now @@ -506,7 +511,6 @@ The logo to use in the system info settings An icon name or absolute path to an icon, which will be used for the system icon in the "System Info" settings app. - . Disabled if no value is set. diff --git a/data/theme/cinnamon.css b/data/theme/cinnamon.css index dddd2d09bf..dda57d8b31 100644 --- a/data/theme/cinnamon.css +++ b/data/theme/cinnamon.css @@ -1244,6 +1244,11 @@ StScrollBar StButton#vhandle:hover { padding-right: 7px; padding-bottom: 7px; } +.menu-category-button:hover { + background-color: rgba(128,128,128,0.2); + border-radius: 4px; + border-image: none; +} .menu-category-button-greyed { padding-top: 7px; padding-left: 7px; @@ -1272,9 +1277,6 @@ StScrollBar StButton#vhandle:hover { } .menu-category-button-label:rtl { padding-right: 5px; - -} -.menu-category-button-selected:hover { } /* Name and description of the currently hovered item in the menu * This appears on the bottom right hand corner of the menu*/ @@ -2095,4 +2097,4 @@ StScrollBar StButton#vhandle:hover { -pie-border-width: 1px; -pie-border-color: rgba(200, 200, 200, 0.8); -pie-background-color: rgba(140, 140, 140, 0.6);; -} \ No newline at end of file +} diff --git a/debian/cinnamon-common.install b/debian/cinnamon-common.install index 1e65f241bf..8f9721440b 100644 --- a/debian/cinnamon-common.install +++ b/debian/cinnamon-common.install @@ -2,6 +2,7 @@ etc/xdg/menus/cinnamon* usr/share/cinnamon usr/share/cinnamon-session usr/share/desktop-directories +usr/share/gir-1.0 usr/share/glib-2.0 usr/share/icons usr/share/polkit-1 diff --git a/files/usr/share/cinnamon/applets/cornerbar@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/cornerbar@cinnamon.org/applet.js index 425a89bf01..e84a968bc2 100644 --- a/files/usr/share/cinnamon/applets/cornerbar@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/cornerbar@cinnamon.org/applet.js @@ -1,4 +1,5 @@ const Applet = imports.ui.applet; +const GLib = imports.gi.GLib; const St = imports.gi.St; const Lang = imports.lang; const Clutter = imports.gi.Clutter; @@ -9,6 +10,8 @@ const SignalManager = imports.misc.signalManager; const Mainloop = imports.mainloop; const Tweener = imports.ui.tweener; +const SCROLL_DELAY = 200; + class CinnamonBarApplet extends Applet.Applet { constructor(orientation, panel_height, instance_id) { super(orientation, panel_height, instance_id); @@ -20,15 +23,20 @@ class CinnamonBarApplet extends Applet.Applet { this.settings.bind("peek-blur", "peek_blur"); this.settings.bind("click-action", "click_action"); this.settings.bind("middle-click-action", "middle_click_action"); + this.settings.bind("scroll-behavior", "scroll_behavior"); this.signals = new SignalManager.SignalManager(null); this.actor.connect('enter-event', Lang.bind(this, this._on_enter)); this.actor.connect('leave-event', Lang.bind(this, this._on_leave)); this.signals.connect(global.stage, 'notify::key-focus', this._on_leave, this); + this.actor.connect('scroll-event', Lang.bind(this, this._on_scroll_event)); this._did_peek = false; this._peek_timeout_id = 0; + this._last_scroll_time = 0; + this._last_scroll_direction = 0; + this.actor.style_class = 'applet-cornerbar-box'; this.setAllowedLayout(Applet.AllowedLayout.BOTH); @@ -154,6 +162,43 @@ class CinnamonBarApplet extends Applet.Applet { } } + _on_scroll_event(actor,event) { + if (this.scroll_behavior == "nothing") { + return GLib.SOURCE_CONTINUE; + } + + if (this._peek_timeout_id > 0) { + Mainloop.source_remove(this._peek_timeout_id); + this._peek_timeout_id = 0; + } + + const edir = event.get_scroll_direction(); + if (edir == Clutter.ScrollDirection.SMOOTH) { + return GLib.SOURCE_CONTINUE; + } + + const etime = event.get_time(); + if (etime > (this._last_scroll_time + SCROLL_DELAY) || + edir !== this._last_scroll_direction) { + + let index = global.screen.get_active_workspace_index(); + + if ((edir == Clutter.ScrollDirection.UP) == (this.scroll_behavior == "normal")) + index = index - 1; + else + index = index + 1; + + if (global.screen.get_workspace_by_index(index) != null) { + global.screen.get_workspace_by_index(index).activate(global.get_current_time()); + } + + this._last_scroll_direction = edir; + this._last_scroll_time = etime; + } + + return GLib.SOURCE_CONTINUE; + } + show_all_windows(time) { let windows = global.get_window_actors(); for(let i = 0; i < windows.length; i++){ diff --git a/files/usr/share/cinnamon/applets/cornerbar@cinnamon.org/settings-schema.json b/files/usr/share/cinnamon/applets/cornerbar@cinnamon.org/settings-schema.json index db84ba405a..e0e8e66b91 100644 --- a/files/usr/share/cinnamon/applets/cornerbar@cinnamon.org/settings-schema.json +++ b/files/usr/share/cinnamon/applets/cornerbar@cinnamon.org/settings-schema.json @@ -25,6 +25,17 @@ "Show the window selector (Scale)": "show_scale" } }, + "scroll-behavior": { + "type": "combobox", + "default": "none", + "description": "Scroll wheel behavior", + "tooltip": ".", + "options": { + "Nothing": "nothing", + "Switch workspaces": "normal", + "Switch workspaces (reversed)": "reversed" + } + }, "peek-at-desktop" : { "type" : "switch", "default" : false, diff --git a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appGroup.js b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appGroup.js index fc1f892604..63a54882ce 100644 --- a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appGroup.js +++ b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appGroup.js @@ -309,7 +309,7 @@ class AppGroup { } flashButton() { - if (!this._needsAttention || !this.actor || this._flashTimer) + if (!this._needsAttention || !this.actor || this.flashTimer) return; if (!this.groupState.groupReady && this.groupState.isFavoriteApp) @@ -884,8 +884,8 @@ class AppGroup { this.groupState.lastFocused.unminimize(); } let ws = this.groupState.lastFocused.get_workspace().index(); - if (ws !== global.screen.get_active_workspace_index()) { - global.screen.get_workspace_by_index(ws).activate(global.get_current_time()); + if (ws !== global.workspace_manager.get_active_workspace_index()) { + global.workspace_manager.get_workspace_by_index(ws).activate(global.get_current_time()); } Main.activateWindow(this.groupState.lastFocused, global.get_current_time()); this.actor.add_style_pseudo_class('focus'); diff --git a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appList.js b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appList.js index e43afb00c7..2a2f3b0996 100644 --- a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appList.js +++ b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/appList.js @@ -50,7 +50,7 @@ class AppList { this.lastFocusedApp = null; // Connect all the signals - this.signals.connect(global.screen, 'window-workspace-changed', (...args) => this.windowWorkspaceChanged(...args)); + this.signals.connect(global.display, 'window-workspace-changed', (...args) => this.windowWorkspaceChanged(...args)); // Ugly change: refresh the removed app instances from all workspaces this.signals.connect(this.metaWorkspace, 'window-removed', (...args) => this.windowRemoved(...args)); this.signals.connect(global.window_manager, 'switch-workspace' , (...args) => this.reloadList(...args)); @@ -235,7 +235,7 @@ class AppList { && this.state.monitorWatchList.indexOf(metaWindow.get_monitor()) > -1; } - windowWorkspaceChanged(screen, metaWorkspace, metaWindow) { + windowWorkspaceChanged(display, metaWorkspace, metaWindow) { this.windowAdded(metaWindow, metaWorkspace); } diff --git a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/applet.js index 5f5c088eda..7225c27806 100644 --- a/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/applet.js @@ -189,7 +189,7 @@ class GroupedWindowListApplet extends Applet.Applet { instance_id, monitorWatchList: [], autoStartApps: [], - currentWs: global.screen.get_active_workspace_index(), + currentWs: global.workspace_manager.get_active_workspace_index(), panelEditMode: global.settings.get_boolean('panel-edit-mode'), menuOpen: false, dragging: { @@ -293,10 +293,10 @@ class GroupedWindowListApplet extends Applet.Applet { this.signals.connect(this.actor, 'scroll-event', (c, e) => this.handleScroll(e)); this.signals.connect(global, 'scale-changed', (...args) => this.onUIScaleChange(...args)); this.signals.connect(global.window_manager, 'switch-workspace', (...args) => this.onSwitchWorkspace(...args)); - this.signals.connect(global.screen, 'workspace-removed', (...args) => this.onWorkspaceRemoved(...args)); - this.signals.connect(global.screen, 'window-monitor-changed', (...args) => this.onWindowMonitorChanged(...args)); + this.signals.connect(global.workspace_manager, 'workspace-removed', (...args) => this.onWorkspaceRemoved(...args)); + this.signals.connect(global.display, 'window-monitor-changed', (...args) => this.onWindowMonitorChanged(...args)); this.signals.connect(Main.panelManager, 'monitors-changed', (...args) => this._onMonitorsChanged(...args)); - this.signals.connect(global.screen, 'window-skip-taskbar-changed', (...args) => this.onWindowSkipTaskbarChanged(...args)); + this.signals.connect(global.display, 'window-skip-taskbar-changed', (...args) => this.onWindowSkipTaskbarChanged(...args)); this.signals.connect(global.display, 'window-marked-urgent', (...args) => this.updateAttentionState(...args)); this.signals.connect(global.display, 'window-demands-attention', (...args) => this.updateAttentionState(...args)); this.signals.connect(global.display, 'window-created', (...args) => this.onWindowCreated(...args)); @@ -446,7 +446,7 @@ class GroupedWindowListApplet extends Applet.Applet { return false; } - onWindowMonitorChanged(screen, metaWindow, metaWorkspace) { + onWindowMonitorChanged(display, metaWindow, metaWorkspace) { if (this.state.monitorWatchList.length !== this.numberOfMonitors) { let appList = this.getCurrentAppList(); if (appList !== null) { @@ -459,11 +459,11 @@ class GroupedWindowListApplet extends Applet.Applet { bindAppKeys() { this.unbindAppKeys(); - for (let i = 1; i < 10; i++) { - if (this.state.settings.SuperNumHotkeys) { + if (this.state.settings.SuperNumHotkeys) { + for (let i = 1; i < 10; i++) { this.bindAppKey(i); + this.bindNewAppKey(i); } - this.bindNewAppKey(i); } Main.keybindingManager.addHotKey('launch-show-apps-order', this.state.settings.showAppsOrderHotkey, () => this.showAppsOrder() @@ -935,7 +935,7 @@ class GroupedWindowListApplet extends Applet.Applet { return true; } - onWorkspaceRemoved(metaScreen, index) { + onWorkspaceRemoved(workspaceManager, index) { if (this.appLists.length <= index) { return; } @@ -955,7 +955,7 @@ class GroupedWindowListApplet extends Applet.Applet { for (let i = removedLists.length - 1; i >= 0; i--) { this.appLists.splice(removedLists[i], 1); } - this.state.set({currentWs: global.screen.get_active_workspace_index()}); + this.state.set({currentWs: global.workspace_manager.get_active_workspace_index()}); } onSwitchWorkspace() { @@ -965,7 +965,7 @@ class GroupedWindowListApplet extends Applet.Applet { _onSwitchWorkspace() { if (!this.state) return; this.state.set({currentWs: global.workspace_manager.get_active_workspace_index()}); - let metaWorkspace = global.screen.get_workspace_by_index(this.state.currentWs); + let metaWorkspace = global.workspace_manager.get_workspace_by_index(this.state.currentWs); // If the workspace we switched to isn't in our list, // we need to create an AppList for it @@ -990,7 +990,7 @@ class GroupedWindowListApplet extends Applet.Applet { this.actor.queue_relayout(); } - onWindowSkipTaskbarChanged(screen, metaWindow) { + onWindowSkipTaskbarChanged(display, metaWindow) { let appList = this.getCurrentAppList(); if (metaWindow.is_skip_taskbar()) { diff --git a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js index abe9d901cc..899e36f242 100644 --- a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js @@ -933,11 +933,12 @@ class CategoryButton extends SimpleMenuItem { } activate() { - if(this.applet.searchActive) + if(this.applet.searchActive || this.categoryId === this.applet.lastSelectedCategory) return; - - this.applet._clearPrevCatSelection(this.actor, true); this.applet._select_category(this.categoryId); + this.applet._previousSelectedAppActor = null; + this.applet.categoriesBox.get_children().forEach(child => + child.set_style_class_name("menu-category-button")); this.actor.style_class = "menu-category-button-selected"; } } @@ -1174,6 +1175,10 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.menu = new Menu(this, orientation); this.menuManager.addMenu(this.menu); + const edit_item = new PopupMenu.PopupIconMenuItem(_("Edit menu"), "document-edit", St.IconType.SYMBOLIC); + edit_item.connect("activate", () => Util.spawnCommandLine("cinnamon-menu-editor")); + this._applet_context_menu.addMenuItem(edit_item); + this.settings = new Settings.AppletSettings(this, "menu@cinnamon.org", instance_id); this.settings.connect("settings-changed", () => { this._size_dirty = true; @@ -1236,10 +1241,8 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._favoriteDocButtons = []; this._categoryButtons = []; this._searchProviderButtons = []; - this._selectedItemIndex = null; - this._previousSelectedActor = null; - this._previousVisibleIndex = null; - this._previousTreeSelectedActor = null; + this._previousSelectedAppActor = null; + this._previousCategoryHoverActor = null; this._activeContainer = null; this._activeActor = null; this._knownApps = new Set(); // Used to keep track of apps that are already installed, so we can highlight newly installed ones @@ -1469,7 +1472,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { if (open) { this.actor.add_style_pseudo_class('active'); global.stage.set_key_focus(this.searchEntry); - this._selectedItemIndex = null; this._activeContainer = null; this._activeActor = null; @@ -1498,11 +1500,10 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } this.selectedAppTitle.set_text(""); this.selectedAppDescription.set_text(""); - this._previousTreeSelectedActor = null; - this._previousSelectedActor = null; + this._previousCategoryHoverActor = null; + this._previousSelectedAppActor = null; this.closeContextMenu(false); - this._previousVisibleIndex = null; - + this._disableVectorMask(); this._scrollToButton(null, this.applicationsScrollBox); this._scrollToButton(null, this.categoriesScrollBox); @@ -1731,7 +1732,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { _onMenuKeyPress(actor, event) { let symbol = event.get_key_symbol(); let item_actor; - let index = 0; this.appBoxIter.reloadVisible(); this.catBoxIter.reloadVisible(); this.favBoxIter.reloadVisible(); @@ -1758,8 +1758,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { return true; } - index = this._selectedItemIndex; - let ctrlKey = modifierState & Clutter.ModifierType.CONTROL_MASK; // If a context menu is open, hijack keyboard navigation and concentrate on the context menu. @@ -1790,18 +1788,21 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { let navigationKey = true; let whichWay = "none"; - + if (this._activeContainer === null) { + this._setKeyFocusToCurrentCategoryButton(); + } + switch (symbol) { case Clutter.KEY_Up: whichWay = "up"; if (this._activeContainer === this.favoritesBox && ctrlKey && - (this.favoritesBox.get_child_at_index(index))._delegate instanceof FavoritesButton) + this._activeActor._delegate instanceof FavoritesButton) navigationKey = false; break; case Clutter.KEY_Down: whichWay = "down"; if (this._activeContainer === this.favoritesBox && ctrlKey && - (this.favoritesBox.get_child_at_index(index))._delegate instanceof FavoritesButton) + this._activeActor._delegate instanceof FavoritesButton) navigationKey = false; break; case Clutter.KEY_Page_Up: @@ -1814,7 +1815,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { if (this._activeContainer === this.applicationsBox) whichWay = "none"; else if (this._activeContainer === this.categoriesBox && this.noRecentDocuments && - (this.categoriesBox.get_child_at_index(index))._delegate.categoryId === "recent") + this._activeActor._delegate.categoryId === "recent") whichWay = "none"; break; case Clutter.KEY_Left: @@ -1822,8 +1823,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { whichWay = "left"; if (this._activeContainer === this.favoritesBox || this._activeContainer === this.systemButtonsBox) whichWay = "none"; - else if (!this.favBoxShow && - (this._activeContainer === this.categoriesBox || this._activeContainer === null)) + else if (!this.favBoxShow && this._activeContainer === this.categoriesBox) whichWay = "none"; break; case Clutter.KEY_Tab: @@ -1844,189 +1844,104 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { if (navigationKey) { switch (this._activeContainer) { - case null: - switch (whichWay) { - case "up": - this._activeContainer = this.categoriesBox; - item_actor = this.catBoxIter.getLastVisible(); - this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); - break; - case "down": - this._activeContainer = this.categoriesBox; - item_actor = this.catBoxIter.getFirstVisible(); - item_actor = this.catBoxIter.getNextVisible(item_actor); - this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); - break; - case "right": - this._activeContainer = this.applicationsBox; - item_actor = this.appBoxIter.getFirstVisible(); - this._scrollToButton(); - break; - case "left": - if (this.favBoxShow) { - this._activeContainer = this.favoritesBox; - item_actor = this.favBoxIter.getFirstVisible(); - } else { - this._activeContainer = this.applicationsBox; - item_actor = this.appBoxIter.getFirstVisible(); - this._scrollToButton(); - } - break; - case "top": - this._activeContainer = this.categoriesBox; - item_actor = this.catBoxIter.getFirstVisible(); - this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); - break; - case "bottom": - this._activeContainer = this.categoriesBox; - item_actor = this.catBoxIter.getLastVisible(); - this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); - break; - } - break; case this.categoriesBox: switch (whichWay) { case "up": - this._previousTreeSelectedActor = this.categoriesBox.get_child_at_index(index); - this._previousTreeSelectedActor._delegate.isHovered = false; item_actor = this.catBoxIter.getPrevVisible(this._activeActor); - this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); break; case "down": - this._previousTreeSelectedActor = this.categoriesBox.get_child_at_index(index); - this._previousTreeSelectedActor._delegate.isHovered = false; item_actor = this.catBoxIter.getNextVisible(this._activeActor); - this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); break; case "right": - if ((this.categoriesBox.get_child_at_index(index))._delegate.categoryId === "recent" && + if (this._activeActor._delegate.categoryId === "recent" && this.noRecentDocuments) { if(this.favBoxShow) { - this._previousSelectedActor = this.categoriesBox.get_child_at_index(index); item_actor = this.favBoxIter.getFirstVisible(); - } else { - item_actor = this.categoriesBox.get_child_at_index(index); } - } - else { - item_actor = (this._previousVisibleIndex != null) ? - this.appBoxIter.getVisibleItem(this._previousVisibleIndex) : - this.appBoxIter.getFirstVisible(); + } else { + item_actor = (this._previousSelectedAppActor != null) ? + this._previousSelectedAppActor : this.appBoxIter.getFirstVisible(); } break; case "left": if(this.favBoxShow) { - this._previousSelectedActor = this.categoriesBox.get_child_at_index(index); item_actor = this.favBoxIter.getFirstVisible(); - this._scrollToButton(null, this.favoritesScrollBox); - } else { - if ((this.categoriesBox.get_child_at_index(index))._delegate.categoryId === "recent" && - this.noRecentDocuments) { - item_actor = this.categoriesBox.get_child_at_index(index); - } else { - item_actor = (this._previousVisibleIndex != null) ? - this.appBoxIter.getVisibleItem(this._previousVisibleIndex) : - this.appBoxIter.getFirstVisible(); - } + } else if (this._activeActor._delegate.categoryId != "recent" || + !this.noRecentDocuments) { + item_actor = (this._previousSelectedAppActor != null) ? + this._previousSelectedAppActor : + this.appBoxIter.getFirstVisible(); } break; case "top": - this._previousTreeSelectedActor = this.categoriesBox.get_child_at_index(index); - this._previousTreeSelectedActor._delegate.isHovered = false; item_actor = this.catBoxIter.getFirstVisible(); - this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); break; case "bottom": - this._previousTreeSelectedActor = this.categoriesBox.get_child_at_index(index); - this._previousTreeSelectedActor._delegate.isHovered = false; item_actor = this.catBoxIter.getLastVisible(); - this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); break; } break; case this.applicationsBox: switch (whichWay) { case "up": - this._previousSelectedActor = this.applicationsBox.get_child_at_index(index); - item_actor = this.appBoxIter.getPrevVisible(this._previousSelectedActor); - this._previousVisibleIndex = this.appBoxIter.getVisibleIndex(item_actor); - this._scrollToButton(item_actor._delegate); + item_actor = this.appBoxIter.getPrevVisible(this._activeActor); break; case "down": - this._previousSelectedActor = this.applicationsBox.get_child_at_index(index); - item_actor = this.appBoxIter.getNextVisible(this._previousSelectedActor); - this._previousVisibleIndex = this.appBoxIter.getVisibleIndex(item_actor); - this._scrollToButton(item_actor._delegate); + item_actor = this.appBoxIter.getNextVisible(this._activeActor); break; case "right": - this._previousSelectedActor = this.applicationsBox.get_child_at_index(index); - item_actor = (this._previousTreeSelectedActor != null) ? - this._previousTreeSelectedActor : - this.catBoxIter.getFirstVisible(); - this._previousTreeSelectedActor = item_actor; - index = item_actor.get_parent()._vis_iter.getAbsoluteIndexOfChild(item_actor); - if (this.favBoxShow) { - this._buttonEnterEvent(item_actor._delegate, true); - this._previousSelectedActor = this.categoriesBox.get_child_at_index(index); item_actor = this.favBoxIter.getFirstVisible(); + } else { + item_actor = (this._previousCategoryHoverActor != null) ? + this._previousCategoryHoverActor : + this.catBoxIter.getFirstVisible(); } break; case "left": - this._previousSelectedActor = this.applicationsBox.get_child_at_index(index); - item_actor = (this._previousTreeSelectedActor != null) ? - this._previousTreeSelectedActor : + item_actor = (this._previousCategoryHoverActor != null) ? + this._previousCategoryHoverActor : this.catBoxIter.getFirstVisible(); - this._previousTreeSelectedActor = item_actor; break; case "top": item_actor = this.appBoxIter.getFirstVisible(); - this._previousVisibleIndex = this.appBoxIter.getVisibleIndex(item_actor); - this._scrollToButton(item_actor._delegate); break; case "bottom": item_actor = this.appBoxIter.getLastVisible(); - this._previousVisibleIndex = this.appBoxIter.getVisibleIndex(item_actor); - this._scrollToButton(item_actor._delegate); break; } break; case this.favoritesBox: switch (whichWay) { case "up": - this._previousSelectedActor = this.favoritesBox.get_child_at_index(index); - if (this._previousSelectedActor === this.favBoxIter.getFirstVisible()) { + if (this._activeActor === this.favBoxIter.getFirstVisible()) { item_actor = this.sysBoxIter.getLastVisible(); } else { - item_actor = this.favBoxIter.getPrevVisible(this._previousSelectedActor); - this._scrollToButton(item_actor._delegate, this.favoritesScrollBox); + item_actor = this.favBoxIter.getPrevVisible(this._activeActor); } break; case "down": - this._previousSelectedActor = this.favoritesBox.get_child_at_index(index); - if (this._previousSelectedActor === this.favBoxIter.getLastVisible()) { + if (this._activeActor === this.favBoxIter.getLastVisible()) { item_actor = this.sysBoxIter.getFirstVisible(); } else { - item_actor = this.favBoxIter.getNextVisible(this._previousSelectedActor); - this._scrollToButton(item_actor._delegate, this.favoritesScrollBox); + item_actor = this.favBoxIter.getNextVisible(this._activeActor); } break; case "right": - item_actor = (this._previousTreeSelectedActor != null) ? - this._previousTreeSelectedActor : + item_actor = (this._previousCategoryHoverActor != null) ? + this._previousCategoryHoverActor : this.catBoxIter.getFirstVisible(); - this._previousTreeSelectedActor = item_actor; break; case "left": - item_actor = (this._previousTreeSelectedActor != null) ? - this._previousTreeSelectedActor : + /*item_actor = (this._previousCategoryHoverActor != null) ? + this._previousCategoryHoverActor : this.catBoxIter.getFirstVisible(); - this._previousTreeSelectedActor = item_actor; + this._previousCategoryHoverActor = item_actor; index = item_actor.get_parent()._vis_iter.getAbsoluteIndexOfChild(item_actor); - this._buttonEnterEvent(item_actor._delegate, true); - item_actor = (this._previousVisibleIndex != null) ? - this.appBoxIter.getVisibleItem(this._previousVisibleIndex) : + this._buttonEnterEvent(item_actor._delegate);*/ + item_actor = (this._previousSelectedAppActor != null) ? + this._previousSelectedAppActor : this.appBoxIter.getFirstVisible(); break; case "top": @@ -2040,39 +1955,34 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { case this.systemButtonsBox: switch (whichWay) { case "up": - this._previousSelectedActor = this.systemButtonsBox.get_child_at_index(index); - if (this._previousSelectedActor === this.sysBoxIter.getFirstVisible()) { + if (this._activeActor === this.sysBoxIter.getFirstVisible()) { item_actor = this.favBoxIter.getLastVisible(); - this._scrollToButton(item_actor._delegate, this.favoritesScrollBox); } else { - item_actor = this.sysBoxIter.getPrevVisible(this._previousSelectedActor); + item_actor = this.sysBoxIter.getPrevVisible(this._activeActor); } break; case "down": - this._previousSelectedActor = this.systemButtonsBox.get_child_at_index(index); - if (this._previousSelectedActor === this.sysBoxIter.getLastVisible()) { + if (this._activeActor === this.sysBoxIter.getLastVisible()) { item_actor = this.favBoxIter.getFirstVisible(); - this._scrollToButton(null, this.favoritesScrollBox); } else { - item_actor = this.sysBoxIter.getNextVisible(this._previousSelectedActor); + item_actor = this.sysBoxIter.getNextVisible(this._activeActor); } break; case "right": - item_actor = (this._previousTreeSelectedActor != null) ? - this._previousTreeSelectedActor : + item_actor = (this._previousCategoryHoverActor != null) ? + this._previousCategoryHoverActor : this.catBoxIter.getFirstVisible(); - this._previousTreeSelectedActor = item_actor; break; case "left": - item_actor = (this._previousTreeSelectedActor != null) ? - this._previousTreeSelectedActor : + /*item_actor = (this._previousCategoryHoverActor != null) ? + this._previousCategoryHoverActor : this.catBoxIter.getFirstVisible(); - this._previousTreeSelectedActor = item_actor; + this._previousCategoryHoverActor = item_actor; index = item_actor.get_parent()._vis_iter.getAbsoluteIndexOfChild(item_actor); - this._buttonEnterEvent(item_actor._delegate, true); - item_actor = (this._previousVisibleIndex != null) ? - this.appBoxIter.getVisibleItem(this._previousVisibleIndex) : + this._buttonEnterEvent(item_actor._delegate);*/ + item_actor = (this._previousSelectedAppActor != null) ? + this._previousSelectedAppActor : this.appBoxIter.getFirstVisible(); break; case "top": @@ -2088,53 +1998,49 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } if (!item_actor) return false; - index = item_actor.get_parent()._vis_iter.getAbsoluteIndexOfChild(item_actor); } else { - if ((this._activeContainer && this._activeContainer !== this.categoriesBox) && - (symbol === Clutter.KEY_Return || symbol === Clutter.KEY_KP_Enter)) { + if (this._activeContainer && (symbol === Clutter.KEY_Return || symbol === Clutter.KEY_KP_Enter)) { if (!ctrlKey) { - item_actor = this._activeContainer.get_child_at_index(this._selectedItemIndex); - item_actor._delegate.activate(); + this._activeActor._delegate.activate(); } else if (ctrlKey && this._activeContainer === this.applicationsBox) { - item_actor = this.applicationsBox.get_child_at_index(this._selectedItemIndex); - this.toggleContextMenu(item_actor._delegate); + this.toggleContextMenu(this._activeActor._delegate); } return true; } else if (this._activeContainer === this.applicationsBox && symbol === Clutter.KEY_Menu) { - item_actor = this.applicationsBox.get_child_at_index(this._selectedItemIndex); - this.toggleContextMenu(item_actor._delegate); + this.toggleContextMenu(this._activeActor._delegate); return true; } else if (!this.searchActive && this._activeContainer === this.favoritesBox && symbol === Clutter.KEY_Delete) { - item_actor = this.favoritesBox.get_child_at_index(this._selectedItemIndex); + item_actor = this._activeActor; + const selectedItemIndex = this._activeContainer._vis_iter.getAbsoluteIndexOfChild(this._activeActor); if (item_actor._delegate instanceof FavoritesButton) { let favorites = AppFavorites.getAppFavorites().getFavorites(); let numFavorites = favorites.length; AppFavorites.getAppFavorites().removeFavorite(item_actor._delegate.app.get_id()); - if (this._selectedItemIndex == (numFavorites-1)) - item_actor = this.favoritesBox.get_child_at_index(this._selectedItemIndex-1); + if (selectedItemIndex == (numFavorites-1)) + item_actor = this.favoritesBox.get_child_at_index(selectedItemIndex-1); else - item_actor = this.favoritesBox.get_child_at_index(this._selectedItemIndex); + item_actor = this.favoritesBox.get_child_at_index(selectedItemIndex); } } else if (this._activeContainer === this.favoritesBox && (symbol === Clutter.KEY_Down || symbol === Clutter.KEY_Up) && ctrlKey && - (this.favoritesBox.get_child_at_index(index))._delegate instanceof FavoritesButton) { - item_actor = this.favoritesBox.get_child_at_index(this._selectedItemIndex); + this._activeActor._delegate instanceof FavoritesButton) { + const selectedItemIndex = this._activeContainer._vis_iter.getAbsoluteIndexOfChild(this._activeActor); + item_actor = this._activeActor; let id = item_actor._delegate.app.get_id(); let appFavorites = AppFavorites.getAppFavorites(); let favorites = appFavorites.getFavorites(); let numFavorites = favorites.length; let favPos = 0; - if (this._selectedItemIndex == (numFavorites-1) && symbol === Clutter.KEY_Down) + if (selectedItemIndex == (numFavorites-1) && symbol === Clutter.KEY_Down) favPos = 0; - else if (this._selectedItemIndex == 0 && symbol === Clutter.KEY_Up) + else if (selectedItemIndex == 0 && symbol === Clutter.KEY_Up) favPos = numFavorites-1; else if (symbol === Clutter.KEY_Down) - favPos = this._selectedItemIndex + 1; + favPos = selectedItemIndex + 1; else - favPos = this._selectedItemIndex - 1; + favPos = selectedItemIndex - 1; appFavorites.moveFavoriteToPos(id, favPos); item_actor = this.favoritesBox.get_child_at_index(favPos); - this._scrollToButton(item_actor._delegate, this.favoritesScrollBox); } else if (this.searchFilesystem && (this._fileFolderAccessActive || symbol === Clutter.KEY_slash)) { if (symbol === Clutter.KEY_Return || symbol === Clutter.KEY_KP_Enter) { if (this._run(this.searchEntry.get_text())) { @@ -2189,124 +2095,89 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.selectedAppTitle.set_text(""); this.selectedAppDescription.set_text(""); - this._selectedItemIndex = index; if (!item_actor || item_actor === this.searchEntry) { return false; } - this._buttonEnterEvent(item_actor._delegate, true); - return true; - } - - _buttonEnterEvent(button, synthetic=false) { - let parent = button.actor.get_parent(); - if (this._activeContainer === this.categoriesBox && parent !== this._activeContainer) { - this._previousTreeSelectedActor = this._activeActor; - this._previousSelectedActor = null; - } - if (this._previousTreeSelectedActor && this._activeContainer !== this.categoriesBox && - parent !== this._activeContainer && button !== this._previousTreeSelectedActor && !this.searchActive) { - this._previousTreeSelectedActor.style_class = "menu-category-button"; - } - if (parent != this._activeContainer && parent._vis_iter) { - parent._vis_iter.reloadVisible(); - } - let _maybePreviousActor = this._activeActor; - if (_maybePreviousActor && this._activeContainer !== this.categoriesBox) { - this._previousSelectedActor = _maybePreviousActor; - this._clearPrevSelection(); - } - if (parent === this.categoriesBox && !this.searchActive) { - this._previousSelectedActor = _maybePreviousActor; - this._clearPrevCatSelection(null, synthetic); - } - this._activeContainer = parent; - this._activeActor = button.actor; - if (this._activeContainer._vis_iter) { - this._selectedItemIndex = this._activeContainer._vis_iter.getAbsoluteIndexOfChild(this._activeActor); + if (item_actor._delegate instanceof CategoryButton) { + this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); + } else if (item_actor._delegate instanceof FavoritesButton) { + this._scrollToButton(item_actor._delegate, this.favoritesScrollBox); + } else if (item_actor.get_parent() === this.applicationsBox) { + this._scrollToButton(item_actor._delegate, this.applicationsScrollBox); } + + this._buttonEnterEvent(item_actor._delegate); + return true; + } - let isFav = false; + _buttonEnterEvent(button) { + this.categoriesBox.get_children().forEach(child => child.remove_style_pseudo_class("hover")); + this.applicationsBox.get_children().forEach(child => child.set_style_class_name("menu-application-button")); + this.favoritesBox.get_children().forEach(child => child.remove_style_pseudo_class("hover")); + this.systemButtonsBox.get_children().forEach(child => child.remove_style_pseudo_class("hover")); + if (button instanceof CategoryButton) { if (this.searchActive) return; - button.isHovered = true; - if (this.categoryHover || (button.categoryId !== this.lastSelectedCategory)) { - this._clearPrevCatSelection(button.actor, synthetic); - } - if (this.categoryHover || synthetic) { - this._select_category(button.categoryId); + + if (button.categoryId !== this.lastSelectedCategory) { + if (this.categoryHover) { + this.categoriesBox.get_children().forEach(child => + child.set_style_class_name("menu-category-button")); + button.activate(); + } else { + button.actor.add_style_pseudo_class("hover"); + } } + this._previousCategoryHoverActor = button.actor; } else { - this._previousVisibleIndex = parent._vis_iter.getVisibleIndex(button.actor); - - isFav = button instanceof FavoritesButton || button instanceof SystemButton; - if (!isFav) - this._clearPrevSelection(button.actor); + const isFav = button instanceof FavoritesButton || button instanceof SystemButton; + if (isFav) { + button.actor.add_style_pseudo_class("hover"); + } else { + button.actor.set_style_class_name(`${button.styleClass}-selected`); + this._previousSelectedAppActor = button.actor; + } this.selectedAppTitle.set_text(button.name); this.selectedAppDescription.set_text(button.description); } - if (isFav) - button.actor.add_style_pseudo_class("hover"); - else - button.actor.set_style_class_name(`${button.styleClass}-selected`); + + let parent = button.actor.get_parent(); + this._activeContainer = parent; + this._activeActor = button.actor; } _buttonLeaveEvent (button) { if (button instanceof CategoryButton) { - if (this._previousTreeSelectedActor === null) { - this._previousTreeSelectedActor = button.actor; - } else { - let prevIdx = this.catBoxIter.getVisibleIndex(this._previousTreeSelectedActor); - let nextIdx = this.catBoxIter.getVisibleIndex(button.actor); - - if (Math.abs(prevIdx - nextIdx) <= 1) { - this._previousTreeSelectedActor = button.actor; + if (button.categoryId !== this.lastSelectedCategory) { + button.actor.set_style_class_name("menu-category-button"); + if (button.actor.has_style_pseudo_class("hover")) { + button.actor.remove_style_pseudo_class("hover"); } } - button.isHovered = false; } else { - this._previousSelectedActor = button.actor; this.selectedAppTitle.set_text(""); this.selectedAppDescription.set_text(""); - // category unselects are handled when the category actually changes if (button instanceof FavoritesButton || button instanceof SystemButton) button.actor.remove_style_pseudo_class("hover"); else button.actor.set_style_class_name(button.styleClass); } - } - _clearPrevSelection(actor) { - if (this._previousSelectedActor - && !this._previousSelectedActor.is_finalized() - && this._previousSelectedActor != actor) { - if (this._previousSelectedActor._delegate instanceof FavoritesButton || - this._previousSelectedActor._delegate instanceof SystemButton) - this._previousSelectedActor.remove_style_pseudo_class("hover"); - else if (!(this._previousSelectedActor._delegate instanceof CategoryButton)) - this._previousSelectedActor.style_class = "menu-application-button"; - } + // This method is only called on mouse leave so return key focus to the + // currently active category button. + this._setKeyFocusToCurrentCategoryButton(); } - _clearPrevCatSelection(actor, synthetic=false) { - if (this._previousTreeSelectedActor && this._previousTreeSelectedActor != actor && - (this.categoryHover ? true : this._previousTreeSelectedActor._delegate.categoryId !== this.lastSelectedCategory)) { - this._previousTreeSelectedActor.style_class = "menu-category-button"; - if (this._previousTreeSelectedActor._delegate) { - this._buttonLeaveEvent(this._previousTreeSelectedActor._delegate); - } - - if (actor !== undefined) { - this._previousVisibleIndex = null; - this._previousTreeSelectedActor = actor; - } - } else { - if (this.categoryHover || synthetic) { - this.categoriesBox.get_children().forEach(child => child.style_class = "menu-category-button"); - } + _setKeyFocusToCurrentCategoryButton() { + const currentSelectedCategoryActor = this.categoriesBox.get_children().find(child => + child._delegate.categoryId === this.lastSelectedCategory); + if (currentSelectedCategoryActor) { + this._activeContainer = this.categoriesBox; + this._activeActor = currentSelectedCategoryActor; } } @@ -2780,10 +2651,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.systemButtonsBox.add(button.actor, { y_align: St.Align.END, y_fill: false }); } - _scrollToButton(button, scrollBox = null) { - if (!scrollBox) - scrollBox = this.applicationsScrollBox; - + _scrollToButton(button, scrollBox = this.applicationsScrollBox) { let adj = scrollBox.get_vscroll_bar().get_adjustment(); if (button) { let box = scrollBox.get_allocation_box(); @@ -2960,6 +2828,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { actors = this.categoriesBox.get_children(); for (let i = 0; i < actors.length; i++){ let actor = actors[i]; + actor.remove_style_pseudo_class("hover") actor.style_class = "menu-category-button"; actor.show(); } @@ -2997,12 +2866,14 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } } - _select_category (name) { - if (name === this.lastSelectedCategory) + _select_category (name = null) { + if (name === this.lastSelectedCategory){ return; + } this.lastSelectedCategory = name; this._displayButtons(name || 'app'); this.closeContextMenu(false); + this._scrollToButton(null); } closeContextMenu(animate) { @@ -3214,9 +3085,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._searchTimeoutId = 0; this._activeContainer = null; this._activeActor = null; - this._selectedItemIndex = null; - this._previousTreeSelectedActor = null; - this._previousSelectedActor = null; + this._previousCategoryHoverActor = null; var acResultButtons = []; // search box autocompletion results var buttons = [] @@ -3241,11 +3110,10 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { if (buttons.length || acResultButtons.length) { this.appBoxIter.reloadVisible(); - let item_actor = this.appBoxIter.getFirstVisible(); - this._selectedItemIndex = this.appBoxIter.getAbsoluteIndexOfChild(item_actor); + this._activeActor = this.appBoxIter.getFirstVisible(); this._activeContainer = this.applicationsBox; - this._scrollToButton(item_actor._delegate); - this._buttonEnterEvent(item_actor._delegate, true); + this._scrollToButton(this._activeActor._delegate); + this._buttonEnterEvent(this._activeActor._delegate); } else { this.selectedAppTitle.set_text(""); this.selectedAppDescription.set_text(""); @@ -3259,13 +3127,12 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { let button = new SearchProviderResultButton(this, provider, results[i]); this._searchProviderButtons.push(button); this.applicationsBox.add_actor(button.actor); - if (this._selectedItemIndex === null) { + if (this._activeActor === null) { this.appBoxIter.reloadVisible(); - let item_actor = this.appBoxIter.getFirstVisible(); - this._selectedItemIndex = this.appBoxIter.getAbsoluteIndexOfChild(item_actor); + this._activeActor = this.appBoxIter.getFirstVisible(); this._activeContainer = this.applicationsBox; - if (item_actor && item_actor != this.searchEntry) { - this._buttonEnterEvent(item_actor._delegate, true); + if (this._activeActor && this._activeActor != this.searchEntry) { + this._buttonEnterEvent(this._activeActor._delegate); } } } diff --git a/files/usr/share/cinnamon/applets/notifications@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/notifications@cinnamon.org/applet.js index 0cb629b07e..ccbb110676 100644 --- a/files/usr/share/cinnamon/applets/notifications@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/notifications@cinnamon.org/applet.js @@ -201,7 +201,7 @@ class CinnamonNotificationsApplet extends Applet.TextIconApplet { if (!this.showNotificationCount) { // Don't show notification count this.set_applet_label(''); - this.clear_action.actor.hide(); + // this.clear_action.actor.hide(); } this.menu_label.label.set_text(stringify(count)); this._notificationbin.queue_relayout(); diff --git a/files/usr/share/cinnamon/applets/panel-launchers@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/panel-launchers@cinnamon.org/applet.js index 496937236f..70c86b1940 100644 --- a/files/usr/share/cinnamon/applets/panel-launchers@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/panel-launchers@cinnamon.org/applet.js @@ -282,12 +282,22 @@ class PanelAppLauncher extends DND.LauncherDraggable { _updateIconSize() { let node = this._iconBox.get_theme_node(); - let maxHeight = this._iconBox.height - node.get_vertical_padding(); - let maxWidth = this._iconBox.width - node.get_horizontal_padding(); - let smallestDim = Math.min(maxHeight, maxWidth) / global.ui_scale; + let enforcedSize = 0; - if (smallestDim < this.icon.get_icon_size()) { - this.icon.set_icon_size(smallestDim); + if (this._iconBox.height > 0) { + enforcedSize = this._iconBox.height - node.get_vertical_padding(); + } + else + if (this._iconBox.width > 0) { + enforcedSize = this._iconBox.width - node.get_horizontal_padding(); + } + else + { + enforcedSize = -1; + } + + if (enforcedSize < this.icon.get_icon_size()) { + this.icon.set_icon_size(enforcedSize); } } @@ -672,9 +682,11 @@ class CinnamonPanelLaunchersApplet extends Applet.Applet { showAddLauncherDialog(timestamp, launcher){ if (launcher) { - Util.spawnCommandLine("cinnamon-desktop-editor -mcinnamon-launcher -f" + launcher.getId() + " " + this.settings.file.get_path()); + Util.spawnCommandLine("cinnamon-desktop-editor -mcinnamon-launcher --icon-size %d -f %s %s" + .format(this.icon_size, launcher.getId(), this.settings.file.get_path())); } else { - Util.spawnCommandLine("cinnamon-desktop-editor -mcinnamon-launcher " + this.settings.file.get_path()); + Util.spawnCommandLine("cinnamon-desktop-editor -mcinnamon-launcher --icon-size %d %s" + .format(this.icon_size, this.settings.file.get_path())) } } diff --git a/files/usr/share/cinnamon/applets/sound@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/sound@cinnamon.org/applet.js index 9bdd5a036d..128ba1defb 100644 --- a/files/usr/share/cinnamon/applets/sound@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/sound@cinnamon.org/applet.js @@ -333,14 +333,15 @@ class Seeker extends Slider.Slider { this._timerTicker = 0; this._getPosition(); } - return true; + return GLib.SOURCE_CONTINUE; } - return false; + this._timeoutId = 0; + return GLib.SOURCE_REMOVE; } _updateTimer() { - if (this._timeoutId !== 0) { + if (this._timeoutId > 0) { Mainloop.source_remove(this._timeoutId); this._timeoutId = 0; } @@ -403,12 +404,14 @@ class Seeker extends Slider.Slider { } destroy() { - if (this._timeoutId != 0) { + if (this._timeoutId > 0) { Mainloop.source_remove(this._timeoutId); this._timeoutId = 0; } - if (this._seekChangedId) + if (this._seekChangedId) { this._mediaServerPlayer.disconnectSignal(this._seekChangedId); + this._seekChangedId = 0; + } this.disconnectAll(); this._mediaServerPlayer = null; @@ -434,16 +437,19 @@ class StreamMenuSection extends PopupMenu.PopupMenuSection { } // Special cases - if(name === "Banshee") { + if (name === "Banshee") { iconName = "banshee"; } else if (name === "Spotify") { iconName = "spotify"; } - if(name === "VBox") { + else if (name === "VBox") { name = "Virtualbox"; iconName = "virtualbox"; } + else if (name === "Firefox") { + iconName = "firefox"; + } else if (iconName === "audio") { iconName = "audio-x-generic"; } @@ -1101,6 +1107,7 @@ class CinnamonSoundApplet extends Applet.TextIconApplet { this.unregisterSystrayIcons(); if (this._iconTimeoutId) { Mainloop.source_remove(this._iconTimeoutId); + this._iconTimeoutId = 0; } this._dbus.disconnectSignal(this._ownerChangedId); @@ -1224,7 +1231,7 @@ class CinnamonSoundApplet extends Applet.TextIconApplet { setIcon(icon, source) { if (this._iconTimeoutId) { Mainloop.source_remove(this._iconTimeoutId); - this._iconTimeoutId = null; + this._iconTimeoutId = 0; } //save the icon @@ -1240,7 +1247,6 @@ class CinnamonSoundApplet extends Applet.TextIconApplet { //if we have an active player, but are changing the volume, show the output icon and after three seconds change back to the player icon this.set_applet_icon_symbolic_name(this._outputIcon); this._iconTimeoutId = Mainloop.timeout_add_seconds(OUTPUT_ICON_SHOW_TIME_SECONDS, () => { - this._iconTimeoutId = null; this.setIcon(); }); } else { diff --git a/files/usr/share/cinnamon/applets/trash@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/trash@cinnamon.org/applet.js index eb51d1435a..13e3deb992 100644 --- a/files/usr/share/cinnamon/applets/trash@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/trash@cinnamon.org/applet.js @@ -1,6 +1,7 @@ const St = imports.gi.St; const ModalDialog = imports.ui.modalDialog; const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; const Lang = imports.lang; const Applet = imports.ui.applet; const PopupMenu = imports.ui.popupMenu; @@ -16,17 +17,20 @@ class CinnamonTrashApplet extends Applet.IconApplet { this.set_applet_icon_symbolic_name("user-trash"); this.set_applet_tooltip(_("Trash")); - this.trash_path = 'trash:///'; - this.trash_directory = Gio.file_new_for_uri(this.trash_path); - - this._initContextMenu(); - this.trash_changed_timeout = 0; - this._onTrashChange(); - - this.monitor = this.trash_directory.monitor_directory(0, null); - this.monitor.connect('changed', Lang.bind(this, this._onTrashChange)); + const vfs = Gio.Vfs.get_default() + if (vfs.get_supported_uri_schemes().includes("trash")) { + this._initContextMenu(); + + this.trash_path = 'trash:///'; + this.trash_directory = Gio.file_new_for_uri(this.trash_path); + this._onTrashChange(); + } else { + this.trash_directory = null; + global.logWarning("trash@cinnamon.org: No trash support, disabling.") + this.actor.hide(); + } } _initContextMenu() { @@ -47,6 +51,28 @@ class CinnamonTrashApplet extends Applet.IconApplet { this._openTrash(); } + on_applet_added_to_panel() { + if (this.trash_directory == null) { + return; + } + + this.monitor = this.trash_directory.monitor_directory(0, null); + this.monitor_changed_id = this.monitor.connect('changed', Lang.bind(this, this._onTrashChange)); + } + + on_applet_removed_from_panel() { + if (this.trash_directory == null) { + return; + } + + if (this.monitor_changed_id > 0) { + this.monitor.disconnect(this.monitor_changed_id); + this.monitor_changed_id = 0; + } + + this.moniitor = 0; + } + _openTrash() { Gio.app_info_launch_default_for_uri(this.trash_directory.get_uri(), null); } @@ -57,19 +83,40 @@ class CinnamonTrashApplet extends Applet.IconApplet { this.trash_changed_timeout = 0; } - this.trash_changed_timeout = Mainloop.timeout_add_seconds(1, Lang.bind(this, this._onTrashChangeTimeout)); + this.trash_changed_timeout = Mainloop.idle_add(Lang.bind(this, this._onTrashChangeTimeout), GLib.PRIORITY_LOW); } _onTrashChangeTimeout() { this.trash_changed_timeout = 0; - if (this.trash_directory.query_exists(null)) { - let children = this.trash_directory.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null); - if (children.next_file(null) == null) { - this.set_applet_icon_symbolic_name("user-trash"); - } else { - this.set_applet_icon_symbolic_name("user-trash-full"); - } - children.close(null); + const children = this.trash_directory.enumerate_children_async( + 'standard::*', + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_LOW, + null, + (...args) => this._enumerateChildrenCallback(...args) + ); + + return GLib.SOURCE_REMOVE; + } + + _enumerateChildrenCallback(file, result) { + try { + const child_info = file.enumerate_children_finish(result); + child_info.next_files_async( + 1, + GLib.PRIORITY_LOW, + null, + (enumerator, res) => { + file = enumerator.next_files_finish(res); + if (file.length > 0) { + this.set_applet_icon_symbolic_name("user-trash-full"); + } else { + this.set_applet_icon_symbolic_name("user-trash"); + } + } + ); + } catch(e) { + global.logWarning(`Could not check trash uri: ${e.message}`); } } diff --git a/files/usr/share/cinnamon/applets/window-list@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/window-list@cinnamon.org/applet.js index 15fe404936..8078856259 100644 --- a/files/usr/share/cinnamon/applets/window-list@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/window-list@cinnamon.org/applet.js @@ -272,7 +272,7 @@ class AppMenuButton { this.drawLabel = false; this.labelVisiblePref = false; this._signals = new SignalManager.SignalManager(); - this.xid = global.screen.get_xwindow_for_window(metaWindow); + this.xid = metaWindow.get_xwindow(); this._flashTimer = null; if (this._applet.orientation == St.Side.TOP) @@ -371,7 +371,7 @@ class AppMenuButton { this._signals.connect(this.metaWindow, 'notify::title', this.setDisplayTitle, this); this._signals.connect(this.metaWindow, "notify::minimized", this.setDisplayTitle, this); - this._signals.connect(this.metaWindow, "notify::tile-type", this.setDisplayTitle, this); + this._signals.connect(this.metaWindow, "notify::tile-mode", this.setDisplayTitle, this); this._signals.connect(this.metaWindow, "notify::icon", this.setIcon, this); this._signals.connect(this.metaWindow, "notify::appears-focused", this.onFocus, this); this._signals.connect(this.metaWindow, "unmanaged", this.onUnmanaged, this); @@ -1057,9 +1057,9 @@ class CinnamonWindowListApplet extends Applet.Applet { this.settings.bind("last-window-order", "lastWindowOrder", null); this.signals.connect(global.display, 'window-created', this._onWindowAddedAsync, this); - this.signals.connect(global.screen, 'window-monitor-changed', this._onWindowMonitorChanged, this); - this.signals.connect(global.screen, 'window-workspace-changed', this._onWindowWorkspaceChanged, this); - this.signals.connect(global.screen, 'window-skip-taskbar-changed', this._onWindowSkipTaskbarChanged, this); + this.signals.connect(global.display, 'window-monitor-changed', this._onWindowMonitorChanged, this); + this.signals.connect(global.display, 'window-workspace-changed', this._onWindowWorkspaceChanged, this); + this.signals.connect(global.display, 'window-skip-taskbar-changed', this._onWindowSkipTaskbarChanged, this); this.signals.connect(Main.panelManager, 'monitors-changed', this._updateWatchedMonitors, this); this.signals.connect(global.window_manager, 'switch-workspace', this._refreshAllItems, this); this.signals.connect(Cinnamon.WindowTracker.get_default(), "window-app-changed", this._onWindowAppChanged, this); @@ -1157,16 +1157,16 @@ class CinnamonWindowListApplet extends Applet.Applet { this.manager.set_spacing(spacing * global.ui_scale); } - _onWindowAddedAsync(screen, metaWindow, monitor) { - Mainloop.timeout_add(20, Lang.bind(this, this._onWindowAdded, screen, metaWindow, monitor)); + _onWindowAddedAsync(display, metaWindow, monitor) { + Mainloop.timeout_add(20, Lang.bind(this, this._onWindowAdded, display, metaWindow, monitor)); } - _onWindowAdded(screen, metaWindow, monitor) { + _onWindowAdded(display, metaWindow, monitor) { if (this._shouldAdd(metaWindow)) this._addWindow(metaWindow, false); } - _onWindowMonitorChanged(screen, metaWindow, monitor) { + _onWindowMonitorChanged(display, metaWindow, monitor) { if (this._shouldAdd(metaWindow)) this._addWindow(metaWindow, false); else @@ -1180,7 +1180,7 @@ class CinnamonWindowListApplet extends Applet.Applet { this._refreshItem(window); } - _onWindowWorkspaceChanged(screen, metaWindow, metaWorkspace) { + _onWindowWorkspaceChanged(display, metaWindow, metaWorkspace) { this._refreshItemByMetaWindow(metaWindow); } @@ -1188,13 +1188,13 @@ class CinnamonWindowListApplet extends Applet.Applet { this._refreshItemByMetaWindow(metaWindow); } - _onWindowSkipTaskbarChanged(screen, metaWindow) { + _onWindowSkipTaskbarChanged(display, metaWindow) { if (metaWindow && metaWindow.is_skip_taskbar()) { this._removeWindow(metaWindow); return; } - this._onWindowAdded(screen, metaWindow, 0); + this._onWindowAdded(display, metaWindow, 0); } _updateAttentionGrabber() { diff --git a/files/usr/share/cinnamon/applets/windows-quick-list@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/windows-quick-list@cinnamon.org/applet.js index 4454f4ed9c..923de8743f 100644 --- a/files/usr/share/cinnamon/applets/windows-quick-list@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/windows-quick-list@cinnamon.org/applet.js @@ -62,10 +62,10 @@ class CinnamonWindowsQuickListApplet extends Applet.IconApplet { let empty_menu = true; let tracker = Cinnamon.WindowTracker.get_default(); - for (let wks = 0; wks < global.screen.n_workspaces; ++wks) { + for (let wks = 0; wks < global.workspace_manager.n_workspaces; ++wks) { // construct a list with all windows let workspace_name = Main.getWorkspaceName(wks); - let metaWorkspace = global.screen.get_workspace_by_index(wks); + let metaWorkspace = global.workspace_manager.get_workspace_by_index(wks); let windows = metaWorkspace.list_windows(); let sticky_windows = windows.filter(function(w) { return !w.is_skip_taskbar() && w.is_on_all_workspaces(); @@ -103,12 +103,12 @@ class CinnamonWindowsQuickListApplet extends Applet.IconApplet { if (wks > 0) { this._addItem(new PopupMenu.PopupSeparatorMenuItem()); } - if (global.screen.n_workspaces > 1) { + if (global.workspace_manager.n_workspaces > 1) { let item = new WindowMenuItem(null, workspace_name); item.actor.reactive = false; item.actor.can_focus = false; item.label.add_style_class_name('popup-subtitle-menu-item'); - if (wks == global.screen.get_active_workspace().index()) { + if (wks == global.workspace_manager.get_active_workspace().index()) { item.setShowDot(true); } this._addItem(item); diff --git a/files/usr/share/cinnamon/applets/workspace-switcher@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/workspace-switcher@cinnamon.org/applet.js index 0c8c6e7280..19dcf23e34 100644 --- a/files/usr/share/cinnamon/applets/workspace-switcher@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/workspace-switcher@cinnamon.org/applet.js @@ -334,6 +334,8 @@ class CinnamonWorkspaceSwitcher extends Applet.Applet { this.actor.connect('scroll-event', this.hook.bind(this)); + this.signals.connect(Main.layoutManager, 'monitors-changed', this.onWorkspacesUpdated, this); + this.queueCreateButtons(); global.workspace_manager.connect('notify::n-workspaces', () => { this.onWorkspacesUpdated() }); global.workspace_manager.connect('workspaces-reordered', () => { this.onWorkspacesUpdated() }); diff --git a/files/usr/share/cinnamon/cinnamon-desktop-editor/cinnamon-desktop-editor.py b/files/usr/share/cinnamon/cinnamon-desktop-editor/cinnamon-desktop-editor.py index 33579e30fd..a8f8ef507d 100755 --- a/files/usr/share/cinnamon/cinnamon-desktop-editor/cinnamon-desktop-editor.py +++ b/files/usr/share/cinnamon/cinnamon-desktop-editor/cinnamon-desktop-editor.py @@ -8,6 +8,7 @@ import shutil import subprocess from setproctitle import setproctitle +from pathlib import Path import gi gi.require_version("Gtk", "3.0") @@ -56,7 +57,7 @@ def ask(msg): class ItemEditor(object): ui_file = None - def __init__(self, item_path=None, callback=None, destdir=None): + def __init__(self, item_path=None, callback=None, destdir=None, icon_size=24): self.builder = Gtk.Builder() self.builder.set_translation_domain('cinnamon') # let it translate! self.builder.add_from_file(self.ui_file) @@ -66,9 +67,13 @@ def __init__(self, item_path=None, callback=None, destdir=None): self.dialog.connect('response', self.on_response) + self.starting_icon = None self.icon_chooser = self.builder.get_object('icon-chooser') self.icon_chooser.get_dialog().set_property("allow-paths", True) + self.icon_size = icon_size + self.icon_chooser.set_icon_size(self.get_gtk_size_for_pixels(icon_size)) + self.build_ui() self.item_path = item_path @@ -76,6 +81,18 @@ def __init__(self, item_path=None, callback=None, destdir=None): self.check_custom_path() self.resync_validity() + def get_gtk_size_for_pixels(self, icon_size): + i = 0 + while True: + try: + valid, width, height = Gtk.IconSize.lookup(Gtk.IconSize(i)) + if height > icon_size: + return Gtk.IconSize(i) + except ValueError: + return Gtk.IconSize.DIALOG + + i += 1 + def build_ui(self): raise NotImplementedError() @@ -139,6 +156,7 @@ def set_icon(self, name): else: print(val) self.icon_chooser.set_icon(val) + self.starting_icon = val print('icon:', self.icon_chooser.get_icon()) def load(self): @@ -178,8 +196,6 @@ def on_response(self, dialog, response): self.callback(True, self.item_path) else: self.callback(False, self.item_path) - self.dialog.destroy() - class LauncherEditor(ItemEditor): ui_file = '/usr/share/cinnamon/cinnamon-desktop-editor/launcher-editor.ui' @@ -295,13 +311,37 @@ def load(self): self.set_icon("Icon") def get_keyfile_edits(self): + icon_theme = Gtk.IconTheme.get_default() + icon = self.icon_chooser.get_icon() + + if icon != self.starting_icon: + info = icon_theme.lookup_icon(icon, self.icon_size, 0) + if info: + filename = info.get_filename() + if not self.in_hicolor(filename): + icon = filename + return dict(Name=self.builder.get_object('name-entry').get_text(), Exec=self.builder.get_object('exec-entry').get_text(), Comment=self.builder.get_object('comment-entry').get_text(), Terminal=self.builder.get_object('terminal-check').get_active(), - Icon=self.icon_chooser.get_icon(), + Icon=icon, Type="Application") + def in_hicolor(self, path): + datadirs = GLib.get_system_data_dirs() + + for datadir in datadirs: + hicolor_folder = Path(os.path.join(datadir, "icons", "hicolor")) + icon_path = Path(path) + try: + if icon_path.relative_to(hicolor_folder) is not None: + return True + except ValueError: + pass + + return False + def pick_exec(self, button): chooser = Gtk.FileChooserDialog(title=_("Choose a command"), parent=self.dialog, @@ -320,6 +360,7 @@ def __init__(self): parser.add_option("-d", "--directory", dest="destination_directory", help="Destination directory of the new launcher", metavar="DEST_DIR") parser.add_option("-f", "--file", dest="desktop_file", help="Name of desktop file (i.e. gnome-terminal.desktop)", metavar="DESKTOP_NAME") parser.add_option("-m", "--mode", dest="mode", default=None, help="Mode to run in: launcher, directory, panel-launcher or nemo-launcher") + parser.add_option("-i", "--icon-size", dest="icon_size", type=int, default=24, help="Size to set the icon picker for (panel-launcher only)") (options, args) = parser.parse_args() if not options.mode: @@ -343,6 +384,7 @@ def __init__(self): if options.mode == "cinnamon-launcher": self.json_path = args[0] + self.icon_size = options.icon_size if self.desktop_file is not None: self.get_desktop_path() @@ -354,7 +396,7 @@ def __init__(self): editor = LauncherEditor(self.orig_file, self.launcher_cb) editor.dialog.show_all() elif self.mode == "cinnamon-launcher": - editor = CinnamonLauncherEditor(self.orig_file, self.panel_launcher_cb) + editor = CinnamonLauncherEditor(self.orig_file, self.panel_launcher_cb, icon_size=self.icon_size) editor.dialog.show_all() elif self.mode == "nemo-launcher": editor = LauncherEditor(self.orig_file, self.nemo_launcher_cb, self.dest_dir) diff --git a/files/usr/share/cinnamon/cinnamon-menu-editor/cme/util.py b/files/usr/share/cinnamon/cinnamon-menu-editor/cme/util.py index 1343b9cbf9..4c6f7a8bbb 100644 --- a/files/usr/share/cinnamon/cinnamon-menu-editor/cme/util.py +++ b/files/usr/share/cinnamon/cinnamon-menu-editor/cme/util.py @@ -20,6 +20,8 @@ import xml.dom.minidom import uuid import sys +from typing import Optional + if sys.version_info[:2] >= (3, 8): from collections.abc import Sequence else: @@ -29,7 +31,7 @@ DESKTOP_GROUP = GLib.KEY_FILE_DESKTOP_GROUP KEY_FILE_FLAGS = GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS -def fillKeyFile(keyfile, items): +def fillKeyFile(keyfile, items) -> None: for key, item in items.items(): if item is None: continue @@ -57,14 +59,14 @@ def getUniqueFileId(name, extension): break return filename -def getUniqueRedoFile(filepath): +def getUniqueRedoFile(filepath) -> str: while 1: new_filepath = filepath + '.redo-' + str(uuid.uuid1()) if not os.path.isfile(new_filepath): break return new_filepath -def getUniqueUndoFile(filepath): +def getUniqueUndoFile(filepath) -> str: filename, extension = os.path.split(filepath)[1].rsplit('.', 1) while 1: if extension == 'desktop': @@ -78,46 +80,46 @@ def getUniqueUndoFile(filepath): break return new_filepath -def getItemPath(file_id): +def getItemPath(file_id) -> Optional[str]: for path in GLib.get_system_data_dirs(): file_path = os.path.join(path, 'applications', file_id) if os.path.isfile(file_path): return file_path return None -def getUserItemPath(): +def getUserItemPath() -> str: item_dir = os.path.join(GLib.get_user_data_dir(), 'applications') if not os.path.isdir(item_dir): os.makedirs(item_dir) return item_dir -def getDirectoryPath(file_id): +def getDirectoryPath(file_id) -> Optional[str]: for path in GLib.get_system_data_dirs(): file_path = os.path.join(path, 'desktop-directories', file_id) if os.path.isfile(file_path): return file_path return None -def getUserDirectoryPath(): +def getUserDirectoryPath() -> str: menu_dir = os.path.join(GLib.get_user_data_dir(), 'desktop-directories') if not os.path.isdir(menu_dir): os.makedirs(menu_dir) return menu_dir -def getUserMenuPath(): +def getUserMenuPath() -> str: menu_dir = os.path.join(GLib.get_user_config_dir(), 'menus') if not os.path.isdir(menu_dir): os.makedirs(menu_dir) return menu_dir -def getSystemMenuPath(file_id): +def getSystemMenuPath(file_id) -> Optional[str]: for path in GLib.get_system_config_dirs(): file_path = os.path.join(path, 'menus', file_id) if os.path.isfile(file_path): return file_path return None -def getUserMenuXml(tree): +def getUserMenuXml(tree) -> str: system_file = getSystemMenuPath(os.path.basename(tree.get_canonical_menu_path())) name = tree.get_root_directory().get_menu_id() menu_xml = "\n" @@ -129,7 +131,7 @@ class SurfaceWrapper: def __init__(self, surface): self.surface = surface -def getIcon(item, widget): +def getIcon(item, widget) -> SurfaceWrapper: wrapper = SurfaceWrapper(None) pixbuf = None if item is None: @@ -163,7 +165,7 @@ def getIcon(item, widget): wrapper.surface = Gdk.cairo_surface_create_from_pixbuf (pixbuf, widget.get_scale_factor(), widget.get_window()) return wrapper -def removeWhitespaceNodes(node): +def removeWhitespaceNodes(node) -> None: remove_list = [] for child in node.childNodes: if child.nodeType == xml.dom.minidom.Node.TEXT_NODE: diff --git a/files/usr/share/cinnamon/cinnamon-settings/appearance-dark.svg b/files/usr/share/cinnamon/cinnamon-settings/appearance-dark.svg new file mode 100644 index 0000000000..092417d993 --- /dev/null +++ b/files/usr/share/cinnamon/cinnamon-settings/appearance-dark.svg @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/files/usr/share/cinnamon/cinnamon-settings/appearance-light.svg b/files/usr/share/cinnamon/cinnamon-settings/appearance-light.svg new file mode 100644 index 0000000000..ca57c723f0 --- /dev/null +++ b/files/usr/share/cinnamon/cinnamon-settings/appearance-light.svg @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/files/usr/share/cinnamon/cinnamon-settings/appearance-mixed.svg b/files/usr/share/cinnamon/cinnamon-settings/appearance-mixed.svg new file mode 100644 index 0000000000..2dd81a3599 --- /dev/null +++ b/files/usr/share/cinnamon/cinnamon-settings/appearance-mixed.svg @@ -0,0 +1,286 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/files/usr/share/cinnamon/cinnamon-settings/bin/ChooserButtonWidgets.py b/files/usr/share/cinnamon/cinnamon-settings/bin/ChooserButtonWidgets.py index 783e850946..baa8b3752f 100644 --- a/files/usr/share/cinnamon/cinnamon-settings/bin/ChooserButtonWidgets.py +++ b/files/usr/share/cinnamon/cinnamon-settings/bin/ChooserButtonWidgets.py @@ -118,13 +118,11 @@ def create_scaled_surface(self, path): try: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path, w, h) + if pixbuf: + return Gdk.cairo_surface_create_from_pixbuf(pixbuf, self.scale) except GLib.Error as e: print("Could not load thumbnail file '%s': %s" % (path, e.message)) - - if pixbuf: - return Gdk.cairo_surface_create_from_pixbuf(pixbuf, self.scale) - else: - return None + return None def set_picture_from_file (self, path): surface = self.create_scaled_surface(path) diff --git a/files/usr/share/cinnamon/cinnamon-settings/bin/Spices.py b/files/usr/share/cinnamon/cinnamon-settings/bin/Spices.py index 3cfab25036..d576496564 100644 --- a/files/usr/share/cinnamon/cinnamon-settings/bin/Spices.py +++ b/files/usr/share/cinnamon/cinnamon-settings/bin/Spices.py @@ -784,11 +784,11 @@ def disable_extension(self, uuid): new_list = [] for enabled_extension in enabled_extensions: if self.collection_type == 'applet': - enabled_uuid = enabled_extension.split(':')[3].strip('!') + enabled_uuid = enabled_extension.split(':')[3].lstrip('!') elif self.collection_type == 'desklet': - enabled_uuid = enabled_extension.split(':')[0].strip('!') + enabled_uuid = enabled_extension.split(':')[0].lstrip('!') else: - enabled_uuid = enabled_extension + enabled_uuid = enabled_extension.lstrip('!') if enabled_uuid != uuid: new_list.append(enabled_extension) diff --git a/files/usr/share/cinnamon/cinnamon-settings/bin/util.py b/files/usr/share/cinnamon/cinnamon-settings/bin/util.py index e20dff0e44..e365e60bbe 100644 --- a/files/usr/share/cinnamon/cinnamon-settings/bin/util.py +++ b/files/usr/share/cinnamon/cinnamon-settings/bin/util.py @@ -18,20 +18,20 @@ def strip_syspath_locals(): gsound_context = None -def _get_gsound_context(): +def _get_gsound_context() -> GSound.Context: global gsound_context if gsound_context is None: gsound_context = GSound.Context() gsound_context.init() return gsound_context -def play_sound_name(name, channel = None): +def play_sound_name(name, channel = None) -> None: params = {GSound.ATTR_EVENT_ID: name, GSound.ATTR_MEDIA_ROLE: "test"} if channel is not None: params[GSound.ATTR_CANBERRA_FORCE_CHANNEL] = channel _get_gsound_context().play_simple(params) -def play_sound_file(path, channel = None): +def play_sound_file(path, channel = None) -> None: params = {GSound.ATTR_MEDIA_FILENAME: path, GSound.ATTR_MEDIA_ROLE: "test"} if channel is not None: params[GSound.ATTR_CANBERRA_FORCE_CHANNEL] = channel diff --git a/files/usr/share/cinnamon/cinnamon-settings/color_dot.svg b/files/usr/share/cinnamon/cinnamon-settings/color_dot.svg new file mode 100644 index 0000000000..da49247810 --- /dev/null +++ b/files/usr/share/cinnamon/cinnamon-settings/color_dot.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/files/usr/share/cinnamon/cinnamon-settings/modules/cs_info.py b/files/usr/share/cinnamon/cinnamon-settings/modules/cs_info.py index ce4f8c5d60..96d579c47b 100755 --- a/files/usr/share/cinnamon/cinnamon-settings/modules/cs_info.py +++ b/files/usr/share/cinnamon/cinnamon-settings/modules/cs_info.py @@ -175,7 +175,7 @@ def on_module_selected(self): if systemIcon != "": try: if "/" in systemIcon: - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale (systemIconPath, -1, 100, True) + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(systemIcon, -1, 100, True) systemIcon = Gtk.Image.new_from_pixbuf(pixbuf) else: systemIcon = Gtk.Image.new_from_icon_name(systemIcon, Gtk.IconSize.DIALOG) @@ -226,8 +226,8 @@ def on_copy_clipboard_button_clicked(self, button): subproc = Gio.Subprocess.new(['inxi', '-Fxxrzc0'], Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE) subproc.wait_check_async(None, self.on_copy_clipboard_complete) except Exception as e: - print ("An error occurred while copying the system information to clipboard") - print (e) + print("An error occurred while copying the system information to clipboard") + print(e) def on_copy_clipboard_complete(self, subproc, result): def _convert_stream_to_string(stream): diff --git a/files/usr/share/cinnamon/cinnamon-settings/modules/cs_themes.py b/files/usr/share/cinnamon/cinnamon-settings/modules/cs_themes.py index e64f89798c..7acfb82842 100755 --- a/files/usr/share/cinnamon/cinnamon-settings/modules/cs_themes.py +++ b/files/usr/share/cinnamon/cinnamon-settings/modules/cs_themes.py @@ -1,8 +1,9 @@ #!/usr/bin/python3 import os +import json -from gi.repository import Gtk +from gi.repository import Gtk, GdkPixbuf from xapp.GSettingsWidgets import * from CinnamonGtkSettings import CssRange, CssOverrideSwitch, GtkSettingsSwitch, PreviewWidget, Gtk2ScrollbarSizeEditor @@ -29,6 +30,54 @@ os.path.join(GLib.get_home_dir(), ".themes") ] + [os.path.join(datadir, "themes") for datadir in GLib.get_system_data_dirs()] + +class Style: + def __init__(self, json_obj): + self.name = json_obj["name"] + self.modes = {} + self.default_mode = None + +class Mode: + def __init__(self, name): + self.name = name + self.default_variant = None + self.variants = [] + + def get_variant_by_name(self, name): + for variant in self.variants: + if name == variant.name: + return variant + + return None + +class Variant: + def __init__(self, json_obj): + self.name = json_obj["name"] + self.gtk_theme = None + self.icon_theme = None + self.cinnamon_theme = None + self.cursor_theme = None + self.color = "#000000" + self.color2 = "#000000" + if "themes" in json_obj: + themes = json_obj["themes"] + self.gtk_theme = themes + self.icon_theme = themes + self.cinnamon_theme = themes + self.cursor_theme = themes + if "gtk" in json_obj: + self.gtk_theme = json_obj["gtk"] + if "icons" in json_obj: + self.icon_theme = json_obj["icons"] + if "cinnamon" in json_obj: + self.cinnamon_theme = json_obj["cinnamon"] + if "cursor" in json_obj: + self.cursor_theme = json_obj["cursor"] + self.color = json_obj["color"] + self.color2 = self.color + if "color2" in json_obj: + self.color2 = json_obj["color2"] + class Module: comment = _("Manage themes to change how your desktop looks") name = "themes" @@ -42,10 +91,80 @@ def __init__(self, content_box): self.sidePage = sidePage self.refreshing = False # flag to ensure we only refresh once at any given moment + def refresh_themes(self): + # Find all installed themes + self.gtk_themes = [] + self.gtk_theme_names = set() + self.icon_theme_names = [] + self.cinnamon_themes = [] + self.cinnamon_theme_names = set() + self.cursor_themes = [] + self.cursor_theme_names = set() + + # Gtk themes -- Only shows themes that have variations for gtk+-3 and gtk+-2 + for (name, path) in walk_directories(THEME_FOLDERS, self.filter_func_gtk_dir, return_directories=True): + for theme in self.gtk_themes: + if name == theme[0]: + if path == THEME_FOLDERS[0]: + continue + else: + self.gtk_themes.remove(theme) + self.gtk_theme_names.add(name) + self.gtk_themes.append((name, path)) + self.gtk_themes.sort(key=lambda a: a[0].lower()) + + # Cinnamon themes + for (name, path) in walk_directories(THEME_FOLDERS, lambda d: os.path.exists(os.path.join(d, "cinnamon")), return_directories=True): + for theme in self.cinnamon_themes: + if name == theme[0]: + if path == THEME_FOLDERS[0]: + continue + else: + self.cinnamon_themes.remove(theme) + self.cinnamon_theme_names.add(name) + self.cinnamon_themes.append((name, path)) + self.cinnamon_themes.sort(key=lambda a: a[0].lower()) + + # Icon themes + walked = walk_directories(ICON_FOLDERS, lambda d: os.path.isdir(d), return_directories=True) + valid = [] + for directory in walked: + if directory[0] in ("gnome", "hicolor"): + continue + path = os.path.join(directory[1], directory[0], "index.theme") + if os.path.exists(path): + try: + for line in list(open(path)): + if line.startswith("Directories="): + valid.append(directory) + break + except Exception as e: + print (e) + valid.sort(key=lambda a: a[0].lower()) + for (name, path) in valid: + if name not in self.icon_theme_names: + self.icon_theme_names.append(name) + + # Cursor themes + for (name, path) in walk_directories(ICON_FOLDERS, lambda d: os.path.isdir(d) and os.path.exists(os.path.join(d, "cursors")), return_directories=True): + for theme in self.cursor_themes: + if name == theme[0]: + if path == ICON_FOLDERS[0]: + continue + else: + self.cursor_themes.remove(theme) + self.cursor_theme_names.add(name) + self.cursor_themes.append((name, path)) + self.cursor_themes.sort(key=lambda a: a[0].lower()) + def on_module_selected(self): if not self.loaded: print("Loading Themes module") + self.refresh_themes() + + self.ui_ready = True + self.spices = Spice_Harvester('theme', self.window) self.sidePage.stack = SettingsStack() @@ -61,10 +180,57 @@ def on_module_selected(self): self.theme_chooser = self.create_button_chooser(self.settings, 'gtk-theme', 'themes', 'gtk-3.0', button_picture_size=35, menu_pictures_size=35, num_cols=4) self.cinnamon_chooser = self.create_button_chooser(self.cinnamon_settings, 'name', 'themes', 'cinnamon', button_picture_size=60, menu_pictures_size=60*self.scale, num_cols=4) + selected_meta_theme = None + + gladefile = "/usr/share/cinnamon/cinnamon-settings/themes.ui" + builder = Gtk.Builder() + builder.set_translation_domain('cinnamon') + builder.add_from_file(gladefile) + page = builder.get_object("page_themes") + page.show() + + self.style_combo = builder.get_object("style_combo") + self.mixed_button = builder.get_object("mixed_button") + self.dark_button = builder.get_object("dark_button") + self.light_button = builder.get_object("light_button") + self.color_box = builder.get_object("color_box") + self.customize_button = builder.get_object("customize_button") + self.preset_button = builder.get_object("preset_button") + self.color_label = builder.get_object("color_label") + self.main_stack = builder.get_object("main_stack") + self.custom_stack = builder.get_object("custom_stack") + self.active_style = None + self.active_mode_name = None + self.active_variant = None + + # HiDPI support + for mode in ["mixed", "dark", "light"]: + path = f"/usr/share/cinnamon/cinnamon-settings/appearance-{mode}.svg" + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path, 112*self.scale, 80*self.scale) + surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, self.scale) + builder.get_object(f"image_{mode}").set_from_surface(surface) + + self.color_dot_svg = "" + with open("/usr/share/cinnamon/cinnamon-settings/color_dot.svg") as f: + self.color_dot_svg = f.read() + + self.reset_look_ui() + + if self.active_variant is None: + self.main_stack.set_visible_child_name("custom_page") + + self.mixed_button.connect("clicked", self.on_mode_button_clicked, "mixed") + self.dark_button.connect("clicked", self.on_mode_button_clicked, "dark") + self.light_button.connect("clicked", self.on_mode_button_clicked, "light") + self.customize_button.connect("clicked", self.on_customize_button_clicked) + self.style_combo.connect("changed", self.on_style_combo_changed) + + self.sidePage.stack.add_named(page, "themes") + page = SettingsPage() - self.sidePage.stack.add_titled(page, "themes", _("Themes")) + self.custom_stack.add_titled(page, "themes", _("Themes")) - settings = page.add_section(_("Themes")) + settings = page.add_section() widget = self.make_group(_("Mouse Pointer"), self.cursor_chooser) settings.add_row(widget) @@ -78,11 +244,17 @@ def on_module_selected(self): widget = self.make_group(_("Desktop"), self.cinnamon_chooser) settings.add_row(widget) + button = Gtk.Button() + button.set_label(_("Simplified settings...")) + button.set_halign(Gtk.Align.END) + button.connect("clicked", self.on_preset_button_clicked) + page.add(button) + page = DownloadSpicesPage(self, 'theme', self.spices, self.window) - self.sidePage.stack.add_titled(page, 'download', _("Add/Remove")) + self.custom_stack.add_titled(page, 'download', _("Add/Remove")) page = SettingsPage() - self.sidePage.stack.add_titled(page, "options", _("Settings")) + self.custom_stack.add_titled(page, "options", _("Settings")) settings = page.add_section(_("Miscellaneous options")) @@ -95,7 +267,7 @@ def on_module_selected(self): try: import tinycss2 except: - self.refresh() + self.refresh_choosers() return settings = page.add_section(_("Scrollbar behavior")) @@ -159,7 +331,234 @@ def on_module_selected(self): # File monitors can fail when the OS runs out of file handles print(e) - self.refresh() + self.refresh_choosers() + + def is_variant_active(self, variant): + # returns whether or not the given variant corresponds to the currently selected themes + if variant.gtk_theme != self.settings.get_string("gtk-theme"): + return False + if variant.icon_theme != self.settings.get_string("icon-theme"): + return False + if variant.cinnamon_theme != self.cinnamon_settings.get_string("name"): + return False + if variant.cursor_theme != self.settings.get_string("cursor-theme"): + return False + return True + + def is_variant_valid(self, variant): + # returns whether or not the given variant is valid (i.e. made of themes which are currently installed) + if variant.gtk_theme is None: + print("No Gtk theme defined") + return False + if variant.icon_theme is None: + print("No icon theme defined") + return False + if variant.cinnamon_theme is None: + print("No Cinnamon theme defined") + return False + if variant.cursor_theme is None: + print("No cursor theme defined") + return False + if variant.gtk_theme not in self.gtk_theme_names: + print("Gtk theme not found:", variant.gtk_theme) + return False + if variant.icon_theme not in self.icon_theme_names: + print("icon theme not found:", variant.icon_theme) + return False + if variant.cinnamon_theme not in self.cinnamon_theme_names and variant.cinnamon_theme != "cinnamon": + print("Cinnamon theme not found:", variant.cinnamon_theme) + return False + if variant.cursor_theme not in self.cursor_theme_names: + print("Cursor theme not found:", variant.cursor_theme) + return False + return True + + def cleanup_ui(self): + self.mixed_button.set_state_flags(Gtk.StateFlags.NORMAL, True) + self.dark_button.set_state_flags(Gtk.StateFlags.NORMAL, True) + self.light_button.set_state_flags(Gtk.StateFlags.NORMAL, True) + self.mixed_button.set_sensitive(False) + self.dark_button.set_sensitive(False) + self.light_button.set_sensitive(False) + for child in self.color_box.get_children(): + self.color_box.remove(child) + self.color_label.hide() + model = self.style_combo.get_model() + model.clear() + + def reset_look_ui(self): + if not self.ui_ready: + return + + self.ui_ready = False + self.cleanup_ui() + + # Read the JSON files + self.styles = {} + self.style_objects = {} + self.active_style = None + self.active_mode_name = None + self.active_variant = None + + path = "/usr/share/cinnamon/styles.d" + for filename in sorted(os.listdir(path)): + if filename.endswith(".styles"): + try: + with open(os.path.join(path, filename)) as f: + json_text = json.loads(f.read()) + for style_json in json_text["styles"]: + style = Style(style_json) + for mode_name in ["mixed", "dark", "light"]: + if mode_name in style_json: + mode = Mode(mode_name) + for variant_json in style_json[mode_name]: + variant = Variant(variant_json) + if self.is_variant_valid(variant): + # Add the variant to the mode + mode.variants.append(variant) + if mode.default_variant is None: + # Assign the first variant as default + mode.default_variant = variant + if "default" in variant_json and variant_json["default"] == "true": + # Override default if specified + mode.default_variant = variant + # Add the mode to the style (if not done already) + if not mode_name in style.modes: + style.modes[mode_name] = mode + # Set it as the default mode if there's no default mode + if style.default_mode is None: + style.default_mode = mode + # Set active variant variables if the variant is active + if self.is_variant_active(variant): + self.active_style= style + self.active_mode_name = mode_name + self.active_variant = variant + # Override the default mode if specified + if "default" in style_json: + default_name = style_json["default"] + if default_name in style.modes: + style.default_mode = style.modes[default_name] + + if style.default_mode is None: + print ("No valid mode/variants found for style:", style.name) + else: + self.styles[style.name] = style + except Exception as e: + print(f"Failed to parse styles from {filename}.") + print(e) + + # Populate the style combo + for name in sorted(self.styles.keys()): + self.style_combo.append_text(name) + + if self.active_variant is not None: + style = self.active_style + mode = self.active_style.modes[self.active_mode_name] + variant = self.active_variant + print("Found active variant:", style.name, mode.name, variant.name) + # Position the style combo + model = self.style_combo.get_model() + iter = model.get_iter_first() + while (iter != None): + name = model.get_value(iter, 0) + if name == style.name: + self.style_combo.set_active_iter(iter) + break + iter = model.iter_next(iter) + # Set the mode buttons + for mode_name in ["mixed", "dark", "light"]: + if mode_name == "mixed": + button = self.mixed_button + elif mode_name == "dark": + button = self.dark_button + else: + button = self.light_button + # Set the button state + if mode_name == mode.name: + button.set_state_flags(Gtk.StateFlags.CHECKED, True) + else: + button.set_state_flags(Gtk.StateFlags.NORMAL, True) + if mode_name in style.modes: + button.set_sensitive(True) + else: + button.set_sensitive(False) + + if len(mode.variants) > 1: + # Generate the color buttons + self.color_label.show() + for variant in mode.variants: + svg = self.color_dot_svg.replace("#8cffbe", variant.color) + svg = svg.replace("#71718e", variant.color2) + svg = str.encode(svg) + stream = Gio.MemoryInputStream.new_from_bytes(GLib.Bytes.new(svg)) + pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, 22*self.scale, 22*self.scale, True, None) + surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, self.scale) + image = Gtk.Image.new_from_surface(surface) + button = Gtk.ToggleButton() + button.add(image) + button.show_all() + self.color_box.add(button) + if variant == self.active_variant: + button.set_state_flags(Gtk.StateFlags.CHECKED, True) + button.connect("clicked", self.on_color_button_clicked, variant) + else: + # Position style combo on "Custom" + self.style_combo.append_text(_("Custom")) + self.style_combo.set_active(len(self.styles.keys())) + self.ui_ready = True + + def on_customize_button_clicked(self, button): + self.set_button_chooser(self.icon_chooser, self.settings.get_string("icon-theme"), 'icons', 'icons', ICON_SIZE) + self.set_button_chooser(self.cursor_chooser, self.settings.get_string("cursor-theme"), 'icons', 'cursors', 32) + self.set_button_chooser(self.theme_chooser, self.settings.get_string("gtk-theme"), 'themes', 'gtk-3.0', 35) + self.set_button_chooser(self.cinnamon_chooser, self.cinnamon_settings.get_string("name"), 'themes', 'cinnamon', 60) + self.main_stack.set_visible_child_name("custom_page") + + def on_preset_button_clicked(self, button): + self.reset_look_ui() + self.main_stack.set_visible_child_name("preset_page") + + def on_color_button_clicked(self, button, variant): + print("Color button clicked") + self.activate_variant(variant) + + def on_mode_button_clicked(self, button, mode_name): + print("Mode button clicked") + if self.active_style is not None: + mode = self.active_style.modes[mode_name] + self.activate_mode(self.active_style, mode) + + def on_style_combo_changed(self, combobox): + if not self.ui_ready: + return + selected_name = combobox.get_active_text() + if selected_name == None or selected_name == _("Custom"): + return + print("Activating style:", selected_name) + for name in self.styles.keys(): + if name == selected_name: + style = self.styles[name] + mode = style.default_mode + self.activate_mode(style, mode) + + def activate_mode(self, style, mode): + print("Activating mode:", mode.name) + + if self.active_variant is not None: + new_same_variant = mode.get_variant_by_name(self.active_variant.name) + if new_same_variant is not None: + self.activate_variant(new_same_variant) + return + + self.activate_variant(mode.default_variant) + + def activate_variant(self, variant): + print("Activating variant:", variant.name) + self.settings.set_string("gtk-theme", variant.gtk_theme) + self.settings.set_string("icon-theme", variant.icon_theme) + self.cinnamon_settings.set_string("name", variant.cinnamon_theme) + self.settings.set_string("cursor-theme", variant.cursor_theme) + self.reset_look_ui() def on_css_override_active_changed(self, switch, pspec=None, data=None): if self.scrollbar_switch.get_active(): @@ -177,27 +576,20 @@ def on_file_changed(self, file, other, event, data): self.refreshing = True GLib.timeout_add_seconds(5, self.refresh) - def refresh(self): - choosers = [(self.cursor_chooser, "cursors", self._load_cursor_themes(), self._on_cursor_theme_selected), - (self.theme_chooser, "gtk-3.0", self._load_gtk_themes(), self._on_gtk_theme_selected), - (self.cinnamon_chooser, "cinnamon", self._load_cinnamon_themes(), self._on_cinnamon_theme_selected), - (self.icon_chooser, "icons", self._load_icon_themes(), self._on_icon_theme_selected)] - for chooser in choosers: - chooser[0].clear_menu() - chooser[0].set_sensitive(False) - chooser[0].progress = 0.0 - - chooser_obj = chooser[0] - path_suffix = chooser[1] - themes = chooser[2] - callback = chooser[3] - payload = (chooser_obj, path_suffix, themes, callback) - self.refresh_chooser(payload) + def refresh_choosers(self): + array = [(self.cursor_chooser, "cursors", self.cursor_themes, self._on_cursor_theme_selected), + (self.theme_chooser, "gtk-3.0", self.gtk_themes, self._on_gtk_theme_selected), + (self.cinnamon_chooser, "cinnamon", self.cinnamon_themes, self._on_cinnamon_theme_selected), + (self.icon_chooser, "icons", self.icon_theme_names, self._on_icon_theme_selected)] + for element in array: + chooser, path_suffix, themes, callback = element + chooser.clear_menu() + chooser.set_sensitive(False) + chooser.progress = 0.0 + self.refresh_chooser(chooser, path_suffix, themes, callback) self.refreshing = False - def refresh_chooser(self, payload): - (chooser, path_suffix, themes, callback) = payload - + def refresh_chooser(self, chooser, path_suffix, themes, callback): inc = 1.0 if len(themes) > 0: inc = 1.0 / len(themes) @@ -307,8 +699,11 @@ def make_group(self, group_label, widget, add_widget_to_size_group=True): def create_button_chooser(self, settings, key, path_prefix, path_suffix, button_picture_size, menu_pictures_size, num_cols): chooser = PictureChooserButton(num_cols=num_cols, button_picture_size=button_picture_size, menu_pictures_size=menu_pictures_size, has_button_label=True) theme = settings.get_string(key) - chooser.set_button_label(theme) - chooser.set_tooltip_text(theme) + self.set_button_chooser(chooser, theme, path_prefix, path_suffix, button_picture_size) + return chooser + + def set_button_chooser(self, chooser, theme, path_prefix, path_suffix, button_picture_size): + self.set_button_chooser_text(chooser, theme) if path_suffix == "cinnamon" and theme == "cinnamon": chooser.set_picture_from_file("/usr/share/cinnamon/theme/thumbnail.png") elif path_suffix == "icons": @@ -319,22 +714,24 @@ def create_button_chooser(self, settings, key, path_prefix, path_suffix, button_ chooser.set_picture_from_file(path) else: try: - for path in ["/usr/share/%s/%s/%s/thumbnail.png" % (path_prefix, theme, path_suffix), - os.path.expanduser("~/.%s/%s/%s/thumbnail.png" % (path_prefix, theme, path_suffix)), + for path in ([os.path.join(datadir, path_prefix, theme, path_suffix, "thumbnail.png") for datadir in GLib.get_system_data_dirs()] + + [os.path.expanduser("~/.%s/%s/%s/thumbnail.png" % (path_prefix, theme, path_suffix)), "/usr/share/cinnamon/thumbnails/%s/%s.png" % (path_suffix, theme), - "/usr/share/cinnamon/thumbnails/%s/unknown.png" % path_suffix]: + "/usr/share/cinnamon/thumbnails/%s/unknown.png" % path_suffix]): if os.path.exists(path): chooser.set_picture_from_file(path) break except: chooser.set_picture_from_file("/usr/share/cinnamon/thumbnails/%s/unknown.png" % path_suffix) - return chooser + + def set_button_chooser_text(self, chooser, theme): + chooser.set_button_label(theme) + chooser.set_tooltip_text(theme) def _on_icon_theme_selected(self, path, theme): try: self.settings.set_string("icon-theme", theme) - self.icon_chooser.set_button_label(theme) - self.icon_chooser.set_tooltip_text(theme) + self.set_button_chooser_text(self.icon_chooser, theme) except Exception as detail: print(detail) return True @@ -342,8 +739,7 @@ def _on_icon_theme_selected(self, path, theme): def _on_gtk_theme_selected(self, path, theme): try: self.settings.set_string("gtk-theme", theme) - self.theme_chooser.set_button_label(theme) - self.theme_chooser.set_tooltip_text(theme) + self.set_button_chooser_text(self.theme_chooser, theme) except Exception as detail: print(detail) return True @@ -351,8 +747,7 @@ def _on_gtk_theme_selected(self, path, theme): def _on_cursor_theme_selected(self, path, theme): try: self.settings.set_string("cursor-theme", theme) - self.cursor_chooser.set_button_label(theme) - self.cursor_chooser.set_tooltip_text(theme) + self.set_button_chooser_text(self.cursor_chooser, theme) except Exception as detail: print(detail) @@ -362,111 +757,19 @@ def _on_cursor_theme_selected(self, path, theme): def _on_cinnamon_theme_selected(self, path, theme): try: self.cinnamon_settings.set_string("name", theme) - self.cinnamon_chooser.set_button_label(theme) - self.cinnamon_chooser.set_tooltip_text(theme) + self.set_button_chooser_text(self.cinnamon_chooser, theme) except Exception as detail: print(detail) return True - def get_theme_sort_key(self, name): - name = name.lower() - legacy = 0 - darker = 0 - dark = 0 - if "legacy" in name: - legacy = 1 - if "darker" in name: - darker = 1 - if "dark" in name and "darker" not in name: - dark = 1 - name = name.replace("darker", "").replace("dark", "").replace("legacy", "") - name = f"{legacy}{dark}{darker}{name}" - return name - - def _load_gtk_themes(self): - """ Only shows themes that have variations for gtk+-3 and gtk+-2 """ - dirs = THEME_FOLDERS - valid = walk_directories(dirs, self.filter_func_gtk_dir, return_directories=True) - valid.sort(key=lambda a: self.get_theme_sort_key(a[0])) - res = [] - for i in valid: - for j in res: - if i[0] == j[0]: - if i[1] == dirs[0]: - continue - else: - res.remove(j) - res.append((i[0], i[1])) - return res - def filter_func_gtk_dir(self, directory): theme_dir = Path(directory) - for gtk3_dir in theme_dir.glob("gtk-3.*"): # Skip gtk key themes if os.path.exists(os.path.join(gtk3_dir, "gtk.css")): return True return False - def _load_icon_themes(self): - dirs = ICON_FOLDERS - walked = walk_directories(dirs, lambda d: os.path.isdir(d), return_directories=True) - valid = [] - for directory in walked: - if directory[0] in ("gnome", "hicolor"): - continue - path = os.path.join(directory[1], directory[0], "index.theme") - if os.path.exists(path): - try: - for line in list(open(path)): - if line.startswith("Directories="): - valid.append(directory) - break - except Exception as e: - print (e) - - valid.sort(key=lambda a: self.get_theme_sort_key(a[0])) - res = [] - for i in valid: - for j in res: - if i[0] == j: - if i[1] == dirs[0]: - continue - else: - res.remove(j) - res.append(i[0]) - return res - - def _load_cursor_themes(self): - dirs = ICON_FOLDERS - valid = walk_directories(dirs, lambda d: os.path.isdir(d) and os.path.exists(os.path.join(d, "cursors")), return_directories=True) - valid.sort(key=lambda a: a[0].lower()) - res = [] - for i in valid: - for j in res: - if i[0] == j[0]: - if i[1] == dirs[0]: - continue - else: - res.remove(j) - res.append((i[0], i[1])) - return res - - def _load_cinnamon_themes(self): - dirs = THEME_FOLDERS - valid = walk_directories(dirs, lambda d: os.path.exists(os.path.join(d, "cinnamon")), return_directories=True) - valid.sort(key=lambda a: self.get_theme_sort_key(a[0])) - res = [] - for i in valid: - for j in res: - if i[0] == j[0]: - if i[1] == dirs[0]: - continue - else: - res.remove(j) - res.append((i[0], i[1])) - return res - def update_cursor_theme_link(self, path, name): default_dir = os.path.join(ICON_FOLDERS[0], "default") index_path = os.path.join(default_dir, "index.theme") diff --git a/files/usr/share/cinnamon/cinnamon-settings/modules/cs_windows.py b/files/usr/share/cinnamon/cinnamon-settings/modules/cs_windows.py index 6427f3e6cf..a7780471fb 100755 --- a/files/usr/share/cinnamon/cinnamon-settings/modules/cs_windows.py +++ b/files/usr/share/cinnamon/cinnamon-settings/modules/cs_windows.py @@ -178,3 +178,6 @@ def update_setting(widget, pspec): widget = GSettingsSwitch(_("Show windows from all workspaces"), "org.cinnamon", "alttab-switcher-show-all-workspaces") settings.add_row(widget) + + widget = GSettingsSwitch(_("Warp mouse pointer to the new focused window"), "org.cinnamon", "alttab-switcher-warp-mouse-pointer") + settings.add_row(widget) diff --git a/files/usr/share/cinnamon/cinnamon-settings/themes.ui b/files/usr/share/cinnamon/cinnamon-settings/themes.ui new file mode 100644 index 0000000000..14def0d33f --- /dev/null +++ b/files/usr/share/cinnamon/cinnamon-settings/themes.ui @@ -0,0 +1,351 @@ + + + + + + True + False + vertical + + + True + False + + + True + True + never + + + True + False + + + + True + False + center + start + 90 + 90 + 45 + 16 + 16 + + + True + False + start + Appearance + + + + + + 0 + 1 + + + + + True + False + start + Color + + + + + + 0 + 3 + + + + + True + False + In mixed mode most applications are light. Some desktop elements and multimedia apps are dark to create contrast. + True + + + 1 + 2 + + + + + True + False + False + True + expand + + + True + False + True + True + + + True + False + 0 + vertical + + + True + False + appearance-mixed.svg + + + False + True + 0 + + + + + True + False + 3 + Mixed + + + + + + False + True + 1 + + + + + + + True + True + 0 + + + + + True + False + True + True + + + True + False + vertical + + + True + False + appearance-dark.svg + + + False + True + 0 + + + + + True + False + 3 + Dark + + + + + + False + True + 1 + + + + + + + True + True + 1 + + + + + True + False + True + True + + + True + False + vertical + + + True + False + appearance-light.svg + + + False + True + 0 + + + + + True + False + 3 + Light + + + + + + False + True + 1 + + + + + + + True + True + 2 + + + + + 1 + 1 + + + + + True + False + False + True + expand + + + + + + 1 + 3 + + + + + Advanced settings... + True + True + True + end + + + 1 + 4 + + + + + True + False + start + Style + + + + + + 0 + 0 + + + + + True + False + + + 1 + 0 + + + + + + + + + + + + + + + preset_page + + + + + True + False + 12 + vertical + 16 + + + True + False + center + custom_stack + + + False + True + 0 + + + + + True + False + + + + + + True + True + 1 + + + + + custom_page + 1 + + + + + True + True + 0 + + + + diff --git a/files/usr/share/cinnamon/styles.d/00_cinnamon.styles b/files/usr/share/cinnamon/styles.d/00_cinnamon.styles new file mode 100644 index 0000000000..96fda3d3c6 --- /dev/null +++ b/files/usr/share/cinnamon/styles.d/00_cinnamon.styles @@ -0,0 +1,22 @@ +{ + "styles": [ + { + "name": "Adwaita", + "default": "mixed", + "mixed": [ + {"default": "true", "name": "blue", "color": "#3584e4", "themes": "Adwaita", "cinnamon": "cinnamon"} + ], + "dark": [ + {"name": "blue", "color": "#15539e", "themes": "Adwaita-dark", "icons": "Adwaita", "cinnamon": "cinnamon", "cursor": "Adwaita"} + ], + "light": [] + }, + { + "name": "HighContrast", + "default": "light", + "light": [ + {"default": "true", "name": "contrast", "color": "#000000", "themes": "HighContrast", "cinnamon": "cinnamon", "cursor": "Adwaita"} + ] + } + ] +} diff --git a/js/misc/signalManager.js b/js/misc/signalManager.js index b824ca969e..602c2ca075 100644 --- a/js/misc/signalManager.js +++ b/js/misc/signalManager.js @@ -54,7 +54,7 @@ const _disconnect = function(results) { * Every Javascript object should have its own @SignalManager, and use it to * connect signals of all objects it takes care of. For example, the panel will * have one #SignalManger object, which manages all signals from #GSettings, - * `global.screen` etc. + * `global.display` etc. * * An example usage is as follows: * ``` diff --git a/js/ui/appSwitcher/appSwitcher.js b/js/ui/appSwitcher/appSwitcher.js index 72935762fa..16c2378d53 100644 --- a/js/ui/appSwitcher/appSwitcher.js +++ b/js/ui/appSwitcher/appSwitcher.js @@ -17,17 +17,17 @@ function sortWindowsByUserTime(win1, win2) { this.minimizedAwareAltTab = global.settings.get_boolean("alttab-minimized-aware"); if (this.minimizedAwareAltTab) { - let m1 = win1.minimized; - let m2 = win2.minimized; - if (m1 == m2) { - return (t2 > t1) ? 1 : -1; - } - else { - return m1 ? 1 : -1; - } + let m1 = win1.minimized; + let m2 = win2.minimized; + if (m1 == m2) { + return (t2 > t1) ? 1 : -1; + } + else { + return m1 ? 1 : -1; + } } else { - return (t2 > t1) ? 1 : -1; + return (t2 > t1) ? 1 : -1; } } @@ -62,29 +62,29 @@ function getWindowsForBinding(binding) { for (let i in windowActors) windows.push(windowActors[i].get_meta_window()); - windows = windows.filter( Main.isInteresting ); + windows = windows.filter(Main.isInteresting); - switch(binding.get_name()) { + switch (binding.get_name()) { case 'switch-panels': case 'switch-panels-backward': // Switch between windows of all workspaces - windows = windows.filter( matchSkipTaskbar ); + windows = windows.filter(matchSkipTaskbar); break; case 'switch-group': case 'switch-group-backward': // Switch between windows of the same application let focused = global.display.focus_window ? global.display.focus_window : windows[0]; - windows = windows.filter( matchWmClass, focused.get_wm_class() ); + windows = windows.filter(matchWmClass, focused.get_wm_class()); this._showAllWorkspaces = global.settings.get_boolean("alttab-switcher-show-all-workspaces"); if (!this._showAllWorkspaces) { - windows = windows.filter( matchWorkspace, global.screen.get_active_workspace() ); + windows = windows.filter(matchWorkspace, global.workspace_manager.get_active_workspace()); } break; default: // Switch between windows of current workspace this._showAllWorkspaces = global.settings.get_boolean("alttab-switcher-show-all-workspaces"); if (!this._showAllWorkspaces) { - windows = windows.filter( matchWorkspace, global.screen.get_active_workspace() ); + windows = windows.filter(matchWorkspace, global.workspace_manager.get_active_workspace()); } break; } @@ -100,7 +100,7 @@ function AppSwitcher() { } AppSwitcher.prototype = { - _init: function(binding) { + _init: function (binding) { this._initialDelayTimeoutId = null; this._binding = binding; this._windows = getWindowsForBinding(binding); @@ -124,7 +124,7 @@ AppSwitcher.prototype = { this._updateActiveMonitor(); }, - _setupModal: function() { + _setupModal: function () { this._haveModal = Main.pushModal(this.actor); if (!this._haveModal) { // Probably someone else has a pointer grab, try again with keyboard only @@ -161,57 +161,57 @@ AppSwitcher.prototype = { return this._haveModal; }, - _popModal: function() { + _popModal: function () { if (this._haveModal) { Main.popModal(this.actor); this._haveModal = false; } }, - _show: function() { + _show: function () { throw new Error("Abstract method _show not implemented"); }, - _hide: function() { + _hide: function () { throw new Error("Abstract method _hide not implemented"); }, - _onDestroy: function() { + _onDestroy: function () { throw new Error("Abstract method _onDestroy not implemented"); }, - _createList: function() { + _createList: function () { throw new Error("Abstract method _createList not implemented"); }, - _updateList: function() { + _updateList: function () { throw new Error("Abstract method _updateList not implemented"); }, - _selectNext: function() { + _selectNext: function () { throw new Error("Abstract method _selectNext not implemented"); }, - _selectPrevious: function() { + _selectPrevious: function () { throw new Error("Abstract method _selectPrevious not implemented"); }, - _onWorkspaceSelected: function() { + _onWorkspaceSelected: function () { throw new Error("Abstract method _onWorkspaceSelected not implemented"); }, - _checkSwitchTime: function() { + _checkSwitchTime: function () { return true; }, - _setCurrentWindow: function(window) { + _setCurrentWindow: function (window) { }, - _next: function() { + _next: function () { if (!this._windows) return; - if(this._windows.length <= 1) { + if (this._windows.length <= 1) { this._currentIndex = 0; this._updateList(0); } else { @@ -222,11 +222,11 @@ AppSwitcher.prototype = { this._setCurrentWindow(this._windows[this._currentIndex]); }, - _previous: function() { + _previous: function () { if (!this._windows) return; - if(this._windows.length <= 1) { + if (this._windows.length <= 1) { this._currentIndex = 0; this._updateList(0); } else { @@ -237,7 +237,7 @@ AppSwitcher.prototype = { this._setCurrentWindow(this._windows[this._currentIndex]); }, - _select: function(index) { + _select: function (index) { if (!this._windows) return; @@ -245,7 +245,7 @@ AppSwitcher.prototype = { this._setCurrentWindow(this._windows[this._currentIndex]); }, - _updateActiveMonitor: function() { + _updateActiveMonitor: function () { this._activeMonitor = null; if (!this._enforcePrimaryMonitor) this._activeMonitor = Main.layoutManager.currentMonitor; @@ -255,7 +255,7 @@ AppSwitcher.prototype = { return this._activeMonitor; }, - _keyPressEvent: function(actor, event) { + _keyPressEvent: function (actor, event) { let modifiers = Cinnamon.get_event_state(event); let symbol = event.get_key_symbol(); let keycode = event.get_key_code(); @@ -266,7 +266,7 @@ AppSwitcher.prototype = { // Switch workspace if (modifiers & Clutter.ModifierType.CONTROL_MASK && - (symbol === Clutter.KEY_Right || symbol === Clutter.KEY_Left)) { + (symbol === Clutter.KEY_Right || symbol === Clutter.KEY_Left)) { if (this._switchWorkspace(symbol)) return true; } @@ -293,14 +293,14 @@ AppSwitcher.prototype = { case Clutter.KEY_Right: case Clutter.KEY_Down: // Right/Down -> navigate to next preview - if(this._checkSwitchTime()) + if (this._checkSwitchTime()) this._next(); return true; case Clutter.KEY_Left: case Clutter.KEY_Up: // Left/Up -> navigate to previous preview - if(this._checkSwitchTime()) + if (this._checkSwitchTime()) this._previous(); return true; } @@ -310,7 +310,7 @@ AppSwitcher.prototype = { case Meta.KeyBindingAction.SWITCH_GROUP: case Meta.KeyBindingAction.SWITCH_WINDOWS: case Meta.KeyBindingAction.SWITCH_PANELS: - if(this._checkSwitchTime()) { + if (this._checkSwitchTime()) { // shift -> backwards if (modifiers & Clutter.ModifierType.SHIFT_MASK) this._previous(); @@ -321,7 +321,7 @@ AppSwitcher.prototype = { case Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD: case Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD: case Meta.KeyBindingAction.SWITCH_PANELS_BACKWARD: - if(this._checkSwitchTime()) + if (this._checkSwitchTime()) this._previous(); return true; } @@ -329,7 +329,7 @@ AppSwitcher.prototype = { return true; }, - _keyReleaseEvent: function(actor, event) { + _keyReleaseEvent: function (actor, event) { let [x, y, mods] = global.get_pointer(); let state = mods & this._modifierMask; @@ -342,17 +342,17 @@ AppSwitcher.prototype = { return true; }, - _failedGrabAction: function() { + _failedGrabAction: function () { if (!["coverflow", "timeline"].includes(global.settings.get_string('alttab-switcher-style'))) { this._keyReleaseEvent(null, null); } }, // allow navigating by mouse-wheel scrolling - _scrollEvent: function(actor, event) { + _scrollEvent: function (actor, event) { if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH) return Clutter.EVENT_STOP; - if(this._checkSwitchTime()) { + if (this._checkSwitchTime()) { actor.set_reactive(false); if (event.get_scroll_direction() == Clutter.ScrollDirection.UP) this._previous(); @@ -363,7 +363,7 @@ AppSwitcher.prototype = { return true; }, - _disableHover : function() { + _disableHover: function () { this._mouseActive = false; if (this._motionTimeoutId != 0) @@ -372,16 +372,16 @@ AppSwitcher.prototype = { this._motionTimeoutId = Mainloop.timeout_add(DISABLE_HOVER_TIMEOUT, Lang.bind(this, this._mouseTimedOut)); }, - _mouseTimedOut : function() { + _mouseTimedOut: function () { this._motionTimeoutId = 0; this._mouseActive = true; }, - _switchWorkspace: function(direction) { - if (global.screen.n_workspaces < 2) + _switchWorkspace: function (direction) { + if (global.workspace_manager.n_workspaces < 2) return false; - let current = global.screen.get_active_workspace_index(); + let current = global.workspace_manager.get_active_workspace_index(); if (direction === Clutter.KEY_Left) Main.wm.actionMoveWorkspaceLeft(); @@ -390,19 +390,19 @@ AppSwitcher.prototype = { else return false; - if (current === global.screen.get_active_workspace_index()) + if (current === global.workspace_manager.get_active_workspace_index()) return false; - let workspace = global.screen.get_active_workspace(); + let workspace = global.workspace_manager.get_active_workspace(); this._onWorkspaceSelected(workspace); return true; }, - _windowDestroyed: function(wm, actor) { + _windowDestroyed: function (wm, actor) { this._removeDestroyedWindow(actor.meta_window); }, - _removeDestroyedWindow: function(window) { + _removeDestroyedWindow: function (window) { for (let i in this._windows) { if (window == this._windows[i]) { if (this._windows.length == 1) @@ -427,14 +427,23 @@ AppSwitcher.prototype = { } }, - _activateSelected: function() { - let workspace_num = this._windows[this._currentIndex].get_workspace().index(); - Main.activateWindow(this._windows[this._currentIndex], global.get_current_time(), workspace_num); + _activateSelected: function () { + const _window = this._windows[this._currentIndex] + const workspace_num = _window.get_workspace().index(); + Main.activateWindow(_window, global.get_current_time(), workspace_num); + this._warpMouse = global.settings.get_boolean("alttab-switcher-warp-mouse-pointer"); + if (this._warpMouse) { + const rect = _window.get_frame_rect(); + const x = rect.x + rect.width / 2; + const y = rect.y + rect.height / 2; + this._pointer = Clutter.get_default_backend().get_default_seat().create_virtual_device(Clutter.InputDeviceType.POINTER_DEVICE); + this._pointer.notify_absolute_motion(global.get_current_time(), x, y); + } if (!this._destroyed) this.destroy(); }, - _showDesktop: function() { + _showDesktop: function () { for (let i in this._windows) { if (!this._windows[i].minimized) this._windows[i].minimize(); @@ -442,7 +451,7 @@ AppSwitcher.prototype = { this.destroy(); }, - destroy: function() { + destroy: function () { this._destroyed = true; this._popModal(); @@ -451,7 +460,7 @@ AppSwitcher.prototype = { else this._hide(); - if(this._initialDelayTimeoutId !== null && this._initialDelayTimeoutId > 0) { + if (this._initialDelayTimeoutId !== null && this._initialDelayTimeoutId > 0) { Mainloop.source_remove(this._initialDelayTimeoutId); this._initialDelayTimeoutId = 0; } diff --git a/js/ui/appSwitcher/appSwitcher3D.js b/js/ui/appSwitcher/appSwitcher3D.js index 30c63544dc..93a08e7c52 100644 --- a/js/ui/appSwitcher/appSwitcher3D.js +++ b/js/ui/appSwitcher/appSwitcher3D.js @@ -89,7 +89,7 @@ AppSwitcher3D.prototype = { let monitor = this._activeMonitor; // preview windows - let currentWorkspace = global.screen.get_active_workspace(); + let currentWorkspace = global.workspace_manager.get_active_workspace(); for (let i in this._previews) { let preview = this._previews[i]; let metaWin = this._windows[i]; @@ -176,7 +176,7 @@ AppSwitcher3D.prototype = { _createList: function() { let monitor = this._activeMonitor; - let currentWorkspace = global.screen.get_active_workspace(); + let currentWorkspace = global.workspace_manager.get_active_workspace(); this._previews = []; @@ -316,7 +316,7 @@ AppSwitcher3D.prototype = { }, _enableMonitorFix: function() { - if(global.screen.get_n_monitors() < 2) + if(global.display.get_n_monitors() < 2) return; this._monitorFix = true; diff --git a/js/ui/appSwitcher/classicSwitcher.js b/js/ui/appSwitcher/classicSwitcher.js index fc8b8fae48..8619f634a0 100644 --- a/js/ui/appSwitcher/classicSwitcher.js +++ b/js/ui/appSwitcher/classicSwitcher.js @@ -759,7 +759,7 @@ AppList.prototype = { SwitcherList.prototype._init.call(this, true, activeMonitor); // Construct the AppIcons, add to the popup - let activeWorkspace = global.screen.get_active_workspace(); + let activeWorkspace = global.workspace_manager.get_active_workspace(); let workspaceIcons = []; let otherIcons = []; for (let i = 0; i < windows.length; i++) { @@ -899,7 +899,7 @@ ThumbnailList.prototype = { _init : function(windows, activeMonitor) { SwitcherList.prototype._init.call(this, false, activeMonitor); - let activeWorkspace = global.screen.get_active_workspace(); + let activeWorkspace = global.workspace_manager.get_active_workspace(); this._labels = new Array(); this._thumbnailBins = new Array(); diff --git a/js/ui/deskletManager.js b/js/ui/deskletManager.js index 1e0d9b5910..42b60d7636 100644 --- a/js/ui/deskletManager.js +++ b/js/ui/deskletManager.js @@ -105,7 +105,7 @@ function updateMouseTracking() { } function hasMouseWindow(){ - let window = global.screen.get_mouse_window(null); + let window = global.display.get_pointer_window(null); return window && window.window_type !== Meta.WindowType.DESKTOP; } diff --git a/js/ui/expoThumbnail.js b/js/ui/expoThumbnail.js index 9b2f477480..09ca739e78 100644 --- a/js/ui/expoThumbnail.js +++ b/js/ui/expoThumbnail.js @@ -652,12 +652,12 @@ ExpoWorkspaceThumbnail.prototype = { this.doRemoveWindow(metaWin); }, - windowEnteredMonitor : function(metaScreen, monitorIndex, metaWin) { + windowEnteredMonitor : function(metaDisplay, monitorIndex, metaWin) { // important if workspaces-only-on-primary is in effect this.doAddWindow(metaWin); }, - windowLeftMonitor : function(metaScreen, monitorIndex, metaWin) { + windowLeftMonitor : function(metaDisplay, monitorIndex, metaWin) { // important if workspaces-only-on-primary is in effect this.doRemoveWindow(metaWin); }, @@ -1144,7 +1144,7 @@ ExpoThumbnailsBox.prototype = { global.window_manager.connect('switch-workspace', Lang.bind(this, this.activeWorkspaceChanged)); - this.workspaceAddedId = global.workspace_manager.connect('workspace-added', Lang.bind(this, function(screen, index) { + this.workspaceAddedId = global.workspace_manager.connect('workspace-added', Lang.bind(this, function(ws_manager, index) { this.addThumbnails(index, 1); })); this.workspaceRemovedId = global.workspace_manager.connect('workspace-removed', Lang.bind(this, function() { diff --git a/js/ui/extension.js b/js/ui/extension.js index f40c610dd2..5428a1c77a 100644 --- a/js/ui/extension.js +++ b/js/ui/extension.js @@ -32,8 +32,7 @@ var knownCinnamon4Conflicts = [ 'vnstat@linuxmint.com', 'netusagemonitor@pdcurtis', // Desklets - 'netusage@30yavash.com', - 'simple-system-monitor@ariel' + 'netusage@30yavash.com' ]; // macro for creating extension types diff --git a/js/ui/hotCorner.js b/js/ui/hotCorner.js index 419c256f7f..99d4a77074 100755 --- a/js/ui/hotCorner.js +++ b/js/ui/hotCorner.js @@ -245,7 +245,7 @@ class HotCorner { Main.overview.toggle(); break; case 'desktop': - global.screen.toggle_desktop(timestamp); + global.workspace_manager.toggle_desktop(timestamp); break; default: Util.spawnCommandLine(this.action); diff --git a/js/ui/layout.js b/js/ui/layout.js index 0bacb9c039..cb7aee7279 100644 --- a/js/ui/layout.js +++ b/js/ui/layout.js @@ -48,7 +48,7 @@ Monitor.prototype = { }, get inFullscreen() { - return global.screen.get_monitor_in_fullscreen(this.index); + return global.display.get_monitor_in_fullscreen(this.index); } }; @@ -230,7 +230,7 @@ LayoutManager.prototype = { }, get currentMonitor() { - let index = global.screen.get_current_monitor(); + let index = global.display.get_current_monitor(); return Main.layoutManager.monitors[index]; }, @@ -488,13 +488,13 @@ Chrome.prototype = { this._layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout)); - global.screen.connect('restacked', + global.display.connect('restacked', Lang.bind(this, this._windowsRestacked)); - global.screen.connect('in-fullscreen-changed', Lang.bind(this, this._updateVisibility)); + global.display.connect('in-fullscreen-changed', Lang.bind(this, this._updateVisibility)); global.window_manager.connect('switch-workspace', Lang.bind(this, this._queueUpdateRegions)); // Need to update struts on new workspaces when they are added - global.screen.connect('notify::n-workspaces', + global.workspace_manager.connect('notify::n-workspaces', Lang.bind(this, this._queueUpdateRegions)); this._relayout(); @@ -635,7 +635,7 @@ Chrome.prototype = { else if (global.stage_input_mode == Cinnamon.StageInputMode.FULLSCREEN) { let monitor = this.findMonitorForActor(actorData.actor); - if (global.screen.get_n_monitors() == 1 || !monitor.inFullscreen) { + if (global.display.get_n_monitors() == 1 || !monitor.inFullscreen) { visible = true; } else { if (Main.modalActorFocusStack.length > 0) { @@ -863,9 +863,9 @@ Chrome.prototype = { global.set_stage_input_region(rects); - let screen = global.screen; - for (let w = 0; w < screen.n_workspaces; w++) { - let workspace = screen.get_workspace_by_index(w); + let ws_manager = global.workspace_manager; + for (let w = 0; w < ws_manager.n_workspaces; w++) { + let workspace = ws_manager.get_workspace_by_index(w); workspace.set_builtin_struts(struts); } diff --git a/js/ui/main.js b/js/ui/main.js index dcbf18d38c..7eab8d17c9 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -227,7 +227,7 @@ function _addXletDirectoriesToSearchPath() { } function _initUserSession() { - global.screen.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, 1, -1); + global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, 1, -1); systrayManager = new Systray.SystrayManager(); @@ -570,7 +570,7 @@ function _fillWorkspaceNames(index) { } function _shouldTrimWorkspace(i) { - return i >= 0 && (i >= global.screen.n_workspaces || !workspace_names[i].length); + return i >= 0 && (i >= global.workspace_manager.n_workspaces || !workspace_names[i].length); } function _trimWorkspaceNames() { @@ -636,12 +636,12 @@ function hasDefaultWorkspaceName(index) { } function _addWorkspace() { - global.screen.append_new_workspace(false, global.get_current_time()); + global.workspace_manager.append_new_workspace(false, global.get_current_time()); return true; } function _removeWorkspace(workspace) { - if (global.screen.n_workspaces == 1) + if (global.workspace_manager.n_workspaces == 1) return false; let index = workspace.index(); if (index < workspace_names.length) { @@ -649,7 +649,7 @@ function _removeWorkspace(workspace) { } _trimWorkspaceNames(); wmSettings.set_strv("workspace-names", workspace_names); - global.screen.remove_workspace(workspace, global.get_current_time()); + global.workspace_manager.remove_workspace(workspace, global.get_current_time()); return true; } @@ -666,16 +666,16 @@ function _removeWorkspace(workspace) { */ function moveWindowToNewWorkspace(metaWindow, switchToNewWorkspace) { if (switchToNewWorkspace) { - let targetCount = global.screen.n_workspaces + 1; - let nnwId = global.screen.connect('notify::n-workspaces', function() { - global.screen.disconnect(nnwId); - if (global.screen.n_workspaces === targetCount) { - let newWs = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1); + let targetCount = global.workspace_manager.n_workspaces + 1; + let nnwId = global.workspace_manager.connect('notify::n-workspaces', function() { + global.workspace_manager.disconnect(nnwId); + if (global.workspace_manager.n_workspaces === targetCount) { + let newWs = global.workspace_manager.get_workspace_by_index(global.workspace_manager.n_workspaces - 1); newWs.activate(global.get_current_time()); } }); } - metaWindow.change_workspace_by_index(global.screen.n_workspaces, true, global.get_current_time()); + metaWindow.change_workspace_by_index(global.workspace_manager.n_workspaces, true, global.get_current_time()); } /** @@ -1320,13 +1320,13 @@ function getRunDialog() { * activation will be handled in muffin. */ function activateWindow(window, time, workspaceNum) { - let activeWorkspaceNum = global.screen.get_active_workspace_index(); + let activeWorkspaceNum = global.workspace_manager.get_active_workspace_index(); if (!time) time = global.get_current_time(); if ((workspaceNum !== undefined) && activeWorkspaceNum !== workspaceNum) { - let workspace = global.screen.get_workspace_by_index(workspaceNum); + let workspace = global.workspace_manager.get_workspace_by_index(workspaceNum); workspace.activate_with_focus(window, time); return; } @@ -1489,8 +1489,7 @@ function isInteresting(metaWindow) { /** * getTabList: - * @workspaceOpt (Meta.Workspace): (optional) workspace, defaults to global.screen.get_active_workspace() - * @screenOpt (Meta.Screen): (optional) screen, defaults to global.screen + * @workspaceOpt (Meta.Workspace): (optional) workspace, defaults to global.workspace_manager.get_active_workspace() * * Return a list of the interesting windows on a workspace (by default, * the active workspace). @@ -1498,14 +1497,12 @@ function isInteresting(metaWindow) { * * Returns (array): list of windows */ -function getTabList(workspaceOpt, screenOpt) { - let screen = screenOpt || global.screen; - let display = screen.get_display(); - let workspace = workspaceOpt || screen.get_active_workspace(); +function getTabList(workspaceOpt) { + let workspace = workspaceOpt || global.workspace_manager.get_active_workspace(); let windows = []; // the array to return - let allwindows = display.get_tab_list(Meta.TabList.NORMAL_ALL, workspace); + let allwindows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, workspace); let registry = {}; // to avoid duplicates for (let i = 0; i < allwindows.length; ++i) { diff --git a/js/ui/osdWindow.js b/js/ui/osdWindow.js index 0d4a46c951..7c234a09cc 100644 --- a/js/ui/osdWindow.js +++ b/js/ui/osdWindow.js @@ -145,7 +145,7 @@ OsdWindow.prototype = { return; if (!this.actor.visible) { - Meta.disable_unredirect_for_screen(global.screen); + Meta.disable_unredirect_for_display(global.display); this._level.setLevelBarHeight(this._sizeMultiplier); this.actor.show(); this.actor.opacity = 0; diff --git a/js/ui/overrides.js b/js/ui/overrides.js index eadcba077b..8d47fb2d5f 100644 --- a/js/ui/overrides.js +++ b/js/ui/overrides.js @@ -243,16 +243,25 @@ function installPolyfills(readOnlyError) { // These abstractions around Mainloop are safer and easier // to use for people learning GObject introspection bindings. - Object.defineProperty(window, 'setTimeout', { - get: function() { - return setTimeout; - }, - set: function() { - readOnlyError('setTimeout'); - }, - configurable: false, - enumerable: false - }); + + // Starting with mozjs 102, these polyfills are no longer needed, and will + // crash Cinnamon if we try to redifine them. Try to do the first one and bail + // if it complains (TypeError: can't redefine non-configurable property) + try { + Object.defineProperty(window, 'setTimeout', { + get: function() { + return setTimeout; + }, + set: function() { + readOnlyError('setTimeout'); + }, + configurable: false, + enumerable: false + }); + } catch (e) { + return; + } + Object.defineProperty(window, 'clearTimeout', { get: function() { return clearTimeout; diff --git a/js/ui/overview.js b/js/ui/overview.js index fb6a16122e..5de19f9e05 100644 --- a/js/ui/overview.js +++ b/js/ui/overview.js @@ -276,7 +276,7 @@ Overview.prototype = { this._coverPane.hide(); // Disable unredirection while in the overview - Meta.disable_unredirect_for_screen(global.screen); + Meta.disable_unredirect_for_display(global.display); this._group.show(); this.workspacesView = new WorkspacesView.WorkspacesView(); diff --git a/js/ui/placesManager.js b/js/ui/placesManager.js index d3b28b82ef..426627a954 100644 --- a/js/ui/placesManager.js +++ b/js/ui/placesManager.js @@ -166,7 +166,7 @@ PlaceDeviceInfo.prototype = { notification.setUrgency(persistent ? MessageTray.Urgency.CRITICAL : MessageTray.Urgency.NORMAL); if (withButton) { notification.addButton('system-undo', _("Retry")); - notification.connect('action-invoked', Lang.bind(this, this.remove())); + notification.connect('action-invoked', Lang.bind(this, this.remove)); } source.notify(notification); if (persistent) { diff --git a/js/ui/virtualKeyboard.js b/js/ui/virtualKeyboard.js index 26dd348a67..8a0fbde0fc 100644 --- a/js/ui/virtualKeyboard.js +++ b/js/ui/virtualKeyboard.js @@ -488,7 +488,7 @@ Keyboard.prototype = { }, _moveTemporarily: function () { - let currentWindow = global.screen.get_display().focus_window; + let currentWindow = global.display.focus_window; let rect = currentWindow.get_outer_rect(); let newX = rect.x; diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js index 052706ab3b..cf4f7923e6 100644 --- a/js/ui/windowManager.js +++ b/js/ui/windowManager.js @@ -1235,7 +1235,7 @@ var WindowManager = class WindowManager { showWorkspaceOSD() { this._hideWorkspaceOSD(true); if (global.settings.get_boolean('workspace-osd-visible')) { - let current_workspace_index = global.screen.get_active_workspace_index(); + let current_workspace_index = global.workspace_manager.get_active_workspace_index(); if (this.wm_settings.get_boolean('workspaces-only-on-primary')) { this._showWorkspaceOSDOnMonitor(Main.layoutManager.primaryMonitor.index, current_workspace_index); } @@ -1311,8 +1311,8 @@ var WindowManager = class WindowManager { return; } this._movingWindow = window; - let workspace = global.screen.get_active_workspace().get_neighbor(direction); - if (workspace != global.screen.get_active_workspace()) { + let workspace = global.workspace_manager.get_active_workspace().get_neighbor(direction); + if (workspace != global.workspace_manager.get_active_workspace()) { window.change_workspace(workspace); workspace.activate_with_focus(window, global.get_current_time()); } @@ -1327,7 +1327,7 @@ var WindowManager = class WindowManager { } moveToWorkspace(workspace, direction_hint) { - let active = global.screen.get_active_workspace(); + let active = global.workspace_manager.get_active_workspace(); // if (workspace != active) { // if (direction_hint) // workspace.activate_with_direction_hint(direction_hint, global.get_current_time()); @@ -1347,7 +1347,7 @@ var WindowManager = class WindowManager { return; } - if (global.screen.n_workspaces === 1) + if (global.workspace_manager.n_workspaces === 1) return; if (bindingName === 'switch-to-workspace-left') { @@ -1358,7 +1358,7 @@ var WindowManager = class WindowManager { } actionMoveWorkspaceLeft() { - let active = global.screen.get_active_workspace(); + let active = global.workspace_manager.get_active_workspace(); let neighbor = active.get_neighbor(Meta.MotionDirection.LEFT) if (active != neighbor) { this.moveToWorkspace(neighbor, Meta.MotionDirection.LEFT); @@ -1366,7 +1366,7 @@ var WindowManager = class WindowManager { } actionMoveWorkspaceRight() { - let active = global.screen.get_active_workspace(); + let active = global.workspace_manager.get_active_workspace(); let neighbor = active.get_neighbor(Meta.MotionDirection.RIGHT) if (active != neighbor) { this.moveToWorkspace(neighbor, Meta.MotionDirection.RIGHT); @@ -1374,15 +1374,15 @@ var WindowManager = class WindowManager { } actionMoveWorkspaceUp() { - global.screen.get_active_workspace().get_neighbor(Meta.MotionDirection.UP).activate(global.get_current_time()); + global.workspace_manager.get_active_workspace().get_neighbor(Meta.MotionDirection.UP).activate(global.get_current_time()); } actionMoveWorkspaceDown() { - global.screen.get_active_workspace().get_neighbor(Meta.MotionDirection.DOWN).activate(global.get_current_time()); + global.workspace_manager.get_active_workspace().get_neighbor(Meta.MotionDirection.DOWN).activate(global.get_current_time()); } actionFlipWorkspaceLeft() { - let active = global.screen.get_active_workspace(); + let active = global.workspace_manager.get_active_workspace(); let neighbor = active.get_neighbor(Meta.MotionDirection.LEFT); if (active != neighbor) { neighbor.activate(global.get_current_time()); @@ -1392,7 +1392,7 @@ var WindowManager = class WindowManager { } actionFlipWorkspaceRight() { - let active = global.screen.get_active_workspace(); + let active = global.workspace_manager.get_active_workspace(); let neighbor = active.get_neighbor(Meta.MotionDirection.RIGHT); if (active != neighbor) { neighbor.activate(global.get_current_time()); diff --git a/js/ui/wmGtkDialogs.js b/js/ui/wmGtkDialogs.js index 531a14c708..3cc77f43ba 100644 --- a/js/ui/wmGtkDialogs.js +++ b/js/ui/wmGtkDialogs.js @@ -73,7 +73,7 @@ var CloseDialog = GObject.registerClass({ this.proc = Gio.Subprocess.new( [ "cinnamon-close-dialog", - global.screen.get_xwindow_for_window(this._window).toString(), + this._window.get_xwindow().toString(), this._window.get_title() ], 0); diff --git a/js/ui/workspace.js b/js/ui/workspace.js index 6a799a5e1f..710545f392 100644 --- a/js/ui/workspace.js +++ b/js/ui/workspace.js @@ -545,9 +545,9 @@ WorkspaceMonitor.prototype = { this._windowRemovedId = this.metaWorkspace.connect('window-removed', this._windowRemoved.bind(this)); } - this._windowEnteredMonitorId = global.screen.connect('window-entered-monitor', + this._windowEnteredMonitorId = global.display.connect('window-entered-monitor', this._windowEnteredMonitor.bind(this)); - this._windowLeftMonitorId = global.screen.connect('window-left-monitor', + this._windowLeftMonitorId = global.display.connect('window-left-monitor', this._windowLeftMonitor.bind(this)); this._animating = false; // Indicate if windows are being repositioned @@ -715,7 +715,7 @@ WorkspaceMonitor.prototype = { // Start the animations let slots = this._computeAllWindowSlots(clones.length); - let currentWorkspace = global.screen.get_active_workspace(); + let currentWorkspace = global.workspace_manager.get_active_workspace(); let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace; if (clones.length > 0 && animate && isOnCurrentWorkspace) { @@ -830,7 +830,7 @@ WorkspaceMonitor.prototype = { }, _showAllOverlays: function() { - let currentWorkspace = global.screen.get_active_workspace(); + let currentWorkspace = global.workspace_manager.get_active_workspace(); let fade = this.metaWorkspace == null || this.metaWorkspace === currentWorkspace; for (let clone of this._windows) { this._showWindowOverlay(clone, fade); @@ -945,13 +945,13 @@ WorkspaceMonitor.prototype = { this._doRemoveWindow(metaWin); }, - _windowEnteredMonitor : function(metaScreen, monitorIndex, metaWin) { + _windowEnteredMonitor : function(metaDisplay, monitorIndex, metaWin) { if (monitorIndex === this.monitorIndex) { this._doAddWindow(metaWin); } }, - _windowLeftMonitor : function(metaScreen, monitorIndex, metaWin) { + _windowLeftMonitor : function(metaDisplay, monitorIndex, metaWin) { if (monitorIndex === this.monitorIndex) { this._doRemoveWindow(metaWin); } @@ -983,7 +983,7 @@ WorkspaceMonitor.prototype = { // Animates the return from Overview mode zoomFromOverview : function() { - let currentWorkspace = global.screen.get_active_workspace(); + let currentWorkspace = global.workspace_manager.get_active_workspace(); this.leavingOverview = true; @@ -1053,8 +1053,8 @@ WorkspaceMonitor.prototype = { this.metaWorkspace.disconnect(this._windowAddedId); this.metaWorkspace.disconnect(this._windowRemovedId); } - global.screen.disconnect(this._windowEnteredMonitorId); - global.screen.disconnect(this._windowLeftMonitorId); + global.display.disconnect(this._windowEnteredMonitorId); + global.display.disconnect(this._windowLeftMonitorId); // Usually, the windows will be destroyed automatically with // their parent (this.actor), but we might have a zoomed window diff --git a/meson.build b/meson.build index 38f0bb8973..d9f0da8f04 100644 --- a/meson.build +++ b/meson.build @@ -16,6 +16,7 @@ desktopdir = join_paths(datadir, 'applications') xsessiondir = join_paths(datadir, 'xsessions') schemadir = join_paths(datadir, 'glib-2.0', 'schemas') pkglibdir = join_paths(libdir, meson.project_name().to_lower()) +girdir = join_paths(datadir, 'gir-1.0') servicedir = join_paths(datadir, 'dbus-1', 'services') pkgdatadir = join_paths(datadir, meson.project_name().to_lower()) po_dir = join_paths(meson.source_root(), 'po') diff --git a/src/cinnamon-app.c b/src/cinnamon-app.c index e3c2d704c7..b0328f2db8 100644 --- a/src/cinnamon-app.c +++ b/src/cinnamon-app.c @@ -188,7 +188,7 @@ get_actor_for_icon_name (CinnamonApp *app, if (icon != NULL) { - actor = g_object_new (ST_TYPE_ICON, "gicon", icon, "icon-size", size, NULL); + actor = g_object_new (ST_TYPE_ICON, "gicon", icon, "icon-type", ST_ICON_FULLCOLOR, "icon-size", size, NULL); g_object_unref (icon); } @@ -199,7 +199,7 @@ static ClutterActor * get_failsafe_icon (int size) { GIcon *icon = g_themed_icon_new ("application-x-executable"); - ClutterActor *actor = g_object_new (ST_TYPE_ICON, "gicon", icon, "icon-size", size, NULL); + ClutterActor *actor = g_object_new (ST_TYPE_ICON, "gicon", icon, "icon-type", ST_ICON_FULLCOLOR, "icon-size", size, NULL); g_object_unref (icon); return actor; } diff --git a/src/cinnamon-global.c b/src/cinnamon-global.c index b23544bff0..89b28061fd 100644 --- a/src/cinnamon-global.c +++ b/src/cinnamon-global.c @@ -1426,7 +1426,7 @@ cinnamon_global_create_app_launch_context (CinnamonGlobal *global) // Make sure that the app is opened on the current workspace even if // the user switches before it starts - gdk_app_launch_context_set_desktop (context, cinnamon_screen_get_active_workspace_index (global->cinnamon_screen)); + gdk_app_launch_context_set_desktop (context, meta_workspace_manager_get_active_workspace_index (global->workspace_manager)); return (GAppLaunchContext *)context; } diff --git a/src/meson.build b/src/meson.build index 288f651cef..c2e9ab5308 100644 --- a/src/meson.build +++ b/src/meson.build @@ -203,7 +203,7 @@ cinnamon_gir = gnome.generate_gir( includes: cinnamon_gir_includes, install: true, install_dir_typelib: pkglibdir, - install_dir_gir: false, + install_dir_gir: girdir, extra_args: [ '-DST_COMPILATION', '--quiet', diff --git a/src/st/meson.build b/src/st/meson.build index 70563f510c..5a337b80db 100644 --- a/src/st/meson.build +++ b/src/st/meson.build @@ -227,7 +227,7 @@ st_gir = gnome.generate_gir( includes: st_gir_includes, install: true, install_dir_typelib: pkglibdir, - install_dir_gir: false, + install_dir_gir: girdir, extra_args: [ '-DST_COMPILATION', '--quiet',