Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vsuharnikov/7fc213e0599da3dc19c8372ab9410f06 to your computer and use it in GitHub Desktop.
Save vsuharnikov/7fc213e0599da3dc19c8372ab9410f06 to your computer and use it in GitHub Desktop.
The following shows how you can tell macOS to assign an application to always show on all desktops, one specific desktop, or to unbind it.

macOS - Setting 'Assign to Desktop' via Terminal

The following shows how you can tell macOS to assign an application to show on one specific desktop, all desktops, or just a single desktop.

Show Current Config

⇒ defaults read com.apple.spaces app-bindings
{
    "com.apple.activitymonitor" = AllSpaces;
    "com.googlecode.iterm2" = AllSpaces;
    "com.riotgames.riotgames.riotclientux" = AllSpaces;
    "com.toggl.toggldesktop.toggldesktop" = AllSpaces;
    "org.audacityteam.audacity" = "7B8802D8-756C-445B-AE72-23FCABFC74C4";
    "org.whispersystems.signal-desktop" = AllSpaces;
    "ru.keepcoder.telegram" = AllSpaces;
}
⇒ /usr/libexec/PlistBuddy -c "Print :app-bindings" ~/Library/Preferences/com.apple.spaces.plist
Dict {
    ru.keepcoder.telegram = AllSpaces
    com.googlecode.iterm2 = AllSpaces
    com.riotgames.riotgames.riotclientux = AllSpaces
    com.toggl.toggldesktop.toggldesktop = AllSpaces
    org.whispersystems.signal-desktop = AllSpaces
    com.apple.activitymonitor = AllSpaces
    org.audacityteam.audacity = 7B8802D8-756C-445B-AE72-23FCABFC74C4
}
⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '."app-bindings"'
{
  "ru.keepcoder.telegram": "AllSpaces",
  "com.googlecode.iterm2": "AllSpaces",
  "com.riotgames.riotgames.riotclientux": "AllSpaces",
  "com.toggl.toggldesktop.toggldesktop": "AllSpaces",
  "org.whispersystems.signal-desktop": "AllSpaces",
  "com.apple.activitymonitor": "AllSpaces",
  "org.audacityteam.audacity": "7B8802D8-756C-445B-AE72-23FCABFC74C4"
}

Assign to 'None'

⇒ /usr/libexec/PlistBuddy -c "Delete :app-bindings:im.beeper" ~/Library/Preferences/com.apple.spaces.plist
# successfully deleted

⇒ killall Dock
# to ensure it is updated properly based on the plist changes
⇒ /usr/libexec/PlistBuddy -c "Delete :app-bindings:im.beeper" ~/Library/Preferences/com.apple.spaces.plist
Delete: Entry, ":app-bindings:im.beeper", Does Not Exist

Assign to 'All Desktops'

⇒ /usr/libexec/PlistBuddy -c "Add :app-bindings:im.beeper string AllSpaces" ~/Library/Preferences/com.apple.spaces.plist

⇒ killall Dock
# to ensure it is updated properly based on the plist changes

Assign to 'This Desktop' (or a specific desktop)

Note: I haven't tested this

⇒ /usr/libexec/PlistBuddy -c "Add :app-bindings:im.beeper string TODO-THE-UUID-OF-THE-DESKTOP" ~/Library/Preferences/com.apple.spaces.plist

⇒ killall Dock
# to ensure it is updated properly based on the plist changes

Getting the Desktop Space UUIDs

To get the current desktop space:

⇒ /usr/libexec/PlistBuddy -c "Print :SpacesDisplayConfiguration:'Management Data':Monitors:0:'Current Space'" ~/Library/Preferences/com.apple.spaces.plist
Dict {
    id64 = 617
    ManagedSpaceID = 617
    type = 0
    uuid = 671BB3AE-0E2C-42C9-B259-C5004B30DEE1
}

Or specifically the uuid for it:

⇒ /usr/libexec/PlistBuddy -c "Print :SpacesDisplayConfiguration:'Management Data':Monitors:0:'Current Space':uuid" ~/Library/Preferences/com.apple.spaces.plist
671BB3AE-0E2C-42C9-B259-C5004B30DEE1

The uuids for the other spaces are available as well, but it's harder to filter for them specifically with PlistBuddy alone:

⇒ /usr/libexec/PlistBuddy -c "Print :SpacesDisplayConfiguration:'Management Data':Monitors:0:Spaces" ~/Library/Preferences/com.apple.spaces.plist
# Lots of data

You can crudely filter for this with a grep like this, but it still leaves a lot of noise:

