14

I am aware you can do it from Mission Control by clicking and there is no shortcut available in 'Keyboard'.

Are there any ways to do this by using a 3rd party program or Applescript?

enter image description here

enter image description here

2

4 Answers 4

1

Update: This method works in OS X 10.11 and earlier at least to OS X 10.8 (didn't test it on anything older then OS X 10.8) but no longer works as coded in macOS 10.12 due to significant changes to Mission Control made by Apple.


To programmatically add a Desktop in Mission Control the code below can be used as an AppleScript or a BASH Script in conjunction with an Automator Service using Run AppleScript or Run Shell Script, respectively, and a key sequence assigned to the Service in System Preferences in Keyboard Shortcuts.


AppleScript Code:

do shell script "open -a 'Mission Control'"
delay 0.5
tell application "System Events" to click (every button whose value of attribute "AXDescription" is "add desktop") of group 1 of process "Dock"
delay 0.5
tell application "System Events" to key code 53

BASH Script Code:

#!/bin/bash

open -a 'Mission Control'
osascript -e 'delay 0.5' \
          -e 'tell application "System Events" to click (every button whose value of attribute "AXDescription" is "add desktop") of group 1 of process "Dock"' \
          -e 'delay 0.5' \
          -e 'tell application "System Events" to key code 53'

  • Open Automator and select Service.

  • Set: Service receives no input in any application

  • Add either a Run AppleScript or Run Shell Script Action.

  • Add the appropriate code for the target Action.

  • Save the Service as, e.g.: Add New Desktop

  • Assign a keyboard shortcut for the Service in System Preferences.

Note: You'll have to assign a key sequence that is not used elsewhere on the System or in Finder if you choose is over any application in the Service.

I tested it with: ⌃⌥⌘D (Control-Option-Command-D)

6
  • Thanks this worked great. Do you think you could make a second script for deleting spaces? Commented Apr 15, 2016 at 0:38
  • @Jonathan, Adding a Desktop is sort of a kludge, programmatically, to begin with and possible because there is an AXButton with the AXDescription of "add desktop" that can be clicked however the AXButton(s) under Mission Control with AXTitle, e.g. "Desktop 2", while it has a close element (a circle with a x, in the top left corner of the button) it is not addressable in the same manner as there is no "remove desktop" button. So I really do not know of an easy way to remove one programmatically, sorry. Commented Apr 15, 2016 at 1:39
  • That makes sense. Thanks for taking the time to explain it to me Commented Apr 15, 2016 at 2:16
  • I've tried this in macOS (10.12.1) and haven't had any luck. It opens Mission Control for the .5 seconds but the New Desktop button isn't pressed.
    – domi91c
    Commented Jan 21, 2017 at 0:34
  • 2
    @user3439894 Yes, I was just commenting in case someone had an answer for MacOS. I hadn't considered creating a separate question; should I? Thanks though, I appreciate the help.
    – domi91c
    Commented Jan 21, 2017 at 2:04
3

OK, using the Automator recording, I made it work with a revised version of the AppleScript in the other answer.

Replace "of group 1" with "of group 2 of group 1 of group 1 of":

on run {input, parameters}

    do shell script "open -a 'Mission Control'"
    delay 0.5
    tell application "System Events" to click (every button whose value of attribute "AXDescription" is "add desktop") of group 2 of group 1 of group 1 of process "Dock"
    delay 0.5
    tell application "System Events" to key code 53

    return input
end run
1
  • The checked answer didn't work for me, but this one did =) Commented Oct 23, 2018 at 20:54
1

Yep, that works, sort of. Problem is that user3439894's solution ends up throwing an error if the active application (Finder, textedit, etc.) hasn't been added to the Security & Privacy Accessibility pane.

To get around this, we need two workflows, user3439894's service with the updated group list as an Automator application, and a second Automator service to launch it.

The Automator Application (Saved into /Applications as "New Desktop".)

on run {input, parameters}

do shell script "open -a 'Mission Control'"

delay 0.5

tell application "System Events" to click (every button whose value of attribute "AXDescription" is "add desktop") of group 2 of group 1 of group 1 of process "Dock"

delay 0.5

tell application "System Events" to key code 53

return input

end run

Then we just need to create the second workflow as a service, using the "Launch Application" action and save it as "New_Desktop"

Last steps are to add “New Desktop.App” to  System Preferences > Security & Privacy > Accessibility

Then add your keyboard shortcut in System Preferences > Keyboard > Shortcuts > Services > General for the New_Desktop.workflow.

0

In 2024 (currently in Sonoma 14.6.1), it's possible to create/destroy spaces using Hammerspoon utility. Below is a simple example (this ensures each monitor has ten spaces, removing or adding spaces as needed).

local spaces = require("hs.spaces")
local hotkey = require("hs.hotkey")
local screen = require("hs.screen")
local menubar = require("hs.menubar")

-- Target number of spaces per screen
local TARGET_SPACES = 10

-- Function to get indexed spaces for a screen
local function getIndexedSpaces(scr)
    local allSpaces = spaces.allSpaces()
    local screenSpaces = allSpaces[scr:getUUID()] or {}
    local indexedSpaces = {}
    for i, spaceID in ipairs(screenSpaces) do
        indexedSpaces[i] = spaceID
    end
    return indexedSpaces
end

-- Function to ensure each screen has exactly TARGET_SPACES spaces
local function ensureSpacesPerScreen()
    for _, scr in ipairs(screen.allScreens()) do
        local indexedSpaces = getIndexedSpaces(scr)
        local spaceCount = #indexedSpaces
        
        if spaceCount < TARGET_SPACES then
            for i = 1, TARGET_SPACES - spaceCount do
                spaces.addSpaceToScreen(scr)
            end
            print("Added " .. (TARGET_SPACES - spaceCount) .. " spaces to screen " .. scr:name())
        elseif spaceCount > TARGET_SPACES then
            for i = spaceCount, TARGET_SPACES + 1, -1 do
                spaces.removeSpace(indexedSpaces[i])
            end
            print("Removed " .. (spaceCount - TARGET_SPACES) .. " spaces from screen " .. scr:name())
        else
            print("Screen " .. scr:name() .. " already has " .. TARGET_SPACES .. " spaces")
        end
    end
    
    hs.timer.doAfter(1, function()
        updateMenuBar()
    end)
end

-- Hotkey to trigger space adjustment
hotkey.bind({"cmd", "alt"}, "S", ensureSpacesPerScreen)

-- Menu bar item to show current space count for each screen
local spaceMenu = menubar.new()

function updateMenuBar()
    local menuText = {}
    for i, scr in ipairs(screen.allScreens()) do
        local indexedSpaces = getIndexedSpaces(scr)
        table.insert(menuText, "Screen " .. i .. ": " .. #indexedSpaces)
    end
    spaceMenu:setTitle(table.concat(menuText, " "))
end

-- Initialize menu bar
updateMenuBar()

-- Watch for space or screen changes
spaces.watcher.new(updateMenuBar):start()
screen.watcher.new(updateMenuBar):start()

print("Space Manager loaded!")

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .