From 041deb559cafa1a00667689a89787b19b254bbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Dzi=C4=99giel?= Date: Mon, 23 May 2022 13:50:27 +0200 Subject: [PATCH] headerbar: Merge code into single subclass We no longer ship the web app that was reusing parts of this code. Combine it into single file without additional subclass. --- src/headerbar.js | 274 +++++++++++++++++++++++++++++++++++++++- src/headerbarBase.js | 288 ------------------------------------------- 2 files changed, 271 insertions(+), 291 deletions(-) delete mode 100644 src/headerbarBase.js diff --git a/src/headerbar.js b/src/headerbar.js index d41a519f..b1551ccf 100644 --- a/src/headerbar.js +++ b/src/headerbar.js @@ -1,11 +1,233 @@ -const { GObject } = imports.gi; -const { HeaderBarBase } = imports.src.headerbarBase; +const { GObject, Gtk } = imports.gi; +const Debug = imports.src.debug; +const Misc = imports.src.misc; + +const { debug } = Debug; var HeaderBar = GObject.registerClass({ GTypeName: 'ClapperHeaderBar', }, -class ClapperHeaderBar extends HeaderBarBase +class ClapperHeaderBar extends Gtk.Box { + _init() + { + super._init({ + can_focus: false, + orientation: Gtk.Orientation.HORIZONTAL, + spacing: 6, + margin_top: 6, + margin_start: 6, + margin_end: 6, + }); + this.add_css_class('osdheaderbar'); + + this.isMaximized = false; + this.isMenuOnLeft = true; + + const uiBuilder = Misc.getBuilderForName('clapper.ui'); + + this.menuWidget = new Gtk.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + valign: Gtk.Align.CENTER, + spacing: 6, + }); + + this.menuButton = new Gtk.MenuButton({ + icon_name: 'open-menu-symbolic', + valign: Gtk.Align.CENTER, + can_focus: false, + }); + const menuToggleButton = this.menuButton.get_first_child(); + menuToggleButton.add_css_class('osd'); + const mainMenuModel = uiBuilder.get_object('mainMenu'); + const mainMenuPopover = new HeaderBarPopover(mainMenuModel); + this.menuButton.set_popover(mainMenuPopover); + this.menuButton.add_css_class('circular'); + this.menuWidget.append(this.menuButton); + + this.extraButtonsBox = new Gtk.Box({ + orientation: Gtk.Orientation.HORIZONTAL, + valign: Gtk.Align.CENTER, + }); + this.extraButtonsBox.add_css_class('linked'); + + const floatButton = new Gtk.Button({ + icon_name: 'pip-in-symbolic', + can_focus: false, + }); + floatButton.add_css_class('osd'); + floatButton.add_css_class('circular'); + floatButton.add_css_class('linkedleft'); + floatButton.connect('clicked', + this._onFloatButtonClicked.bind(this) + ); + this.extraButtonsBox.append(floatButton); + + const separator = new Gtk.Separator({ + orientation: Gtk.Orientation.VERTICAL, + }); + separator.add_css_class('linkseparator'); + this.extraButtonsBox.append(separator); + + const fullscreenButton = new Gtk.Button({ + icon_name: 'view-fullscreen-symbolic', + can_focus: false, + }); + fullscreenButton.add_css_class('osd'); + fullscreenButton.add_css_class('circular'); + fullscreenButton.add_css_class('linkedright'); + fullscreenButton.connect('clicked', + this._onFullscreenButtonClicked.bind(this) + ); + this.extraButtonsBox.append(fullscreenButton); + this.menuWidget.append(this.extraButtonsBox); + + this.spacerWidget = new Gtk.Box({ + hexpand: true, + }); + + this.minimizeWidget = this._getWindowButton('minimize'); + this.maximizeWidget = this._getWindowButton('maximize'); + this.closeWidget = this._getWindowButton('close'); + + const gtkSettings = Gtk.Settings.get_default(); + this._onLayoutUpdate(gtkSettings); + + gtkSettings.connect( + 'notify::gtk-decoration-layout', + this._onLayoutUpdate.bind(this) + ); + } + + setMenuOnLeft(isOnLeft) + { + if(this.isMenuOnLeft === isOnLeft) + return; + + if(isOnLeft) { + this.menuWidget.reorder_child_after( + this.extraButtonsBox, this.menuButton + ); + } + else { + this.menuWidget.reorder_child_after( + this.menuButton, this.extraButtonsBox + ); + } + + this.isMenuOnLeft = isOnLeft; + } + + setMaximized(isMaximized) + { + if(this.isMaximized === isMaximized) + return; + + this.maximizeWidget.icon_name = (isMaximized) + ? 'window-restore-symbolic' + : 'window-maximize-symbolic'; + + this.isMaximized = isMaximized; + } + + _onLayoutUpdate(gtkSettings) + { + const gtkLayout = gtkSettings.gtk_decoration_layout; + + this._replaceButtons(gtkLayout); + } + + _replaceButtons(gtkLayout) + { + const modLayout = gtkLayout.replace(':', ',spacer,'); + const layoutArr = modLayout.split(','); + + let lastWidget = null; + + let showMinimize = false; + let showMaximize = false; + let showClose = false; + + let menuAdded = false; + let spacerAdded = false; + + debug(`headerbar layout: ${modLayout}`); + + for(let name of layoutArr) { + /* Menu might be named "appmenu" */ + if(!menuAdded && (!name || name === 'appmenu' || name === 'icon')) + name = 'menu'; + + const widget = this[`${name}Widget`]; + if(!widget) continue; + + if(!widget.parent) + this.append(widget); + else + this.reorder_child_after(widget, lastWidget); + + switch(name) { + case 'spacer': + spacerAdded = true; + break; + case 'minimize': + showMinimize = true; + break; + case 'maximize': + showMaximize = true; + break; + case 'close': + showClose = true; + break; + case 'menu': + this.setMenuOnLeft(!spacerAdded); + menuAdded = true; + break; + default: + break; + } + + lastWidget = widget; + } + + this.minimizeWidget.visible = showMinimize; + this.maximizeWidget.visible = showMaximize; + this.closeWidget.visible = showClose; + } + + _getWindowButton(name) + { + const button = new Gtk.Button({ + icon_name: `window-${name}-symbolic`, + valign: Gtk.Align.CENTER, + can_focus: false, + }); + button.add_css_class('osd'); + button.add_css_class('circular'); + + if(name === 'maximize') + name = 'toggle-maximized'; + + button.connect('clicked', + this._onWindowButtonActivate.bind(this, name) + ); + + return button; + } + + _updateFloatIcon(isFloating) + { + const floatButton = this.extraButtonsBox.get_first_child(); + if(!floatButton) return; + + const iconName = (isFloating) + ? 'pip-out-symbolic' + : 'pip-in-symbolic'; + + if(floatButton.icon_name !== iconName) + floatButton.icon_name = iconName; + } + _onWindowButtonActivate(action) { this.activate_action(`window.${action}`, null); @@ -29,3 +251,49 @@ class ClapperHeaderBar extends HeaderBarBase this.root.fullscreen(); } }); + +var HeaderBarPopover = GObject.registerClass({ + GTypeName: 'ClapperHeaderBarPopover', +}, +class ClapperHeaderBarPopover extends Gtk.PopoverMenu +{ + _init(model) + { + super._init({ + menu_model: model, + }); + + this.connect('map', this._onMap.bind(this)); + this.connect('closed', this._onClosed.bind(this)); + } + + _onMap() + { + const { child } = this.root; + + if( + !child + || !child.player + || !child.player.widget + ) + return; + + child.revealControls(); + child.isPopoverOpen = true; + } + + _onClosed() + { + const { child } = this.root; + + if( + !child + || !child.player + || !child.player.widget + ) + return; + + child.revealControls(); + child.isPopoverOpen = false; + } +}); diff --git a/src/headerbarBase.js b/src/headerbarBase.js deleted file mode 100644 index 46950070..00000000 --- a/src/headerbarBase.js +++ /dev/null @@ -1,288 +0,0 @@ -const { GObject, Gtk } = imports.gi; -const Debug = imports.src.debug; -const Misc = imports.src.misc; - -const { debug } = Debug; - -var HeaderBarBase = GObject.registerClass({ - GTypeName: 'ClapperHeaderBarBase', -}, -class ClapperHeaderBarBase extends Gtk.Box -{ - _init() - { - super._init({ - can_focus: false, - orientation: Gtk.Orientation.HORIZONTAL, - spacing: 6, - margin_top: 6, - margin_start: 6, - margin_end: 6, - }); - this.add_css_class('osdheaderbar'); - - this.isMaximized = false; - this.isMenuOnLeft = true; - - const uiBuilder = Misc.getBuilderForName('clapper.ui'); - - this.menuWidget = new Gtk.Box({ - orientation: Gtk.Orientation.HORIZONTAL, - valign: Gtk.Align.CENTER, - spacing: 6, - }); - - this.menuButton = new Gtk.MenuButton({ - icon_name: 'open-menu-symbolic', - valign: Gtk.Align.CENTER, - can_focus: false, - }); - const menuToggleButton = this.menuButton.get_first_child(); - menuToggleButton.add_css_class('osd'); - const mainMenuModel = uiBuilder.get_object('mainMenu'); - const mainMenuPopover = new HeaderBarPopover(mainMenuModel); - this.menuButton.set_popover(mainMenuPopover); - this.menuButton.add_css_class('circular'); - this.menuWidget.append(this.menuButton); - - this.extraButtonsBox = new Gtk.Box({ - orientation: Gtk.Orientation.HORIZONTAL, - valign: Gtk.Align.CENTER, - }); - this.extraButtonsBox.add_css_class('linked'); - - const floatButton = new Gtk.Button({ - icon_name: 'pip-in-symbolic', - can_focus: false, - }); - floatButton.add_css_class('osd'); - floatButton.add_css_class('circular'); - floatButton.add_css_class('linkedleft'); - floatButton.connect('clicked', - this._onFloatButtonClicked.bind(this) - ); - this.extraButtonsBox.append(floatButton); - - const separator = new Gtk.Separator({ - orientation: Gtk.Orientation.VERTICAL, - }); - separator.add_css_class('linkseparator'); - this.extraButtonsBox.append(separator); - - const fullscreenButton = new Gtk.Button({ - icon_name: 'view-fullscreen-symbolic', - can_focus: false, - }); - fullscreenButton.add_css_class('osd'); - fullscreenButton.add_css_class('circular'); - fullscreenButton.add_css_class('linkedright'); - fullscreenButton.connect('clicked', - this._onFullscreenButtonClicked.bind(this) - ); - this.extraButtonsBox.append(fullscreenButton); - this.menuWidget.append(this.extraButtonsBox); - - this.spacerWidget = new Gtk.Box({ - hexpand: true, - }); - - this.minimizeWidget = this._getWindowButton('minimize'); - this.maximizeWidget = this._getWindowButton('maximize'); - this.closeWidget = this._getWindowButton('close'); - - const gtkSettings = Gtk.Settings.get_default(); - this._onLayoutUpdate(gtkSettings); - - gtkSettings.connect( - 'notify::gtk-decoration-layout', - this._onLayoutUpdate.bind(this) - ); - } - - setMenuOnLeft(isOnLeft) - { - if(this.isMenuOnLeft === isOnLeft) - return; - - if(isOnLeft) { - this.menuWidget.reorder_child_after( - this.extraButtonsBox, this.menuButton - ); - } - else { - this.menuWidget.reorder_child_after( - this.menuButton, this.extraButtonsBox - ); - } - - this.isMenuOnLeft = isOnLeft; - } - - setMaximized(isMaximized) - { - if(this.isMaximized === isMaximized) - return; - - this.maximizeWidget.icon_name = (isMaximized) - ? 'window-restore-symbolic' - : 'window-maximize-symbolic'; - - this.isMaximized = isMaximized; - } - - _onLayoutUpdate(gtkSettings) - { - const gtkLayout = gtkSettings.gtk_decoration_layout; - - this._replaceButtons(gtkLayout); - } - - _replaceButtons(gtkLayout) - { - const modLayout = gtkLayout.replace(':', ',spacer,'); - const layoutArr = modLayout.split(','); - - let lastWidget = null; - - let showMinimize = false; - let showMaximize = false; - let showClose = false; - - let menuAdded = false; - let spacerAdded = false; - - debug(`headerbar layout: ${modLayout}`); - - for(let name of layoutArr) { - /* Menu might be named "appmenu" */ - if(!menuAdded && (!name || name === 'appmenu' || name === 'icon')) - name = 'menu'; - - const widget = this[`${name}Widget`]; - if(!widget) continue; - - if(!widget.parent) - this.append(widget); - else - this.reorder_child_after(widget, lastWidget); - - switch(name) { - case 'spacer': - spacerAdded = true; - break; - case 'minimize': - showMinimize = true; - break; - case 'maximize': - showMaximize = true; - break; - case 'close': - showClose = true; - break; - case 'menu': - this.setMenuOnLeft(!spacerAdded); - menuAdded = true; - break; - default: - break; - } - - lastWidget = widget; - } - - this.minimizeWidget.visible = showMinimize; - this.maximizeWidget.visible = showMaximize; - this.closeWidget.visible = showClose; - } - - _getWindowButton(name) - { - const button = new Gtk.Button({ - icon_name: `window-${name}-symbolic`, - valign: Gtk.Align.CENTER, - can_focus: false, - }); - button.add_css_class('osd'); - button.add_css_class('circular'); - - if(name === 'maximize') - name = 'toggle-maximized'; - - button.connect('clicked', - this._onWindowButtonActivate.bind(this, name) - ); - - return button; - } - - _updateFloatIcon(isFloating) - { - const floatButton = this.extraButtonsBox.get_first_child(); - if(!floatButton) return; - - const iconName = (isFloating) - ? 'pip-out-symbolic' - : 'pip-in-symbolic'; - - if(floatButton.icon_name !== iconName) - floatButton.icon_name = iconName; - } - - _onWindowButtonActivate(action) - { - } - - _onFloatButtonClicked(button) - { - } - - _onFullscreenButtonClicked(button) - { - } -}); - -var HeaderBarPopover = GObject.registerClass({ - GTypeName: 'ClapperHeaderBarPopover', -}, -class ClapperHeaderBarPopover extends Gtk.PopoverMenu -{ - _init(model) - { - super._init({ - menu_model: model, - }); - - this.connect('map', this._onMap.bind(this)); - this.connect('closed', this._onClosed.bind(this)); - } - - _onMap() - { - const { child } = this.root; - - if( - !child - || !child.player - || !child.player.widget - ) - return; - - child.revealControls(); - child.isPopoverOpen = true; - } - - _onClosed() - { - const { child } = this.root; - - if( - !child - || !child.player - || !child.player.widget - ) - return; - - child.revealControls(); - child.isPopoverOpen = false; - } -});