Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d83fe5f
first commit
hanspr Sep 12, 2025
f22a7a2
inform current monitor limitations
hanspr Sep 12, 2025
dd3c550
inform no support for multipe monitors
hanspr Sep 12, 2025
c6ad713
avoid errors while adding, removing window buttons order in config
hanspr Sep 13, 2025
ae3574f
add window title change feedback
hanspr Sep 13, 2025
c4c73c3
add options, improve instructions
hanspr Sep 13, 2025
1c8583e
control restart errors better
hanspr Sep 13, 2025
c68400c
control restart errors
hanspr Sep 13, 2025
6420f45
typos
hanspr Sep 14, 2025
7fa813c
typos
hanspr Sep 14, 2025
f9c7425
add version number
hanspr Sep 14, 2025
b6b1edd
typos
hanspr Sep 16, 2025
67d07eb
remove comas
hanspr Sep 16, 2025
df28686
consider monitors
hanspr Oct 3, 2025
d3a35d5
added window monitor change support
hanspr Oct 3, 2025
5135765
improve instructions
hanspr Oct 3, 2025
669c5f1
regex default
hanspr Oct 3, 2025
83e9798
improve instructions
hanspr Oct 3, 2025
6f888c5
fix ignore by window type
hanspr Oct 3, 2025
781eb0e
improve focus visual
hanspr Oct 4, 2025
32a915c
improve focus visual
hanspr Oct 4, 2025
54bc55a
fix error in metadata
hanspr Oct 4, 2025
e290022
fix metadata
hanspr Oct 4, 2025
f82f824
fix error messages on startup
hanspr Oct 4, 2025
5916650
improve settings descriptions
hanspr Oct 4, 2025
9ba891f
improve readme instructions, limitations
hanspr Oct 4, 2025
f795c9b
fix regex changed by user
hanspr Oct 5, 2025
ea9d7a0
fix: return default
hanspr Oct 5, 2025
df49b48
let user pick background color
hanspr Oct 6, 2025
2dc9741
do not show buttons on desktop selected
hanspr Oct 16, 2025
503235a
refactor, simplify code
hanspr Oct 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions maximus-buttons@hanspr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Maximus Buttons
--------------------

This applet is desinged to work in pair with:

* maximus-title@hanspr
* maximus extension to remove the title bar on maximized windows
* Multiple monitors: Add the applet to panels in all monitors to set the buttons on the active window monitor
* Multiple monitors: buttons will be visible on the current focused monitor window to improve focus visibility between monitors

# Features
* It will show the minimize, maximize, close buttons on the panel when a window is maximized
* It only make sense with Maximus extension, because you loose those buttons, after maximize

# How to configure
* Install the applet
* Add applet with the plus sign
* Edit the panel and reposition the applet at the far right or left of your panel.
* It makes more sense when the panel is on the top, but it will work on bottom panels as well

# Limitations
* No consideration for vertical panels, it's been tested on horizontal panels only

# Errors
* Please report any errors in github `https://github.com/linuxmint/cinnamon-spices-applets/issues`
342 changes: 342 additions & 0 deletions maximus-buttons@hanspr/files/maximus-buttons@hanspr/applet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
const Main = imports.ui.main
const Applet = imports.ui.applet
const Settings = imports.ui.settings
const SignalManager = imports.misc.signalManager
const Cinnamon = imports.gi.Cinnamon
const St = imports.gi.St

const APPNAME = 'Maximus Tittle Buttons'
const tracker = Cinnamon.WindowTracker.get_default()
const UUID = 'maximus-title-buttons@hanspr'

