You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

633 lines
18KB

  1. // "$Id: Fl_Native_File_Chooser_MAC.mm 8784 2011-06-06 12:11:04Z manolo $"
  2. //
  3. // FLTK native OS file chooser widget
  4. //
  5. // Copyright 1998-2010 by Bill Spitzak and others.
  6. // Copyright 2004 Greg Ercolano.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems to:
  24. //
  25. // http://www.fltk.org/str.php
  26. //
  27. // TODO:
  28. // o When doing 'open file', only dir is preset, not filename.
  29. // Possibly 'preset_file' could be used to select the filename.
  30. //
  31. #ifdef __APPLE__
  32. #include "Fl_Native_File_Chooser_common.cxx" // strnew/strfree/strapp/chrcat
  33. #include <libgen.h> // dirname(3)
  34. #include <sys/types.h> // stat(2)
  35. #include <sys/stat.h> // stat(2)
  36. #include <FL/Fl.H>
  37. #include <FL/Fl_Native_File_Chooser.H>
  38. #include <FL/Fl_File_Chooser.H>
  39. #include <FL/filename.H>
  40. // FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS
  41. void Fl_Native_File_Chooser::clear_pathnames() {
  42. if ( _pathnames ) {
  43. while ( --_tpathnames >= 0 ) {
  44. _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]);
  45. }
  46. delete [] _pathnames;
  47. _pathnames = NULL;
  48. }
  49. _tpathnames = 0;
  50. }
  51. // SET A SINGLE PATHNAME
  52. void Fl_Native_File_Chooser::set_single_pathname(const char *s) {
  53. clear_pathnames();
  54. _pathnames = new char*[1];
  55. _pathnames[0] = strnew(s);
  56. _tpathnames = 1;
  57. }
  58. // CONSTRUCTOR
  59. Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
  60. _btype = val;
  61. _panel = NULL;
  62. _options = NO_OPTIONS;
  63. _pathnames = NULL;
  64. _tpathnames = 0;
  65. _title = NULL;
  66. _filter = NULL;
  67. _filt_names = NULL;
  68. memset(_filt_patt, 0, sizeof(char*) * MAXFILTERS);
  69. _filt_total = 0;
  70. _filt_value = 0;
  71. _directory = NULL;
  72. _preset_file = NULL;
  73. _errmsg = NULL;
  74. }
  75. // DESTRUCTOR
  76. Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
  77. // _opts // nothing to manage
  78. // _options // nothing to manage
  79. // _keepstate // nothing to manage
  80. // _tempitem // nothing to manage
  81. clear_pathnames();
  82. _directory = strfree(_directory);
  83. _title = strfree(_title);
  84. _preset_file = strfree(_preset_file);
  85. _filter = strfree(_filter);
  86. //_filt_names // managed by clear_filters()
  87. //_filt_patt[i] // managed by clear_filters()
  88. //_filt_total // managed by clear_filters()
  89. clear_filters();
  90. //_filt_value // nothing to manage
  91. _errmsg = strfree(_errmsg);
  92. }
  93. // GET TYPE OF BROWSER
  94. int Fl_Native_File_Chooser::type() const {
  95. return(_btype);
  96. }
  97. // SET OPTIONS
  98. void Fl_Native_File_Chooser::options(int val) {
  99. _options = val;
  100. }
  101. // GET OPTIONS
  102. int Fl_Native_File_Chooser::options() const {
  103. return(_options);
  104. }
  105. // SHOW THE BROWSER WINDOW
  106. // Returns:
  107. // 0 - user picked a file
  108. // 1 - user cancelled
  109. // -1 - failed; errmsg() has reason
  110. //
  111. int Fl_Native_File_Chooser::show() {
  112. // Make sure fltk interface updates before posting our dialog
  113. Fl::flush();
  114. // POST BROWSER
  115. int err = post();
  116. _filt_total = 0;
  117. return(err);
  118. }
  119. // SET ERROR MESSAGE
  120. // Internal use only.
  121. //
  122. void Fl_Native_File_Chooser::errmsg(const char *msg) {
  123. _errmsg = strfree(_errmsg);
  124. _errmsg = strnew(msg);
  125. }
  126. // RETURN ERROR MESSAGE
  127. const char *Fl_Native_File_Chooser::errmsg() const {
  128. return(_errmsg ? _errmsg : "No error");
  129. }
  130. // GET FILENAME
  131. const char* Fl_Native_File_Chooser::filename() const {
  132. if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]);
  133. return("");
  134. }
  135. // GET FILENAME FROM LIST OF FILENAMES
  136. const char* Fl_Native_File_Chooser::filename(int i) const {
  137. if ( _pathnames && i < _tpathnames ) return(_pathnames[i]);
  138. return("");
  139. }
  140. // GET TOTAL FILENAMES CHOSEN
  141. int Fl_Native_File_Chooser::count() const {
  142. return(_tpathnames);
  143. }
  144. // PRESET PATHNAME
  145. // Value can be NULL for none.
  146. //
  147. void Fl_Native_File_Chooser::directory(const char *val) {
  148. _directory = strfree(_directory);
  149. _directory = strnew(val);
  150. }
  151. // GET PRESET PATHNAME
  152. // Returned value can be NULL if none set.
  153. //
  154. const char* Fl_Native_File_Chooser::directory() const {
  155. return(_directory);
  156. }
  157. // SET TITLE
  158. // Value can be NULL if no title desired.
  159. //
  160. void Fl_Native_File_Chooser::title(const char *val) {
  161. _title = strfree(_title);
  162. _title = strnew(val);
  163. }
  164. // GET TITLE
  165. // Returned value can be NULL if none set.
  166. //
  167. const char *Fl_Native_File_Chooser::title() const {
  168. return(_title);
  169. }
  170. // SET FILTER
  171. // Can be NULL if no filter needed
  172. //
  173. void Fl_Native_File_Chooser::filter(const char *val) {
  174. _filter = strfree(_filter);
  175. _filter = strnew(val);
  176. // Parse filter user specified
  177. // IN: _filter = "C Files\t*.{cxx,h}\nText Files\t*.txt"
  178. // OUT: _filt_names = "C Files\tText Files"
  179. // _filt_patt[0] = "*.{cxx,h}"
  180. // _filt_patt[1] = "*.txt"
  181. // _filt_total = 2
  182. //
  183. parse_filter(_filter);
  184. }
  185. // GET FILTER
  186. // Returned value can be NULL if none set.
  187. //
  188. const char *Fl_Native_File_Chooser::filter() const {
  189. return(_filter);
  190. }
  191. // CLEAR ALL FILTERS
  192. // Internal use only.
  193. //
  194. void Fl_Native_File_Chooser::clear_filters() {
  195. _filt_names = strfree(_filt_names);
  196. for (int i=0; i<_filt_total; i++) {
  197. _filt_patt[i] = strfree(_filt_patt[i]);
  198. }
  199. _filt_total = 0;
  200. }
  201. // PARSE USER'S FILTER SPEC
  202. // Parses user specified filter ('in'),
  203. // breaks out into _filt_patt[], _filt_names, and _filt_total.
  204. //
  205. // Handles:
  206. // IN: OUT:_filt_names OUT: _filt_patt
  207. // ------------------------------------ ------------------ ---------------
  208. // "*.{ma,mb}" "*.{ma,mb} Files" "*.{ma,mb}"
  209. // "*.[abc]" "*.[abc] Files" "*.[abc]"
  210. // "*.txt" "*.txt Files" "*.c"
  211. // "C Files\t*.[ch]" "C Files" "*.[ch]"
  212. // "C Files\t*.[ch]\nText Files\t*.cxx" "C Files" "*.[ch]"
  213. //
  214. // Parsing Mode:
  215. // IN:"C Files\t*.{cxx,h}"
  216. // ||||||| |||||||||
  217. // mode: nnnnnnn wwwwwwwww
  218. // \_____/ \_______/
  219. // Name Wildcard
  220. //
  221. void Fl_Native_File_Chooser::parse_filter(const char *in) {
  222. clear_filters();
  223. if ( ! in ) return;
  224. int has_name = strchr(in, '\t') ? 1 : 0;
  225. char mode = has_name ? 'n' : 'w'; // parse mode: n=title, w=wildcard
  226. char wildcard[1024] = ""; // parsed wildcard
  227. char name[1024] = "";
  228. // Parse filter user specified
  229. for ( ; 1; in++ ) {
  230. //// DEBUG
  231. //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n",
  232. //// *in, mode, name, wildcard);
  233. switch (*in) {
  234. // FINISHED PARSING NAME?
  235. case '\t':
  236. if ( mode != 'n' ) goto regchar;
  237. mode = 'w';
  238. break;
  239. // ESCAPE NEXT CHAR
  240. case '\\':
  241. ++in;
  242. goto regchar;
  243. // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
  244. case '\r':
  245. case '\n':
  246. case '\0':
  247. // TITLE
  248. // If user didn't specify a name, make one
  249. //
  250. if ( name[0] == '\0' ) {
  251. sprintf(name, "%.*s Files", (int)sizeof(name)-10, wildcard);
  252. }
  253. // APPEND NEW FILTER TO LIST
  254. if ( wildcard[0] ) {
  255. // Add to filtername list
  256. // Tab delimit if more than one. We later break
  257. // tab delimited string into CFArray with
  258. // CFStringCreateArrayBySeparatingStrings()
  259. //
  260. if ( _filt_total ) {
  261. _filt_names = strapp(_filt_names, "\t");
  262. }
  263. _filt_names = strapp(_filt_names, name);
  264. // Add filter to the pattern array
  265. _filt_patt[_filt_total++] = strnew(wildcard);
  266. }
  267. // RESET
  268. wildcard[0] = name[0] = '\0';
  269. mode = strchr(in, '\t') ? 'n' : 'w';
  270. // DONE?
  271. if ( *in == '\0' ) return; // done
  272. else continue; // not done yet, more filters
  273. // Parse all other chars
  274. default: // handle all non-special chars
  275. regchar: // handle regular char
  276. switch ( mode ) {
  277. case 'n': chrcat(name, *in); continue;
  278. case 'w': chrcat(wildcard, *in); continue;
  279. }
  280. break;
  281. }
  282. }
  283. //NOTREACHED
  284. }
  285. // SET PRESET FILE
  286. // Value can be NULL for none.
  287. //
  288. void Fl_Native_File_Chooser::preset_file(const char* val) {
  289. _preset_file = strfree(_preset_file);
  290. _preset_file = strnew(val);
  291. }
  292. // PRESET FILE
  293. // Returned value can be NULL if none set.
  294. //
  295. const char* Fl_Native_File_Chooser::preset_file() const {
  296. return(_preset_file);
  297. }
  298. void Fl_Native_File_Chooser::filter_value(int val) {
  299. _filt_value = val;
  300. }
  301. int Fl_Native_File_Chooser::filter_value() const {
  302. return(_filt_value);
  303. }
  304. int Fl_Native_File_Chooser::filters() const {
  305. return(_filt_total);
  306. }
  307. #import <Cocoa/Cocoa.h>
  308. #define UNLIKELYPREFIX "___fl_very_unlikely_prefix_"
  309. #ifndef MAC_OS_X_VERSION_10_6
  310. #define MAC_OS_X_VERSION_10_6 1060
  311. #endif
  312. int Fl_Native_File_Chooser::get_saveas_basename(void) {
  313. char *q = strdup( [[(NSSavePanel*)_panel filename] fileSystemRepresentation] );
  314. id delegate = [(NSSavePanel*)_panel delegate];
  315. if (delegate != nil) {
  316. const char *d = [[(NSSavePanel*)_panel directory] fileSystemRepresentation];
  317. int l = strlen(d) + 1;
  318. int lu = strlen(UNLIKELYPREFIX);
  319. // Remove UNLIKELYPREFIX between directory and filename parts
  320. memmove(q + l, q + l + lu, strlen(q + l + lu) + 1);
  321. }
  322. set_single_pathname( q );
  323. free(q);
  324. return 0;
  325. }
  326. // SET THE TYPE OF BROWSER
  327. void Fl_Native_File_Chooser::type(int val) {
  328. _btype = val;
  329. }
  330. /* Input
  331. filter= "C files\t*.{c,h}\nText files\t*.txt\n"
  332. patterns[0] = "*.{c,h}"
  333. patterns[1] = "*.txt"
  334. count = 2
  335. Return:
  336. "C files (*.{c,h})\nText files (*.txt)\n"
  337. */
  338. static char *prepareMacFilter(int count, const char *filter, char **patterns) {
  339. int rank = 0, l = 0;
  340. for (int i = 0; i < count; i++) {
  341. l += strlen(patterns[i]) + 3;
  342. }
  343. const char *p = filter;
  344. char *q; q = new char[strlen(p) + l + 1];
  345. const char *r, *s;
  346. char *t;
  347. t = q;
  348. do { // copy to t what is in filter removing what is between \t and \n, if any
  349. r = strchr(p, '\n');
  350. if (!r) r = p + strlen(p);
  351. s = strchr(p, '\t');
  352. if (s && s < r) {
  353. memcpy(q, p, s - p);
  354. q += s - p;
  355. if (rank < count) { sprintf(q, " (%s)", patterns[rank]); q += strlen(q); }
  356. }
  357. else {
  358. memcpy(q, p, r - p);
  359. q += r - p;
  360. }
  361. rank++;
  362. *(q++) = '\n';
  363. if (*p) p = r + 1;
  364. } while(*p);
  365. *q = 0;
  366. return t;
  367. }
  368. @interface FLopenDelegate : NSObject
  369. #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  370. <NSOpenSavePanelDelegate>
  371. #endif
  372. {
  373. NSPopUpButton *nspopup;
  374. char **filter_pattern;
  375. }
  376. - (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern;
  377. - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
  378. @end
  379. @implementation FLopenDelegate
  380. - (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern
  381. {
  382. nspopup = popup;
  383. filter_pattern = pattern;
  384. return self;
  385. }
  386. - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
  387. {
  388. if ( [nspopup indexOfSelectedItem] == [nspopup numberOfItems] - 1) return YES;
  389. const char *pathname = [filename fileSystemRepresentation];
  390. if ( fl_filename_isdir(pathname) ) return YES;
  391. if ( fl_filename_match(pathname, filter_pattern[ [nspopup indexOfSelectedItem] ]) ) return YES;
  392. return NO;
  393. }
  394. @end
  395. @interface FLsaveDelegate : NSObject
  396. #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  397. <NSOpenSavePanelDelegate>
  398. #endif
  399. {
  400. }
  401. - (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag;
  402. @end
  403. @implementation FLsaveDelegate
  404. - (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
  405. {
  406. if (! okFlag) return filename;
  407. // User has clicked save, and no overwrite confirmation should occur.
  408. // To get the latter, we need to change the name we return (hence the prefix):
  409. return [@ UNLIKELYPREFIX stringByAppendingString:filename];
  410. }
  411. @end
  412. static NSPopUpButton *createPopupAccessory(NSSavePanel *panel, const char *filter, const char *title, int rank)
  413. {
  414. NSPopUpButton *popup;
  415. NSRect rectview = NSMakeRect(5, 5, 350, 30 );
  416. NSView *view = [[[NSView alloc] initWithFrame:rectview] autorelease];
  417. NSRect rectbox = NSMakeRect(0, 3, 140, 20 );
  418. NSBox *box = [[[NSBox alloc] initWithFrame:rectbox] autorelease];
  419. NSRect rectpop = NSMakeRect(105, 0, 246, 30 );
  420. popup = [[[NSPopUpButton alloc ] initWithFrame:rectpop pullsDown:NO] autorelease];
  421. [view addSubview:box];
  422. [view addSubview:popup];
  423. [box setBorderType:NSNoBorder];
  424. NSString *nstitle = [[NSString alloc] initWithUTF8String:title];
  425. [box setTitle:nstitle];
  426. [nstitle release];
  427. NSFont *font = [NSFont controlContentFontOfSize:NSRegularControlSize];
  428. [box setTitleFont:font];
  429. [box sizeToFit];
  430. // horizontally move box to fit the locale-dependent width of its title
  431. NSRect r=[box frame];
  432. NSPoint o = r.origin;
  433. o.x = rectpop.origin.x - r.size.width + 15;
  434. [box setFrameOrigin:o];
  435. CFStringRef tab = CFSTR("\n");
  436. CFStringRef tmp_cfs;
  437. tmp_cfs = CFStringCreateWithCString(NULL, filter, kCFStringEncodingUTF8);
  438. CFArrayRef array = CFStringCreateArrayBySeparatingStrings(NULL, tmp_cfs, tab);
  439. CFRelease(tmp_cfs);
  440. CFRelease(tab);
  441. [popup addItemsWithTitles:(NSArray*)array];
  442. NSMenuItem *item = [popup itemWithTitle:@""];
  443. if (item) [popup removeItemWithTitle:@""];
  444. CFRelease(array);
  445. [popup selectItemAtIndex:rank];
  446. [panel setAccessoryView:view];
  447. return popup;
  448. }
  449. // POST BROWSER
  450. // Internal use only.
  451. // Assumes '_opts' has been initialized.
  452. //
  453. // Returns:
  454. // 0 - user picked a file
  455. // 1 - user cancelled
  456. // -1 - failed; errmsg() has reason
  457. //
  458. int Fl_Native_File_Chooser::post() {
  459. // INITIALIZE BROWSER
  460. if ( _filt_total == 0 ) { // Make sure they match
  461. _filt_value = 0; // TBD: move to someplace more logical?
  462. }
  463. NSAutoreleasePool *localPool;
  464. localPool = [[NSAutoreleasePool alloc] init];
  465. switch (_btype) {
  466. case BROWSE_FILE:
  467. case BROWSE_MULTI_FILE:
  468. case BROWSE_DIRECTORY:
  469. case BROWSE_MULTI_DIRECTORY:
  470. _panel = [NSOpenPanel openPanel];
  471. break;
  472. case BROWSE_SAVE_DIRECTORY:
  473. case BROWSE_SAVE_FILE:
  474. _panel = [NSSavePanel savePanel];
  475. break;
  476. }
  477. int retval;
  478. NSString *nstitle = [NSString stringWithUTF8String: (_title ? _title : "No Title")];
  479. [(NSSavePanel*)_panel setTitle:nstitle];
  480. switch (_btype) {
  481. case BROWSE_MULTI_FILE:
  482. [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES];
  483. break;
  484. case BROWSE_MULTI_DIRECTORY:
  485. [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES];
  486. /* FALLTHROUGH */
  487. case BROWSE_DIRECTORY:
  488. [(NSOpenPanel*)_panel setCanChooseDirectories:YES];
  489. break;
  490. case BROWSE_SAVE_DIRECTORY:
  491. [(NSSavePanel*)_panel setCanCreateDirectories:YES];
  492. break;
  493. }
  494. // SHOW THE DIALOG
  495. if ( [(NSSavePanel*)_panel isKindOfClass:[NSOpenPanel class]] ) {
  496. NSPopUpButton *popup = nil;
  497. if (_filt_total) {
  498. char *t = prepareMacFilter(_filt_total, _filter, _filt_patt);
  499. popup = createPopupAccessory((NSSavePanel*)_panel, t, Fl_File_Chooser::show_label, 0);
  500. delete[] t;
  501. [[popup menu] addItem:[NSMenuItem separatorItem]];
  502. [popup addItemWithTitle:[[NSString alloc] initWithUTF8String:Fl_File_Chooser::all_files_label]];
  503. [popup setAction:@selector(validateVisibleColumns)];
  504. [popup setTarget:(NSObject*)_panel];
  505. static FLopenDelegate *openDelegate = nil;
  506. if (openDelegate == nil) {
  507. // not to be ever freed
  508. openDelegate = [[FLopenDelegate alloc] init];
  509. }
  510. [openDelegate setPopup:popup filter_pattern:_filt_patt];
  511. [(NSOpenPanel*)_panel setDelegate:openDelegate];
  512. }
  513. NSString *dir = nil;
  514. NSString *fname = nil;
  515. NSString *preset = nil;
  516. if (_preset_file) {
  517. preset = [[NSString alloc] initWithUTF8String:_preset_file];
  518. if (strchr(_preset_file, '/') != NULL)
  519. dir = [[NSString alloc] initWithString:[preset stringByDeletingLastPathComponent]];
  520. fname = [preset lastPathComponent];
  521. }
  522. if (_directory && !dir) dir = [[NSString alloc] initWithUTF8String:_directory];
  523. retval = [(NSOpenPanel*)_panel runModalForDirectory:dir file:fname types:nil];
  524. [dir release];
  525. [preset release];
  526. if (_filt_total) {
  527. _filt_value = [popup indexOfSelectedItem];
  528. }
  529. if ( retval == NSOKButton ) {
  530. clear_pathnames();
  531. NSArray *array = [(NSOpenPanel*)_panel filenames];
  532. _tpathnames = [array count];
  533. _pathnames = new char*[_tpathnames];
  534. for(int i = 0; i < _tpathnames; i++) {
  535. _pathnames[i] = strnew([(NSString*)[array objectAtIndex:i] fileSystemRepresentation]);
  536. }
  537. }
  538. }
  539. else {
  540. NSString *dir = nil;
  541. NSString *fname = nil;
  542. NSString *preset = nil;
  543. NSPopUpButton *popup = nil;
  544. [(NSSavePanel*)_panel setAllowsOtherFileTypes:YES];
  545. if ( !(_options & SAVEAS_CONFIRM) ) {
  546. static FLsaveDelegate *saveDelegate = nil;
  547. if (saveDelegate == nil)saveDelegate = [[FLsaveDelegate alloc] init]; // not to be ever freed
  548. [(NSSavePanel*)_panel setDelegate:saveDelegate];
  549. }
  550. if (_preset_file) {
  551. preset = [[NSString alloc] initWithUTF8String:_preset_file];
  552. if (strchr(_preset_file, '/') != NULL) {
  553. dir = [[NSString alloc] initWithString:[preset stringByDeletingLastPathComponent]];
  554. }
  555. fname = [preset lastPathComponent];
  556. }
  557. if (_directory && !dir) dir = [[NSString alloc] initWithUTF8String:_directory];
  558. if (_filt_total) {
  559. char *t = prepareMacFilter(_filt_total, _filter, _filt_patt);
  560. popup = createPopupAccessory((NSSavePanel*)_panel, t, [[(NSSavePanel*)_panel nameFieldLabel] UTF8String], _filt_value);
  561. delete[] t;
  562. }
  563. retval = [(NSSavePanel*)_panel runModalForDirectory:dir file:fname];
  564. if (_filt_total) {
  565. _filt_value = [popup indexOfSelectedItem];
  566. }
  567. [dir release];
  568. [preset release];
  569. if ( retval == NSOKButton ) get_saveas_basename();
  570. }
  571. [localPool release];
  572. return (retval == NSOKButton ? 0 : 1);
  573. }
  574. #endif // __APPLE__
  575. //
  576. // End of "$Id: Fl_Native_File_Chooser_MAC.mm 8784 2011-06-06 12:11:04Z manolo $".
  577. //