Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to loop through all Mac desktop spaces

Tags:

macos

swift

cocoa

I'm trying to set a desktop background for all screens AND spaces (preexisting and new). However, I can't seem to find a way to set the background for all the existing spaces (and any new spaces created use the old background).

Here is what I have so far:

let sqlData = NSMutableArray()
let paths = NSSearchPathForDirectoriesInDomains(.ApplicationSupportDirectory, .UserDomainMask, true)
let appSupportDirectory = paths.first! as NSString
let dbPath = appSupportDirectory.stringByAppendingPathComponent("Dock/desktoppicture.db") as NSString

var db: COpaquePointer = nil
if sqlite3_open(dbPath.UTF8String, &db) == SQLITE_OK {
    var statement: COpaquePointer = nil

    if sqlite3_exec(db, "DELETE FROM data", nil, nil, nil) != SQLITE_OK {
        let errmsg = String.fromCString(sqlite3_errmsg(db))
        print("error deleting table row: \(errmsg)")
    }

    if sqlite3_exec(db, "INSERT INTO DATA (VALUE) VALUES ('\(getBackgroundImagePath())');", nil, nil, nil) != SQLITE_OK {
        let errmsg = String.fromCString(sqlite3_errmsg(db))
        print("error inserting table row: \(errmsg)")
    }

    let workspace = NSWorkspace.sharedWorkspace()

    for screen in NSScreen.screens()! {
        do {
            let options = workspace.desktopImageOptionsForScreen(screen)
            try workspace.setDesktopImageURL(NSURL(fileURLWithPath: getBackgroundImagePath()), forScreen: screen, options: options!)
        } catch let error as NSError {
            NSLog("\(error.localizedDescription)")
        }
    }

    system("/usr/bin/killall Dock")
}

sqlite3_close(db)

Note: I update the .db file found in ~/Library/Application Support/Dock/desktoppicture.db. Since this doesn't actually update the background, I then proceed to loop through each screen and set them manually.

Although this changes all of the screen's backgrounds, any non-active spaces are not changed, and any new spaces created use the old background.

I'm using this code within a small app I made on GitHub, and this is an issue a user reported. You can find the issue here (with a terminal solution).

Apple has a seemingly relevant project here, but even they don't update multiple spaces.

Also, if you update the background through the default mac settings app, it also doesn't change pre-existing spaces. Is it impossible?

like image 930
Josue Espinosa Avatar asked Mar 23 '16 18:03

Josue Espinosa


People also ask

How do you scroll between desktops on a Mac?

Move between spacesOn a trackpad, swipe left or right with three or four fingers. On a Magic Mouse, swipe with two fingers. Press the Control key and the Right or Left arrow key. Enter Mission Control, move the pointer to the top edge of the screen, then click a space in the Spaces bar.

How do I Auto organize my Mac desktop?

If you want your desktop icons to be auto-arranged, you can do so by clicking on the View menu and then hold on the ALT key on the keyboard until you see the "Keep Arranged By" option show up on the View menu.

How do you switch desktops on a Mac without trackpad?

Using the Mouse: Switch between desktops by clicking on them in the top menu bar. Trackpad Gesture: Switching between desktops can also be done by swiping four fingers to the right or left on the trackpad. Keyboard Shortcut: Using the Control key along with the right or left arrow key will also switch between desktops.

How do I see all open windows on a Mac?

Show or move all open windows Show all open windows for the current app: Press Control-Down Arrow. If App Exposé is selected in Trackpad preferences, you can also swipe down with three fingers. To return to the desktop, press the keys again or swipe up.


1 Answers

OS X Desktop Picture Global Updating Across Spaces

In desktoppicture.db an update query can be run on the data table with the path of the new image (value). It shouldn't be necessary to delete and then insert the values, or use loops. Using an unscoped query calls update, and by doing so it will update every row in the data table.

(The example below uses the SQLite.swift language layer, which uses a type-safe pure Swift interface)

func globalDesktopPicture(image: String) {

    let paths: [String] = NSSearchPathForDirectoriesInDomains(.ApplicationSupportDirectory,
                                                              .UserDomainMask, true)
    let appSup: String = paths.first!
    let dbPath: String = (appSup as NSString).stringByAppendingPathComponent("Dock/desktoppicture.db")

    let dbase = try? Connection("\(dbPath)")
    let value = Expression<String?>("value")    
    let table = Table("data")
    try! dbase!.run(table.update(value <- image))

    system("/usr/bin/killall Dock")
}

The same concept/principle of updating the db applies just the same if you instead decide to use the traditional/legacy (bridging headers) method of doing SQLite3 queries:

func legacyGlobalDesktopPicture(image: String) {

    let paths: [String] = NSSearchPathForDirectoriesInDomains(.ApplicationSupportDirectory,
                                                              .UserDomainMask, true)
    let appSup: String = paths.first!
    let dbPath: String = (appSup as NSString).stringByAppendingPathComponent("Dock/desktoppicture.db")

    var db: COpaquePointer = nil
    if sqlite3_open(dbPath, &db) == SQLITE_OK {

        if sqlite3_exec(db, "UPDATE DATA SET VALUE = ('\(image)');", nil, nil, nil) != SQLITE_OK {
            let errmsg = String.fromCString(sqlite3_errmsg(db))
            print("error inserting table row: \(errmsg)")
        }

        system("/usr/bin/killall Dock")
    }
    sqlite3_close(db)
}

NOTE: The examples above are quite minimal and should include some error checking, etc.

Additional Info:

  • How to get the path to the current space wallpaper?
  • SQLite.swift Documentation : Updating Rows
  • SQLite.swift / A type-safe, Swift-language layer over SQLite3
like image 185
l'L'l Avatar answered Sep 28 '22 04:09

l'L'l