class MyApplet extends Applet.TextIconApplet {
constructor(metadata, orientation, panelHeight, instanceId) {
try {
super(orientation, panelHeight, instanceId)
this.metadata = metadata
this.uuid = metadata.uuid
this.orientation = orientation
this.panelHeight = panelHeight
this.instanceId = instanceId
this.appletPath = metadata.path
this.hide_applet_label(false)
this.bindSettings()
this.initButtons()
this.connectSignals()
setTimeout(() => {
this.initialized = true
}, 500)
} catch (e) {
global.logError(e)
}
}

initButtons() {
let buttons = this.buttons_style.split(":")
if (this.checkButton(buttons, "maximize") || this.checkButton(buttons, "minimize") || this.checkButton(buttons, "close")) {
this.loadTheme()
}
this.button = []
this.createButtons(this.buttons_style)
this.on_panel_edit_mode_changed
this._showButtons(global.display.focus_window)
}

bindSettings() {
this.settings = new Settings.AppletSettings(this, this.uuid, this.instanceId)

this.settings.bind("buttons-style", "buttons_style", this.on_settings_changed)
this.settings.bind("buttons-theme", "buttonsTheme")
this.settings.bind("only-maximized", "onlyMaximized", this.on_settings_changed)
this.settings.bind("hide-buttons", "hideButtons", this.on_settings_changed)
this.settings.bind("on-desktop-shutdown", "onDesktopShutdown", this.on_settings_changed)
}

connectSignals() {
this.signalManager = new SignalManager.SignalManager(null)

this.signalManager.connect(Main.themeManager, 'theme-set', this.loadTheme, this)
this.signalManager.connect(global.settings, 'changed::panel-edit-mode', this.on_panel_edit_mode_changed, this)
this.signalManager.connect(global.window_manager, 'size-change', () => {
let w = global.display.focus_window
if (w) {
this._showButtons(w)
}
}, this)

this.signalManager.connect(global.display, 'notify::focus-window', () => {
let w = global.display.focus_window
if (w) {
this._showButtons(w)
}
}, this)
this.signalManager.connect(global.screen, 'window-monitor-changed', () => {
let w = global.display.focus_window
if (w) {
this._showButtons(w)
}
}, this)
this.signalManager.connect(global.screen, 'monitors-changed', () => {
let w = global.display.focus_window
if (w == null) {
this.setButtons("hide")
} else {
this._showButtons(w)
}
}, this)
}

on_panel_edit_mode_changed() {
let reactive = !global.settings.get_boolean("panel-edit-mode")

let b = this.buttons_style.split(":")
for (let i = 0; i < b.length; ++i) {
this.button[b[i]].reactive = reactive
}
}

getCssPath(theme) {
let cssPath = this.appletPath + "/themes/" + theme + "/style.css"
return cssPath
}

loadTheme() {
this.actor.set_style_class_name("window-buttons")
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme()
theme.load_stylesheet(this.getCssPath(this.buttonsTheme))
this.oldTheme = this.buttonsTheme
}

createButtons(buttonsStyle) {
buttonsStyle = buttonsStyle.split(":")
for (let i = 0; i < buttonsStyle.length; ++i) {
let buttonName = buttonsStyle[i] + "Button"
if (this[buttonName]) {
this[buttonName]()
}
}
}

iconButton() {
this.button["icon"] = new St.Button({
name: "iconButton",
style_class: "window-list-item",
reactive: true
})
this.actor.add(this.button["icon"])
}

minimizeButton() {
this.button["minimize"] = new St.Button({
name: "windowButton",
style_class: "minimize window-button",
reactive: true
})
this.actor.add(this.button["minimize"])
this.button["minimize"].connect("button-press-event", (actor, event) => {
let button = event.get_button()
if (button == 1) {
this.minimizeWindow()
return true
} else if (button == 3) {
this._applet_context_menu.toggle()
}
return true
})
}

minimizeWindow() {
if (this.button["minimize"].opacity == 0) {
return false
}
let activeWindow = global.display.focus_window
let app = tracker.get_window_app(activeWindow)
if (!app) {
return
} else {
activeWindow.minimize()
}
}

maximizeButton() {
this.button["maximize"] = new St.Button({
name: "windowButton",
style_class: "maximize window-button",
reactive: true
})
this.actor.add(this.button["maximize"])
this.button["maximize"].connect("button-press-event", (actor, event) => {
let button = event.get_button()
if (button == 1) {
this.maximizeWindow()
return true
} else if (button == 3) {
this._applet_context_menu.toggle()
}
return true
})
}

maximizeWindow() {
if (this.button["maximize"].opacity == 0) {
return false
}
let activeWindow = global.display.focus_window
if (activeWindow) {
let app = tracker.get_window_app(activeWindow)
if (!app) {
return
} else {
if (activeWindow.get_maximized()) {
activeWindow.unmaximize(3)
} else {
activeWindow.maximize(3)
}
}
}

}

closeButton() {
this.button["close"] = new St.Button({
name: "windowButton",
style_class: "close window-button",
reactive: true
})
this.actor.add(this.button["close"])
this.button["close"].connect("button-press-event", (actor, event) => {
let button = event.get_button()
if (button == 1) {
this.closeWindow()
return true
} else if (button == 3) {
this._applet_context_menu.toggle()
}
return true
})
}

closeWindow() {
if (this.button["close"].opacity == 0) {
return false
}
let activeWindow = global.display.focus_window
let app = tracker.get_window_app(activeWindow)

if (!app) {
if (this.onDesktopShutdown == true) {
this._session.ShutdownRemote()
}
return
} else {
activeWindow.delete(global.get_current_time())
}

}

updateWindowIcon() {
let activeWindow = global.display.focus_window
if (activeWindow) {
let app = tracker.get_window_app(activeWindow)
if (app) {
let icon = tracker.get_window_app(activeWindow).create_icon_texture(20)
this.button["icon"].set_child(icon)
this.actor.add(this.button['icon'])
} else {
let icon = new St.Icon({
icon_name: "video-display",
icon_type: St.IconType.SYMBOLIC,
style: "icon-size:20px;"
})
this.button["icon"].set_child(icon)
}
} else {
let icon = new St.Icon({
icon_name: "video-display",
icon_type: St.IconType.SYMBOLIC,
style: "icon-size:20px;"
})
this.button["icon"].set_child(icon)
}
}

_showButtons(w) {
if (!w) {
return
}
if (w.get_monitor() != this.panel.monitorIndex) {
this.setButtons("hide")
return
}
if (w.get_window_type() >= 1) {
this.setButtons("hide")
return
}
let buttons = this.buttons_style.split(":")
if (this.checkButton(buttons, "icon")) {
this.updateWindowIcon()
}
if (this.onlyMaximized == true) {
this.onlyMaximize(w)
} else {
this.setButtons("show")
}
}

on_settings_changed() {
this.actor.destroy_all_children()
let buttons = this.buttons_style.split(":")
if (this.checkButton(buttons, "maximize") || this.checkButton(buttons, "minimize") || this.checkButton(buttons, "close")) {
this.loadTheme()
}
this.button = []
this.createButtons(this.buttons_style)
this._showButtons(global.display.focus_window)
}

checkButton(arr, obj) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == obj) {
return true
}
}
return null
}

