Jump to content
Sign in to follow this  
ToddFrankson

MACOS "setDesktopImageURL"

Recommended Posts

So I have the ability to set the MACOS wallpaper on the current screen using this code (I believe Dave Nottage posted it).

 

procedure SetDesktopBackground(const ImagePath: string; const FillColor: TAlphaColor);
var
  NSFileURL: NSURL;
  NSWorkspace1: NSWorkspace;
  MainScreen: NSScreen;
  Error: NSError;
begin
  try
    // Convert Delphi file path to NSURL
    NSFileURL := TNSURL.Wrap(TNSURL.OCClass.fileURLWithPath(StrToNSStr(ImagePath)));
    NSWorkspace1 := TNSWorkspace.Wrap(TNSWorkspace.OCClass.sharedWorkspace);
    MainScreen := TNSScreen.Wrap(TNSScreen.OCClass.mainScreen);

    // Set the desktop image for the main screen
    if not NSWorkspace1.setDesktopImageURL(NSFileURL, MainScreen, nil, @Error) then
    begin
      ShowMessage('Failed to set desktop image: ' + NSStrToStr(Error.localizedDescription));
    end;
  except
    on E: Exception do
    begin
      ShowMessage('Error setting desktop image: ' + E.Message);
    end;
  end;

end;

 

My problem has been the 3rd parameter in SetDesktopImageURL.....

 

Evidently it takes an NSDictionary.  I have spent 3 days attempting to get this part to work with various attempts at translating ObjectiveC and swift code, using my brain and even several AI coding websites.  Nothing I seem to do actually builds the dictionary.

 

Can anyone lend me a hand?

 

 

I have managed to find the following constants (Not defined in Delphi BTW):

const
  NSImageScaleNone = 0;
  NSImageScaleAxesIndependently = 1;
  NSImageScaleProportionallyUpOrDown = 2;
  NSImageScaleProportionallyDown = 3;

 

Here's the Dictionary documentation : https://developer.apple.com/documentation/foundation/nsdictionary?language=objc

And the Documentation on the keys in the dictionary(Defined in the constants above): https://developer.apple.com/documentation/appkit/nsworkspace/desktopimageoptionkey?language=objc

 

 

Thanks

 

If someone could help me understand this, so I can get past it, I'd appreciate it.

Share this post


Link to post
14 minutes ago, ToddFrankson said:

I believe Dave Nottage posted it

I did? 🙂

15 minutes ago, ToddFrankson said:

My problem has been the 3rd parameter in SetDesktopImageURL....

This code works for me:

procedure SetDesktopBackground(const ImagePath: string; const FillColor: TAlphaColor);
var
  NSFileURL: NSURL;
  NSWorkspace1: NSWorkspace;
  MainScreen: NSScreen;
  LPointer: Pointer;
  Error: NSError;
begin
  try
    // Convert Delphi file path to NSURL
    NSFileURL := TNSURL.Wrap(TNSURL.OCClass.fileURLWithPath(StrToNSStr(ImagePath)));
    NSWorkspace1 := TNSWorkspace.Wrap(TNSWorkspace.OCClass.sharedWorkspace);
    MainScreen := TNSScreen.Wrap(TNSScreen.OCClass.mainScreen);

    LPointer := nil;
    // Set the desktop image for the main screen
    if not NSWorkspace1.setDesktopImageURL(NSFileURL, MainScreen, nil, @LPointer) then
    begin
      Error := TNSError.Wrap(LPointer);
      ShowMessage('Failed to set desktop image: ' + NSStrToStr(Error.localizedDescription));
    end;
  except
    on E: Exception do
    begin
      ShowMessage('Error setting desktop image: ' + E.Message);
    end;
  end;
end;

If you're having trouble creating a dictionary for the options, please show what code you attempted.

Share this post


Link to post
1 hour ago, Dave Nottage said:

I did? 🙂

This code works for me:

If you're having trouble creating a dictionary for the options, please show what code you attempted.

I think you posted it....I may be mistaken.  

 

Here is 1 variation:

procedure SetDesktopBackground(const ImagePath: string; const FillColor: TAlphaColor);
var
  Err: NSError;
  Options: NSMutableDictionary;
  ImageURL: NSURL;
  FillColorObj: NSColor;
