@@ -61,7 +61,8 @@ extension Ghostty {
6161 action_cb: { app, target, action in App . action ( app!, target: target, action: action) } ,
6262 read_clipboard_cb: { userdata, loc, state in App . readClipboard ( userdata, location: loc, state: state) } ,
6363 confirm_read_clipboard_cb: { userdata, str, state, request in App . confirmReadClipboard ( userdata, string: str, state: state, request: request ) } ,
64- write_clipboard_cb: { userdata, str, loc, confirm in App . writeClipboard ( userdata, string: str, location: loc, confirm: confirm) } ,
64+ write_clipboard_cb: { userdata, loc, content, len, confirm in
65+ App . writeClipboard ( userdata, location: loc, content: content, len: len, confirm: confirm) } ,
6566 close_surface_cb: { userdata, processAlive in App . closeSurface ( userdata, processAlive: processAlive) }
6667 )
6768
@@ -276,8 +277,9 @@ extension Ghostty {
276277
277278 static func writeClipboard(
278279 _ userdata: UnsafeMutableRawPointer ? ,
279- string: UnsafePointer < CChar > ? ,
280280 location: ghostty_clipboard_e ,
281+ content: UnsafePointer < ghostty_clipboard_content_s > ? ,
282+ len: Int ,
281283 confirm: Bool
282284 ) { }
283285
@@ -364,23 +366,53 @@ extension Ghostty {
364366 }
365367 }
366368
367- static func writeClipboard( _ userdata: UnsafeMutableRawPointer ? , string: UnsafePointer < CChar > ? , location: ghostty_clipboard_e , confirm: Bool ) {
369+ static func writeClipboard(
370+ _ userdata: UnsafeMutableRawPointer ? ,
371+ location: ghostty_clipboard_e ,
372+ content: UnsafePointer < ghostty_clipboard_content_s > ? ,
373+ len: Int ,
374+ confirm: Bool
375+ ) {
368376 let surface = self . surfaceUserdata ( from: userdata)
369-
370-
371377 guard let pasteboard = NSPasteboard . ghostty ( location) else { return }
372- guard let valueStr = String ( cString: string!, encoding: . utf8) else { return }
378+ guard let content = content, len > 0 else { return }
379+
380+ // Convert the C array to Swift array
381+ let contentArray = ( 0 ..< len) . compactMap { i in
382+ Ghostty . ClipboardContent. from ( content: content [ i] )
383+ }
384+ guard !contentArray. isEmpty else { return }
385+
386+ // Assert there is only one text/plain entry. For security reasons we need
387+ // to guarantee this for now since our confirmation dialog only shows one.
388+ assert ( contentArray. filter ( { $0. mime == " text/plain " } ) . count <= 1 ,
389+ " clipboard contents should have at most one text/plain entry " )
390+
373391 if !confirm {
374- pasteboard. declareTypes ( [ . string] , owner: nil )
375- pasteboard. setString ( valueStr, forType: . string)
392+ // Declare all types
393+ let types = contentArray. compactMap { item in
394+ NSPasteboard . PasteboardType ( mimeType: item. mime)
395+ }
396+ pasteboard. declareTypes ( types, owner: nil )
397+
398+ // Set data for each type
399+ for item in contentArray {
400+ guard let type = NSPasteboard . PasteboardType ( mimeType: item. mime) else { continue }
401+ pasteboard. setString ( item. data, forType: type)
402+ }
376403 return
377404 }
378405
406+ // For confirmation, use the text/plain content if it exists
407+ guard let textPlainContent = contentArray. first ( where: { $0. mime == " text/plain " } ) else {
408+ return
409+ }
410+
379411 NotificationCenter . default. post (
380412 name: Notification . confirmClipboard,
381413 object: surface,
382414 userInfo: [
383- Notification . ConfirmClipboardStrKey: valueStr ,
415+ Notification . ConfirmClipboardStrKey: textPlainContent . data ,
384416 Notification . ConfirmClipboardRequestKey: Ghostty . ClipboardRequest. osc_52_write ( pasteboard) ,
385417 ]
386418 )
0 commit comments