onlyMaximize(w) {
let app = tracker.get_window_app(w)
if (app && w.get_maximized()) {
this.setButtons("show")
} else {
this.setButtons("hide")
}
}

setButtons(what) {
let buttons = this.buttons_style.split(":")
let skip = 0
if (what == "show") {
skip = 255
}
for (let i = 0; i < buttons.length; ++i) {
if (buttons[i] == undefined || buttons[i] == "icon" || this.button[buttons[i]] == undefined || this.button[buttons[i]].opacity == skip) {
continue
}
if (what == "show") {
if (!this.hideButtons) {
this.button[buttons[i]].show()
}
this.button[buttons[i]].opacity = 255
} else {
if (!this.hideButtons) {
this.button[buttons[i]].hide()
}
this.button[buttons[i]].opacity = 0
}
}
}
}

function main(metadata, orientation, panelHeight, instanceId) {
return new MyApplet(metadata, orientation, panelHeight, instanceId)
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions maximus-buttons@hanspr/files/maximus-buttons@hanspr/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"max-instances": -1,
"description": "Maximus buttons",
"uuid": "maximus-buttons@hanspr",
"name": "Maximus Buttons",
"website": "https://github.com/linuxmint/cinnamon-spices-applets",
"version": "0.0.1",
"author": "hanspr",
"contributors": "Hans Peyrot"
}
Loading