begin
  // Convert the image file path to NSURL
  ImageURL := TNSURL.Wrap(TNSURL.OCClass.fileURLWithPath(NSStr(ImagePath)));

  if ImageURL = nil then
  begin
    Showmessage('Failed to create NSURL for the image file.');
    Exit;
  end;

  // Create a dictionary for desktop image options
  Options := TNSMutableDictionary.Wrap(TNSMutableDictionary.OCClass.dictionary);

  // Set the desktop image fill color
  FillColorObj := TNSColor.Wrap(TNSColor.OCClass.colorWithCalibratedRed(
    TAlphaColorRec(FillColor).R / 255,
    TAlphaColorRec(FillColor).G / 255,
    TAlphaColorRec(FillColor).B / 255,
    TAlphaColorRec(FillColor).A / 255));
  Options.setObject(FillColorObj, NSWorkspaceDesktopImageFillColorKey);

  // Set the desktop image scaling to none
  Options.setObject(TNSNumber.Wrap(TNSNumber.OCClass.numberWithInt(NSImageScaleProportionallyUpOrDown)),
                    NSWorkspaceDesktopImageScalingKey);

  // Set the desktop image for the main screen
  if not TNSWorkspace.Wrap(TNSWorkspace.OCClass.sharedWorkspace).setDesktopImageURL(ImageURL,
                        TNSScreen.Wrap(TNSScreen.OCClass.mainScreen),
                        Options,
                        @Err) then
  begin
    if Err <> nil then
      Writeln(Format('Error setting desktop background: %s', [NSStrToStr(Err.localizedDescription)]));
  end;
end;

 

It hangs here:  Options.setObject(FillColorObj, NSWorkspaceDesktopImageFillColorKey);

 

 

 

Here is another:

 

procedure SetDesktopColor(const Color: TAlphaColor);
var
  Err: NSError;
  Options: NSMutableDictionary;
  URL: NSURL;
  TempFile: string;
begin
  // Create a temporary file path for the color image
  TempFile := TPath.Combine(TPath.GetTempPath, 'SolidColorDesktop.png');
  // Create a solid color image
  CreateSolidColorImage(Color, TempFile);
  // Load the image as an NSURL
  URL := TNSURL.Wrap(TNSURL.OCClass.fileURLWithPath(NSStr(TempFile)));
  if URL = nil then
    begin
      Showmessage('Failed to create NSURL for the temporary file.');
      Exit;
    end;
  // Create a mutable dictionary for desktop image options
  Options := TNSMutableDictionary.Wrap(TNSMutableDictionary.OCClass.dictionary);
  // Set the desktop image fill color (not used in this case)
  Options.setObject(TNSColor.Wrap(TNSColor.OCClass.whiteColor), NSWorkspaceDesktopImageFillColorKey);
  // Set the desktop image scaling
  Options.setObject(TNSNumber.Wrap(TNSNumber.OCClass.numberWithInt(NSImageScaleNone)), NSWorkspaceDesktopImageScalingKey);
  // Set the desktop image for the main screen
  if not TNSWorkspace.Wrap(TNSWorkspace.OCClass.sharedWorkspace).setDesktopImageURL(URL,
                          TNSScreen.Wrap(TNSScreen.OCClass.mainScreen), Options, @Err) then
    begin
      if Err <> nil then
        Showmessage(Format('Error setting desktop color: %s', [NSStrToStr(Err.localizedDescription)]));
    end;
end;

 

 

I have tried using NSDictionary in place of NSMutableDictionary, and used the SetValue method.  That gives me an Exception in the onButtonUp event deep in FMX code.

 

I tried this to get the current settings:

 

function GetCurrentDesktopImageOptions: TDictionary<string, string>;
var
  Options: NSDictionary;
  KeyEnumerator: NSEnumerator;
  Key: Pointer;
  OptionKey: string;
  OptionValue: string;
  ResultDict: TDictionary<string, string>;
begin
  ResultDict := TDictionary<string, string>.Create;
  try
    Options := TNSWorkspace.Wrap(TNSWorkspace.OCClass.sharedWorkspace)
      .desktopImageOptionsForScreen(TNSScreen.Wrap(TNSScreen.OCClass.mainScreen));

    if Options <> nil then
    begin
      KeyEnumerator := Options.keyEnumerator;
      while True do
      begin
        Key := KeyEnumerator.nextObject;
        if Key = nil then
          Break;

        OptionKey := NSStrToStr(TNSString.Wrap(Key));
        OptionValue := NSStrToStr(TNSString.Wrap(Options.objectForKey(Key)));
        ResultDict.Add(OptionKey, OptionValue);
      end;
    end;

    Result := ResultDict;
  except
    ResultDict.Free;
    raise;
  end;
end;
 

 

This returns absolutely nothing.

 

What am I doing wrong?  I'd love to pass the dictionary with the Scaled image, and background color in the dictionary.

 

Apple documentation gives me a headache.  I'm surprised I got this far.....

 

Share this post


Link to post
1 minute ago, ToddFrankson said:

Options := TNSMutableDictionary.Wrap(TNSMutableDictionary.OCClass.dictionary);

This should be:

Options := TNSMutableDictionary.Create;

 

5 minutes ago, ToddFrankson said:

Options.setObject(TNSColor.Wrap(TNSColor.OCClass.whiteColor), NSWorkspaceDesktopImageFillColorKey);

This should be:

Options.setObject(TNSColor.OCClass.whiteColor, NSObjectToID(NSWorkspaceDesktopImageFillColorKey));

Since setObject takes pointer parameters, for both. The rest should follow the same rule. Incidentally, there's loads of examples of using an NSMutableDictionary in the Delphi source (as well as in Kastri)

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×