⇒ /usr/libexec/PlistBuddy -c "Print :SpacesDisplayConfiguration:'Management Data':Monitors:0:Spaces" ~/Library/Preferences/com.apple.spaces.plist | grep -B 4 'uuid ='
# More focussed data, but still noisy

You could also potentially get the uuids for all of the spaces with a command like this, but it doesn't leave a lot of context as to which one maps to which:

⇒ /usr/libexec/PlistBuddy -c "Print :SpacesDisplayConfiguration:'Space Properties'" ~/Library/Preferences/com.apple.spaces.plist
Array {
    Dict {
        name = 9160DD0A-9F52-4B1E-A4C9-B4F6ADD92A78
        windows = Array {
            74392
            325
            142
            6672
            41189
            45074
            14759
        }
    }
    Dict {
        name = 60D3C0EA-F836-4033-90C3-461D667C13FA
        windows = Array {
            74392
            325
            142
            264
            268
            14761
        }
    }
# ..snip..

Another way to achieve this is by using plutil to convert the plist to JSON, then pipe that to jq, which allows for much more powerful filtering/manipulation.

Get the current space:

⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors[0]."Current Space"'
{
  "id64": 617,
  "ManagedSpaceID": 617,
  "type": 0,
  "uuid": "671BB3AE-0E2C-42C9-B259-C5004B30DEE1"
}

Or just the uuid of it:

⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors[0]."Current Space".uuid'
"671BB3AE-0E2C-42C9-B259-C5004B30DEE1"

# Or if we want to make this more robust even if the first item in the array isn't the one with the 'Current Space'
⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors | map(select(has("Current Space"))."Current Space") | first | .uuid'
"671BB3AE-0E2C-42C9-B259-C5004B30DEE1"

We can also be a little bit fancier, and get the uuids from all of the elements within the Management Data key, as well as the Display Identifier associated with that space:

⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors[] | {displayIdentifier: ."Display Identifier", uuid: (if has("Current Space") then ."Current Space".uuid else ."Collapsed Space".uuid end)}'
{
  "displayIdentifier": "Main",
  "uuid": "671BB3AE-0E2C-42C9-B259-C5004B30DEE1"
}
{
  "displayIdentifier": "62F91CDC-6EA4-194B-17B7-E58AA676B272",
  "uuid": "AA7F793A-5D1D-4752-B46E-39FFBEBDEA09"
}
{
  "displayIdentifier": "B17DC16B-9DA0-4B53-B720-A946ADC56B8C",
  "uuid": "AFFB5DFA-AD24-4ED7-A1DA-A44BEFDDFEE0"
}
{
  "displayIdentifier": "C8E42782-7DDB-C015-81BD-04B21E4C01F2",
  "uuid": "8911EACB-5CED-48B0-8FA5-88994B43C732"
}

We can see details about all of the current spaces that are open with:

⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors | map(select(has("Current Space"))) | first | .Spaces'
# Lots of data

But to narrow that down more, we can seperate between 'normal' desktop spaces (which seem to be type: 0):

# Full data
⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors | map(select(has("Current Space"))) | first | .Spaces | map(select(has("TileLayoutManager") | not))'
[
  {
    "id64": 617,
    "ManagedSpaceID": 617,
    "type": 0,
    "uuid": "671BB3AE-0E2C-42C9-B259-C5004B30DEE1"
  },
  {
    "id64": 14,
    "ManagedSpaceID": 14,
    "type": 0,
    "uuid": "9160DD0A-9F52-4B1E-A4C9-B4F6ADD92A78"
  },
  # ..snip..
]

# Just the UUIDs
⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors | map(select(has("Current Space"))) | first | .Spaces | map(select(has("TileLayoutManager") | not).uuid)'
[
  "671BB3AE-0E2C-42C9-B259-C5004B30DEE1",
  "9160DD0A-9F52-4B1E-A4C9-B4F6ADD92A78",
  "6A913ADE-99CD-47CA-94AC-F7D3D41C3475",
  "60D3C0EA-F836-4033-90C3-461D667C13FA",
  "56BB3123-46D8-410A-AC13-C1702362A25C",
  "02F34F40-3FE7-40E6-9DDF-A3B2AA65B862",
  "6D19DEE8-FD58-44EB-B1C2-5ED709AA7A6F",
  "7B8802D8-756C-445B-AE72-23FCABFC74C4"
]

And those that are based on a maximised window (or multiple maximised windows):

# Full data
⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors | map(select(has("Current Space"))) | first | .Spaces | map(select(has("TileLayoutManager")))'
[
  {
    "fs_wid": 168,
    "id64": 27,
    "TileLayoutManager": { /* ..snip..*/ },
    "uuid": "0ADEC86B-0C91-47A4-892E-995CA8CC008A",
    "ManagedSpaceID": 27,
    "type": 4,
    "WallSpace": {
      "id64": 28,
      "ManagedSpaceID": 27,
      "type": 6,
      "uuid": "C3DB5651-B361-4392-B0F6-C8716F9FADA2"
    },
    "pid": 727
  },
  {
    "id64": 98,
    "TileLayoutManager": { /* ..snip..*/ },
    "uuid": "918481C6-3272-4BE6-B981-107BA85FA8D9",
    "ManagedSpaceID": 98,
    "type": 4,
    "WallSpace": {
      "id64": 99,
      "ManagedSpaceID": 98,
      "type": 6,
      "uuid": "2C1163D2-081E-4484-9DD0-9385640649BB"
    },
    "pid": [
      78743,
      14348
    ]
  },
  // ..snip..
]

# Just the UUIDs
⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors | map(select(has("Current Space"))) | first | .Spaces | map(select(has("TileLayoutManager")).uuid)'
[
  "0ADEC86B-0C91-47A4-892E-995CA8CC008A",
  "918481C6-3272-4BE6-B981-107BA85FA8D9",
  "9E77A145-5756-44D2-9877-3CD3F3FBB01A"
]

We can see that the spaces of maximised windows (which appear to be type: 4) additionally contain a TileLayoutManager object, a WallSpace object, the pid of the maximised window(s) (either integer, or array of integers), a fs_wid

The TileSpaces in particular seems to contain interesting data, so let's filter in on that.

Here is an example of the TileLayoutManager data for a space that contains a single maximised window:

⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors | map(select(has("Current Space"))) | first | .Spaces | map(select(has("TileLayoutManager") and (.pid | type != "array"))) | first | .TileLayoutManager'
{
  "Age": 483877.12677943,
  "PreferredLayout": [
    {
      "FirstTileSize": {
        "Width": 1792,
        "Height": 1120
      },
      "DisplaySize": {
        "Width": 1792,
        "Height": 1120
      }
    },
    {
      "FirstTileSize": {
        "Width": 3440,
        "Height": 1440
      },
      "DisplaySize": {
        "Width": 3440,
        "Height": 1440
      }
    }
  ],
  "Layout Rect": {
    "Width": 3440,
    "Height": 1440,
    "Y": 0,
    "X": 0
  },
  "Max Tile Config": {
    "Width": 2,
    "Height": 1
  },
  "ReservedArea": {
    "Right": 0,
    "Left": 0,
    "Bottom": 0,
    "Top": 0
  },
  "TileSpaces": [
    {
      "uuid": "242659BA-8816-433B-BB28-27506B129806",
      "id64": 29,
      "TileLimitedClipping": true,
      "TileType": "Primary",
      "ManagedSpaceID": 27,
      "fromSpace": "9160DD0A-9F52-4B1E-A4C9-B4F6ADD92A78",
      "TileWindowID": 168,
      "fs_wid": 168,
      "type": 5,
      "SizeConstraints": {
        "Min": {
          "Width": 86,
          "Height": 29
        },
        "Max": {
          "Width": 100000,
          "Height": 100000
        },
        "Preferred": {
          "Width": 1600,
          "Height": 928
        }
      },
      "appName": "Spotify",
      "TileRect": {
        "Width": 3440,
        "Height": 1440,
        "Y": 0,
        "X": 0
      },
      "pid": 727,
      "name": "Spotify Premium",
      "com.apple.appkit.disablemcexit": false
    }
  ],
  "ConfigAge": 483877.126187566,
  "Inter-Tile Spacing": {
    "Width": 12,
    "Height": 12
  }
}

And this is an example of the TileLayoutManager data for a space that contains a multiple maximised windows:

⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors | map(select(has("Current Space"))) | first | .Spaces | map(select(has("TileLayoutManager") and (.pid | type == "array"))) | first | .TileLayoutManager'
{
  "Age": 480896.491663617,
  "PreferredLayout": [
    {
      "FirstTileSize": {
        "Width": 1965,
        "Height": 1440
      },
      "DisplaySize": {
        "Width": 3440,
        "Height": 1440
      }
    }
  ],
  "Layout Rect": {
    "Width": 3440,
    "Height": 1440,
    "Y": 0,
    "X": 0
  },
  "Max Tile Config": {
    "Width": 2,
    "Height": 1
  },
  "ReservedArea": {
    "Right": 0,
    "Left": 0,
    "Bottom": 0,
    "Top": 0
  },
  "TileSpaces": [
    {
      "uuid": "95AB747E-C62C-4ABE-B274-687250EC2592",
      "id64": 818,
      "TileLimitedClipping": true,
      "TileType": "Primary",
      "ManagedSpaceID": 98,
      "fromSpace": "671BB3AE-0E2C-42C9-B259-C5004B30DEE1",
      "TileWindowID": 42954,
      "fs_wid": 42954,
      "type": 5,
      "SizeConstraints": {
        "Min": {
          "Width": 727,
          "Height": 480
        },
        "Max": {
          "Width": 100000,
          "Height": 100000
        },
        "Preferred": {
          "Width": 1965,
          "Height": 1440
        }
      },
      "appName": "Fantastical",
      "TileRect": {
        "Width": 1965,
        "Height": 1440,
        "Y": 0,
        "X": 0
      },
      "pid": 78743,
      "name": "Fantastical",
      "com.apple.appkit.disablemcexit": false
    },
    {
      "uuid": "94253DF6-03DB-49FB-8608-BD86932B4267",
      "id64": 108,
      "TileLimitedClipping": true,
      "TileType": "Primary",
      "ManagedSpaceID": 98,
      "fromSpace": "9160DD0A-9F52-4B1E-A4C9-B4F6ADD92A78",
      "TileWindowID": 1111,
      "fs_wid": 1111,
      "type": 5,
      "SizeConstraints": {
        "Min": {
          "Width": 351,
          "Height": 524
        },
        "Max": {
          "Width": 100000,
          "Height": 100000
        },
        "Preferred": {
          "Width": 1463,
          "Height": 1440
        }
      },
      "appName": "Reminders",
      "TileRect": {
        "Width": 1463,
        "Height": 1440,
        "Y": 0,
        "X": 1977
      },
      "pid": 14348,
      "name": "Reminders",
      "com.apple.appkit.disablemcexit": false
    }
  ],
  "ConfigAge": 216451.82905787101,
  "Inter-Tile Spacing": {
    "Width": 12,
    "Height": 12
  }
}

Notice that the TileLayoutManager's TileSpaces array appears to have an entry for each maximised window, and they appear to be of type: 5. Within that are keys including:

  • SizeContraints object that has Min/Max/Preferred objects, each with a Width/Height
  • TileRect object contains the Width/Height/X/Y of each window (which can also be used to determine which maximised window is on the left, and which on the right)
  • pid/name/appName contains the process id / name of the application
  • fromSpace appears to contain the UUID that the window was maximised from
  • etc

Based on the above, we can filter some of the noise down to easily see the which apps are the maximised window(s) that are in each of these spaces, the window size, the uuid of the space the windows came from, and the uuid for that 'maximised window' space, among other things:

⇒ plutil -convert json -o - ~/Library/Preferences/com.apple.spaces.plist | jq '.SpacesDisplayConfiguration."Management Data".Monitors | map(select(has("Current Space"))) | first | .Spaces | map(select(.TileLayoutManager) | (.TileLayoutManager.TileSpaces | map(pick(.type, .uuid, .fromSpace, .pid, .appName, .name, .TileRect))) as $TileSpaces | pick(.type, .uuid) + { TileLayoutManager: { $TileSpaces } } )'
[
  {
    "type": 4,
    "uuid": "0ADEC86B-0C91-47A4-892E-995CA8CC008A",
    "TileLayoutManager": {
      "TileSpaces": [
        {
          "type": 5,
          "uuid": "242659BA-8816-433B-BB28-27506B129806",
          "fromSpace": "9160DD0A-9F52-4B1E-A4C9-B4F6ADD92A78",
          "pid": 727,
          "appName": "Spotify",
          "name": "Spotify Premium",
          "TileRect": {
            "Width": 3440,
            "Height": 1440,
            "Y": 0,
            "X": 0
          }
        }
      ]
    }
  },
  {
    "type": 4,
    "uuid": "918481C6-3272-4BE6-B981-107BA85FA8D9",
    "TileLayoutManager": {
      "TileSpaces": [
        {
          "type": 5,
          "uuid": "95AB747E-C62C-4ABE-B274-687250EC2592",
          "fromSpace": "671BB3AE-0E2C-42C9-B259-C5004B30DEE1",
          "pid": 78743,
          "appName": "Fantastical",
          "name": "Fantastical",
          "TileRect": {
            "Width": 1965,
            "Height": 1440,
            "Y": 0,
            "X": 0
          }
        },
        {
          "type": 5,
          "uuid": "94253DF6-03DB-49FB-8608-BD86932B4267",
          "fromSpace": "9160DD0A-9F52-4B1E-A4C9-B4F6ADD92A78",
          "pid": 14348,
          "appName": "Reminders",
          "name": "Reminders",
          "TileRect": {
            "Width": 1463,
            "Height": 1440,
            "Y": 0,
            "X": 1977
          }
        }
      ]
    }
  },
  // ..snip..
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment