summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FL/Fl_Native_File_Chooser.H47
-rw-r--r--FL/Fl_Native_File_Chooser_FLTK.H111
-rw-r--r--FL/Fl_Native_File_Chooser_MAC.H156
-rw-r--r--FL/Fl_Native_File_Chooser_WIN32.H106
-rw-r--r--src/Fl_Native_File_Chooser.cxx45
-rw-r--r--src/Fl_Native_File_Chooser_FLTK.cxx395
-rw-r--r--src/Fl_Native_File_Chooser_MAC.cxx1087
-rw-r--r--src/Fl_Native_File_Chooser_WIN32.cxx848
-rw-r--r--src/Fl_Native_File_Chooser_common.cxx83
-rw-r--r--src/Fl_cocoa.mm1030
-rw-r--r--src/Makefile6
-rw-r--r--src/makedepend2
-rw-r--r--src/makefile.wat1
-rw-r--r--test/Makefile4
-rw-r--r--test/makefile.wat3
-rw-r--r--test/native-filechooser.cxx83
16 files changed, 3479 insertions, 528 deletions
diff --git a/FL/Fl_Native_File_Chooser.H b/FL/Fl_Native_File_Chooser.H
new file mode 100644
index 000000000..77b10dbd0
--- /dev/null
+++ b/FL/Fl_Native_File_Chooser.H
@@ -0,0 +1,47 @@
+//
+// "$Id$"
+//
+// FLTK native OS file chooser widget
+//
+// Copyright 1998-2009 by Bill Spitzak and others.
+// Copyright 2004 Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+#ifndef FL_NATIVE_FILE_CHOOSER_H
+#define FL_NATIVE_FILE_CHOOSER_H
+
+// Use Windows' chooser
+#ifdef _WIN32
+#include <FL/Fl_Native_File_Chooser_WIN32.H>
+#endif
+
+// Use Apple's chooser
+#ifdef __APPLE__
+#include <FL/Fl_Native_File_Chooser_MAC.H>
+#endif
+
+// All else falls back to FLTK's own chooser
+#if ! defined(__APPLE__) && !defined(_WIN32)
+#include <FL/Fl_Native_File_Chooser_FLTK.H>
+#endif
+
+#endif /*FL_NATIVE_FILE_CHOOSER_H*/
diff --git a/FL/Fl_Native_File_Chooser_FLTK.H b/FL/Fl_Native_File_Chooser_FLTK.H
new file mode 100644
index 000000000..afc671048
--- /dev/null
+++ b/FL/Fl_Native_File_Chooser_FLTK.H
@@ -0,0 +1,111 @@
+//
+// "$Id$"
+//
+// FLTK native OS file chooser widget
+//
+// Copyright 1998-2009 by Bill Spitzak and others.
+// Copyright 2005 by Nathan Vander Wilt.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+#include <FL/Fl_File_Chooser.H>
+#include <string.h>
+
+class Fl_Native_File_Chooser {
+public:
+ enum Type {
+ BROWSE_FILE = 0,
+ BROWSE_DIRECTORY,
+ BROWSE_MULTI_FILE,
+ BROWSE_MULTI_DIRECTORY,
+ BROWSE_SAVE_FILE,
+ BROWSE_SAVE_DIRECTORY
+ };
+ enum Option {
+ NO_OPTIONS = 0x0000, // no options enabled
+ SAVEAS_CONFIRM = 0x0001, // Show native 'Save As' overwrite confirm dialog (if supported)
+ NEW_FOLDER = 0x0002, // Show 'New Folder' icon (if supported)
+ PREVIEW = 0x0004 // enable preview mode
+ };
+private:
+ int _btype; // kind-of browser to show()
+ int _options; // general options
+ char *_filter; // user supplied filter
+ char *_parsedfilt; // parsed filter
+ int _filtvalue; // selected filter
+ char *_preset_file;
+ char *_prevvalue; // Returned filename
+ char *_directory;
+ char *_errmsg; // error message
+ Fl_File_Chooser *file_chooser;
+
+ int exist_dialog() {
+ return(fl_choice("File exists. Are you sure you want to overwrite?",
+ "Cancel", " OK ", NULL));
+ }
+ void load_system_icons() {
+ Fl_File_Icon::load_system_icons();
+ }
+
+ int _nfilters;
+
+ //added by MG
+ Fl_File_Browser *my_fileList;
+ Fl_Check_Button *show_hidden;
+ char old_dir[300];
+ int prev_filtervalue;
+ static void show_hidden_cb(Fl_Check_Button *o, void *data);
+ static void remove_hidden_files(Fl_File_Browser *my_fileList);
+
+ // Private methods
+ void errmsg(const char *msg);
+ int type_fl_file(int);
+ void parse_filter();
+ void keeplocation();
+
+public:
+ Fl_Native_File_Chooser(int val=BROWSE_FILE);
+ ~Fl_Native_File_Chooser();
+
+ // Public methods
+ void type(int);
+ int type() const;
+ void options(int);
+ int options() const;
+ int count() const;
+ const char *filename() const;
+ const char *filename(int i) const;
+ void directory(const char *val);
+ const char *directory() const;
+ void title(const char *);
+ const char* title() const;
+ const char *filter() const;
+ void filter(const char *);
+ int filters() const { return(_nfilters); }
+ void filter_value(int i);
+ int filter_value() const;
+ void preset_file(const char*);
+ const char* preset_file() const;
+ const char *errmsg() const;
+ int show();
+ // added by MG
+ Fl_Choice *showChoice;
+};
diff --git a/FL/Fl_Native_File_Chooser_MAC.H b/FL/Fl_Native_File_Chooser_MAC.H
new file mode 100644
index 000000000..c65e8909e
--- /dev/null
+++ b/FL/Fl_Native_File_Chooser_MAC.H
@@ -0,0 +1,156 @@
+//
+// "$Id$"
+//
+// FLTK native OS file chooser widget
+//
+// Copyright 1998-2009 by Bill Spitzak and others.
+// Copyright 2004 Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+// OSX-SPECIFIC NATIVE BROWSER
+#ifdef __APPLE_CC__
+#include <Carbon/Carbon.h>
+#else /*__APPLE_CC__*/
+#include <Carbon.h>
+#endif /*__APPLE_CC__*/
+#include <config.h>
+
+#undef check // necessary for use of Fl::check()
+
+#include <FL/filename.H>
+#define MAXFILTERS 80
+
+class Fl_Native_File_Chooser {
+public:
+ enum Type {
+ BROWSE_FILE = 0,
+ BROWSE_DIRECTORY,
+ BROWSE_MULTI_FILE,
+ BROWSE_MULTI_DIRECTORY,
+ BROWSE_SAVE_FILE,
+ BROWSE_SAVE_DIRECTORY
+ };
+ enum Option {
+ NO_OPTIONS = 0x0000, // no options enabled
+ SAVEAS_CONFIRM = 0x0001, // Show native 'Save As' overwrite confirm dialog (if supported)
+ NEW_FOLDER = 0x0002, // Show 'New Folder' icon (if supported)
+ PREVIEW = 0x0004, // enable preview mode
+ };
+#ifndef __APPLE_COCOA__
+protected:
+ NavDialogCreationOptions _opts; // file navigation options
+#endif
+private:
+ int _btype; // kind-of browser to show()
+ int _options; // general options
+#ifdef __APPLE_COCOA__
+ void *_panel;
+#else
+ NavDialogRef _ref; // file navigation reference
+#endif
+ NavActionState _keepstate; // holds button permissions
+ NavMenuItemSpec _tempitem; // Popup menu selection
+ char **_pathnames; // array of pathnames
+ int _tpathnames; // total pathnames
+ char *_directory; // default pathname to use
+ char *_title; // title for window
+ char *_preset_file; // the 'save as' filename
+
+ char *_filter; // user-side search filter, eg:
+ // C Files\t*.[ch]\nText Files\t*.txt"
+
+ char *_filt_names; // filter names (tab delimited)
+ // eg. "C Files\tText Files"
+
+ char *_filt_patt[MAXFILTERS];
+ // array of filter patterns, eg:
+ // _filt_patt[0]="*.{cxx,h}"
+ // _filt_patt[1]="*.txt"
+
+ int _filt_total; // parse_filter() # of filters loaded
+ int _filt_value; // index of the selected filter
+ char *_errmsg; // error message
+
+#ifndef __APPLE_COCOA__
+ // PRIVATE CLASS TO HANDLE NAVIGATION DIALOG REPLY STRUCT
+ // Class-ified, mainly to ensure proper cleanup.
+ //
+ class NavReply {
+ int _valid_reply;
+ NavReplyRecord _reply;
+ public:
+ NavReply();
+ ~NavReply();
+ int get_reply(NavDialogRef& ref);
+ int get_saveas_basename(char *s, int slen);
+ int get_dirname(char *s, int slen);
+ int get_pathnames(char **&pathnames, int& tpathnames);
+ };
+#endif
+ // Private methods
+ void errmsg(const char *msg);
+ void clear_pathnames();
+ void set_single_pathname(const char *s);
+#ifdef __APPLE_COCOA__
+ int get_saveas_basename(void);
+#else
+ int get_saveas_basename(NavDialogRef& ref);
+#endif
+ int get_pathnames(NavDialogRef& ref);
+ static void event_handler(NavEventCallbackMessage callBackSelector,
+ NavCBRecPtr cbparm, void *data);
+
+ void clear_filters();
+ void add_filter(const char *, const char *);
+ void parse_filter(const char *from);
+#ifndef __APPLE_COCOA__
+ static Boolean filter_proc_cb(AEDesc *, void *, void *, NavFilterModes);
+ Boolean filter_proc_cb2(AEDesc*, void*, void*, NavFilterModes);
+#endif
+ int post();
+
+public:
+ Fl_Native_File_Chooser(int val = BROWSE_FILE);
+ ~Fl_Native_File_Chooser();
+
+ // Public methods
+ void type(int);
+ int type() const;
+ void options(int);
+ int options() const;
+ int count() const;
+ const char *filename() const;
+ const char *filename(int i) const;
+ void directory(const char *);
+ const char *directory() const;
+ void title(const char *);
+ const char *title() const;
+ const char *filter() const;
+ void filter(const char *);
+ void filter_value(int i) { _filt_value = i; }
+ int filter_value() { return(_filt_value); }
+ int filters() { return(_filt_total); }
+ void preset_file(const char *);
+ const char *preset_file();
+ const char *errmsg() const;
+ int show();
+};
diff --git a/FL/Fl_Native_File_Chooser_WIN32.H b/FL/Fl_Native_File_Chooser_WIN32.H
new file mode 100644
index 000000000..6429e461c
--- /dev/null
+++ b/FL/Fl_Native_File_Chooser_WIN32.H
@@ -0,0 +1,106 @@
+//
+// Fl_Native_File_Chooser_WINDOWS.H -- FLTK native OS file chooser widget
+//
+// Copyright 2004 by Greg Ercolano.
+// April 2005 - API changes, improved filter processing by Nathan Vander Wilt
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+
+// #define _WIN32_WINNT 0x0501 // needed for OPENFILENAME's 'FlagsEx'
+#include <stdio.h>
+#include <stdlib.h> // malloc
+#include <windows.h>
+#include <commdlg.h> // OPENFILENAME, GetOpenFileName()
+#include <shlobj.h> // BROWSEINFO, SHBrowseForFolder()
+
+class Fl_Native_File_Chooser {
+public:
+ enum Type {
+ BROWSE_FILE = 0,
+ BROWSE_DIRECTORY,
+ BROWSE_MULTI_FILE,
+ BROWSE_MULTI_DIRECTORY,
+ BROWSE_SAVE_FILE,
+ BROWSE_SAVE_DIRECTORY
+ };
+ enum Option {
+ NO_OPTIONS = 0x0000, // no options enabled
+ SAVEAS_CONFIRM = 0x0001, // Show native 'Save As' overwrite confirm dialog (if supported)
+ NEW_FOLDER = 0x0002, // Show 'New Folder' icon (if supported)
+ PREVIEW = 0x0004, // enable preview mode
+ };
+private:
+ int _btype; // kind-of browser to show()
+ int _options; // general options
+ OPENFILENAMEW _ofn; // GetOpenFileName() & GetSaveFileName() struct
+ BROWSEINFO _binf; // SHBrowseForFolder() struct
+ char **_pathnames; // array of pathnames
+ int _tpathnames; // total pathnames
+ char *_directory; // default pathname to use
+ char *_title; // title for window
+ char *_filter; // user-side search filter
+ char *_parsedfilt; // filter parsed for Windows dialog
+ int _nfilters; // number of filters parse_filter counted
+ char *_preset_file; // the file to preselect
+ char *_errmsg; // error message
+
+ // Private methods
+ void errmsg(const char *msg);
+
+ void clear_pathnames();
+ void set_single_pathname(const char *s);
+ void add_pathname(const char *s);
+
+ void FreePIDL(ITEMIDLIST *pidl);
+ void ClearOFN();
+ void ClearBINF();
+ void Win2Unix(char *s);
+ void Unix2Win(char *s);
+ int showfile();
+ static int CALLBACK Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data);
+ int showdir();
+
+ void parse_filter(const char *);
+ void clear_filters();
+ void add_filter(const char *, const char *);
+
+public:
+ Fl_Native_File_Chooser(int val = BROWSE_FILE);
+ ~Fl_Native_File_Chooser();
+
+ // Public methods
+ void type(int val);
+ int type() const;
+ void options(int);
+ int options() const;
+ int count() const;
+ const char *filename() const;
+ const char *filename(int i) const;
+ void directory(const char *val);
+ const char *directory() const;
+ void title(const char *val);
+ const char *title() const;
+ const char *filter() const;
+ void filter(const char *val);
+ int filters() const { return _nfilters; }
+ void filter_value(int i);
+ int filter_value() const;
+ void preset_file(const char *);
+ const char *preset_file() const;
+ const char *errmsg() const;
+ int show();
+};
diff --git a/src/Fl_Native_File_Chooser.cxx b/src/Fl_Native_File_Chooser.cxx
new file mode 100644
index 000000000..62bb526e4
--- /dev/null
+++ b/src/Fl_Native_File_Chooser.cxx
@@ -0,0 +1,45 @@
+// "$Id$"
+//
+// FLTK native OS file chooser widget
+//
+// Copyright 1998-2005 by Bill Spitzak and others.
+// Copyright 2004 Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems to:
+//
+// http://www.fltk.org/str.php
+//
+
+// Use Windows' chooser
+#ifdef _WIN32
+#include "Fl_Native_File_Chooser_WIN32.cxx"
+#endif
+
+// Use Apple's chooser
+#ifdef __APPLE__
+#include "Fl_Native_File_Chooser_MAC.cxx"
+#endif
+
+// All else falls back to FLTK's own chooser
+#if ! defined(__APPLE__) && !defined(_WIN32)
+#include "Fl_Native_File_Chooser_FLTK.cxx"
+#endif
+
+//
+// End of "$Id:".
+//
diff --git a/src/Fl_Native_File_Chooser_FLTK.cxx b/src/Fl_Native_File_Chooser_FLTK.cxx
new file mode 100644
index 000000000..e77e18700
--- /dev/null
+++ b/src/Fl_Native_File_Chooser_FLTK.cxx
@@ -0,0 +1,395 @@
+// "$Id$"
+//
+// FLTK native OS file chooser widget
+//
+// Copyright 1998-2005 by Bill Spitzak and others.
+// Copyright 2004 Greg Ercolano.
+// API changes + filter improvements by Nathan Vander Wilt 2005
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems to:
+//
+// http://www.fltk.org/str.php
+//
+
+#include <FL/Fl_Native_File_Chooser.H>
+#include <FL/Fl_File_Icon.H>
+#define FNFC_CLASS Fl_Native_File_Chooser
+#define FNFC_CTOR Fl_Native_File_Chooser
+#define FLTK_CHOOSER_SINGLE Fl_File_Chooser::SINGLE
+#define FLTK_CHOOSER_DIRECTORY Fl_File_Chooser::DIRECTORY
+#define FLTK_CHOOSER_MULTI Fl_File_Chooser::MULTI
+#define FLTK_CHOOSER_CREATE Fl_File_Chooser::CREATE
+
+#include "Fl_Native_File_Chooser_common.cxx"
+#include <sys/stat.h>
+
+// CTOR
+FNFC_CLASS::FNFC_CTOR(int val) {
+ //// CANT USE THIS -- MESSES UP LINKING/CREATES DEPENDENCY ON fltk_images.
+ //// Have user call this from app instead.
+ ////
+ //// static int init = 0; // 'first time' initialize flag
+ //// if ( init == 0 ) {
+ //// // Initialize when instanced for first time
+ //// Fl_File_Icon::load_system_icons();
+ //// init = 1;
+ //// }
+ _btype = val;
+ _options = NO_OPTIONS;
+ _filter = NULL;
+ _filtvalue = 0;
+ _parsedfilt = NULL;
+ _preset_file = NULL;
+ _prevvalue = NULL;
+ _directory = NULL;
+ _errmsg = NULL;
+ file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
+ type(val); // do this after file_chooser created
+ _nfilters = 0;
+
+ // Added by MG
+ Fl_Button *b = file_chooser->previewButton;
+ Fl_Window *w = b->window();
+ Fl_Group::current(w); // adds a "Show hidden files" check button in file_chooser's window
+ show_hidden = new Fl_Check_Button(b->x() + b->w() + 10, b->y(), 145, b->h(), "Show hidden files");
+ show_hidden->callback((Fl_Callback*)show_hidden_cb, this);
+ // This is a hack to bypass the fact that fileList is a private member of file_chooser.
+ // Find it as 1st child of 2nd child of file_chooser's window.
+ Fl_Group *g = (Fl_Group *)w->array()[1];
+ my_fileList = (Fl_File_Browser *)g->array()[0];
+ old_dir[0] = 0; // to detect directory changes
+ prev_filtervalue = file_chooser->filter_value(); // to detect filter changes
+ // Hack to get file_chooser's showChoice widget.
+ // Find it as 1st child of 1st child of file_chooser's window.
+ g = (Fl_Group *)w->array()[0];
+ showChoice = (Fl_Choice *)g->array()[0];
+}
+
+// DTOR
+FNFC_CLASS::~FNFC_CTOR() {
+ delete file_chooser;
+ _filter = strfree(_filter);
+ _parsedfilt = strfree(_parsedfilt);
+ _preset_file = strfree(_preset_file);
+ _prevvalue = strfree(_prevvalue);
+ _directory = strfree(_directory);
+ _errmsg = strfree(_errmsg);
+}
+
+// PRIVATE: SET ERROR MESSAGE
+void FNFC_CLASS::errmsg(const char *msg) {
+ _errmsg = strfree(_errmsg);
+ _errmsg = strnew(msg);
+}
+
+// PRIVATE: translate Native types to Fl_File_Chooser types
+int FNFC_CLASS::type_fl_file(int val) {
+ switch (val) {
+ case BROWSE_FILE:
+ return(FLTK_CHOOSER_SINGLE);
+ case BROWSE_DIRECTORY:
+ return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_DIRECTORY);
+ case BROWSE_MULTI_FILE:
+ return(FLTK_CHOOSER_MULTI);
+ case BROWSE_MULTI_DIRECTORY:
+ return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI);
+ case BROWSE_SAVE_FILE:
+ return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_CREATE);
+ case BROWSE_SAVE_DIRECTORY:
+ return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI | FLTK_CHOOSER_CREATE);
+ default:
+ return(FLTK_CHOOSER_SINGLE);
+ }
+}
+
+void FNFC_CLASS::type(int val) {
+ _btype = val;
+ file_chooser->type(type_fl_file(val));
+}
+
+int FNFC_CLASS::type() const {
+ return(_btype);
+}
+
+// SET OPTIONS
+void FNFC_CLASS::options(int val) {
+ _options = val;
+}
+
+// GET OPTIONS
+int FNFC_CLASS::options() const {
+ return(_options);
+}
+
+// Show chooser, blocks until done.
+// RETURNS:
+// 0 - user picked a file
+// 1 - user cancelled
+// -1 - failed; errmsg() has reason
+//
+int FNFC_CLASS::show() {
+ // FILTER
+ if ( _parsedfilt ) {
+ file_chooser->filter(_parsedfilt);
+ }
+
+ // FILTER VALUE
+ // Set this /after/ setting the filter
+ //
+ file_chooser->filter_value(_filtvalue);
+
+ // DIRECTORY
+ if ( _directory && _directory[0] ) {
+ file_chooser->directory(_directory);
+ } else {
+ file_chooser->directory(_prevvalue);
+ }
+
+ // PRESET FILE
+ if ( _preset_file ) {
+ file_chooser->value(_preset_file);
+ }
+
+ // OPTIONS: PREVIEW
+ file_chooser->preview( (options() & PREVIEW) ? 1 : 0);
+
+ // OPTIONS: NEW FOLDER
+ if ( options() & NEW_FOLDER )
+ file_chooser->type(file_chooser->type() | FLTK_CHOOSER_CREATE); // on
+
+ // SHOW
+ file_chooser->show();
+
+ // BLOCK WHILE BROWSER SHOWN
+ while ( file_chooser->shown() ) {
+ if(strcmp(old_dir, file_chooser->directory()) != 0) {
+ strcpy(old_dir, file_chooser->directory());
+ if(!show_hidden->value()) remove_hidden_files(my_fileList);
+ } else if(prev_filtervalue != file_chooser->filter_value() ) {
+ prev_filtervalue = file_chooser->filter_value();
+ if(!show_hidden->value() ) remove_hidden_files(my_fileList);
+ }
+ Fl::wait();
+ }
+
+ if ( file_chooser->value() && file_chooser->value()[0] ) {
+ _prevvalue = strfree(_prevvalue);
+ _prevvalue = strnew(file_chooser->value());
+ _filtvalue = file_chooser->filter_value(); // update filter value
+
+ // HANDLE SHOWING 'SaveAs' CONFIRM
+ if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
+ struct stat buf;
+ if ( stat(file_chooser->value(), &buf) != -1 ) {
+ if ( buf.st_mode & S_IFREG ) { // Regular file + exists?
+ if ( exist_dialog() == 0 ) {
+ return(1);
+ }
+ }
+ }
+ }
+ }
+
+ if ( file_chooser->count() ) return(0);
+ else return(1);
+}
+
+// RETURN ERROR MESSAGE
+const char *FNFC_CLASS::errmsg() const {
+ return(_errmsg ? _errmsg : "No error");
+}
+
+// GET FILENAME
+const char* FNFC_CLASS::filename() const {
+ if ( file_chooser->count() > 0 ) return(file_chooser->value());
+ return("");
+}
+
+// GET FILENAME FROM LIST OF FILENAMES
+const char* FNFC_CLASS::filename(int i) const {
+ if ( i < file_chooser->count() )
+ return(file_chooser->value(i+1)); // convert fltk 1 based to our 0 based
+ return("");
+}
+
+// SET TITLE
+// Can be NULL if no title desired.
+//
+void FNFC_CLASS::title(const char *val) {
+ file_chooser->label(val);
+}
+
+// GET TITLE
+// Can return NULL if none set.
+//
+const char *FNFC_CLASS::title() const {
+ return(file_chooser->label());
+}
+
+// SET FILTER
+// Can be NULL if no filter needed
+//
+void FNFC_CLASS::filter(const char *val) {
+ _filter = strfree(_filter);
+ _filter = strnew(val);
+ parse_filter();
+}
+
+// GET FILTER
+const char *FNFC_CLASS::filter() const {
+ return(_filter);
+}
+
+// SET SELECTED FILTER
+void FNFC_CLASS::filter_value(int val) {
+ _filtvalue = val;
+}
+
+// RETURN SELECTED FILTER
+int FNFC_CLASS::filter_value() const {
+ return(_filtvalue);
+}
+
+// GET TOTAL FILENAMES CHOSEN
+int FNFC_CLASS::count() const {
+ return(file_chooser->count());
+}
+
+// PRESET PATHNAME
+// Can be NULL if no preset is desired.
+//
+void FNFC_CLASS::directory(const char *val) {
+ _directory = strfree(_directory);
+ _directory = strnew(val);
+}
+
+// GET PRESET PATHNAME
+// Can return NULL if none set.
+//
+const char *FNFC_CLASS::directory() const {
+ return(_directory);
+}
+
+// Convert our filter format to fltk's chooser format
+// FROM TO (FLTK)
+// ------------------------- --------------------------
+// "*.cxx" "*.cxx Files(*.cxx)"
+// "C Files\t*.{cxx,h}" "C Files(*.{cxx,h})"
+// "C Files\t*.{cxx,h}\nText Files\t*.txt" "C Files(*.{cxx,h})\tText Files(*.txt)"
+//
+// Returns a modified version of the filter that the caller is responsible
+// for freeing with strfree().
+//
+void FNFC_CLASS::parse_filter() {
+ _parsedfilt = strfree(_parsedfilt); // clear previous parsed filter (if any)
+ _nfilters = 0;
+ char *in = _filter;
+ if ( !in ) return;
+
+ int has_name = strchr(in, '\t') ? 1 : 0;
+
+ char mode = has_name ? 'n' : 'w'; // parse mode: n=title, w=wildcard
+ char wildcard[1024] = ""; // parsed wildcard
+ char name[1024] = "";
+
+ // Parse filter user specified
+ for ( ; 1; in++ ) {
+ /*** DEBUG
+ printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n",
+ *in, mode, name, wildcard);
+ ***/
+
+ switch (*in) {
+ // FINISHED PARSING NAME?
+ case '\t':
+ if ( mode != 'n' ) goto regchar;
+ mode = 'w';
+ break;
+ // ESCAPE NEXT CHAR
+ case '\\':
+ ++in;
+ goto regchar;
+ // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
+ case '\r':
+ case '\n':
+ case '\0':
+ // APPEND NEW FILTER TO LIST
+ if ( wildcard[0] ) {
+ // OUT: "name(wild)\tname(wild)"
+ char comp[2048];
+ sprintf(comp, "%s%.511s(%.511s)", ((_parsedfilt)?"\t":""),
+ name, wildcard);
+ _parsedfilt = strapp(_parsedfilt, comp);
+ _nfilters++;
+ //DEBUG printf("DEBUG: PARSED FILT NOW <%s>\n", _parsedfilt);
+ }
+ // RESET
+ wildcard[0] = name[0] = '\0';
+ mode = strchr(in, '\t') ? 'n' : 'w';
+ // DONE?
+ if ( *in == '\0' ) return; // done
+ else continue; // not done yet, more filters
+
+ // Parse all other chars
+ default: // handle all non-special chars
+ regchar: // handle regular char
+ switch ( mode ) {
+ case 'n': chrcat(name, *in); continue;
+ case 'w': chrcat(wildcard, *in); continue;
+ }
+ break;
+ }
+ }
+ //NOTREACHED
+}
+
+// SET PRESET FILENAME
+void FNFC_CLASS::preset_file(const char* val) {
+ _preset_file = strfree(_preset_file);
+ _preset_file = strnew(val);
+}
+
+// GET PRESET FILENAME
+const char* FNFC_CLASS::preset_file() const {
+ return(_preset_file);
+}
+
+void FNFC_CLASS::show_hidden_cb(Fl_Check_Button *o, void *data)
+{
+ Fl_Native_File_Chooser *mychooser = (Fl_Native_File_Chooser *)data;
+ if(o->value()) {
+ mychooser->my_fileList->load(mychooser->file_chooser->directory());
+ } else {
+ remove_hidden_files(mychooser->my_fileList);
+ mychooser->my_fileList->redraw();
+ }
+}
+
+void FNFC_CLASS::remove_hidden_files(Fl_File_Browser *my_fileList)
+{
+ int count = my_fileList->size();
+ for(int num = count; num >= 1; num--) {
+ const char *p = my_fileList->text(num);
+ if(*p == '.' && strcmp(p, "../") != 0) my_fileList->remove(num);
+ }
+ my_fileList->topline(1);
+}
+
+//
+// End of "$Id:".
+//
diff --git a/src/Fl_Native_File_Chooser_MAC.cxx b/src/Fl_Native_File_Chooser_MAC.cxx
new file mode 100644
index 000000000..8d3b3f9d9
--- /dev/null
+++ b/src/Fl_Native_File_Chooser_MAC.cxx
@@ -0,0 +1,1087 @@
+// "$Id$"
+//
+// FLTK native OS file chooser widget
+//
+// Copyright 1998-2005 by Bill Spitzak and others.
+// Copyright 2004 Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems to:
+//
+// http://www.fltk.org/str.php
+//
+
+// TODO:
+// o When doing 'open file', only dir is preset, not filename.
+// Possibly 'preset_file' could be used to select the filename.
+//
+
+#include "Fl_Native_File_Chooser_common.cxx" // strnew/strfree/strapp/chrcat
+#include <libgen.h> // dirname(3)
+#include <sys/types.h> // stat(2)
+#include <sys/stat.h> // stat(2)
+
+
+#include <FL/Fl.H>
+#include <FL/Fl_Native_File_Chooser.H>
+#include <FL/filename.H>
+#define FNFC_CLASS Fl_Native_File_Chooser
+#define FNFC_CTOR Fl_Native_File_Chooser
+
+#ifndef __APPLE_COCOA__
+// TRY TO CONVERT AN AEDesc TO AN FSRef
+// As per Apple Technical Q&A QA1274
+// eg: http://developer.apple.com/qa/qa2001/qa1274.html
+// Returns 'noErr' if OK, or an 'OSX result code' on error.
+//
+static int AEDescToFSRef(const AEDesc* desc, FSRef* fsref) {
+ OSStatus err = noErr;
+ AEDesc coerceDesc;
+ // If AEDesc isn't already an FSRef, convert it to one
+ if ( desc->descriptorType != typeFSRef ) {
+ if ( ( err = AECoerceDesc(desc, typeFSRef, &coerceDesc) ) == noErr ) {
+ // Get FSRef out of AEDesc
+ err = AEGetDescData(&coerceDesc, fsref, sizeof(FSRef));
+ AEDisposeDesc(&coerceDesc);
+ }
+ } else {
+ err = AEGetDescData(desc, fsref, sizeof(FSRef));
+ }
+ return( err );
+}
+
+// NAVREPLY: CTOR
+FNFC_CLASS::NavReply::NavReply() {
+ _valid_reply = 0;
+}
+
+// NAVREPLY: DTOR
+FNFC_CLASS::NavReply::~NavReply() {
+ if ( _valid_reply ) {
+ NavDisposeReply(&_reply);
+ }
+}
+
+// GET REPLY FROM THE NAV* DIALOG
+int FNFC_CLASS::NavReply::get_reply(NavDialogRef& ref) {
+ if ( _valid_reply ) {
+ NavDisposeReply(&_reply); // dispose of previous
+ _valid_reply = 0;
+ }
+ if ( ref == NULL || NavDialogGetReply(ref, &_reply) != noErr ) {
+ return(-1);
+ }
+ _valid_reply = 1;
+ return(0);
+}
+
+// RETURN THE BASENAME USER WANTS TO 'Save As'
+int FNFC_CLASS::NavReply::get_saveas_basename(char *s, int slen) {
+ if (CFStringGetCString(_reply.saveFileName, s, slen-1, kCFStringEncodingUTF8) == false) {
+ s[0] = '\0';
+ return(-1);
+ }
+ return(0);
+}
+
+// RETURN THE DIRECTORY NAME
+// Returns 0 on success, -1 on error.
+//
+int FNFC_CLASS::NavReply::get_dirname(char *s, int slen) {
+ FSRef fsref;
+ if ( AEDescToFSRef(&_reply.selection, &fsref) != noErr ) {
+ // Conversion failed? Return empty name
+ s[0] = 0;
+ return(-1);
+ }
+ FSRefMakePath(&fsref, (UInt8 *)s, slen);
+ return(0);
+}
+
+// RETURN MULTIPLE DIRECTORIES
+// Returns: 0 on success with pathnames[] containing pathnames selected,
+// -1 on error
+//
+int FNFC_CLASS::NavReply::get_pathnames(char **&pathnames, int& tpathnames) {
+ // How many items selected?
+ long count = 0;
+ if ( AECountItems(&_reply.selection, &count) != noErr ) {
+ return(-1);
+ }
+
+ // Allocate space for that many pathnames
+ pathnames = new char*[count];
+ memset((void*)pathnames, 0, count*sizeof(char*));
+ tpathnames = count;
+
+ // Walk list of pathnames selected
+ for (short index=1; index<=count; index++) {
+ AEKeyword keyWord;
+ AEDesc desc;
+ if (AEGetNthDesc(&_reply.selection, index, typeFSRef, &keyWord, &desc) != noErr) {
+ pathnames[index-1] = strnew("");
+ continue;
+ }
+ FSRef fsref;
+ if (AEGetDescData(&desc, &fsref, sizeof(FSRef)) != noErr ) {
+ pathnames[index-1] = strnew("");
+ continue;
+ }
+ char s[4096];
+ FSRefMakePath(&fsref, (UInt8 *)s, sizeof(s)-1);
+ pathnames[index-1] = strnew(s);
+ AEDisposeDesc(&desc);
+ }
+ return(0);
+}
+#endif /* !__APPLE_COCOA__ */
+
+// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS
+void FNFC_CLASS::clear_pathnames() {
+ if ( _pathnames ) {
+ while ( --_tpathnames >= 0 ) {
+ _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]);
+ }
+ delete [] _pathnames;
+ _pathnames = NULL;
+ }
+ _tpathnames = 0;
+}
+
+// SET A SINGLE PATHNAME
+void FNFC_CLASS::set_single_pathname(const char *s) {
+ clear_pathnames();
+ _pathnames = new char*[1];
+ _pathnames[0] = strnew(s);
+ _tpathnames = 1;
+}
+
+#ifndef __APPLE_COCOA__
+// GET THE 'Save As' FILENAME
+// Returns -1 on error, errmsg() has reason, filename == "".
+// 0 if OK, filename() has filename chosen.
+//
+int FNFC_CLASS::get_saveas_basename(NavDialogRef& ref) {
+ if ( ref == NULL ) {
+ errmsg("get_saveas_basename: ref is NULL");
+ return(-1);
+ }
+ NavReply reply;
+ OSStatus err;
+ if ((err = reply.get_reply(ref)) != noErr ) {
+ errmsg("NavReply::get_reply() failed");
+ clear_pathnames();
+ return(-1);
+ }
+
+ char pathname[4096] = "";
+ // Directory name..
+ // -2 leaves room to append '/'
+ //
+ if ( reply.get_dirname(pathname, sizeof(pathname)-2) < 0 ) {
+ clear_pathnames();
+ errmsg("NavReply::get_dirname() failed");
+ return(-1);
+ }
+ // Append '/'
+ int len = strlen(pathname);
+ pathname[len++] = '/';
+ pathname[len] = '\0';
+ // Basename..
+ if ( reply.get_saveas_basename(pathname+len, sizeof(pathname)-len) < 0 ) {
+ clear_pathnames();
+ errmsg("NavReply::get_saveas_basename() failed");
+ return(-1);
+ }
+ set_single_pathname(pathname);
+ return(0);
+}
+
+// GET (POTENTIALLY) MULTIPLE FILENAMES
+// Returns:
+// -1 -- error, errmsg() has reason, filename == ""
+// 0 -- OK, pathnames()/filename() has pathname(s) chosen
+//
+int FNFC_CLASS::get_pathnames(NavDialogRef& ref) {
+ if ( ref == NULL ) {
+ errmsg("get_saveas_basename: ref is NULL");
+ return(-1);
+ }
+ NavReply reply;
+ OSStatus err;
+ if ((err = reply.get_reply(ref)) != noErr ) {
+ errmsg("NavReply::get_reply() failed");
+ clear_pathnames();
+ return(-1);
+ }
+ // First, clear pathnames array of any previous contents
+ clear_pathnames();
+ if ( reply.get_pathnames(_pathnames, _tpathnames) < 0 ) {
+ clear_pathnames();
+ errmsg("NavReply::get_dirname() failed");
+ return(-1);
+ }
+ return(0);
+}
+
+// IS PATHNAME A DIRECTORY?
+// 1 - path is a dir
+// 0 - path not a dir or error
+//
+static int IsDir(const char *pathname) {
+ struct stat buf;
+ if ( stat(pathname, &buf) != -1 ) {
+ if ( buf.st_mode & S_IFDIR ) return(1);
+ }
+ return(0);
+}
+
+// PRESELECT PATHNAME IN BROWSER
+static void PreselectPathname(NavCBRecPtr cbparm, const char *path) {
+ // XXX: path must be a dir, or kNavCtlSetLocation fails with -50.
+ // Why, I don't know. Let me know with a bug report. -erco
+ //
+ if ( ! IsDir(path) ) {
+ path = dirname((char*)path);
+ }
+ OSStatus err;
+ FSRef fsref;
+ err = FSPathMakeRef((const UInt8*)path, &fsref, NULL);
+ if ( err != noErr) {
+ fprintf(stderr, "FSPathMakeRef(%s) failed: err=%d\n", path, (int)err);
+ return;
+ }
+ AEDesc desc;
+ err = AECreateDesc(typeFSRef, &fsref, sizeof(FSRef), &desc);
+ if ( err != noErr) {
+ fprintf(stderr, "AECreateDesc() failed: err=%d\n", (int)err);
+ }
+ err = NavCustomControl(cbparm->context, kNavCtlSetLocation, &desc);
+ if ( err != noErr) {
+ fprintf(stderr, "NavCustomControl() failed: err=%d\n", (int)err);
+ }
+ AEDisposeDesc(&desc);
+}
+
+// NAV CALLBACK EVENT HANDLER
+void FNFC_CLASS::event_handler(NavEventCallbackMessage callBackSelector,
+ NavCBRecPtr cbparm,
+ void *data) {
+ FNFC_CLASS *nfb = (FNFC_CLASS*)data;
+ switch (callBackSelector) {
+ case kNavCBStart:
+ {
+ if ( nfb->directory() ) { // dir specified?
+ PreselectPathname(cbparm, nfb->directory()); // use it first
+ } else if ( nfb->preset_file() ) { // file specified?
+ PreselectPathname(cbparm, nfb->preset_file()); // use if no dir
+ }
+ if ( nfb->_btype == BROWSE_SAVE_FILE && nfb->preset_file() ) {
+ const char *p, *q;
+ p = nfb->preset_file();//don't use the path part of preset_file
+ q = strrchr(p, '/');
+ if(q == NULL) q = p; else q++;
+ CFStringRef namestr = CFStringCreateWithCString(NULL,
+ q,
+ kCFStringEncodingUTF8);
+ NavDialogSetSaveFileName(cbparm->context, namestr);
+ CFRelease(namestr);
+ }
+ NavCustomControl(cbparm->context,
+ kNavCtlSetActionState,
+ &nfb->_keepstate);
+ // Select the right filter in pop-up menu
+ if ( nfb->_filt_value == nfb->_filt_total ) {
+ // Select All Documents
+ NavPopupMenuItem kAll = kNavAllFiles;
+ NavCustomControl(cbparm->context, kNavCtlSelectAllType, &kAll);
+ } else if (nfb->_filt_value < nfb->_filt_total) {
+ // Select custom filter
+ nfb->_tempitem.version = kNavMenuItemSpecVersion;
+ nfb->_tempitem.menuCreator = 'extn';
+ nfb->_tempitem.menuType = nfb->_filt_value;
+ *nfb->_tempitem.menuItemName = '\0'; // needed on 10.3+
+ NavCustomControl(cbparm->context,
+ kNavCtlSelectCustomType,
+ &(nfb->_tempitem));
+ }
+ break;
+ }
+ case kNavCBPopupMenuSelect:
+ {
+ NavMenuItemSpecPtr ptr;
+ // they really buried this one!
+ ptr = (NavMenuItemSpecPtr)cbparm->eventData.eventDataParms.param;
+ if ( ptr->menuCreator ) {
+ // Gets index to filter ( menuCreator = 'extn' )
+ nfb->_filt_value = ptr->menuType;
+ } else {
+ // All docs filter selected ( menuCreator = '\0\0\0\0' )
+ nfb->_filt_value = nfb->_filt_total;
+ }
+ break;
+ }
+ case kNavCBSelectEntry:
+ {
+ NavActionState astate;
+ switch ( nfb->_btype ) {
+ // These don't need selection override
+ case BROWSE_MULTI_FILE:
+ case BROWSE_MULTI_DIRECTORY:
+ case BROWSE_SAVE_FILE:
+ break;
+
+ // These need to allow only one item, so disable
+ // Open button if user tries to select multiple files
+ case BROWSE_SAVE_DIRECTORY:
+ case BROWSE_DIRECTORY:
+ case BROWSE_FILE:
+ {
+ long selectcount;
+ AECountItems((AEDescList*)cbparm->
+ eventData.eventDataParms.param,
+ &selectcount);
+ if ( selectcount > 1 ) {
+ NavCustomControl(cbparm->context,
+ kNavCtlSetSelection,
+ NULL);
+ astate = nfb->_keepstate |
+ kNavDontOpenState |
+ kNavDontChooseState;
+ NavCustomControl(cbparm->context,
+ kNavCtlSetActionState,
+ &astate );
+ } else {
+ astate= nfb->_keepstate | kNavNormalState;
+ NavCustomControl(cbparm->context,
+ kNavCtlSetActionState,
+ &astate );
+ }
+ break;
+ }
+ }
+ }
+ break;
+ }
+}
+#endif /* !__APPLE_COCOA__ */
+
+// CONSTRUCTOR
+FNFC_CLASS::FNFC_CTOR(int val) {
+ _btype = val;
+#ifdef __APPLE_COCOA__
+ _panel = NULL;
+#else
+ NavGetDefaultDialogCreationOptions(&_opts);
+ _opts.optionFlags |= kNavDontConfirmReplacement; // no confirms for "save as"
+ _ref = NULL;
+#endif
+ _options = NO_OPTIONS;
+ memset(&_tempitem, 0, sizeof(_tempitem));
+ _pathnames = NULL;
+ _tpathnames = 0;
+ _title = NULL;
+ _filter = NULL;
+ _filt_names = NULL;
+ memset(_filt_patt, 0, sizeof(char*) * MAXFILTERS);
+ _filt_total = 0;
+ _filt_value = 0;
+ _directory = NULL;
+ _preset_file = NULL;
+ _errmsg = NULL;
+ _keepstate = kNavNormalState;
+}
+
+// DESTRUCTOR
+FNFC_CLASS::~FNFC_CTOR() {
+ // _opts // nothing to manage
+#ifndef __APPLE_COCOA__
+ if (_ref) { NavDialogDispose(_ref); _ref = NULL; }
+#endif
+ // _options // nothing to manage
+ // _keepstate // nothing to manage
+ // _tempitem // nothing to manage
+ clear_pathnames();
+ _directory = strfree(_directory);
+ _title = strfree(_title);
+ _preset_file = strfree(_preset_file);
+ _filter = strfree(_filter);
+ //_filt_names // managed by clear_filters()
+ //_filt_patt[i] // managed by clear_filters()
+ //_filt_total // managed by clear_filters()
+ clear_filters();
+ //_filt_value // nothing to manage
+ _errmsg = strfree(_errmsg);
+}
+
+#ifndef __APPLE_COCOA__
+// SET THE TYPE OF BROWSER
+void FNFC_CLASS::type(int val) {
+ _btype = val;
+}
+#endif /* !__APPLE_COCOA__ */
+
+// GET TYPE OF BROWSER
+int FNFC_CLASS::type() const {
+ return(_btype);
+}
+
+// SET OPTIONS
+void FNFC_CLASS::options(int val) {
+ _options = val;
+}
+
+// GET OPTIONS
+int FNFC_CLASS::options() const {
+ return(_options);
+}
+
+// SHOW THE BROWSER WINDOW
+// Returns:
+// 0 - user picked a file
+// 1 - user cancelled
+// -1 - failed; errmsg() has reason
+//
+int FNFC_CLASS::show() {
+
+ // Make sure fltk interface updates before posting our dialog
+ Fl::flush();
+
+ _keepstate = kNavNormalState;
+#ifndef __APPLE_COCOA__
+ // BROWSER TITLE
+ CFStringRef cfs_title;
+ cfs_title = CFStringCreateWithCString(NULL,
+ _title ? _title : "No Title",
+ kCFStringEncodingUTF8);
+ _opts.windowTitle = cfs_title;
+ // BROWSER FILTERS
+ CFArrayRef filter_array = NULL;
+
+ // One or more filters specified?
+ if ( _filt_total ) {
+ // NAMES -> CFArrayRef
+ CFStringRef tab = CFSTR("\t");
+ CFStringRef tmp_cfs;
+ tmp_cfs = CFStringCreateWithCString(NULL,
+ _filt_names,
+ kCFStringEncodingUTF8);
+ filter_array = CFStringCreateArrayBySeparatingStrings(NULL,
+ tmp_cfs,
+ tab);
+ CFRelease(tmp_cfs);
+ CFRelease(tab);
+ _opts.popupExtension = filter_array;
+ _opts.optionFlags |= kNavAllFilesInPopup;
+ } else {
+ filter_array = NULL;
+ _opts.popupExtension = NULL;
+ _opts.optionFlags |= kNavAllFilesInPopup;
+ }
+
+ // HANDLE OPTIONS WE SUPPORT
+ if ( _options & SAVEAS_CONFIRM ) {
+ _opts.optionFlags &= ~kNavDontConfirmReplacement; // enables confirm
+ } else {
+ _opts.optionFlags |= kNavDontConfirmReplacement; // disables confirm
+ }
+ // _opts.optionFlags |= kNavSupportPackages; // enables *.app TODO: Make a flag to control this
+#endif /* !__APPLE_COCOA__ */
+
+ // POST BROWSER
+ int err = post();
+
+#ifndef __APPLE_COCOA__
+ // RELEASE _FILT_ARR
+ if ( filter_array ) CFRelease(filter_array);
+ filter_array = NULL;
+ _opts.popupExtension = NULL;
+ // RELEASE TITLE
+ if ( cfs_title ) CFRelease(cfs_title);
+ cfs_title = NULL;
+#endif /* !__APPLE_COCOA__ */
+ _filt_total = 0;
+
+ return(err);
+}
+
+#ifndef __APPLE_COCOA__
+int FNFC_CLASS::post() {
+
+ // INITIALIZE BROWSER
+ OSStatus err;
+ if ( _filt_total == 0 ) { // Make sure they match
+ _filt_value = 0; // TBD: move to someplace more logical?
+ }
+
+ if ( ! ( _options & NEW_FOLDER ) ) {
+ _keepstate |= kNavDontNewFolderState;
+ }
+
+ switch (_btype) {
+ case BROWSE_FILE:
+ case BROWSE_MULTI_FILE:
+ // Prompt user for one or more files
+ if ((err = NavCreateGetFileDialog(&_opts, // options
+ 0, // file types
+ event_handler, // event handler
+ 0, // preview callback
+ filter_proc_cb, // filter callback
+ (void*)this, // callback data
+ &_ref)) != noErr ) { // dialog ref
+ errmsg("NavCreateGetFileDialog: failed");
+ return(-1);
+ }
+ break;
+
+ case BROWSE_DIRECTORY:
+ case BROWSE_MULTI_DIRECTORY:
+ case BROWSE_SAVE_DIRECTORY:
+ // Prompts user for one or more files or folders
+ if ((err = NavCreateChooseFolderDialog(&_opts, // options
+ event_handler, // event callback
+ 0, // filter callback
+ (void*)this, // callback data
+ &_ref)) != noErr ) { // dialog ref
+ errmsg("NavCreateChooseFolderDialog: failed");
+ return(-1);
+ }
+ break;
+
+ case BROWSE_SAVE_FILE:
+ // Prompt user for filename to 'save as'
+ if ((err = NavCreatePutFileDialog(&_opts, // options
+ 0, // file types
+ kNavGenericSignature, //file creator
+ event_handler, // event handler
+ (void*)this, // callback data
+ &_ref)) != noErr ) { // dialog ref
+ errmsg("NavCreatePutFileDialog: failed");
+ return(-1);
+ }
+ break;
+ }
+
+ // SHOW THE DIALOG
+ if ( ( err = NavDialogRun(_ref) ) != 0 ) {
+ char msg[80];
+ sprintf(msg, "NavDialogRun: failed (err=%d)", (int)err);
+ errmsg(msg);
+ return(-1);
+ }
+
+ // WHAT ACTION DID USER CHOOSE?
+ NavUserAction act = NavDialogGetUserAction(_ref);
+ if ( act == kNavUserActionNone ) {
+ errmsg("Nothing happened yet (dialog still open)");
+ return(-1);
+ }
+ else if ( act == kNavUserActionCancel ) { // user chose 'cancel'
+ return(1);
+ }
+ else if ( act == kNavUserActionSaveAs ) { // user chose 'save as'
+ return(get_saveas_basename(_ref));
+ }
+
+ // TOO MANY FILES CHOSEN?
+ int ret = get_pathnames(_ref);
+ if ( _btype == BROWSE_FILE && ret == 0 && _tpathnames != 1 ) {
+ char msg[80];
+ sprintf(msg, "Expected only one file to be chosen.. you chose %d.", (int)_tpathnames);
+ errmsg(msg);
+ return(-1);
+ }
+ return(err);
+}
+#endif /* !__APPLE_COCOA__ */
+
+// SET ERROR MESSAGE
+// Internal use only.
+//
+void FNFC_CLASS::errmsg(const char *msg) {
+ _errmsg = strfree(_errmsg);
+ _errmsg = strnew(msg);
+}
+
+// RETURN ERROR MESSAGE
+const char *FNFC_CLASS::errmsg() const {
+ return(_errmsg ? _errmsg : "No error");
+}
+
+// GET FILENAME
+const char* FNFC_CLASS::filename() const {
+ if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]);
+ return("");
+}
+
+// GET FILENAME FROM LIST OF FILENAMES
+const char* FNFC_CLASS::filename(int i) const {
+ if ( _pathnames && i < _tpathnames ) return(_pathnames[i]);
+ return("");
+}
+
+// GET TOTAL FILENAMES CHOSEN
+int FNFC_CLASS::count() const {
+ return(_tpathnames);
+}
+
+// PRESET PATHNAME
+// Value can be NULL for none.
+//
+void FNFC_CLASS::directory(const char *val) {
+ _directory = strfree(_directory);
+ _directory = strnew(val);
+}
+
+// GET PRESET PATHNAME
+// Returned value can be NULL if none set.
+//
+const char* FNFC_CLASS::directory() const {
+ return(_directory);
+}
+
+// SET TITLE
+// Value can be NULL if no title desired.
+//
+void FNFC_CLASS::title(const char *val) {
+ _title = strfree(_title);
+ _title = strnew(val);
+}
+
+// GET TITLE
+// Returned value can be NULL if none set.
+//
+const char *FNFC_CLASS::title() const {
+ return(_title);
+}
+
+// SET FILTER
+// Can be NULL if no filter needed
+//
+void FNFC_CLASS::filter(const char *val) {
+ _filter = strfree(_filter);
+ _filter = strnew(val);
+
+ // Parse filter user specified
+ // IN: _filter = "C Files\t*.{cxx,h}\nText Files\t*.txt"
+ // OUT: _filt_names = "C Files\tText Files"
+ // _filt_patt[0] = "*.{cxx,h}"
+ // _filt_patt[1] = "*.txt"
+ // _filt_total = 2
+ //
+ parse_filter(_filter);
+}
+
+// GET FILTER
+// Returned value can be NULL if none set.
+//
+const char *FNFC_CLASS::filter() const {
+ return(_filter);
+}
+
+// CLEAR ALL FILTERS
+// Internal use only.
+//
+void FNFC_CLASS::clear_filters() {
+ _filt_names = strfree(_filt_names);
+ for (int i=0; i<_filt_total; i++) {
+ _filt_patt[i] = strfree(_filt_patt[i]);
+ }
+ _filt_total = 0;
+}
+
+// PARSE USER'S FILTER SPEC
+// Parses user specified filter ('in'),
+// breaks out into _filt_patt[], _filt_names, and _filt_total.
+//
+// Handles:
+// IN: OUT:_filt_names OUT: _filt_patt
+// ------------------------------------ ------------------ ---------------
+// "*.{ma,mb}" "*.{ma,mb} Files" "*.{ma,mb}"
+// "*.[abc]" "*.[abc] Files" "*.[abc]"
+// "*.txt" "*.txt Files" "*.c"
+// "C Files\t*.[ch]" "C Files" "*.[ch]"
+// "C Files\t*.[ch]\nText Files\t*.cxx" "C Files" "*.[ch]"
+//
+// Parsing Mode:
+// IN:"C Files\t*.{cxx,h}"
+// ||||||| |||||||||
+// mode: nnnnnnn wwwwwwwww
+// \_____/ \_______/
+// Name Wildcard
+//
+void FNFC_CLASS::parse_filter(const char *in) {
+ clear_filters();
+ if ( ! in ) return;
+ int has_name = strchr(in, '\t') ? 1 : 0;
+
+ char mode = has_name ? 'n' : 'w'; // parse mode: n=title, w=wildcard
+ char wildcard[1024] = ""; // parsed wildcard
+ char name[1024] = "";
+
+ // Parse filter user specified
+ for ( ; 1; in++ ) {
+
+ //// DEBUG
+ //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n",
+ //// *in, mode, name, wildcard);
+
+ switch (*in) {
+ // FINISHED PARSING NAME?
+ case '\t':
+ if ( mode != 'n' ) goto regchar;
+ mode = 'w';
+ break;
+
+ // ESCAPE NEXT CHAR
+ case '\\':
+ ++in;
+ goto regchar;
+
+ // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
+ case '\r':
+ case '\n':
+ case '\0':
+ // TITLE
+ // If user didn't specify a name, make one
+ //
+ if ( name[0] == '\0' ) {
+ sprintf(name, "%.*s Files", (int)sizeof(name)-10, wildcard);
+ }
+ // APPEND NEW FILTER TO LIST
+ if ( wildcard[0] ) {
+ // Add to filtername list
+ // Tab delimit if more than one. We later break
+ // tab delimited string into CFArray with
+ // CFStringCreateArrayBySeparatingStrings()
+ //
+ if ( _filt_total ) {
+ _filt_names = strapp(_filt_names, "\t");
+ }
+ _filt_names = strapp(_filt_names, name);
+
+ // Add filter to the pattern array
+ _filt_patt[_filt_total++] = strnew(wildcard);
+ }
+ // RESET
+ wildcard[0] = name[0] = '\0';
+ mode = strchr(in, '\t') ? 'n' : 'w';
+ // DONE?
+ if ( *in == '\0' ) return; // done
+ else continue; // not done yet, more filters
+
+ // Parse all other chars
+ default: // handle all non-special chars
+ regchar: // handle regular char
+ switch ( mode ) {
+ case 'n': chrcat(name, *in); continue;
+ case 'w': chrcat(wildcard, *in); continue;
+ }
+ break;
+ }
+ }
+ //NOTREACHED
+}
+
+#ifndef __APPLE_COCOA__
+// STATIC: FILTER CALLBACK
+Boolean FNFC_CLASS::filter_proc_cb(AEDesc *theItem,
+ void *info,
+ void *callBackUD,
+ NavFilterModes filterMode) {
+ return((FNFC_CLASS*)callBackUD)->filter_proc_cb2(theItem,
+ info,
+ callBackUD,
+ filterMode);
+}
+
+// FILTER CALLBACK
+// Return true if match,
+// false if no match.
+//
+Boolean FNFC_CLASS::filter_proc_cb2(AEDesc *theItem,
+ void *info,
+ void *callBackUD,
+ NavFilterModes filterMode) {
+ // All files chosen or no filters
+ if ( _filt_value == _filt_total ) return(true);
+
+ FSRef fsref;
+ char pathname[4096];
+
+ // On fail, filter should return true by default
+ if ( AEDescToFSRef(theItem, &fsref) != noErr ) {
+ return(true);
+ }
+ FSRefMakePath(&fsref, (UInt8 *)pathname, sizeof(pathname)-1);
+
+ if ( fl_filename_isdir(pathname) ) return(true);
+ if ( fl_filename_match(pathname, _filt_patt[_filt_value]) ) return(true);
+ else return(false);
+}
+#endif
+
+// SET PRESET FILE
+// Value can be NULL for none.
+//
+void FNFC_CLASS::preset_file(const char* val) {
+ _preset_file = strfree(_preset_file);
+ _preset_file = strnew(val);
+}
+
+// PRESET FILE
+// Returned value can be NULL if none set.
+//
+const char* FNFC_CLASS::preset_file() {
+ return(_preset_file);
+}
+
+#ifdef __APPLE_COCOA__
+#import <Cocoa/Cocoa.h>
+#define UNLIKELYPREFIX "___fl_very_unlikely_prefix_"
+
+int FNFC_CLASS::get_saveas_basename(void) {
+ char *q = strdup( [[(NSSavePanel*)_panel filename] fileSystemRepresentation] );
+ id delegate = [(NSSavePanel*)_panel delegate];
+ if(delegate != nil) {
+ const char *d = [[(NSSavePanel*)_panel directory] fileSystemRepresentation];
+ int l = strlen(d) + 1;
+ int lu = strlen(UNLIKELYPREFIX);
+ //remove UNLIKELYPREFIX between directory and filename parts
+ memmove(q + l, q + l + lu, strlen(q + l + lu) + 1);
+ }
+ set_single_pathname( q );
+ free(q);
+ return 0;
+}
+
+// SET THE TYPE OF BROWSER
+void FNFC_CLASS::type(int val) {
+ _btype = val;
+ switch (_btype) {
+ case BROWSE_FILE:
+ case BROWSE_MULTI_FILE:
+ case BROWSE_DIRECTORY:
+ case BROWSE_MULTI_DIRECTORY:
+ _panel = [NSOpenPanel openPanel];
+ break;
+ case BROWSE_SAVE_DIRECTORY:
+ case BROWSE_SAVE_FILE:
+ _panel = [NSSavePanel savePanel];
+ break;
+ }
+}
+
+@interface FLopenDelegate : NSObject {
+ NSPopUpButton *nspopup;
+ char **filter_pattern;
+}
+- (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern;
+- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
+@end
+@implementation FLopenDelegate
+- (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern
+{
+ nspopup = popup;
+ filter_pattern = pattern;
+ return self;
+}
+- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
+{
+ if( [nspopup indexOfSelectedItem] == [nspopup numberOfItems] - 1) return YES;
+ const char *pathname = [filename fileSystemRepresentation];
+ if ( fl_filename_isdir(pathname) ) return YES;
+ if ( fl_filename_match(pathname, filter_pattern[ [nspopup indexOfSelectedItem] ]) ) return YES;
+ return NO;
+}
+@end
+
+@interface FLsaveDelegate : NSObject {
+}
+- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag;
+@end
+@implementation FLsaveDelegate
+- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
+{
+ if(! okFlag) return filename;
+ // User has clicked save, and no overwrite confirmation should occur.
+ // To get the latter, we need to change the name we return (hence the prefix):
+ return [@ UNLIKELYPREFIX stringByAppendingString:filename];
+}
+@end
+
+static NSPopUpButton *createPopupAccessory(NSSavePanel *panel, const char *filter, const char *title, int rank)
+{
+ NSPopUpButton *popup;
+ NSRect rectview = NSMakeRect(5, 5, 350, 30 );
+ NSView *view = [[[NSView alloc] initWithFrame:rectview] autorelease];
+ NSRect rectbox = NSMakeRect(0, 3, 50, 1 );
+ NSBox *box = [[[NSBox alloc] initWithFrame:rectbox] autorelease];
+ NSRect rectpop = NSMakeRect(60, 0, 250, 30 );
+ popup = [[[NSPopUpButton alloc ] initWithFrame:rectpop pullsDown:NO] autorelease];
+ [view addSubview:box];
+ [view addSubview:popup];
+ [box setBorderType:NSNoBorder];
+ NSString *nstitle = [[NSString alloc] initWithUTF8String:title];
+ [box setTitle:nstitle];
+ [nstitle release];
+ NSFont *font = [NSFont controlContentFontOfSize:NSRegularControlSize];
+ [box setTitleFont:font];
+ [box sizeToFit];
+ CFStringRef tab = CFSTR("\n");
+ CFStringRef tmp_cfs;
+ tmp_cfs = CFStringCreateWithCString(NULL, filter, kCFStringEncodingASCII);
+ CFArrayRef array = CFStringCreateArrayBySeparatingStrings(NULL, tmp_cfs, tab);
+ CFRelease(tmp_cfs);
+ CFRelease(tab);
+ [popup addItemsWithTitles:(NSArray*)array];
+ NSMenuItem *item = [popup itemWithTitle:@""];
+ if(item) [popup removeItemWithTitle:@""];
+ CFRelease(array);
+ [popup selectItemAtIndex:rank];
+ [panel setAccessoryView:view];
+ return popup;
+}
+
+// POST BROWSER
+// Internal use only.
+// Assumes '_opts' has been initialized.
+//
+// Returns:
+// 0 - user picked a file
+// 1 - user cancelled
+// -1 - failed; errmsg() has reason
+//
+int FNFC_CLASS::post() {
+ // INITIALIZE BROWSER
+ if ( _filt_total == 0 ) { // Make sure they match
+ _filt_value = 0; // TBD: move to someplace more logical?
+ }
+ NSAutoreleasePool *localPool;
+ localPool = [[NSAutoreleasePool alloc] init];
+ int retval;
+ NSString *nstitle = [NSString stringWithUTF8String: (_title ? _title : "No Title")];
+ [(NSSavePanel*)_panel setTitle:nstitle];
+ switch (_btype) {
+ case BROWSE_MULTI_FILE:
+ [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES];
+ break;
+ case BROWSE_MULTI_DIRECTORY:
+ [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES];
+ case BROWSE_DIRECTORY:
+ [(NSOpenPanel*)_panel setCanChooseDirectories:YES];
+ break;
+ case BROWSE_SAVE_DIRECTORY:
+ [(NSSavePanel*)_panel setCanCreateDirectories:YES];
+ break;
+ }
+
+ // SHOW THE DIALOG
+ if( [(NSSavePanel*)_panel isKindOfClass:[NSOpenPanel class]] ) {
+ NSPopUpButton *popup = nil;
+ if(_filt_total) {
+ char *p; p = _filter;
+ char *q; q = new char[strlen(p) + 1];
+ char *r, *s, *t;
+ t = q;
+ do { //copy to t what is in _filter removing what is between \t and \n, if any
+ r = strchr(p, '\n');
+ if(!r) r = p + strlen(p) - 1;
+ s = strchr(p, '\t');
+ if(s && s < r) { memcpy(q, p, s - p); q += s - p; *(q++) = '\n'; }
+ else { memcpy(q, p, r - p + 1); q += r - p + 1; }
+ *q = 0;
+ p = r + 1;
+ } while(*p);
+ popup = createPopupAccessory((NSSavePanel*)_panel, t, "Enable:", 0);
+ delete t;
+ [[popup menu] addItem:[NSMenuItem separatorItem]];
+ [popup addItemWithTitle:@"All Documents"];
+ [popup setAction:@selector(validateVisibleColumns)];
+ [popup setTarget:(NSObject*)_panel];
+ static FLopenDelegate *openDelegate = nil;
+ if(openDelegate == nil) {
+ // not to be ever freed
+ openDelegate = [[FLopenDelegate alloc] init];
+ }
+ [openDelegate setPopup:popup filter_pattern:_filt_patt];
+ [(NSOpenPanel*)_panel setDelegate:openDelegate];
+ }
+ NSString *dir = nil;
+ NSString *fname = nil;
+ NSString *preset = nil;
+ if(_preset_file) {
+ preset = [[NSString alloc] initWithUTF8String:_preset_file];
+ if(strchr(_preset_file, '/') != NULL)
+ dir = [[NSString alloc] initWithString:[preset stringByDeletingLastPathComponent]];
+ fname = [preset lastPathComponent];
+ }
+ if(_directory && !dir) dir = [[NSString alloc] initWithUTF8String:_directory];
+ retval = [(NSOpenPanel*)_panel runModalForDirectory:dir file:fname types:nil];
+ [dir release];
+ [preset release];
+ if(_filt_total) {
+ _filt_value = [popup indexOfSelectedItem];
+ }
+ if ( retval == NSOKButton ) {
+ clear_pathnames();
+ NSArray *array = [(NSOpenPanel*)_panel filenames];
+ _tpathnames = [array count];
+ _pathnames = new char*[_tpathnames];
+ for(int i = 0; i < _tpathnames; i++) {
+ _pathnames[i] = strnew([(NSString*)[array objectAtIndex:i] fileSystemRepresentation]);
+ }
+ }
+ }
+ else {
+ NSString *dir = nil;
+ NSString *fname = nil;
+ NSString *preset = nil;
+ NSPopUpButton *popup = nil;
+ if( !(_options & SAVEAS_CONFIRM) ) {
+ static FLsaveDelegate *saveDelegate = nil;
+ if(saveDelegate == nil)saveDelegate = [[FLsaveDelegate alloc] init];//not to be ever freed
+ [(NSSavePanel*)_panel setDelegate:saveDelegate];
+ }
+ if(_preset_file) {
+ preset = [[NSString alloc] initWithUTF8String:_preset_file];
+ if(strchr(_preset_file, '/') != NULL) {
+ dir = [[NSString alloc] initWithString:[preset stringByDeletingLastPathComponent]];
+ }
+ fname = [preset lastPathComponent];
+ }
+ if(_directory && !dir) dir = [[NSString alloc] initWithUTF8String:_directory];
+ if(_filt_total) {
+ popup = createPopupAccessory((NSSavePanel*)_panel, _filter, "Format:", _filt_value);
+ }
+ retval = [(NSSavePanel*)_panel runModalForDirectory:dir file:fname];
+ if(_filt_total) {
+ _filt_value = [popup indexOfSelectedItem];
+ }
+ [dir release];
+ [preset release];
+ if ( retval == NSOKButton ) get_saveas_basename();
+ }
+ [localPool release];
+ return (retval == NSOKButton ? 0 : 1);
+}
+
+#endif //__APPLE_COCOA__
+
+//
+// End of "$Id:".
+//
diff --git a/src/Fl_Native_File_Chooser_WIN32.cxx b/src/Fl_Native_File_Chooser_WIN32.cxx
new file mode 100644
index 000000000..3d9545903
--- /dev/null
+++ b/src/Fl_Native_File_Chooser_WIN32.cxx
@@ -0,0 +1,848 @@
+// "$Id$"
+//
+// FLTK native OS file chooser widget
+//
+// Copyright 1998-2005 by Bill Spitzak and others.
+// Copyright 2004 Greg Ercolano.
+// API changes + filter improvements by Nathan Vander Wilt 2005
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems to:
+//
+// http://www.fltk.org/str.php
+//
+
+// Any application to multi-folder implementation:
+// http://www.codeproject.com/dialog/selectfolder.asp
+//
+
+#include <stdio.h> // debugging
+#include <wchar.h> //MG
+#include "Fl_Native_File_Chooser_common.cxx" // strnew/strfree/strapp/chrcat
+typedef const wchar_t *LPCWSTR; //MG
+LPCWSTR utf8towchar(const char *in); //MG
+char *wchartoutf8(LPCWSTR in); //MG
+
+#include <FL/Fl_Native_File_Chooser.H>
+#define FNFC_CLASS Fl_Native_File_Chooser
+#define FNFC_CTOR Fl_Native_File_Chooser
+
+#define LCURLY_CHR '{'
+#define RCURLY_CHR '}'
+#define LBRACKET_CHR '['
+#define RBRACKET_CHR ']'
+#define MAXFILTERS 80
+
+// STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG)
+static void dnullprint(char *wp) {
+ if ( ! wp ) return;
+ for ( int t=0; true; t++ ) {
+ if ( wp[t] == '\0' && wp[t+1] == '\0' ) {
+ printf("\\0\\0");
+ fflush(stdout);
+ return;
+ } else if ( wp[t] == '\0' ) {
+ printf("\\0");
+ } else {
+ printf("%c",wp[t]);
+ }
+ }
+}
+
+// RETURN LENGTH OF DOUBLENULL STRING
+// Includes single nulls in count, excludes trailing doublenull.
+//
+// 1234 567
+// |||/\|||
+// IN: "one\0two\0\0"
+// OUT: 7
+//
+static int dnulllen(const char *wp) {
+ int len = 0;
+ while ( ! ( *(wp+0) == 0 && *(wp+1) == 0 ) ) {
+ ++wp;
+ ++len;
+ }
+ return(len);
+}
+
+// STATIC: Append a string to another, leaving terminated with DOUBLE NULL.
+// Automatically handles extending length of string.
+// wp can be NULL (a new wp will be allocated and initialized).
+// string must be NULL terminated.
+// The pointer wp may be modified on return.
+//
+static void dnullcat(char*&wp, const char *string, int n = -1 ) {
+ //DEBUG printf("DEBUG: dnullcat IN: <"); dnullprint(wp); printf(">\n");
+ int inlen = ( n < 0 ) ? strlen(string) : n;
+ if ( ! wp ) {
+ wp = new char[inlen + 4];
+ *(wp+0) = '\0';
+ *(wp+1) = '\0';
+ } else {
+ int wplen = dnulllen(wp);
+ // Make copy of wp into larger buffer
+ char *tmp = new char[wplen + inlen + 4];
+ memcpy(tmp, wp, wplen+2); // copy of wp plus doublenull
+ delete [] wp; // delete old wp
+ wp = tmp; // use new copy
+ //DEBUG printf("DEBUG: dnullcat COPY: <"); dnullprint(wp); printf("> (wplen=%d)\n", wplen);
+ }
+
+ // Find end of double null string
+ // *wp2 is left pointing at second null.
+ //
+ char *wp2 = wp;
+ if ( *(wp2+0) != '\0' && *(wp2+1) != '\0' ) {
+ for ( ; 1; wp2++ )
+ if ( *(wp2+0) == '\0' && *(wp2+1) == '\0' ) {
+ wp2++;
+ break;
+ }
+ }
+
+ if ( n == -1 ) n = strlen(string);
+ strncpy(wp2, string, n);
+
+ // Leave string double-null terminated
+ *(wp2+n+0) = '\0';
+ *(wp2+n+1) = '\0';
+ //DEBUG printf("DEBUG: dnullcat OUT: <"); dnullprint(wp); printf(">\n\n");
+}
+
+// CTOR
+FNFC_CLASS::FNFC_CTOR(int val) {
+ _btype = val;
+ _options = NO_OPTIONS;
+ memset((void*)&_ofn, 0, sizeof(OPENFILENAMEW));
+ _ofn.lStructSize = sizeof(OPENFILENAMEW);
+ _ofn.hwndOwner = NULL;
+ memset((void*)&_binf, 0, sizeof(BROWSEINFO));
+ _pathnames = NULL;
+ _tpathnames = 0;
+ _directory = NULL;
+ _title = NULL;
+ _filter = NULL;
+ _parsedfilt = NULL;
+ _nfilters = 0;
+ _preset_file = NULL;
+ _errmsg = NULL;
+}
+
+// DTOR
+FNFC_CLASS::~FNFC_CTOR() {
+ //_pathnames // managed by clear_pathnames()
+ //_tpathnames // managed by clear_pathnames()
+ _directory = strfree(_directory);
+ _title = strfree(_title);
+ _filter = strfree(_filter);
+ //_parsedfilt // managed by clear_filters()
+ //_nfilters // managed by clear_filters()
+ _preset_file = strfree(_preset_file);
+ _errmsg = strfree(_errmsg);
+ clear_filters();
+ clear_pathnames();
+ ClearOFN();
+ ClearBINF();
+}
+
+// SET TYPE OF BROWSER
+void FNFC_CLASS::type(int val) {
+ _btype = val;
+}
+
+// GET TYPE OF BROWSER
+int FNFC_CLASS::type() const {
+ return( _btype );
+}
+
+// SET OPTIONS
+void FNFC_CLASS::options(int val) {
+ _options = val;
+}
+
+// GET OPTIONS
+int FNFC_CLASS::options() const {
+ return(_options);
+}
+
+// PRIVATE: SET ERROR MESSAGE
+void FNFC_CLASS::errmsg(const char *val) {
+ _errmsg = strfree(_errmsg);
+ _errmsg = strnew(val);
+}
+
+// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS
+void FNFC_CLASS::clear_pathnames() {
+ if ( _pathnames ) {
+ while ( --_tpathnames >= 0 ) {
+ _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]);
+ }
+ delete [] _pathnames;
+ _pathnames = NULL;
+ }
+ _tpathnames = 0;
+}
+
+// SET A SINGLE PATHNAME
+void FNFC_CLASS::set_single_pathname(const char *s) {
+ clear_pathnames();
+ _pathnames = new char*[1];
+ _pathnames[0] = strnew(s);
+ _tpathnames = 1;
+}
+
+// ADD PATHNAME TO EXISTING ARRAY
+void FNFC_CLASS::add_pathname(const char *s) {
+ if ( ! _pathnames ) {
+ // Create first element in array
+ ++_tpathnames;
+ _pathnames = new char*[_tpathnames];
+ } else {
+ // Grow array by 1
+ char **tmp = new char*[_tpathnames+1]; // create new buffer
+ memcpy((void*)tmp, (void*)_pathnames,
+ sizeof(char*)*_tpathnames); // copy old
+ delete [] _pathnames; // delete old
+ _pathnames = tmp; // use new
+ ++_tpathnames;
+ }
+ _pathnames[_tpathnames-1] = strnew(s);
+}
+
+// FREE A PIDL (Pointer to IDentity List)
+void FNFC_CLASS::FreePIDL(ITEMIDLIST *pidl) {
+ IMalloc *imalloc = NULL;
+ if ( SUCCEEDED(SHGetMalloc(&imalloc)) ) {
+ imalloc->Free(pidl);
+ imalloc->Release();
+ imalloc = NULL;
+ }
+}
+
+// CLEAR MICROSOFT OFN (OPEN FILE NAME) CLASS
+void FNFC_CLASS::ClearOFN() {
+ // Free any previously allocated lpstrFile before zeroing out _ofn
+ if ( _ofn.lpstrFile ) {
+ delete [] _ofn.lpstrFile;
+ _ofn.lpstrFile = NULL;
+ }
+ if ( _ofn.lpstrInitialDir ) {
+ delete [] _ofn.lpstrInitialDir;
+ _ofn.lpstrInitialDir = NULL;
+ }
+ _ofn.lpstrFilter = NULL; // (deleted elsewhere)
+ int temp = _ofn.nFilterIndex; // keep the filter_value
+ memset((void*)&_ofn, 0, sizeof(_ofn));
+ _ofn.lStructSize = sizeof(OPENFILENAMEW);
+ _ofn.nFilterIndex = temp;
+}
+
+// CLEAR MICROSOFT BINF (BROWSER INFO) CLASS
+void FNFC_CLASS::ClearBINF() {
+ if ( _binf.pidlRoot ) {
+ FreePIDL((ITEMIDLIST*)_binf.pidlRoot);
+ _binf.pidlRoot = NULL;
+ }
+ memset((void*)&_binf, 0, sizeof(_binf));
+}
+
+// CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES
+void FNFC_CLASS::Win2Unix(char *s) {
+ for ( ; *s; s++ )
+ if ( *s == '\\' ) *s = '/';
+}
+
+// CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES
+void FNFC_CLASS::Unix2Win(char *s) {
+ for ( ; *s; s++ )
+ if ( *s == '/' ) *s = '\\';
+}
+
+// SHOW FILE BROWSER
+int FNFC_CLASS::showfile() {
+ ClearOFN();
+ clear_pathnames();
+ size_t fsize = MAX_PATH;
+ _ofn.Flags |= OFN_NOVALIDATE; // prevent disabling of front slashes
+ _ofn.Flags |= OFN_HIDEREADONLY; // hide goofy readonly flag
+ // USE NEW BROWSER
+ _ofn.Flags |= OFN_EXPLORER; // use newer explorer windows
+ _ofn.Flags |= OFN_ENABLESIZING; // allow window to be resized (hey, why not?)
+
+ // XXX: The docs for OFN_NOCHANGEDIR says the flag is 'ineffective' on XP/2K/NT!
+ // But let's set it anyway..
+ //
+ _ofn.Flags |= OFN_NOCHANGEDIR; // prevent dialog for messing up the cwd
+
+ switch ( _btype ) {
+ case BROWSE_DIRECTORY:
+ case BROWSE_MULTI_DIRECTORY:
+ case BROWSE_SAVE_DIRECTORY:
+ abort(); // never happens: handled by showdir()
+ case BROWSE_FILE:
+ fsize = 65536; // XXX: there must be a better way
+ break;
+ case BROWSE_MULTI_FILE:
+ _ofn.Flags |= OFN_ALLOWMULTISELECT;
+ fsize = 65536; // XXX: there must be a better way
+ break;
+ case BROWSE_SAVE_FILE:
+ if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
+ _ofn.Flags |= OFN_OVERWRITEPROMPT;
+ }
+ break;
+ }
+ // SPACE FOR RETURNED FILENAME
+ _ofn.lpstrFile = new WCHAR[fsize];
+ _ofn.nMaxFile = fsize-1;
+ _ofn.lpstrFile[0] = 0;
+ _ofn.lpstrFile[1] = 0; // dnull
+ // PARENT WINDOW
+ _ofn.hwndOwner = GetForegroundWindow();
+ // DIALOG TITLE
+ if (_title) {
+ static WCHAR wtitle[200];
+ wcscpy(wtitle, utf8towchar(_title));
+ _ofn.lpstrTitle = wtitle;
+ } else {
+ _ofn.lpstrTitle = NULL;
+ }
+ // FILTER
+ if (_parsedfilt != NULL) { // to convert a null-containing char string into a widechar string
+ static WCHAR wpattern[MAX_PATH];
+ const char *p = _parsedfilt;
+ while(*(p + strlen(p) + 1) != 0) p += strlen(p) + 1;
+ p += strlen(p) + 2;
+ MultiByteToWideChar(CP_UTF8, 0, _parsedfilt, p - _parsedfilt, wpattern, MAX_PATH);
+ _ofn.lpstrFilter = wpattern;
+ } else {
+ _ofn.lpstrFilter = NULL;
+ }
+ // PRESET FILE
+ // If set, supercedes _directory. See KB Q86920 for details
+ //
+ if ( _preset_file ) {
+ size_t len = strlen(_preset_file);
+ if ( len >= _ofn.nMaxFile ) {
+ char msg[80];
+ sprintf(msg, "preset_file() filename is too long: %ld is >=%ld", (long)len, (long)fsize);
+ return(-1);
+ }
+ wcscpy(_ofn.lpstrFile, utf8towchar(_preset_file));
+// Unix2Win(_ofn.lpstrFile);
+ len = wcslen(_ofn.lpstrFile);
+ _ofn.lpstrFile[len+0] = 0; // multiselect needs dnull
+ _ofn.lpstrFile[len+1] = 0;
+ }
+ if ( _directory ) {
+ // PRESET DIR
+ // XXX: See KB Q86920 for doc bug:
+ // http://support.microsoft.com/default.aspx?scid=kb;en-us;86920
+ //
+ _ofn.lpstrInitialDir = new WCHAR[MAX_PATH];
+ wcscpy((WCHAR *)_ofn.lpstrInitialDir, utf8towchar(_directory));
+ // Unix2Win((char*)_ofn.lpstrInitialDir);
+ }
+ // SAVE THE CURRENT DIRECTORY
+ // XXX: Save the cwd because GetOpenFileName() is probably going to
+ // change it, in spite of the OFN_NOCHANGEDIR flag, due to its docs
+ // saying the flag is 'ineffective'. %^(
+ //
+ char oldcwd[MAX_PATH];
+ GetCurrentDirectory(MAX_PATH, oldcwd);
+ oldcwd[MAX_PATH-1] = '\0';
+ // OPEN THE DIALOG WINDOW
+ int err;
+ if ( _btype == BROWSE_SAVE_FILE ) {
+ err = GetSaveFileNameW(&_ofn);
+ } else {
+ err = GetOpenFileNameW(&_ofn);
+ }
+ if ( err == 0 ) {
+ // EXTENDED ERROR CHECK
+ int err = CommDlgExtendedError();
+ // CANCEL?
+ if ( err == 0 ) return(1); // user hit 'cancel'
+ // AN ERROR OCCURRED
+ char msg[80];
+ sprintf(msg, "CommDlgExtendedError() code=%d", err);
+ errmsg(msg);
+ // XXX: RESTORE CWD
+ if ( oldcwd[0] ) SetCurrentDirectory(oldcwd);
+ return(-1);
+ }
+ // XXX: RESTORE CWD
+ if ( oldcwd[0] ) {
+ SetCurrentDirectory(oldcwd);
+ }
+ // PREPARE PATHNAMES FOR RETURN
+ switch ( _btype ) {
+ case BROWSE_FILE:
+ case BROWSE_SAVE_FILE:
+ set_single_pathname(wchartoutf8(_ofn.lpstrFile));
+ // Win2Unix(_pathnames[_tpathnames-1]);
+ break;
+ case BROWSE_MULTI_FILE: {
+ // EXTRACT MULTIPLE FILENAMES
+ const WCHAR *dirname = _ofn.lpstrFile;
+ int dirlen = wcslen(dirname);
+ if ( dirlen > 0 ) {
+ // WALK STRING SEARCHING FOR 'DOUBLE-NULL'
+ // eg. "/dir/name\0foo1\0foo2\0foo3\0\0"
+ //
+ char pathname[MAX_PATH];
+ for ( const WCHAR *s = dirname + dirlen + 1;
+ *s; s+= (wcslen(s)+1)) {
+ strcpy(pathname, wchartoutf8(dirname));
+ strcat(pathname, "\\");
+ strcat(pathname, wchartoutf8(s));
+ add_pathname(pathname);
+ }
+ }
+ // XXX
+ // Work around problem where pasted forward-slash pathname
+ // into the file browser causes new "Explorer" interface
+ // not to grok forward slashes, passing back as a 'filename'..!
+ //
+ if ( _tpathnames == 0 ) {
+ add_pathname(wchartoutf8(dirname));
+ // Win2Unix(_pathnames[_tpathnames-1]);
+ }
+ break;
+ }
+ case BROWSE_DIRECTORY:
+ case BROWSE_MULTI_DIRECTORY:
+ case BROWSE_SAVE_DIRECTORY:
+ abort(); // never happens: handled by showdir()
+ }
+ return(0);
+}
+
+// Used by SHBrowseForFolder(), sets initial selected dir.
+// Ref: Usenet: microsoft.public.vc.mfc, Dec 8 2000, 1:38p David Lowndes
+// Subject: How to specify to select an initial folder .."
+//
+int CALLBACK FNFC_CLASS::Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data) {
+ switch (msg) {
+ case BFFM_INITIALIZED:
+ if (data) ::SendMessage(win, BFFM_SETSELECTION, TRUE, data);
+ break;
+ case BFFM_SELCHANGED:
+ TCHAR path[MAX_PATH];
+ if ( SHGetPathFromIDList((ITEMIDLIST*)param, path) ) {
+ ::SendMessage(win, BFFM_ENABLEOK, 0, 1);
+ } else {
+ //disable ok button if not a path
+ ::SendMessage(win, BFFM_ENABLEOK, 0, 0);
+ }
+ break;
+ case BFFM_VALIDATEFAILED:
+ // we could pop up an annoying message here.
+ // also needs set ulFlags |= BIF_VALIDATE
+ break;
+ default:
+ break;
+ }
+ return(0);
+}
+
+// SHOW DIRECTORY BROWSER
+int FNFC_CLASS::showdir() {
+ OleInitialize(NULL); // init needed by BIF_USENEWUI
+ ClearBINF();
+ clear_pathnames();
+ // PARENT WINDOW
+ _binf.hwndOwner = GetForegroundWindow();
+ // DIALOG TITLE
+ _binf.lpszTitle = _title ? _title : NULL;
+ // FLAGS
+ _binf.ulFlags = 0; // initialize
+
+ // TBD: make sure matches to runtime system, if need be.
+ //(what if _WIN32_IE doesn't match system? does the program not run?)
+ //
+ // TBD: match all 3 types of directories
+ //
+ // NOTE: *Don't* use BIF_SHAREABLE. It /disables/ mapped network shares
+ // from being visible in BROWSE_DIRECTORY mode.
+ // See Walter Garm's comments in ./TODO.
+
+#if defined(BIF_NONEWFOLDERBUTTON) // Version 6.0
+ if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_NONEWFOLDERBUTTON;
+ _binf.ulFlags |= BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
+#elif defined(BIF_USENEWUI) // Version 5.0
+ if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_EDITBOX;
+ else if ( _btype == BROWSE_SAVE_DIRECTORY ) _binf.ulFlags |= BIF_USENEWUI;
+ _binf.ulFlags |= BIF_RETURNONLYFSDIRS;
+#elif defined(BIF_EDITBOX) // Version 4.71
+ _binf.ulFlags |= BIF_RETURNONLYFSDIRS | BIF_EDITBOX;
+#else // Version Old
+ _binf.ulFlags |= BIF_RETURNONLYFSDIRS;
+#endif
+
+ // BUFFER
+ char displayname[MAX_PATH];
+ _binf.pszDisplayName = displayname;
+ // PRESET DIR
+ char presetname[MAX_PATH];
+ if ( _directory ) {
+ strcpy(presetname, _directory);
+ // Unix2Win(presetname);
+ _binf.lParam = (LPARAM)presetname;
+ }
+ else _binf.lParam = 0;
+ _binf.lpfn = Dir_CB;
+ // OPEN BROWSER
+ ITEMIDLIST *pidl = SHBrowseForFolder(&_binf);
+ // CANCEL?
+ if ( pidl == NULL ) return(1);
+
+ // GET THE PATHNAME(S) THE USER SELECTED
+ // TBD: expand NetHood shortcuts from this PIDL??
+ // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shbrowseforfolder.asp
+
+ TCHAR path[MAX_PATH];
+ if ( SHGetPathFromIDList(pidl, path) ) {
+ // Win2Unix(path);
+ add_pathname(path);
+ }
+ FreePIDL(pidl);
+ if ( !strlen(path) ) return(1); // don't return empty pathnames
+ return(0);
+}
+
+// RETURNS:
+// 0 - user picked a file
+// 1 - user cancelled
+// -1 - failed; errmsg() has reason
+//
+int FNFC_CLASS::show() {
+ if ( _btype == BROWSE_DIRECTORY ||
+ _btype == BROWSE_MULTI_DIRECTORY ||
+ _btype == BROWSE_SAVE_DIRECTORY ) {
+ return(showdir());
+ } else {
+ return(showfile());
+ }
+}
+
+// RETURN ERROR MESSAGE
+const char *FNFC_CLASS::errmsg() const {
+ return(_errmsg ? _errmsg : "No error");
+}
+
+// GET FILENAME
+const char* FNFC_CLASS::filename() const {
+ if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]);
+ return("");
+}
+
+// GET FILENAME FROM LIST OF FILENAMES
+const char* FNFC_CLASS::filename(int i) const {
+ if ( _pathnames && i < _tpathnames ) return(_pathnames[i]);
+ return("");
+}
+
+// GET TOTAL FILENAMES CHOSEN
+int FNFC_CLASS::count() const {
+ return(_tpathnames);
+}
+
+// PRESET PATHNAME
+// Can be NULL if no preset is desired.
+//
+void FNFC_CLASS::directory(const char *val) {
+ _directory = strfree(_directory);
+ _directory = strnew(val);
+}
+
+// GET PRESET PATHNAME
+// Can return NULL if none set.
+//
+const char *FNFC_CLASS::directory() const {
+ return(_directory);
+}
+
+// SET TITLE
+// Can be NULL if no title desired.
+//
+void FNFC_CLASS::title(const char *val) {
+ _title = strfree(_title);
+ _title = strnew(val);
+}
+
+// GET TITLE
+// Can return NULL if none set.
+//
+const char *FNFC_CLASS::title() const {
+ return(_title);
+}
+
+// SET FILTER
+// Can be NULL if no filter needed
+//
+void FNFC_CLASS::filter(const char *val) {
+ _filter = strfree(_filter);
+ clear_filters();
+ if ( val ) {
+ _filter = strnew(val);
+ parse_filter(_filter);
+ }
+ add_filter("All Files", "*.*"); // always include 'all files' option
+
+#ifdef DEBUG
+ nullprint(_parsedfilt);
+#endif /*DEBUG*/
+}
+
+// GET FILTER
+// Can return NULL if none set.
+//
+const char *FNFC_CLASS::filter() const {
+ return(_filter);
+}
+
+// CLEAR FILTERS
+void FNFC_CLASS::clear_filters() {
+ _nfilters = 0;
+ _parsedfilt = strfree(_parsedfilt);
+}
+
+// ADD A FILTER
+void FNFC_CLASS::add_filter(const char *name_in, // name of filter (optional: can be null)
+ const char *winfilter) { // windows style filter (eg. "*.cxx;*.h")
+ // No name? Make one..
+ char name[1024];
+ if ( !name_in || name_in[0] == '\0' ) {
+ sprintf(name, "%.*s Files", sizeof(name)-10, winfilter);
+ } else {
+ sprintf(name, "%.*s", sizeof(name)-10, name_in);
+ }
+ dnullcat(_parsedfilt, name);
+ dnullcat(_parsedfilt, winfilter);
+ _nfilters++;
+ //DEBUG printf("DEBUG: ADD FILTER name=<%s> winfilter=<%s>\n", name, winfilter);
+}
+
+// CONVERT FLTK STYLE PATTERN MATCHES TO WINDOWS 'DOUBLENULL' PATTERN
+// Handles:
+// IN OUT
+// ----------- -----------------------------
+// *.{ma,mb} "*.{ma,mb} Files\0*.ma;*.mb\0\0"
+// *.[abc] "*.[abc] Files\0*.a;*.b;*.c\0\0"
+// *.txt "*.txt Files\0*.txt\0\0"
+// C Files\t*.[ch] "C Files\0*.c;*.h\0\0"
+//
+// Example:
+// IN: "*.{ma,mb}"
+// OUT: "*.ma;*.mb Files\0*.ma;*.mb\0All Files\0*.*\0\0"
+// --------------- --------- --------- ---
+// | | | |
+// Title Wildcards Title Wildcards
+//
+// Parsing Mode:
+// IN:"C Files\t*.{cxx,h}"
+// ||||||| |||||||||
+// mode: nnnnnnn ww{{{{{{{
+// \_____/ \_______/
+// Name Wildcard
+//
+void FNFC_CLASS::parse_filter(const char *in) {
+ clear_filters();
+ if ( ! in ) return;
+
+ int has_name = strchr(in, '\t') ? 1 : 0;
+
+ char mode = has_name ? 'n' : 'w'; // parse mode: n=name, w=wildcard
+ int nwildcards = 0;
+ char wildcards[MAXFILTERS][1024]; // parsed wildcards (can be several)
+ char wildprefix[512] = "";
+ char name[512] = "";
+
+ // Init
+ int t;
+ for ( t=0; t<MAXFILTERS; t++ ) {
+ wildcards[t][0] = '\0';
+ }
+
+ // Parse
+ for ( ; 1; in++ ) {
+
+ //// DEBUG
+ //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildprefix=<%s> nwildcards=%d wildcards[n]=<%s>\n",
+ //// *in, mode, name, wildprefix, nwildcards, wildcards[nwildcards]);
+
+ switch (*in) {
+ case ',':
+ case '|':
+ if ( mode == LCURLY_CHR ) {
+ // create new wildcard, copy in prefix
+ strcat(wildcards[nwildcards++], wildprefix);
+ continue;
+ } else {
+ goto regchar;
+ }
+ continue;
+
+ // FINISHED PARSING A NAME?
+ case '\t':
+ if ( mode != 'n' ) goto regchar;
+ // finish parsing name? switch to wildcard mode
+ mode = 'w';
+ break;
+
+ // ESCAPE NEXT CHAR
+ case '\\':
+ ++in;
+ goto regchar;
+
+ // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
+ case '\r':
+ case '\n':
+ case '\0':
+ {
+ if ( mode == 'w' ) { // finished parsing wildcard?
+ if ( nwildcards == 0 ) {
+ strcpy(wildcards[nwildcards++], wildprefix);
+ }
+ // Append wildcards in Microsoft's "*.one;*.two" format
+ char comp[4096] = "";
+ for ( t=0; t<nwildcards; t++ ) {
+ if ( t != 0 ) strcat(comp, ";");
+ strcat(comp, wildcards[t]);
+ }
+ // Add if not empty
+ if ( comp[0] ) {
+ add_filter(name, comp);
+ }
+ }
+ // RESET
+ for ( t=0; t<MAXFILTERS; t++ ) {
+ wildcards[t][0] = '\0';
+ }
+ nwildcards = 0;
+ wildprefix[0] = name[0] = '\0';
+ mode = strchr(in,'\t') ? 'n' : 'w';
+ // DONE?
+ if ( *in == '\0' ) return; // done
+ continue; // not done yet, more filters
+ }
+
+ // STARTING A WILDCARD?
+ case LBRACKET_CHR:
+ case LCURLY_CHR:
+ mode = *in;
+ if ( *in == LCURLY_CHR ) {
+ // create new wildcard
+ strcat(wildcards[nwildcards++], wildprefix);
+ }
+ continue;
+
+ // ENDING A WILDCARD?
+ case RBRACKET_CHR:
+ case RCURLY_CHR:
+ mode = 'w'; // back to wildcard mode
+ continue;
+
+ // ALL OTHER NON-SPECIAL CHARACTERS
+ default:
+ regchar: // handle regular char
+ switch ( mode ) {
+ case LBRACKET_CHR:
+ // create new wildcard
+ ++nwildcards;
+ // copy in prefix
+ strcpy(wildcards[nwildcards-1], wildprefix);
+ // append search char
+ chrcat(wildcards[nwildcards-1], *in);
+ continue;
+
+ case LCURLY_CHR:
+ if ( nwildcards > 0 ) {
+ chrcat(wildcards[nwildcards-1], *in);
+ }
+ continue;
+
+ case 'n':
+ chrcat(name, *in);
+ continue;
+
+ case 'w':
+ chrcat(wildprefix, *in);
+ for ( t=0; t<nwildcards; t++ ) {
+ chrcat(wildcards[t], *in);
+ }
+ continue;
+ }
+ break;
+ }
+ }
+}
+
+// SET 'CURRENTLY SELECTED FILTER'
+void FNFC_CLASS::filter_value(int i) {
+ _ofn.nFilterIndex = i + 1;
+}
+
+// RETURN VALUE OF 'CURRENTLY SELECTED FILTER'
+int FNFC_CLASS::filter_value() const {
+ return(_ofn.nFilterIndex ? _ofn.nFilterIndex-1 : _nfilters+1);
+}
+
+// PRESET FILENAME FOR 'SAVE AS' CHOOSER
+void FNFC_CLASS::preset_file(const char* val) {
+ _preset_file = strfree(_preset_file);
+ _preset_file = strnew(val);
+}
+
+// GET PRESET FILENAME FOR 'SAVE AS' CHOOSER
+const char* FNFC_CLASS::preset_file() const {
+ return(_preset_file);
+}
+
+char *wchartoutf8(LPCWSTR in)
+{
+ static char *out = NULL;
+ static int lchar = 0;
+ if (in == NULL)return NULL;
+ int utf8len = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL);
+ if (utf8len > lchar) {
+ lchar = utf8len;
+ out = (char *)realloc(out, lchar * sizeof(char));
+ }
+ WideCharToMultiByte(CP_UTF8, 0, in, -1, out, utf8len, NULL, NULL);
+ return out;
+}
+
+LPCWSTR utf8towchar(const char *in)
+{
+ static WCHAR *wout = NULL;
+ static int lwout = 0;
+ if (in == NULL)return NULL;
+ int wlen = MultiByteToWideChar(CP_UTF8, 0, in, -1, NULL, 0);
+ if (wlen > lwout) {
+ lwout = wlen;
+ wout = (WCHAR *)realloc(wout, lwout * sizeof(WCHAR));
+ }
+ MultiByteToWideChar(CP_UTF8, 0, in, -1, wout, wlen);
+ return wout;
+}
+
+//
+// End of "$Id:".
+//
diff --git a/src/Fl_Native_File_Chooser_common.cxx b/src/Fl_Native_File_Chooser_common.cxx
new file mode 100644
index 000000000..4eefcad14
--- /dev/null
+++ b/src/Fl_Native_File_Chooser_common.cxx
@@ -0,0 +1,83 @@
+// "$Id$"
+//
+// FLTK native OS file chooser widget
+//
+// Copyright 1998-2005 by Bill Spitzak and others.
+// Copyright 2004 Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems to:
+//
+// http://www.fltk.org/str.php
+//
+
+#include <string.h>
+#include <FL/Enumerations.H>
+
+// COPY A STRING WITH 'new'
+// Value can be NULL
+//
+static char *strnew(const char *val) {
+ if ( val == NULL ) return(NULL);
+ char *s = new char[strlen(val)+1];
+ strcpy(s, val);
+ return(s);
+}
+
+// FREE STRING CREATED WITH strnew(), NULLS OUT STRING
+// Value can be NULL
+//
+static char *strfree(char *val) {
+ if ( val ) delete [] val;
+ return(NULL);
+}
+
+// 'DYNAMICALLY' APPEND ONE STRING TO ANOTHER
+// Returns newly allocated string, or NULL
+// if s && val == NULL.
+// 's' can be NULL; returns a strnew(val).
+// 'val' can be NULL; s is returned unmodified.
+//
+// Usage:
+// char *s = strnew("foo"); // s = "foo"
+// s = strapp(s, "bar"); // s = "foobar"
+//
+static char *strapp(char *s, const char *val) {
+ if ( ! val ) {
+ return(s); // Nothing to append? return s
+ }
+ if ( ! s ) {
+ return(strnew(val)); // New string? return copy of val
+ }
+ char *news = new char[strlen(s)+strlen(val)+1];
+ strcpy(news, s);
+ strcat(news, val);
+ delete [] s; // delete old string
+ return(news); // return new copy
+}
+
+// APPEND A CHARACTER TO A STRING
+// This does NOT allocate space for the new character.
+//
+static void chrcat(char *s, char c) {
+ char tmp[2] = { c, '\0' };
+ strcat(s, tmp);
+}
+
+//
+// End of "$Id:".
+//
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm
index 1e8068a95..215637225 100644
--- a/src/Fl_cocoa.mm
+++ b/src/Fl_cocoa.mm
@@ -1,5 +1,5 @@
//
-// "$Id: Fl_mac.cxx 6971 2009-04-13 07:32:01Z matt $"
+// "$Id: Fl_cocoa.mm 6971 2009-04-13 07:32:01Z matt $"
//
// MacOS specific code for the Fast Light Tool Kit (FLTK).
//
@@ -63,7 +63,7 @@ extern "C" {
#import <Cocoa/Cocoa.h>
-#ifndef NSINTEGER_DEFINED //appears with 10.5 in NSObjCRuntime.h
+#ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h
#if defined(__LP64__) && __LP64__
typedef long NSInteger;
typedef unsigned long NSUInteger;
@@ -146,7 +146,7 @@ void fl_set_status(int x, int y, int w, int h)
{
}
-/**
+/*
* Mac keyboard lookup table
*/
static unsigned short macKeyLookUp[128] =
@@ -178,7 +178,7 @@ static unsigned short macKeyLookUp[128] =
FL_F+2, FL_Page_Down, FL_F+1, FL_Left, FL_Right, FL_Down, FL_Up, 0/*FL_Power*/,
};
-/**
+/*
* convert the current mouse chord into the FLTK modifier state
*/
static unsigned int mods_to_e_state( NSUInteger mods )
@@ -197,7 +197,7 @@ static unsigned int mods_to_e_state( NSUInteger mods )
}
-/**
+/*
* convert the current mouse chord into the FLTK keysym
*/
/*
@@ -211,7 +211,8 @@ static unsigned int mods_to_e_state( NSUInteger mods )
else if ( mods & NSAlphaShiftKeyMask ) Fl::e_keysym = FL_Caps_Lock;
else Fl::e_keysym = 0;
//printf( "to sym 0x%08x (%04x)\n", Fl::e_keysym, mods );
- }*/
+ }
+ */
// these pointers are set by the Fl::lock() function:
static void nothing() {}
void (*fl_lock_function)() = nothing;
@@ -327,17 +328,16 @@ void DataReady::AddFD(int n, int events, void (*cb)(int, void*), void *v)
void DataReady::RemoveFD(int n, int events)
{
int i,j;
- for (i=j=0; i<nfds; i++)
- {
- if (fds[i].fd == n)
- {
+ for (i=j=0; i<nfds; i++) {
+ if (fds[i].fd == n) {
int e = fds[i].events & ~events;
if (!e) continue; // if no events left, delete this fd
fds[i].events = e;
}
// move it down in the array if necessary:
- if (j<i)
- { fds[j] = fds[i]; }
+ if (j<i) {
+ fds[j] = fds[i];
+ }
j++;
}
nfds = j;
@@ -358,23 +358,22 @@ int DataReady::CheckData(fd_set& r, fd_set& w, fd_set& x)
/*LOCK*/ r = _fdsets[0], w = _fdsets[1], x = _fdsets[2];
/*LOCK*/ ret = ::select(_maxfd+1, &r, &w, &x, &t);
DataUnlock();
- if ( ret == -1 )
- { DEBUGPERRORMSG("CheckData(): select()"); }
+ if ( ret == -1 ) {
+ DEBUGPERRORMSG("CheckData(): select()");
+ }
return(ret);
}
// HANDLE DATA READY CALLBACKS
void DataReady::HandleData(fd_set& r, fd_set& w, fd_set& x)
{
- for (int i=0; i<nfds; i++)
- {
+ for (int i=0; i<nfds; i++) {
int f = fds[i].fd;
short revents = 0;
if (FD_ISSET(f, &r)) revents |= POLLIN;
if (FD_ISSET(f, &w)) revents |= POLLOUT;
if (FD_ISSET(f, &x)) revents |= POLLERR;
- if (fds[i].events & revents)
- {
+ if (fds[i].events & revents) {
DEBUGMSG("DOING CALLBACK: ");
fds[i].cb(f, fds[i].arg);
DEBUGMSG("DONE\n");
@@ -391,8 +390,7 @@ void* DataReady::DataReadyThread(void *o)
DataReady *self = (DataReady*)o;
NSAutoreleasePool *localPool;
localPool = [[NSAutoreleasePool alloc] init];
- while ( 1 ) // loop until thread cancel or error
- {
+ while ( 1 ) { // loop until thread cancel or error
// Thread safe local copies of data before each select()
self->DataLock();
/*LOCK*/ int maxfd = self->_maxfd;
@@ -409,8 +407,7 @@ void* DataReady::DataReadyThread(void *o)
timeval t = { 2, 0 }; // HACK: 2 secs prevents 'hanging' problem
int ret = ::select(maxfd+1, &r, &w, &x, &t);
pthread_testcancel(); // OSX 10.0.4 and older: needed for parent to cancel
- switch ( ret )
- {
+ switch ( ret ) {
case 0: // NO DATA
continue;
case -1: // ERROR
@@ -421,7 +418,7 @@ void* DataReady::DataReadyThread(void *o)
default: // DATA READY
{
if (FD_ISSET(cancelpipe, &r) || FD_ISSET(cancelpipe, &x)) // cancel?
- { return(NULL); } // just exit
+ { return(NULL); } // just exit
DEBUGMSG("CHILD THREAD: DATA IS READY\n");
NSPoint pt={0,0};
NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:pt
@@ -451,12 +448,10 @@ void DataReady::StartThread(void *new_userdata)
// CANCEL 'DATA READY' THREAD, CLOSE PIPE
void DataReady::CancelThread(const char *reason)
{
- if ( tid )
- {
+ if ( tid ) {
DEBUGMSG("*** CANCEL THREAD: ");
DEBUGMSG(reason);
- if ( pthread_cancel(tid) == 0 ) // cancel first
- {
+ if ( pthread_cancel(tid) == 0 ) { // cancel first
DataLock();
/*LOCK*/ write(_cancelpipe[1], "x", 1); // wake thread from select
DataUnlock();
@@ -473,26 +468,33 @@ void DataReady::CancelThread(const char *reason)
}
void Fl::add_fd( int n, int events, void (*cb)(int, void*), void *v )
-{ dataready.AddFD(n, events, cb, v); }
+{
+ dataready.AddFD(n, events, cb, v);
+}
void Fl::add_fd(int fd, void (*cb)(int, void*), void* v)
-{ dataready.AddFD(fd, POLLIN, cb, v); }
+{
+ dataready.AddFD(fd, POLLIN, cb, v);
+}
void Fl::remove_fd(int n, int events)
-{ dataready.RemoveFD(n, events); }
+{
+ dataready.RemoveFD(n, events);
+}
void Fl::remove_fd(int n)
-{ dataready.RemoveFD(n, -1); }
+{
+ dataready.RemoveFD(n, -1);
+}
-/**
+/*
* Check if there is actually a message pending!
*/
int fl_ready()
{
- NSEvent *retval = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate dateWithTimeIntervalSinceNow:0]
- inMode:NSDefaultRunLoopMode dequeue:NO];
- if(retval != nil) [retval release];
- return retval != nil;
+ NSEvent *retval = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate dateWithTimeIntervalSinceNow:0]
+ inMode:NSDefaultRunLoopMode dequeue:NO];
+ return retval != nil;
}
@@ -503,8 +505,7 @@ static void processFLTKEvent(void) {
// Check to see what's ready, and invoke user's cb's
//
fd_set r,w,x;
- switch(dataready.CheckData(r,w,x))
- {
+ switch(dataready.CheckData(r,w,x)) {
case 0: // NO DATA
break;
case -1: // ERROR
@@ -517,7 +518,7 @@ static void processFLTKEvent(void) {
}
-/**
+/*
* break the current event loop
*/
static void breakMacEventLoop()
@@ -549,7 +550,6 @@ static MacTimeout* mac_timers;
static int mac_timer_alloc;
static int mac_timer_used;
-
static void realloc_timers()
{
if (mac_timer_alloc == 0) {
@@ -573,7 +573,6 @@ static void delete_timer(MacTimeout& t)
}
}
-
static void do_timer(EventLoopTimerRef timer, void* data)
{
for (int i = 0; i < mac_timer_used; ++i) {
@@ -589,7 +588,6 @@ static void do_timer(EventLoopTimerRef timer, void* data)
breakMacEventLoop();
}
-
@interface FLWindow : NSWindow {
Fl_Window *w;
BOOL containsGLsubwindow;
@@ -613,10 +611,10 @@ static void do_timer(EventLoopTimerRef timer, void* data)
defer:(BOOL)deferCreation
{
self = [super initWithContentRect:rect styleMask:windowStyle backing:bufferingType defer:deferCreation];
- if(self) {
+ if (self) {
w = flw;
containsGLsubwindow = NO;
- }
+ }
return self;
}
- (Fl_Window *)getFl_Window;
@@ -641,7 +639,7 @@ static void do_timer(EventLoopTimerRef timer, void* data)
}
@end
-/**
+/*
* This function is the central event handler.
* It reads events from the event queue using the given maximum time
* Funny enough, it returns the same time that it got as the argument.
@@ -651,53 +649,46 @@ static double do_queued_events( double time = 0.0 )
got_events = 0;
// Check for re-entrant condition
- if ( dataready.IsThreadRunning() )
- { dataready.CancelThread(DEBUGTEXT("AVOID REENTRY\n")); }
+ if ( dataready.IsThreadRunning() ) {
+ dataready.CancelThread(DEBUGTEXT("AVOID REENTRY\n"));
+ }
// Start thread to watch for data ready
- if ( dataready.GetNfds() )
- { dataready.StartThread((void*)GetCurrentEventQueue()); }
+ if ( dataready.GetNfds() ) {
+ dataready.StartThread((void*)GetCurrentEventQueue());
+ }
fl_unlock_function();
- //necessary so that after closing a non-FLTK window (e.g., Fl_Native_File_Chooser)
- //the front window turns key again
+ // necessary so that after closing a non-FLTK window (e.g., Fl_Native_File_Chooser)
+ // the front window turns key again
NSWindow *nsk = [NSApp keyWindow];
NSWindow *nsm = [NSApp mainWindow];
- if([nsm isMemberOfClass:[FLWindow class]] && (nsk == nil || ( ! [nsk isMemberOfClass:[FLWindow class]] &&
+ if ([nsm isMemberOfClass:[FLWindow class]] && (nsk == nil || ( ! [nsk isMemberOfClass:[FLWindow class]] &&
! [nsk isVisible] ) ) ) {
[nsm makeKeyAndOrderFront:nil];
- }
-/* if([NSApp keyWindow] == nil) {
- Fl_Window *w = Fl::first_window();
- if (w) {
- NSWindow *cw = (NSWindow*)Fl_X::i(w)->xid;
- if([cw isVisible] && ![cw isMiniaturized] && ([cw styleMask] & NSTitledWindowMask) ) {
- if(![cw isKeyWindow]) {//always make Fl::first_window() the key window
- [cw makeKeyAndOrderFront:nil];
- }
- }
- }
- } */
+ }
NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate dateWithTimeIntervalSinceNow:time]
inMode:NSDefaultRunLoopMode dequeue:YES];
- BOOL needSendEvent = YES;
- if([event type] == NSLeftMouseDown) {
- Fl_Window *grab = Fl::grab();
- if(grab && grab != [(FLWindow *)[event window] getFl_Window]) {
- //a click event out of a menu window, so we should close this menu
- //done here to catch also clicks on window title bar/resize box
- cocoaMouseHandler(event);
+ if (event != nil) {
+ BOOL needSendEvent = YES;
+ if ([event type] == NSLeftMouseDown) {
+ Fl_Window *grab = Fl::grab();
+ if (grab && grab != [(FLWindow *)[event window] getFl_Window]) {
+ // a click event out of a menu window, so we should close this menu
+ // done here to catch also clicks on window title bar/resize box
+ cocoaMouseHandler(event);
}
}
- else if([event type] == NSApplicationDefined) {
- if([event subtype] == FLTKDataReadyEvent) {
- processFLTKEvent();
+ else if ([event type] == NSApplicationDefined) {
+ if ([event subtype] == FLTKDataReadyEvent) {
+ processFLTKEvent();
}
- needSendEvent = NO;
+ needSendEvent = NO;
}
- if(needSendEvent) [NSApp sendEvent:event];
+ if (needSendEvent) [NSApp sendEvent:event];
+ }
fl_lock_function();
#if CONSOLIDATE_MOTION
@@ -710,8 +701,7 @@ static double do_queued_events( double time = 0.0 )
return time;
}
-
-/**
+/*
* This public function handles all events. It wait a maximum of
* 'time' seconds for an event. This version returns 1 if events
* other than the timeout timer were processed.
@@ -724,10 +714,7 @@ int fl_wait( double time )
return (got_events);
}
-
-
-
-/**
+/*
* Cocoa Mousewheel handler
*/
void cocoaMouseWheelHandler(NSEvent *theEvent)
@@ -738,24 +725,22 @@ void cocoaMouseWheelHandler(NSEvent *theEvent)
fl_lock_function();
Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window];
- if ( !window->shown() )
- {
+ if ( !window->shown() ) {
fl_unlock_function();
return;
}
Fl::first_window(window);
- if([theEvent deltaX] != 0) {
- Fl::e_dx = -[theEvent deltaX];
+ if ([theEvent deltaX] != 0) {
+ Fl::e_dx = (int)-[theEvent deltaX];
Fl::e_dy = 0;
if ( Fl::e_dx) Fl::handle( FL_MOUSEWHEEL, window );
- } else if([theEvent deltaY] != 0) {
+ } else if ([theEvent deltaY] != 0) {
Fl::e_dx = 0;
- Fl::e_dy = -[theEvent deltaY];
+ Fl::e_dy = (int)-[theEvent deltaY];
if ( Fl::e_dy) Fl::handle( FL_MOUSEWHEEL, window );
} else {
fl_unlock_function();
-
return;
}
@@ -764,8 +749,7 @@ void cocoaMouseWheelHandler(NSEvent *theEvent)
// return noErr;
}
-
-/**
+/*
* Cocoa Mouse Button Handler
*/
static void cocoaMouseHandler(NSEvent *theEvent)
@@ -777,13 +761,12 @@ static void cocoaMouseHandler(NSEvent *theEvent)
fl_lock_function();
Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window];
- if ( !window->shown() )
- {
+ if ( !window->shown() ) {
fl_unlock_function();
return;
}
Fl_Window *first = Fl::first_window();
- if(first != window && !(first->modal() || first->non_modal())) Fl::first_window(window);
+ if (first != window && !(first->modal() || first->non_modal())) Fl::first_window(window);
NSPoint pos = [theEvent locationInWindow];
pos.y = window->h() - pos.y;
NSInteger btn = [theEvent buttonNumber] + 1;
@@ -791,26 +774,25 @@ static void cocoaMouseHandler(NSEvent *theEvent)
NSUInteger mods = [theEvent modifierFlags];
int sendEvent = 0;
- switch ( [theEvent type] )
- {
- case NSLeftMouseDown:
- case NSRightMouseDown:
- case NSOtherMouseDown:
+ switch ( [theEvent type] ) {
+ case NSLeftMouseDown:
+ case NSRightMouseDown:
+ case NSOtherMouseDown:
suppressed = 0;
sendEvent = FL_PUSH;
Fl::e_is_click = 1;
- px = pos.x; py = pos.y;
- if(btn == 1) Fl::e_state |= FL_BUTTON1;
- else if(btn == 3) Fl::e_state |= FL_BUTTON2;
- else if(btn == 2) Fl::e_state |= FL_BUTTON3;
+ px = (int)pos.x; py = (int)pos.y;
+ if (btn == 1) Fl::e_state |= FL_BUTTON1;
+ else if (btn == 3) Fl::e_state |= FL_BUTTON2;
+ else if (btn == 2) Fl::e_state |= FL_BUTTON3;
if (clickCount>1)
Fl::e_clicks++;
else
Fl::e_clicks = 0;
// fall through
- case NSLeftMouseUp:
- case NSRightMouseUp:
- case NSOtherMouseUp:
+ case NSLeftMouseUp:
+ case NSRightMouseUp:
+ case NSOtherMouseUp:
Fl::e_state &= 0xff0000;
if (suppressed) {
suppressed = 0;
@@ -822,19 +804,19 @@ static void cocoaMouseHandler(NSEvent *theEvent)
}
Fl::e_keysym = keysym[ btn ];
// fall through
- case NSMouseMoved:
+ case NSMouseMoved:
suppressed = 0;
if ( !sendEvent ) {
sendEvent = FL_MOVE;
}
// fall through
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged: {
+ case NSLeftMouseDragged:
+ case NSRightMouseDragged:
+ case NSOtherMouseDragged: {
if (suppressed) break;
if ( !sendEvent ) {
sendEvent = FL_MOVE; // Fl::handle will convert into FL_DRAG
- if (abs(pos.x-px)>5 || abs(pos.y-py)>5)
+ if (fabs(pos.x-px)>5 || fabs(pos.y-py)>5)
Fl::e_is_click = 0;
}
mods_to_e_state( mods );
@@ -844,9 +826,10 @@ static void cocoaMouseHandler(NSEvent *theEvent)
Fl::e_x = pos.x;
Fl::e_y = pos.y;
Fl::handle( sendEvent, window );
- } break;
- default:
- break;
+ }
+ break;
+ default:
+ break;
}
fl_unlock_function();
@@ -867,112 +850,111 @@ static void cocoaMouseHandler(NSEvent *theEvent)
unsigned char, // not used in this function
unsigned short) // not used in this function
{
- // first get the keyboard mapping in a post 10.2 way
-
- Ptr resource;
- TextEncoding encoding;
- static TextEncoding lastEncoding = kTextEncodingMacRoman;
- int len = 0;
- KeyboardLayoutRef currentLayout = NULL;
- static KeyboardLayoutRef lastLayout = NULL;
- SInt32 currentLayoutId = 0;
- static SInt32 lastLayoutId;
- int hasLayoutChanged = false;
- static Ptr uchr = NULL;
- static Ptr KCHR = NULL;
- // ScriptCode currentKeyScript;
-
- KLGetCurrentKeyboardLayout(&currentLayout);
- if (currentLayout) {
- KLGetKeyboardLayoutProperty(currentLayout, kKLIdentifier, (const void**)&currentLayoutId);
- if ( (lastLayout != currentLayout) || (lastLayoutId != currentLayoutId) ) {
- lastLayout = currentLayout;
- lastLayoutId = currentLayoutId;
- uchr = NULL;
- KCHR = NULL;
- if ((KLGetKeyboardLayoutProperty(currentLayout, kKLuchrData, (const void**)&uchr) == noErr) && (uchr != NULL)) {
- // done
- } else if ((KLGetKeyboardLayoutProperty(currentLayout, kKLKCHRData, (const void**)&KCHR) == noErr) && (KCHR != NULL)) {
- // done
- }
- // FIXME No Layout property found. Now we have a problem.
- }
- }
- if (hasLayoutChanged) {
- //deadKeyStateUp = deadKeyStateDown = 0;
- if (KCHR != NULL) {
- // FIXME this must not happen
- } else if (uchr == NULL) {
- KCHR = (Ptr) GetScriptManagerVariable(smKCHRCache);
- }
- }
- if (uchr != NULL) {
- // this is what I expect
- resource = uchr;
- } else {
- resource = KCHR;
- encoding = lastEncoding;
- // this is actually not supported by the following code and will likely crash
- }
-
- // now apply that keyboard mapping to our keycode
-
- int action;
- //OptionBits options = 0;
- // not used yet: OptionBits options = kUCKeyTranslateNoDeadKeysMask;
- unsigned long keyboardType;
- keycode &= 0xFF;
- modifiers = (modifiers >> 8) & 0xFF;
- keyboardType = LMGetKbdType();
- OSStatus status;
- UniCharCount actuallength;
- UniChar utext[10];
-
- switch(eKind) {
- case kEventRawKeyDown: action = kUCKeyActionDown; break;
- case kEventRawKeyUp: action = kUCKeyActionUp; break;
- case kEventRawKeyRepeat: action = kUCKeyActionAutoKey; break;
- default: return 0;
- }
-
- UInt32 deadKeyState = *deadKeyStatePtr;
- if ((action==kUCKeyActionUp)&&(*deadKeyStatePtr))
- deadKeyStatePtr = &deadKeyState;
-
- status = UCKeyTranslate(
- (const UCKeyboardLayout *) uchr,
- keycode, action, modifiers, keyboardType,
- 0, deadKeyStatePtr,
- 10, &actuallength, utext);
-
- if (noErr != status) {
- fprintf(stderr,"UCKeyTranslate failed: %d\n", (int) status);
- actuallength = 0;
- }
-
- // convert the list of unicode chars into utf8
- // FIXME no bounds check (see maxchars)
- unsigned i;
- for (i=0; i<actuallength; ++i) {
- len += fl_utf8encode(utext[i], uniChars+len);
- }
- uniChars[len] = 0;
- return len;
+ // first get the keyboard mapping in a post 10.2 way
+
+ Ptr resource;
+ TextEncoding encoding;
+ static TextEncoding lastEncoding = kTextEncodingMacRoman;
+ int len = 0;
+ KeyboardLayoutRef currentLayout = NULL;
+ static KeyboardLayoutRef lastLayout = NULL;
+ SInt32 currentLayoutId = 0;
+ static SInt32 lastLayoutId;
+ int hasLayoutChanged = false;
+ static Ptr uchr = NULL;
+ static Ptr KCHR = NULL;
+ // ScriptCode currentKeyScript;
+
+ KLGetCurrentKeyboardLayout(&currentLayout);
+ if (currentLayout) {
+ KLGetKeyboardLayoutProperty(currentLayout, kKLIdentifier, (const void**)&currentLayoutId);
+ if ( (lastLayout != currentLayout) || (lastLayoutId != currentLayoutId) ) {
+ lastLayout = currentLayout;
+ lastLayoutId = currentLayoutId;
+ uchr = NULL;
+ KCHR = NULL;
+ if ((KLGetKeyboardLayoutProperty(currentLayout, kKLuchrData, (const void**)&uchr) == noErr) && (uchr != NULL)) {
+ // done
+ } else if ((KLGetKeyboardLayoutProperty(currentLayout, kKLKCHRData, (const void**)&KCHR) == noErr) && (KCHR != NULL)) {
+ // done
+ }
+ // FIXME No Layout property found. Now we have a problem.
+ }
+ }
+ if (hasLayoutChanged) {
+ // deadKeyStateUp = deadKeyStateDown = 0;
+ if (KCHR != NULL) {
+ // FIXME this must not happen
+ } else if (uchr == NULL) {
+ KCHR = (Ptr) GetScriptManagerVariable(smKCHRCache);
+ }
+ }
+ if (uchr != NULL) {
+ // this is what I expect
+ resource = uchr;
+ } else {
+ resource = KCHR;
+ encoding = lastEncoding;
+ // this is actually not supported by the following code and will likely crash
+ }
+
+ // now apply that keyboard mapping to our keycode
+
+ int action;
+ //OptionBits options = 0;
+ // not used yet: OptionBits options = kUCKeyTranslateNoDeadKeysMask;
+ unsigned long keyboardType;
+ keycode &= 0xFF;
+ modifiers = (modifiers >> 8) & 0xFF;
+ keyboardType = LMGetKbdType();
+ OSStatus status;
+ UniCharCount actuallength;
+ UniChar utext[10];
+
+ switch(eKind) {
+ case kEventRawKeyDown: action = kUCKeyActionDown; break;
+ case kEventRawKeyUp: action = kUCKeyActionUp; break;
+ case kEventRawKeyRepeat: action = kUCKeyActionAutoKey; break;
+ default: return 0;
+ }
+
+ UInt32 deadKeyState = *deadKeyStatePtr;
+ if ((action==kUCKeyActionUp)&&(*deadKeyStatePtr)) {
+ deadKeyStatePtr = &deadKeyState;
+ }
+
+ status = UCKeyTranslate((const UCKeyboardLayout *) uchr,
+ keycode, action, modifiers, keyboardType,
+ 0, deadKeyStatePtr,
+ 10, &actuallength, utext);
+
+ if (noErr != status) {
+ fprintf(stderr,"UCKeyTranslate failed: %d\n", (int) status);
+ actuallength = 0;
+ }
+
+ // convert the list of unicode chars into utf8
+ // FIXME no bounds check (see maxchars)
+ unsigned i;
+ for (i=0; i<actuallength; ++i) {
+ len += fl_utf8encode(utext[i], uniChars+len);
+ }
+ uniChars[len] = 0;
+ return len;
}
*/
/*
* keycode_function for pre-10.5 systems, this is the "historic" fltk Mac key handling
*/
-static int keycode_wrap_old(
- char * buffer,
+static int keycode_wrap_old(char * buffer,
int, EventKind, UInt32, // not used in this function
UInt32, UInt32 *, // not used in this function
unsigned char key,
unsigned short sym)
{
if ( (sym >= FL_KP && sym <= FL_KP_Last) || !(sym & 0xff00) ||
- sym == FL_Tab || sym == FL_Enter) {
+ sym == FL_Tab || sym == FL_Enter) {
buffer[0] = key;
return 1;
} else {
@@ -980,6 +962,7 @@ static int keycode_wrap_old(
return 0;
}
} /* keycode_wrap_old */
+
/*
* Stub pointer to select appropriate keycode_function per operating system version. This function pointer
* is initialised in fl_open_display, based on the runtime identification of the host OS version. This is
@@ -990,19 +973,19 @@ static int (*keycode_function)(char*, int, EventKind, UInt32, UInt32, UInt32*, u
// EXPERIMENTAL!
-//this gets called by CJK character palette input
+// this gets called by CJK character palette input
OSStatus carbonTextHandler( EventHandlerCallRef nextHandler, EventRef event, void *unused )
{
- //make sure the key window is an FLTK window
+ // make sure the key window is an FLTK window
NSWindow *keywindow = [NSApp keyWindow];
- if(keywindow == nil || ![keywindow isMemberOfClass:[FLWindow class]]) return eventNotHandledErr;
- //under 10.5 this gets called only after character palette inputs
- //but under 10.6 this gets also called by interpretKeyEvents
- //during character composition when we don't want to run it
- if([[NSApp currentEvent] type] != NSSystemDefined) return eventNotHandledErr;
+ if (keywindow == nil || ![keywindow isMemberOfClass:[FLWindow class]]) return eventNotHandledErr;
+ // under 10.5 this gets called only after character palette inputs
+ // but under 10.6 this gets also called by interpretKeyEvents
+ // during character composition when we don't want to run it
+ if ([[NSApp currentEvent] type] != NSSystemDefined) return eventNotHandledErr;
Fl_Window *window = [(FLWindow*)keywindow getFl_Window];
fl_lock_function();
- //int kind = GetEventKind(event);
+ // int kind = GetEventKind(event);
unsigned short buf[200];
ByteCount size;
GetEventParameter( event, kEventParamTextInputSendText, typeUnicodeText,
@@ -1028,27 +1011,27 @@ OSStatus carbonTextHandler( EventHandlerCallRef nextHandler, EventRef event, voi
}
static void processCompositionSequence(CFStringRef s, Fl_Window *window)
-//composed character sequences are sent here
-//they contain 2 unichars, the first comes from the deadkey and can be non ascii (e.g., diaeresis),
-//the second is the character to be modified (e.g., e to be accented)
+// composed character sequences are sent here
+// they contain 2 unichars, the first comes from the deadkey and can be non ascii (e.g., diaeresis),
+// the second is the character to be modified (e.g., e to be accented)
{
- //unicodes: non-ascii unicode chars produced by deadkeys
- //asciis: corresponding ascii chars expected by Fl::compose()
+ // unicodes: non-ascii unicode chars produced by deadkeys
+ // asciis: corresponding ascii chars expected by Fl::compose()
// diaeresis acute-accent circumflex tilde ring-above
static UniChar unicodes[] = {0xA8, 0xB4, 0x2C6, 0x2DC, 0x2DA };
static char asciis[] = { ':', '\'', '^', '~', '*' };
- if(CFStringGetLength(s) == 0) return;
+ if (CFStringGetLength(s) == 0) return;
char text[10];
char buffer[10];
UniChar unis[2];
CFStringGetCharacters(s, CFRangeMake(0, 2), unis);
for(unsigned int i = 0; i < sizeof(asciis)/sizeof(char); i++) {
- if(unis[0] == unicodes[i]) {
- //replace the non-ascii unicode by the corresponding ascii value
+ if (unis[0] == unicodes[i]) {
+ // replace the non-ascii unicode by the corresponding ascii value
unis[0] = (UniChar)asciis[i];
break;
- }
}
+ }
CFStringRef smod = CFStringCreateWithCharacters(kCFAllocatorDefault, unis, 2);
CFStringGetCString(smod, buffer, sizeof(buffer), kCFStringEncodingUTF8);
CFRelease(smod);
@@ -1066,7 +1049,7 @@ static void processCompositionSequence(CFStringRef s, Fl_Window *window)
}
-/**
+/*
* handle cocoa keyboard events
*/
OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
@@ -1094,11 +1077,11 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
static BOOL compose = NO;
static NSText *edit;
static int countevents;
- static CFMutableStringRef sequence;//will contain the two characters of the composition sequence
- if(compose) {//we are in a composition sequence
- //the only benefit of sending events to the NSText object edit is that the deadkey becomes visible
- //at its keyUp event; without this, the deadkey remains invisible
- if([s length] == 0) {//occurs if 2 deadkeys are typed successively by error
+ static CFMutableStringRef sequence; // will contain the two characters of the composition sequence
+ if (compose) { // we are in a composition sequence
+ // the only benefit of sending events to the NSText object edit is that the deadkey becomes visible
+ // at its keyUp event; without this, the deadkey remains invisible
+ if ([s length] == 0) { // occurs if 2 deadkeys are typed successively by error
compose = NO;
[edit setString:@""];
CFRelease(sequence);
@@ -1109,55 +1092,53 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
countevents++;
UniChar deadkey;
CFStringGetCharacters((CFStringRef)s, CFRangeMake(0, 1), &deadkey);
- CFStringAppendCharacters(sequence, &deadkey, 1);//done for keyUp of deadkey and keyDown of next key
- if(countevents >= 3) {//end of composition sequence
+ CFStringAppendCharacters(sequence, &deadkey, 1);// done for keyUp of deadkey and keyDown of next key
+ if (countevents >= 3) { // end of composition sequence
processCompositionSequence( sequence, window );
CFRelease(sequence);
- [edit setString:@""];//clear the content of the edit object
- compose=NO;//character composition is now complete
+ [edit setString:@""]; // clear the content of the edit object
+ compose=NO; // character composition is now complete
}
fl_unlock_function();
return noErr;
}
- if([s length] == 0) {//this is a dead key that must be combined with the next key to be pressed
+ if ([s length] == 0) { // this is a dead key that must be combined with the next key to be pressed
while (window->parent()) window = window->window();
- Fl::e_keysym = FL_Control_R;//first simulate pressing of the compose key (FL_Control_R)
+ Fl::e_keysym = FL_Control_R; // first simulate pressing of the compose key (FL_Control_R)
Fl::e_text = (char*)"";
Fl::e_length = 0;
Fl::handle(FL_KEYBOARD, window);
compose=YES;
- //then send remaining events to an object of type NSText that helps handle character composition sequences
+ // then send remaining events to an object of type NSText that helps handle character composition sequences
edit = [[theEvent window] fieldEditor:YES forObject:nil];
[edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
countevents = 1;
sequence = CFStringCreateMutable(NULL, 2);
fl_unlock_function();
return noErr;
- }
- else {
+ } else {
char buff[10];
CFStringGetCString((CFStringRef)s, buff, sizeof(buff), kCFStringEncodingUnicode);
key = *(unichar*)buff;
keychar = buff[0];
- }
+ }
// extended keyboards can also send sequences on key-up to generate Kanji etc. codes.
// Some observed prefixes are 0x81 to 0x83, followed by an 8 bit keycode.
// In this mode, there seem to be no key-down codes
// printf("%08x %08x %08x\n", keyCode, mods, key);
maskedKeyCode = keyCode & 0x7f;
/* output a human readable event identifier for debugging
- const char *ev = "";
- switch (kind) {
- case kEventRawKeyDown: ev = "kEventRawKeyDown"; break;
- case kEventRawKeyRepeat: ev = "kEventRawKeyRepeat"; break;
- case kEventRawKeyUp: ev = "kEventRawKeyUp"; break;
- case kEventRawKeyModifiersChanged: ev = "kEventRawKeyModifiersChanged"; break;
- default: ev = "unknown";
- }
- printf("%08x %08x %08x '%c' %s \n", mods, keyCode, key, key, ev);
+ * const char *ev = "";
+ * switch (kind) {
+ * case kEventRawKeyDown: ev = "kEventRawKeyDown"; break;
+ * case kEventRawKeyRepeat: ev = "kEventRawKeyRepeat"; break;
+ * case kEventRawKeyUp: ev = "kEventRawKeyUp"; break;
+ * case kEventRawKeyModifiersChanged: ev = "kEventRawKeyModifiersChanged"; break;
+ * default: ev = "unknown"; break;
+ * }
+ * printf("%08x %08x %08x '%c' %s \n", mods, keyCode, key, key, ev);
*/
- switch([theEvent type])
- {
+ switch([theEvent type]) {
case NSKeyDown:
sendEvent = FL_KEYBOARD;
// fall through
@@ -1166,7 +1147,7 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
sendEvent = FL_KEYUP;
Fl::e_state &= 0xbfffffff; // clear the deadkey flag
}
- mods_to_e_state( mods ); //we process modifier keys at the same time
+ mods_to_e_state( mods ); // we process modifier keys at the same time
// if the user pressed alt/option, event_key should have the keycap,
// but event_text should generate the international symbol
sym = macKeyLookUp[maskedKeyCode];
@@ -1174,26 +1155,25 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
sym = tolower(key);
else if ( Fl::e_state&FL_CTRL && key<32 && sym<0xff00)
sym = key+96;
-
- else if ( Fl::e_state&FL_ALT && sym<0xff00) {// find the keycap of this key
+ else if ( Fl::e_state&FL_ALT && sym<0xff00) { // find the keycap of this key
NSString *sim = [theEvent charactersIgnoringModifiers];
UniChar one;
CFStringGetCharacters((CFStringRef)sim, CFRangeMake(0, 1), &one);
sym = one;
- }
+ }
Fl::e_keysym = Fl::e_original_keysym = sym;
// Handle FL_KP_Enter on regular keyboards and on Powerbooks
if ( maskedKeyCode==0x4c || maskedKeyCode==0x34) key=0x0d;
static UInt32 deadKeyState = 0; // must be cleared when losing focus
int l = (*keycode_function)(buffer, 31, kind, keyCode, mods, &deadKeyState, keychar, sym);
- if(l > 0) {
+ if (l > 0) {
CFStringGetCString((CFStringRef)s, buffer, sizeof(buffer), kCFStringEncodingUTF8);
}
Fl::e_length = strlen(buffer);
Fl::e_text = buffer;
buffer[Fl::e_length] = 0; // just in case...
- }
+ }
break;
default:
fl_unlock_function();
@@ -1211,14 +1191,14 @@ OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
-/**
+/*
* Open callback function to call...
*/
static void (*open_cb)(const char *) = 0;
-/**
+/*
* Install an open documents event handler...
*/
@interface FLAppleEventHandler : NSObject
@@ -1250,7 +1230,7 @@ static void (*open_cb)(const char *) = 0;
(*open_cb)(filename);
}
- }
+ }
// Unlock access to FLTK for all threads...
fl_unlock_function();
@@ -1261,10 +1241,10 @@ void fl_open_callback(void (*cb)(const char *)) {
static NSAppleEventManager *aeventmgr = nil;
static FLAppleEventHandler *handler;
fl_open_display();
- if(!aeventmgr) {
+ if (!aeventmgr) {
aeventmgr = [NSAppleEventManager sharedAppleEventManager];
handler = [[FLAppleEventHandler alloc] init];
- }
+ }
open_cb = cb;
if (cb) {
@@ -1276,7 +1256,7 @@ void fl_open_callback(void (*cb)(const char *)) {
}
-/**
+/*
* initialize the Mac toolboxes, dock status, and set the default menubar
*/
@@ -1310,10 +1290,10 @@ extern "C" {
pt.x = 0;
pt.y = [[nsw contentView] frame].size.height;
pt2 = [nsw convertBaseToScreen:pt];
- window->position(pt2.x, [[nsw screen] frame].size.height - pt2.y);
- if([nsw containsGLsubwindow] ) {
- [nsw display];//redraw window after moving if it contains OpenGL subwindows
- }
+ window->position((int)pt2.x, (int)([[nsw screen] frame].size.height - pt2.y));
+ if ([nsw containsGLsubwindow] ) {
+ [nsw display];// redraw window after moving if it contains OpenGL subwindows
+ }
}
- (void)windowDidResize:(NSNotification *)notif
{
@@ -1325,7 +1305,10 @@ extern "C" {
pt.y = [[nsw contentView] frame].size.height;
pt2 = [nsw convertBaseToScreen:pt];
resize_from_system = window;
- window->resize(pt2.x, [[nsw screen] frame].size.height - pt2.y, r.size.width, r.size.height);
+ window->resize((int)pt2.x,
+ (int)([[nsw screen] frame].size.height - pt2.y),
+ (int)r.size.width,
+ (int)r.size.height);
}
- (void)windowDidBecomeKey:(NSNotification *)notif
{
@@ -1354,13 +1337,13 @@ extern "C" {
- (void)windowWillClose:(NSNotification *)notif
{
Fl_Window *w = Fl::first_window();
- if(!w) return;
+ if (!w) return;
NSWindow *cw = (NSWindow*)Fl_X::i(w)->xid;
- if( ![cw isMiniaturized] && ([cw styleMask] & NSTitledWindowMask) ) {
- if(![cw isKeyWindow]) {//always make Fl::first_window() the key widow
+ if ( ![cw isMiniaturized] && ([cw styleMask] & NSTitledWindowMask) ) {
+ if (![cw isKeyWindow]) { // always make Fl::first_window() the key widow
[cw makeKeyAndOrderFront:nil];
}
- if(![cw isMainWindow]) {//always make Fl::first_window() the main widow
+ if (![cw isMainWindow]) { // always make Fl::first_window() the main widow
[cw makeMainWindow];
}
}
@@ -1386,7 +1369,7 @@ static FLDelegate *mydelegate;
void fl_open_display() {
static char beenHereDoneThat = 0;
- if ( !beenHereDoneThat ) {
+ if ( !beenHereDoneThat ) {
beenHereDoneThat = 1;
[NSApplication sharedApplication];
@@ -1404,13 +1387,11 @@ void fl_open_display() {
// bring the application into foreground without a 'CARB' resource
Boolean same_psn;
ProcessSerialNumber cur_psn, front_psn;
- if( !GetCurrentProcess( &cur_psn ) && !GetFrontProcess( &front_psn ) &&
- !SameProcess( &front_psn, &cur_psn, &same_psn ) && !same_psn )
- {
+ if ( !GetCurrentProcess( &cur_psn ) && !GetFrontProcess( &front_psn ) &&
+ !SameProcess( &front_psn, &cur_psn, &same_psn ) && !same_psn ) {
// only transform the application type for unbundled apps
CFBundleRef bundle = CFBundleGetMainBundle();
- if( bundle )
- {
+ if ( bundle ) {
FSRef execFs;
CFURLRef execUrl = CFBundleCopyExecutableURL( bundle );
CFURLGetFSRef( execUrl, &execFs );
@@ -1418,23 +1399,24 @@ void fl_open_display() {
FSRef bundleFs;
GetProcessBundleLocation( &cur_psn, &bundleFs );
- if( !FSCompareFSRefs( &execFs, &bundleFs ) )
+ if ( !FSCompareFSRefs( &execFs, &bundleFs ) )
bundle = NULL;
CFRelease(execUrl);
}
- keycode_function = keycode_wrap_old; //under Cocoa we always use this one
+ keycode_function = keycode_wrap_old; // under Cocoa we always use this one
/* // imm: keycode handler stub setting - use Gestalt to determine the running system version,
- // then set the keycode_function pointer accordingly
- if(MACsystemVersion >= 0x1050) { // 10.5.0 or later
- keycode_function = keycodeToUnicode;
- }
- else {
- keycode_function = keycode_wrap_old; // pre-10.5 mechanism
- }*/
+ * // then set the keycode_function pointer accordingly
+ * if (MACsystemVersion >= 0x1050) { // 10.5.0 or later
+ * keycode_function = keycodeToUnicode;
+ * }
+ * else {
+ * keycode_function = keycode_wrap_old; // pre-10.5 mechanism
+ * }
+ */
- if( !bundle )
+ if ( !bundle )
{
// Earlier versions of this code tried to use weak linking, however it
// appears that this does not work on 10.2. Since 10.3 and higher provide
@@ -1460,17 +1442,18 @@ void fl_open_display() {
createAppleMenu();
// Install Carbon Event handler for character palette input
static EventTypeSpec textEvents[] = {
- { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } };
+ { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }
+ };
EventHandlerUPP textHandler = NewEventHandlerUPP( carbonTextHandler );
InstallEventHandler(GetEventDispatcherTarget(), textHandler, 1, textEvents, NULL, 0L);
}
}
-/**
+/*
* get rid of allocated resources
*/
-void fl_close_display() {
+void fl_close_display() {
}
@@ -1484,7 +1467,7 @@ static void get_window_frame_sizes(int &bx, int &by, int &bt) {
bt = outside.size.height - inside.size.height - by;
}
-/**
+/*
* smallest x ccordinate in screen space
*/
int Fl::x() {
@@ -1492,7 +1475,7 @@ int Fl::x() {
}
-/**
+/*
* smallest y coordinate in screen space
*/
int Fl::y() {
@@ -1502,7 +1485,7 @@ int Fl::y() {
}
-/**
+/*
* screen width (single monitor!?)
*/
int Fl::w() {
@@ -1510,7 +1493,7 @@ int Fl::w() {
}
-/**
+/*
* screen height (single monitor!?)
*/
int Fl::h() {
@@ -1520,7 +1503,7 @@ int Fl::h() {
}
-/**
+/*
* get the current mouse pointer world coordinates
*/
void Fl::get_mouse(int &x, int &y)
@@ -1532,19 +1515,19 @@ void Fl::get_mouse(int &x, int &y)
}
-/**
+/*
* convert Mac keystrokes to FLTK
*/
/*
- unsigned short mac2fltk(ulong macKey)
- {
- unsigned short cc = macKeyLookUp[(macKey>>8)&0x7f];
- if (cc) return cc;
- return macKey&0xff;
- }
+ * unsigned short mac2fltk(ulong macKey)
+ * {
+ * unsigned short cc = macKeyLookUp[(macKey>>8)&0x7f];
+ * if (cc) return cc;
+ * return macKey&0xff;
+ * }
*/
-/**
+/*
* Initialize the given port for redraw and call the window's flush() to actually draw the content
*/
void Fl_X::flush()
@@ -1552,15 +1535,14 @@ void Fl_X::flush()
w->flush();
if (fl_gc) {
CGContextFlush(fl_gc);
- if(viewWithLockedFocus) {
- [viewWithLockedFocus unlockFocus];
- viewWithLockedFocus = nil;
+ if (viewWithLockedFocus) {
+ [viewWithLockedFocus unlockFocus];
+ viewWithLockedFocus = nil;
}
- }
+ }
}
-
-/**
+/*
* Gets called when a window is created, resized, or deminiaturized
*/
static void handleUpdateEvent( Fl_Window *window )
@@ -1571,29 +1553,28 @@ static void handleUpdateEvent( Fl_Window *window )
// FIXME: Matt: this is in the Carbon version. Does it need to be here?
/*
- //I don't think so (MG). This function gets called only when a full
- //redraw is needed (creation, resize, deminiaturization)
- //and later in it we set damages to DAMAGE_ALL, so there is no
- //point in limiting redraw to i->region
- if ( i->xid && window->damage() ) {
- NSView *view = [(NSWindow*)i->xid contentView];
- if ( view && i->region ) {
- int ix;
- Fl_Region rgn = i->region;
- for (ix=0; ix<rgn->count; ix++) {
- NSRect rect = NSRectFromCGRect(rgn->rects[ix]);
- [view setNeedsDisplayInRect:rect];
- }
- }
- }
- */
+ * // I don't think so (MG). This function gets called only when a full
+ * // redraw is needed (creation, resize, deminiaturization)
+ * // and later in it we set damages to DAMAGE_ALL, so there is no
+ * // point in limiting redraw to i->region
+ * if ( i->xid && window->damage() ) {
+ * NSView *view = [(NSWindow*)i->xid contentView];
+ * if ( view && i->region ) {
+ * int ix;
+ * Fl_Region rgn = i->region;
+ * for (ix=0; ix<rgn->count; ix++) {
+ * NSRect rect = NSRectFromCGRect(rgn->rects[ix]);
+ * [view setNeedsDisplayInRect:rect];
+ * }
+ * }
+ * }
+ */
if ( i->region ) {
XDestroyRegion(i->region);
i->region = 0;
}
- for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext )
- {
+ for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext ) {
if ( cx->region ) {
XDestroyRegion(cx->region);
cx->region = 0;
@@ -1619,7 +1600,7 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
get_window_frame_sizes(bx, by, bt);
}
}
- //The coordinates of the whole window, including non-client area
+ // The coordinates of the whole window, including non-client area
xoff = bx;
yoff = by + bt;
dx = 2*bx;
@@ -1629,7 +1610,7 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
W = w->w()+dx;
H = w->h()+dy;
- //Proceed to positioning the window fully inside the screen, if possible
+ // Proceed to positioning the window fully inside the screen, if possible
// let's get a little elaborate here. Mac OS X puts a lot of stuff on the desk
// that we want to avoid when positioning our window, namely the Dock and the
@@ -1649,7 +1630,7 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
&& cy >= r.origin.y && cy <= r.origin.y + r.size.height)
break;
}
- if(i < count) gd = [a objectAtIndex:i];
+ if (i < count) gd = [a objectAtIndex:i];
// if the center doesn't fall on a screen, try the top left
if (!gd) {
@@ -1659,7 +1640,7 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
&& r.size.height - Y >= r.origin.y && r.size.height - Y <= r.origin.y + r.size.height)
break;
}
- if(i < count) gd = [a objectAtIndex:i];
+ if (i < count) gd = [a objectAtIndex:i];
}
// if that doesn't fall on a screen, try the top right
if (!gd) {
@@ -1669,7 +1650,7 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
&& r.size.height - Y >= r.origin.y && r.size.height - Y <= r.origin.y + r.size.height)
break;
}
- if(i < count) gd = [a objectAtIndex:i];
+ if (i < count) gd = [a objectAtIndex:i];
}
// if that doesn't fall on a screen, try the bottom left
if (!gd) {
@@ -1679,7 +1660,7 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
&& Y-H >= r.origin.y && Y-H <= r.origin.y + r.size.height)
break;
}
- if(i < count) gd = [a objectAtIndex:i];
+ if (i < count) gd = [a objectAtIndex:i];
}
// last resort, try the bottom right
if (!gd) {
@@ -1689,7 +1670,7 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
&& Y-H >= r.origin.y && Y-H <= r.origin.y + r.size.height)
break;
}
- if(i < count) gd = [a objectAtIndex:i];
+ if (i < count) gd = [a objectAtIndex:i];
}
// if we still have not found a screen, we will use the main
// screen, the one that has the application menu bar.
@@ -1703,7 +1684,7 @@ int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by)
if ( Y < sh - (r.origin.y + r.size.height) ) Y = sh - (r.origin.y + r.size.height);
}
- //Return the client area's top left corner in (X,Y)
+ // Return the client area's top left corner in (X,Y)
X+=xoff;
Y+=yoff;
@@ -1725,7 +1706,7 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) {
- (void)drawRect:(NSRect)rect;
- (BOOL)acceptsFirstResponder;
- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent;
-//- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
+- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
- (void)mouseUp:(NSEvent *)theEvent;
- (void)rightMouseUp:(NSEvent *)theEvent;
- (void)otherMouseUp:(NSEvent *)theEvent;
@@ -1755,12 +1736,11 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) {
{
return YES;
}
-/*
- (BOOL)performKeyEquivalent:(NSEvent*)theEvent
{
OSStatus err = cocoaKeyboardHandler(theEvent);
return (err ? NO : YES);
-}*/
+}
- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent
{
Fl_Window *w = [(FLWindow*)[theEvent window] getFl_Window];
@@ -1837,8 +1817,8 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) {
return NO;
}
NSPasteboard *pboard;
- //NSDragOperation sourceDragMask;
- //sourceDragMask = [sender draggingSourceOperationMask];
+ // NSDragOperation sourceDragMask;
+ // sourceDragMask = [sender draggingSourceOperationMask];
pboard = [sender draggingPasteboard];
NSPoint pt = [sender draggingLocation];
Fl::e_x = pt.x;
@@ -1846,22 +1826,22 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) {
Fl::e_x_root = [[self window] frame].origin.x + Fl::e_x;
Fl::e_y_root = [[self window] frame].origin.y + pt.y;
Fl::e_y_root = [[[self window] screen] frame].size.height - Fl::e_y_root;
- if(DragData) { free(DragData); DragData = NULL; }
+ if (DragData) { free(DragData); DragData = NULL; }
if ( [[pboard types] containsObject:NSFilenamesPboardType] ) {
- CFArrayRef files = (CFArrayRef)[pboard propertyListForType:NSFilenamesPboardType];
- CFStringRef all = CFStringCreateByCombiningStrings(NULL, files, CFSTR("\n"));
- int l = CFStringGetMaximumSizeForEncoding(CFStringGetLength(all), kCFStringEncodingUTF8);
- DragData = (char *)malloc(l + 1);
- CFStringGetCString(all, DragData, l + 1, kCFStringEncodingUTF8);
- CFRelease(all);
- }
+ CFArrayRef files = (CFArrayRef)[pboard propertyListForType:NSFilenamesPboardType];
+ CFStringRef all = CFStringCreateByCombiningStrings(NULL, files, CFSTR("\n"));
+ int l = CFStringGetMaximumSizeForEncoding(CFStringGetLength(all), kCFStringEncodingUTF8);
+ DragData = (char *)malloc(l + 1);
+ CFStringGetCString(all, DragData, l + 1, kCFStringEncodingUTF8);
+ CFRelease(all);
+ }
else if ( [[pboard types] containsObject:NSStringPboardType] ) {
- NSData *data = [pboard dataForType:NSStringPboardType];
- DragData = (char *)malloc([data length] + 1);
- [data getBytes:DragData];
- DragData[[data length]] = 0;
- convert_crlf(DragData, strlen(DragData));
- }
+ NSData *data = [pboard dataForType:NSStringPboardType];
+ DragData = (char *)malloc([data length] + 1);
+ [data getBytes:DragData];
+ DragData[[data length]] = 0;
+ convert_crlf(DragData, strlen(DragData));
+ }
else {
breakMacEventLoop();
return NO;
@@ -1871,7 +1851,7 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) {
int old_event = Fl::e_number;
Fl::belowmouse()->handle(Fl::e_number = FL_PASTE);
Fl::e_number = old_event;
- if(DragData) { free(DragData); DragData = NULL; }
+ if (DragData) { free(DragData); DragData = NULL; }
Fl::e_text = NULL;
Fl::e_length = 0;
fl_dnd_target_window = NULL;
@@ -1880,8 +1860,7 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) {
}
- (void)draggingExited:(id < NSDraggingInfo >)sender
{
- if ( fl_dnd_target_window )
- {
+ if ( fl_dnd_target_window ) {
Fl::handle( FL_DND_LEAVE, fl_dnd_target_window );
fl_dnd_target_window = 0;
}
@@ -1893,15 +1872,14 @@ static void q_set_window_title(NSWindow *nsw, const char * name ) {
@end
-/**
+/*
* go ahead, create that (sub)window
* \todo we should make menu windows slightly transparent for the new Mac look
*/
void Fl_X::make(Fl_Window* w)
{
static int xyPos = 100;
- if ( w->parent() ) // create a subwindow
- {
+ if ( w->parent() ) { // create a subwindow
Fl_Group::current(0);
Rect wRect;
wRect.top = w->y();
@@ -1914,50 +1892,52 @@ void Fl_X::make(Fl_Window* w)
x->region = 0;
x->subRegion = 0;
x->cursor = fl_default_cursor;
- x->gc = 0; // stay 0 for Quickdraw; fill with CGContext for Quartz
+ x->gc = 0; // stay 0 for Quickdraw; fill with CGContext for Quartz
Fl_Window *win = w->window();
Fl_X *xo = Fl_X::i(win);
if (xo) {
x->xidNext = xo->xidChildren;
x->xidChildren = 0L;
xo->xidChildren = x;
- x->xid = win->i->xid;
+ x->xid = win->i->xid;
x->w = w; w->i = x;
x->wait_for_expose = 0;
- Fl_X *z = xo->next; //we don't want a subwindow in Fl_X::first
- xo->next = x;
- x->next = z;
+ {
+ Fl_X *z = xo->next; // we don't want a subwindow in Fl_X::first
+ xo->next = x;
+ x->next = z;
+ }
int old_event = Fl::e_number;
w->handle(Fl::e_number = FL_SHOW);
Fl::e_number = old_event;
- w->redraw(); // force draw to happen
+ w->redraw(); // force draw to happen
}
fl_show_iconic = 0;
}
- else // create a desktop window
- {
+ else { // create a desktop window
NSAutoreleasePool *localPool;
localPool = [[NSAutoreleasePool alloc] init];
Fl_Group::current(0);
fl_open_display();
NSInteger winlevel = NSNormalWindowLevel;
NSUInteger winstyle;
- if(w->border()) winstyle = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask;
+ if (w->border()) winstyle = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask;
else winstyle = NSBorderlessWindowMask;
int xp = w->x();
int yp = w->y();
int wp = w->w();
int hp = w->h();
if (w->size_range_set) {
- if ( w->minh != w->maxh || w->minw != w->maxw)
+ if ( w->minh != w->maxh || w->minw != w->maxw) {
winstyle |= NSResizableWindowMask;
+ }
} else {
if (w->resizable()) {
Fl_Widget *o = w->resizable();
int minw = o->w(); if (minw > 100) minw = 100;
int minh = o->h(); if (minh > 100) minh = 100;
w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0);
- winstyle |= NSResizableWindowMask;
+ winstyle |= NSResizableWindowMask;
} else {
w->size_range(w->w(), w->h(), w->w(), w->h());
}
@@ -1974,7 +1954,7 @@ void Fl_X::make(Fl_Window* w)
}
} else if (w->modal()) {
winstyle &= ~(NSResizableWindowMask | NSMiniaturizableWindowMask);
- // winlevel = NSModalPanelWindowLevel;
+ // winlevel = NSModalPanelWindowLevel;
}
else if (w->non_modal()) {
winlevel = NSFloatingWindowLevel;
@@ -2040,8 +2020,7 @@ void Fl_X::make(Fl_Window* w)
[cw setLevel:winlevel];
q_set_window_title(cw, name);
- if (!(w->flags() & Fl_Window::FORCE_POSITION))
- {
+ if (!(w->flags() & Fl_Window::FORCE_POSITION)) {
if (w->modal()) {
[cw center];
} else if (w->non_modal()) {
@@ -2058,8 +2037,7 @@ void Fl_X::make(Fl_Window* w)
// Install DnD handlers
[myview registerForDraggedTypes:[NSArray arrayWithObjects:
NSStringPboardType, NSFilenamesPboardType, nil]];
- if ( ! Fl_X::first->next ) // if this is the first window, we need to bring the application to the front
- {
+ if ( ! Fl_X::first->next ) { // if this is the first window, we need to bring the application to the front
ProcessSerialNumber psn;
OSErr err = GetCurrentProcess( &psn );
if ( err==noErr ) SetFrontProcess( &psn );
@@ -2067,7 +2045,7 @@ void Fl_X::make(Fl_Window* w)
if (w->size_range_set) w->size_range_();
- if(winlevel != NSMainMenuWindowLevel) {
+ if (winlevel != NSMainMenuWindowLevel) {
Fl_Tooltip::enter(0);
}
[cw makeKeyAndOrderFront:nil];
@@ -2098,7 +2076,7 @@ void Fl_X::make(Fl_Window* w)
}
-/**
+/*
* Tell the OS what window sizes we want to allow
*/
void Fl_Window::size_range_() {
@@ -2108,35 +2086,34 @@ void Fl_Window::size_range_() {
NSSize minSize = { minw, minh + bt };
NSSize maxSize = { maxw?maxw:32000, maxh?maxh + bt:32000 };
if (i && i->xid) {
- [(NSWindow*)i->xid setMinSize:minSize];
- [(NSWindow*)i->xid setMaxSize:maxSize];
- }
+ [(NSWindow*)i->xid setMinSize:minSize];
+ [(NSWindow*)i->xid setMaxSize:maxSize];
+ }
}
-/**
+/*
* returns pointer to the filename, or null if name ends with ':'
*/
const char *fl_filename_name( const char *name )
{
const char *p, *q;
if (!name) return (0);
- for ( p = q = name ; *p ; )
- {
- if ( ( p[0] == ':' ) && ( p[1] == ':' ) )
- {
+ for ( p = q = name ; *p ; ) {
+ if ( ( p[0] == ':' ) && ( p[1] == ':' ) ) {
q = p+2;
p++;
}
- else if (p[0] == '/')
+ else if (p[0] == '/') {
q = p + 1;
+ }
p++;
}
return q;
}
-/**
+/*
* set the window title bar
* \todo make the titlebar icon work!
*/
@@ -2148,7 +2125,7 @@ void Fl_Window::label(const char *name,const char */*iname*/) {
}
-/**
+/*
* make a window visible
*/
void Fl_Window::show() {
@@ -2163,27 +2140,25 @@ void Fl_Window::show() {
if (!shown() || !i) {
Fl_X::make(this);
} else {
- if ( !parent() )
- {
- if([(NSWindow*)i->xid isMiniaturized]) {
- i->w->redraw();
- [(NSWindow*)i->xid deminiaturize:nil];
- }
-
- if (!fl_capture) {
- [(NSWindow*)i->xid makeKeyAndOrderFront:nil];
+ if ( !parent() ) {
+ if ([(NSWindow*)i->xid isMiniaturized]) {
+ i->w->redraw();
+ [(NSWindow*)i->xid deminiaturize:nil];
}
- }
+ if (!fl_capture) {
+ [(NSWindow*)i->xid makeKeyAndOrderFront:nil];
+ }
+ }
}
}
-/**
+/*
* resize a window
*/
void Fl_Window::resize(int X,int Y,int W,int H) {
int bx, by, bt;
- if( ! this->border() ) bt = 0;
+ if ( ! this->border() ) bt = 0;
else get_window_frame_sizes(bx, by, bt);
if (W<=0) W = 1; // OS X does not like zero width windows
if (H<=0) H = 1;
@@ -2228,7 +2203,7 @@ void Fl_Window::resize(int X,int Y,int W,int H) {
}
-/**
+/*
* make all drawing go into this window (called by subclass flush() impl.)
*/
void Fl_Window::make_current()
@@ -2239,8 +2214,7 @@ void Fl_Window::make_current()
int xp = 0, yp = 0;
Fl_Window *win = this;
- while ( win )
- {
+ while ( win ) {
if ( !win->window() )
break;
xp += win->x();
@@ -2249,29 +2223,27 @@ void Fl_Window::make_current()
}
viewWithLockedFocus = [(NSWindow*)i->xid contentView];
- [viewWithLockedFocus lockFocusIfCanDraw];//important
+ [viewWithLockedFocus lockFocusIfCanDraw];// important
i->gc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
fl_gc = i->gc;
if ( fl_window_region ) XDestroyRegion(fl_window_region);
- if(this->window()) {
+ if (this->window()) {
fl_window_region = XRectangleRegion(0,0,w(),h());
- }
- else {
+ } else {
fl_window_region = XRectangleRegion(0, 0, w(), h());
- for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext )
- {//clip-out all sub-windows
- Fl_Window *cw = cx->w;
- Fl_Region from = fl_window_region;
- fl_window_region = MacRegionMinusRect(from, cw->x(), cw->y(), cw->w(), cw->h() );
- XDestroyRegion(from);
- }
+ for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext ) { // clip-out all sub-windows
+ Fl_Window *cw = cx->w;
+ Fl_Region from = fl_window_region;
+ fl_window_region = MacRegionMinusRect(from, cw->x(), cw->y(), cw->w(), cw->h() );
+ XDestroyRegion(from);
+ }
}
- //antialiasing must be deactivated because it applies to rectangles too
- //and escapes even clipping!!!
- //it gets activated when needed (e.g., draw text)
+ // antialiasing must be deactivated because it applies to rectangles too
+ // and escapes even clipping!!!
+ // it gets activated when needed (e.g., draw text)
CGContextSetShouldAntialias(fl_gc, false);
- //this is the native view context with origin at bottom left
+ // this is the native view context with origin at bottom left
CGContextSaveGState(fl_gc);
#if defined(USE_CAIRO)
if (Fl::cairo_autolink_context()) Fl::cairo_make_current(this); // capture gc changes automatically to update the cairo context adequately
@@ -2296,7 +2268,7 @@ void Fl_X::q_fill_context() {
if (!fl_gc) return;
int hgt = 0;
if (fl_window) {
- hgt = [[(NSWindow*)Fl_X::i(Fl_Window::current_)->xid contentView] frame].size.height;
+ hgt = [[(NSWindow*)Fl_X::i(Fl_Window::current_)->xid contentView] frame].size.height;
} else {
hgt = CGBitmapContextGetHeight(fl_gc);
}
@@ -2305,13 +2277,13 @@ void Fl_X::q_fill_context() {
fl_font(fl_fontsize);
fl_color(fl_color_);
fl_quartz_restore_line_style_();
- if (fl_window) {//translate to subwindow origin if this is a subwindow context
+ if (fl_window) { // translate to subwindow origin if this is a subwindow context
Fl_Window *w = Fl_Window::current_;
while(w && w->window()) {
CGContextTranslateCTM(fl_gc, w->x(), w->y());
w = w->window();
- }
- }
+ }
+ }
}
// The only way to reset clipping to its original state is to pop the current graphics
@@ -2326,7 +2298,7 @@ void Fl_X::q_clear_clipping() {
void Fl_X::q_release_context(Fl_X *x) {
if (x && x->gc!=fl_gc) return;
if (!fl_gc) return;
- CGContextRestoreGState(fl_gc); //matches the CGContextSaveGState of make_current
+ CGContextRestoreGState(fl_gc); // matches the CGContextSaveGState of make_current
fl_gc = 0;
#if defined(USE_CAIRO)
if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0); // capture gc changes automatically to update the cairo context adequately
@@ -2387,7 +2359,7 @@ static void allocatePasteboard() {
}
-/**
+/*
* create a selection
* owner: widget that created the selection
* stuff: pointer to selected data
@@ -2430,7 +2402,7 @@ void Fl::paste(Fl_Widget &receiver, int clipboard) {
ItemCount nFlavor = 0, i, j;
err = PasteboardGetItemCount(myPasteboard, &nFlavor);
if (err==noErr) {
- for (i=1; i<=nFlavor; i++) {
+ for (i=1; i<=nFlavor; i++) {
PasteboardItemID itemID = 0;
CFArrayRef flavorTypeArray = NULL;
found = false;
@@ -2447,18 +2419,18 @@ void Fl::paste(Fl_Widget &receiver, int clipboard) {
CFStringRef flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex);
if (UTTypeConformsTo(flavorType, flavorNames[j])) {
err = PasteboardCopyItemFlavorData( myPasteboard, itemID, flavorNames[j], &flavorData );
- if(err != noErr) continue;
+ if (err != noErr) continue;
encoding = encodings[j];
found = true;
break;
}
}
- if(found) break;
+ if (found) break;
}
if (flavorTypeArray) {CFRelease(flavorTypeArray); flavorTypeArray = NULL;}
if (found) break;
- }
- if(found) {
+ }
+ if (found) {
CFIndex len = CFDataGetLength(flavorData);
CFStringRef mycfs = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(flavorData), len, encoding, false);
CFRelease(flavorData);
@@ -2473,7 +2445,7 @@ void Fl::paste(Fl_Widget &receiver, int clipboard) {
len = strlen(fl_selection_buffer[1]);
fl_selection_length[1] = len;
convert_crlf(fl_selection_buffer[1],len); // turn all \r characters into \n:
- }
+ }
}
}
Fl::e_text = fl_selection_buffer[clipboard];
@@ -2485,7 +2457,7 @@ void Fl::paste(Fl_Widget &receiver, int clipboard) {
void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
{
// check, if this timer slot exists already
- for (int i = 0; i < mac_timer_used; ++i) {
+ for (int i = 0; i < mac_timer_used; ++i) {
MacTimeout& t = mac_timers[i];
// if so, simply change the fire interval
if (t.callback == cb && t.data == data) {
@@ -2497,7 +2469,7 @@ void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
// no existing timer to use. Create a new one:
int timer_id = -1;
// find an empty slot in the timer array
- for (int i = 0; i < mac_timer_used; ++i) {
+ for (int i = 0; i < mac_timer_used; ++i) {
if ( !mac_timers[i].timer ) {
timer_id = i;
break;
@@ -2539,7 +2511,7 @@ void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data)
int Fl::has_timeout(Fl_Timeout_Handler cb, void* data)
{
- for (int i = 0; i < mac_timer_used; ++i) {
+ for (int i = 0; i < mac_timer_used; ++i) {
MacTimeout& t = mac_timers[i];
if (t.callback == cb && t.data == data && t.pending) {
return 1;
@@ -2550,7 +2522,7 @@ int Fl::has_timeout(Fl_Timeout_Handler cb, void* data)
void Fl::remove_timeout(Fl_Timeout_Handler cb, void* data)
{
- for (int i = 0; i < mac_timer_used; ++i) {
+ for (int i = 0; i < mac_timer_used; ++i) {
MacTimeout& t = mac_timers[i];
if (t.callback == cb && ( t.data == data || data == NULL)) {
delete_timer(t);
@@ -2603,13 +2575,13 @@ void MacDestroyWindow(Fl_Window *w, void *p) {
if (w && !w->parent() && p) {
[[(NSWindow *)p contentView] release];
[(NSWindow *)p close];
- }
+ }
}
void MacMapWindow(Fl_Window *w, void *p) {
if (w && p) {
[(NSWindow *)p orderFront:nil];
- }
+ }
//+ link to window list
if (w && w->parent()) {
MacRelinkWindow(Fl_X::i(w), Fl_X::i(w->window()));
@@ -2620,7 +2592,7 @@ void MacMapWindow(Fl_Window *w, void *p) {
void MacUnmapWindow(Fl_Window *w, void *p) {
if (w && !w->parent() && p) {
[(NSWindow *)p orderOut:nil];
- }
+ }
if (w && Fl_X::i(w))
MacUnlinkWindow(Fl_X::i(w));
}
@@ -2636,38 +2608,38 @@ Fl_Region MacRegionMinusRect(Fl_Region r, int x,int y,int w,int h)
for( int i = 0; i < r->count; i++) {
CGRect A = r->rects[i];
CGRect test = CGRectIntersection(A, rect);
- if(CGRectIsEmpty(test)) {
+ if (CGRectIsEmpty(test)) {
outr->rects[(outr->count)++] = A;
- }
+ }
else {
const CGFloat verylarge = 100000.;
- CGRect side = CGRectMake(0,0,rect.origin.x,verylarge);//W side
+ CGRect side = CGRectMake(0,0,rect.origin.x,verylarge);// W side
test = CGRectIntersection(A, side);
- if( ! CGRectIsEmpty(test)) {
+ if ( ! CGRectIsEmpty(test)) {
outr->rects[(outr->count)++] = test;
- }
- side = CGRectMake(0,rect.origin.y + rect.size.height,verylarge,verylarge);//N side
+ }
+ side = CGRectMake(0,rect.origin.y + rect.size.height,verylarge,verylarge);// N side
test = CGRectIntersection(A, side);
- if( ! CGRectIsEmpty(test)) {
+ if ( ! CGRectIsEmpty(test)) {
outr->rects[(outr->count)++] = test;
- }
- side = CGRectMake(rect.origin.x + rect.size.width, 0, verylarge, verylarge);//E side
+ }
+ side = CGRectMake(rect.origin.x + rect.size.width, 0, verylarge, verylarge);// E side
test = CGRectIntersection(A, side);
- if( ! CGRectIsEmpty(test)) {
+ if ( ! CGRectIsEmpty(test)) {
outr->rects[(outr->count)++] = test;
- }
- side = CGRectMake(0, 0, verylarge, rect.origin.y);//S side
+ }
+ side = CGRectMake(0, 0, verylarge, rect.origin.y);// S side
test = CGRectIntersection(A, side);
- if( ! CGRectIsEmpty(test)) {
+ if ( ! CGRectIsEmpty(test)) {
outr->rects[(outr->count)++] = test;
- }
}
}
- if(outr->count == 0) {
+ }
+ if (outr->count == 0) {
free(outr->rects);
free(outr);
outr = XRectangleRegion(0,0,0,0);
- }
+ }
else outr->rects = (CGRect*)realloc(outr->rects, outr->count * sizeof(CGRect));
return outr;
}
@@ -2676,23 +2648,23 @@ Fl_Region MacRectRegionIntersect(Fl_Region current, int x,int y,int w, int h)
/* intersects current and x,y,w,h rectangle and returns result as a new Fl_Region
*/
{
- if(current == NULL) return XRectangleRegion(x,y,w,h);
+ if (current == NULL) return XRectangleRegion(x,y,w,h);
CGRect r = CGRectMake(x, y, w - 1, h - 1);
Fl_Region outr = (Fl_Region)malloc(sizeof(*outr));
outr->count = current->count;
outr->rects =(CGRect*)malloc(outr->count * sizeof(CGRect));
int j = 0;
for(int i = 0; i < current->count; i++) {
- CGRect test = CGRectIntersection(current->rects[i], r);
- if(!CGRectIsEmpty(test)) outr->rects[j++] = test;
+ CGRect test = CGRectIntersection(current->rects[i], r);
+ if (!CGRectIsEmpty(test)) outr->rects[j++] = test;
}
- if(j) {
- outr->count = j;
- outr->rects = (CGRect*)realloc(outr->rects, outr->count * sizeof(CGRect));
+ if (j) {
+ outr->count = j;
+ outr->rects = (CGRect*)realloc(outr->rects, outr->count * sizeof(CGRect));
}
else {
- XDestroyRegion(outr);
- outr = XRectangleRegion(0,0,0,0);
+ XDestroyRegion(outr);
+ outr = XRectangleRegion(0,0,0,0);
}
return outr;
}
@@ -2703,7 +2675,7 @@ void MacCollapseWindow(Window w)
}
static NSImage *CGBitmapContextToNSImage(CGContextRef c)
-//the returned NSImage is autoreleased
+// the returned NSImage is autoreleased
{
unsigned char *pdata = (unsigned char *)CGBitmapContextGetData(c);
NSBitmapImageRep *imagerep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pdata
@@ -2723,7 +2695,7 @@ static NSImage *CGBitmapContextToNSImage(CGContextRef c)
static NSCursor *PrepareCursor(NSCursor *cursor, CGContextRef (*f)() )
{
- if(cursor == nil) {
+ if (cursor == nil) {
CGContextRef c = f();
NSImage *image = CGBitmapContextToNSImage(c);
fl_delete_offscreen( (Fl_Offscreen)c );
@@ -2794,14 +2766,14 @@ int MACscreen_init(XRectangle screens[])
NSRect r;
int i, num_screens = 0;
for( i = 0; i < count; i++) {
- r = [[a objectAtIndex:i] frame];
+ r = [[a objectAtIndex:i] frame];
screens[num_screens].x = r.origin.x;
screens[num_screens].y = r.size.height - (r.origin.y + r.size.height);
screens[num_screens].width = r.size.width;
screens[num_screens].height = r.size.height;
num_screens ++;
if (num_screens >= 16) break;
- }
+ }
[localPool release];
return num_screens;
}
@@ -2827,7 +2799,7 @@ static NSMenu *appleMenu;
static void createAppleMenu(void)
{
static BOOL donethat = NO;
- if(donethat) return;
+ if (donethat) return;
donethat = YES;
NSMenu *mainmenu, *services;
NSMenuItem *menuItem;
@@ -2845,7 +2817,7 @@ static void createAppleMenu(void)
[[appleMenu itemAtIndex:0] setTarget:about];
[appleMenu addItem:[NSMenuItem separatorItem]];
// Services Menu
- services = [[[NSMenu alloc] init] autorelease];
+ services = [[NSMenu alloc] init];
[appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
[appleMenu setSubmenu: services forItem: [appleMenu itemWithTitle: @"Services"]];
// Hide AppName
@@ -2866,7 +2838,7 @@ static void createAppleMenu(void)
[menuItem setSubmenu:appleMenu];
mainmenu = [[NSMenu alloc] initWithTitle:@""];
[mainmenu addItem:menuItem];
- if(MACsystemVersion < 0x1060) {
+ if (MACsystemVersion < 0x1060) {
// [NSApp setAppleMenu:appleMenu];
// to avoid compiler warning raised by use of undocumented setAppleMenu :
[NSApp performSelector:@selector(setAppleMenu:) withObject:appleMenu];
@@ -2892,12 +2864,12 @@ static void createAppleMenu(void)
int flRank = [self tag];
const Fl_Menu_Item *items = fl_sys_menu_bar->Fl_Menu_::menu();
const Fl_Menu_Item *item = items + flRank;
- if(item) {
+ if (item) {
fl_sys_menu_bar->picked(item);
- if ( item->flags & FL_MENU_TOGGLE ) {// update the menu toggle symbol
+ if ( item->flags & FL_MENU_TOGGLE ) { // update the menu toggle symbol
[self setState:(item->value() ? NSOnState : NSOffState)];
}
- else if ( item->flags & FL_MENU_RADIO ) {// update the menu radio symbols
+ else if ( item->flags & FL_MENU_RADIO ) { // update the menu radio symbols
int from = flRank;
while( from > 0 && items[from - 1].label() && (items[from - 1].flags & FL_MENU_RADIO) &&
!(items[from - 1].flags & FL_MENU_DIVIDER) ) {
@@ -2912,7 +2884,7 @@ static void createAppleMenu(void)
int nsrank = (int)[nsmenu indexOfItem:self];
for(int i = from - flRank + nsrank ; i <= to - flRank + nsrank; i++) {
NSMenuItem *nsitem = [nsmenu itemAtIndex:i];
- if(nsitem != self) [nsitem setState:NSOffState];
+ if (nsitem != self) [nsitem setState:NSOffState];
else [nsitem setState:(item->value() ? NSOnState : NSOffState) ];
}
}
@@ -2921,7 +2893,7 @@ static void createAppleMenu(void)
- (void) directCallback:(id)unused
{
Fl_Menu_Item *item = (Fl_Menu_Item *)[(NSData*)[self representedObject] bytes];
- if( item && item->callback() ) item->do_callback(NULL);
+ if ( item && item->callback() ) item->do_callback(NULL);
}
@end
@@ -2952,10 +2924,10 @@ void fl_mac_set_about( Fl_Callback *cb, void *user_data, int shortcut)
FLMenuItem *item = [[[FLMenuItem alloc] initWithTitle:(NSString*)cfname
action:@selector(directCallback:)
keyEquivalent:@""] autorelease];
- if(aboutItem.shortcut()) {
+ if (aboutItem.shortcut()) {
Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setKeyEquivalent, item, aboutItem.shortcut() & 0xff);
Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setKeyEquivalentModifierMask, item, aboutItem.shortcut() );
- }
+ }
NSData *pointer = [NSData dataWithBytes:&aboutItem length:sizeof(Fl_Menu_Item)];
[item setRepresentedObject:pointer];
[appleMenu insertItem:item atIndex:0];
@@ -2998,12 +2970,12 @@ void *Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::menuOrItemOperatio
va_list ap;
va_start(ap, operation);
- if(operation == Fl_Sys_Menu_Bar::itemAtIndex) {//arguments: NSMenu*, int. Returns the item
+ if (operation == Fl_Sys_Menu_Bar::itemAtIndex) { // arguments: NSMenu*, int. Returns the item
menu = va_arg(ap, NSMenu*);
value = va_arg(ap, int);
retval = (void *)[menu itemAtIndex:value];
}
- else if(operation == Fl_Sys_Menu_Bar::setKeyEquivalent) {//arguments: NSMenuItem*, int
+ else if (operation == Fl_Sys_Menu_Bar::setKeyEquivalent) { // arguments: NSMenuItem*, int
item = va_arg(ap, NSMenuItem*);
value = va_arg(ap, int);
char key = value;
@@ -3011,7 +2983,7 @@ void *Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::menuOrItemOperatio
[item setKeyEquivalent:equiv];
[equiv release];
}
- else if(operation == Fl_Sys_Menu_Bar::setKeyEquivalentModifierMask) {//arguments: NSMenuItem*, int
+ else if (operation == Fl_Sys_Menu_Bar::setKeyEquivalentModifierMask) { // arguments: NSMenuItem*, int
item = va_arg(ap, NSMenuItem*);
value = va_arg(ap, int);
NSUInteger macMod = 0;
@@ -3021,13 +2993,13 @@ void *Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::menuOrItemOperatio
if ( value & FL_CTRL ) macMod |= NSControlKeyMask;
[item setKeyEquivalentModifierMask:macMod];
}
- else if(operation == Fl_Sys_Menu_Bar::setState) {//arguments: NSMenuItem*, int
+ else if (operation == Fl_Sys_Menu_Bar::setState) { // arguments: NSMenuItem*, int
item = va_arg(ap, NSMenuItem*);
value = va_arg(ap, int);
[item setState:(value ? NSOnState : NSOffState)];
}
- else if(operation == Fl_Sys_Menu_Bar::initWithTitle) {//arguments: const char*title. Returns the newly created menu
- //creates a new (sub)menu
+ else if (operation == Fl_Sys_Menu_Bar::initWithTitle) { // arguments: const char*title. Returns the newly created menu
+ // creates a new (sub)menu
char *ts = remove_ampersand(va_arg(ap, char *));
CFStringRef title = CFStringCreateWithCString(NULL, ts, kCFStringEncodingUTF8);
free(ts);
@@ -3036,29 +3008,29 @@ void *Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::menuOrItemOperatio
[menu setAutoenablesItems:NO];
retval = (void *)menu;
}
- else if(operation == Fl_Sys_Menu_Bar::numberOfItems) {//arguments: NSMenu *menu, int *pcount
- //upon return, *pcount is set to menu's item count
+ else if (operation == Fl_Sys_Menu_Bar::numberOfItems) { // arguments: NSMenu *menu, int *pcount
+ // upon return, *pcount is set to menu's item count
menu = va_arg(ap, NSMenu*);
pter = va_arg(ap, void *);
*(int*)pter = [menu numberOfItems];
}
- else if(operation == Fl_Sys_Menu_Bar::setSubmenu) {//arguments: NSMenuItem *item, NSMenu *menu
- //sets 'menu' as submenu attached to 'item'
+ else if (operation == Fl_Sys_Menu_Bar::setSubmenu) { // arguments: NSMenuItem *item, NSMenu *menu
+ // sets 'menu' as submenu attached to 'item'
item = va_arg(ap, NSMenuItem*);
menu = va_arg(ap, NSMenu*);
[item setSubmenu:menu];
[menu release];
}
- else if(operation == Fl_Sys_Menu_Bar::setEnabled) {//arguments: NSMenuItem*, int
+ else if (operation == Fl_Sys_Menu_Bar::setEnabled) { // arguments: NSMenuItem*, int
item = va_arg(ap, NSMenuItem*);
value = va_arg(ap, int);
[item setEnabled:(value ? YES : NO)];
}
- else if(operation == Fl_Sys_Menu_Bar::addSeparatorItem) {//arguments: NSMenu*
+ else if (operation == Fl_Sys_Menu_Bar::addSeparatorItem) { // arguments: NSMenu*
menu = va_arg(ap, NSMenu*);
[menu addItem:[NSMenuItem separatorItem]];
}
- else if(operation == Fl_Sys_Menu_Bar::setTitle) {//arguments: NSMenuItem*, const char *
+ else if (operation == Fl_Sys_Menu_Bar::setTitle) { // arguments: NSMenuItem*, const char *
item = va_arg(ap, NSMenuItem*);
char *ts = remove_ampersand(va_arg(ap, char *));
CFStringRef title = CFStringCreateWithCString(NULL, ts, kCFStringEncodingUTF8);
@@ -3066,15 +3038,15 @@ void *Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::menuOrItemOperatio
[item setTitle:(NSString*)title];
CFRelease(title);
}
- else if(operation == Fl_Sys_Menu_Bar::removeItem) {//arguments: NSMenu*, int
+ else if (operation == Fl_Sys_Menu_Bar::removeItem) { // arguments: NSMenu*, int
menu = va_arg(ap, NSMenu*);
value = va_arg(ap, int);
[menu removeItem:[menu itemAtIndex:value]];
}
- else if(operation == Fl_Sys_Menu_Bar::addNewItem) {//arguments: NSMenu *menu, int flrank, int *prank
- //creates a new menu item at the end of 'menu'
- //attaches the item of rank flrank (counted in Fl_Menu_) of fl_sys_menu_bar to it
- //upon return, puts the rank (counted in NSMenu) of the new item in *prank unless prank is NULL
+ else if (operation == Fl_Sys_Menu_Bar::addNewItem) { // arguments: NSMenu *menu, int flrank, int *prank
+ // creates a new menu item at the end of 'menu'
+ // attaches the item of rank flrank (counted in Fl_Menu_) of fl_sys_menu_bar to it
+ // upon return, puts the rank (counted in NSMenu) of the new item in *prank unless prank is NULL
menu = va_arg(ap, NSMenu*);
int flRank = va_arg(ap, int);
char *name = remove_ampersand( (fl_sys_menu_bar->Fl_Menu_::menu() + flRank)->label());
@@ -3088,27 +3060,27 @@ void *Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::menuOrItemOperatio
[menu addItem:item];
CFRelease(cfname);
[item setTarget:item];
- if(prank != NULL) *prank = [menu indexOfItem:item];
+ if (prank != NULL) *prank = [menu indexOfItem:item];
[item release];
- }
- else if(operation == Fl_Sys_Menu_Bar::renameItem) {//arguments: int rank, const char *newname
- //renames the system menu item numbered rank in fl_sys_menu_bar->menu()
+ }
+ else if (operation == Fl_Sys_Menu_Bar::renameItem) { // arguments: int rank, const char *newname
+ // renames the system menu item numbered rank in fl_sys_menu_bar->menu()
int rank = va_arg(ap, int);
char *newname = remove_ampersand( va_arg(ap, const char *) );
int countmenus = [(NSMenu*)fl_system_menu numberOfItems];
bool found = NO;
- NSMenuItem *macitem;
+ NSMenuItem *macitem = 0;
for(int i = 1; (!found) && i < countmenus; i++) {
NSMenuItem *item = [(NSMenu*)fl_system_menu itemAtIndex:i];
NSMenu *submenu = [item submenu];
- if(submenu == nil) continue;
+ if (submenu == nil) continue;
int countitems = [submenu numberOfItems];
for(int j = 0; j < countitems; j++) {
macitem = [submenu itemAtIndex:j];
- if([macitem tag] == rank) { found = YES; break; }
+ if ([macitem tag] == rank) { found = YES; break; }
}
}
- if(found) {
+ if (found) {
[macitem setTitle:[[[NSString alloc] initWithUTF8String:newname] autorelease]];
}
free(newname);
@@ -3133,13 +3105,13 @@ static NSImage *imageFromText(const char *text, int *pwidth, int *pheight)
while((q=strchr(p, '\n')) != NULL) {
nl++;
w2 = fl_width(p, q - p);
- if(w2 > width) width = w2;
+ if (w2 > width) width = w2;
p = q + 1;
}
- if(text[ ltext - 1] != '\n') {
+ if (text[ ltext - 1] != '\n') {
nl++;
w2 = fl_width(p);
- if(w2 > width) width = w2;
+ if (w2 > width) width = w2;
}
height = nl * fl_height() + 3;
width += 6;
@@ -3152,8 +3124,9 @@ static NSImage *imageFromText(const char *text, int *pwidth, int *pheight)
int y = fl_height();
while(TRUE) {
q = strchr(p, '\n');
- if(q) fl_draw(p, q - p, 3, y);
- else {
+ if (q) {
+ fl_draw(p, q - p, 3, y);
+ } else {
fl_draw(p, 3, y);
break;
}
@@ -3198,20 +3171,22 @@ int MACpreparedrag(void)
CFRelease(text);
Fl_Widget *w = Fl::pushed();
Fl_Window *win = w->window();
- if(win == NULL) { win = (Fl_Window*)w; }
- else { while(win->window()) win = win->window(); }
+ if (win == NULL) {
+ win = (Fl_Window*)w;
+ } else {
+ while(win->window()) win = win->window();
+ }
NSView *myview = [(NSWindow*)Fl_X::i(win)->xid contentView];
NSEvent *theEvent = [NSApp currentEvent];
int width, height;
NSImage *image;
- if( dynamic_cast<Fl_Input_*>(w) != NULL) {
+ if ( dynamic_cast<Fl_Input_*>(w) != NULL) {
fl_selection_buffer[0][ fl_selection_length[0] ] = 0;
image = imageFromText(fl_selection_buffer[0], &width, &height);
- }
- else {
+ } else {
image = defaultDragImage(&width, &height);
- }
+ }
static NSSize offset={0,0};
NSPoint pt = [theEvent locationInWindow];
@@ -3220,8 +3195,7 @@ int MACpreparedrag(void)
[myview dragImage:image at:pt offset:offset
event:theEvent pasteboard:mypasteboard
source:myview slideBack:YES];
- if ( w )
- {
+ if ( w ) {
int old_event = Fl::e_number;
w->handle(Fl::e_number = FL_RELEASE);
Fl::e_number = old_event;
@@ -3232,20 +3206,20 @@ int MACpreparedrag(void)
}
unsigned char *MACbitmapFromRectOfWindow(Fl_Window *win, int x, int y, int w, int h, int *bytesPerPixel)
-//delete the returned pointer after use
+// delete the returned pointer after use
{
while(win->window()) {
- x += win->x();
- y += win->y();
- win = win->window();
+ x += win->x();
+ y += win->y();
+ win = win->window();
}
NSView *myview = [(NSWindow*)Fl_X::i(win)->xid contentView];
[myview lockFocus];
CGFloat epsilon = 0;
- if(MACsystemVersion >= 0x1060) epsilon = 0.001;
- //The epsilon offset is absolutely necessary under 10.6. Without it, the top pixel row and
- //left pixel column are not read, and bitmap is read shifted by one pixel in both directions.
- //Under 10.5, we want no offset.
+ if (MACsystemVersion >= 0x1060) epsilon = 0.001;
+ // The epsilon offset is absolutely necessary under 10.6. Without it, the top pixel row and
+ // left pixel column are not read, and bitmap is read shifted by one pixel in both directions.
+ // Under 10.5, we want no offset.
NSRect rect = NSMakeRect(x - epsilon, y - epsilon, w, h);
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:rect];
[myview unlockFocus];
@@ -3262,7 +3236,7 @@ void imgProviderReleaseData (void *info, const void *data, size_t size)
}
CGImageRef MAC_CGImageFromRectOfWindow(Fl_Window *win, int x, int y, int w, int h)
-//CFRelease the returned CGImageRef after use
+// CFRelease the returned CGImageRef after use
{
int bpp;
unsigned char *bitmap = MACbitmapFromRectOfWindow(win, x, y, w, h, &bpp);
@@ -3284,10 +3258,10 @@ void MACsetContainsGLsubwindow(Fl_Window *w)
WindowRef MACwindowRef(Fl_Window *w)
{
- return (WindowRef)[(FLWindow*)Fl_X::i(w)->xid windowRef];
+ return (WindowRef)[(FLWindow*)Fl_X::i(w)->xid windowRef];
}
#endif // FL_DOXYGEN
//
-// End of "$Id: Fl_mac.cxx 6971 2009-04-13 07:32:01Z matt $".
+// End of "$Id: Fl_cocoa.mm 6971 2009-04-13 07:32:01Z matt $".
//
diff --git a/src/Makefile b/src/Makefile
index 0aa6ed1ba..f1ef45132 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -63,6 +63,7 @@ CPPFILES = \
Fl_Menu_add.cxx \
Fl_Menu_global.cxx \
Fl_Multi_Label.cxx \
+ Fl_Native_File_Chooser.cxx \
Fl_Overlay_Window.cxx \
Fl_Pack.cxx \
Fl_Pixmap.cxx \
@@ -476,6 +477,8 @@ include makedepend
# These dependencies aren't part of the makedepend file since
# they are part of the WIN32 and MacOS code base...
Fl_get_key.o: Fl_get_key_mac.cxx Fl_get_key_win32.cxx
+Fl_Native_File_Chooser.o : Fl_Native_File_Chooser_MAC.cxx Fl_Native_File_Chooser_WIN32.cxx \
+ Fl_Native_File_Chooser_FLTK.cxx
Fl.o: Fl_mac.cxx Fl_win32.cxx Fl_cocoa.mm
fl_color.o: fl_color_mac.cxx fl_color_win32.cxx
fl_dnd.o: fl_dnd_mac.cxx fl_dnd_win32.cxx fl_dnd_x.cxx
@@ -512,6 +515,9 @@ Fl_Image.o: ../FL/mac.H ../FL/win32.H
fl_line_style.o: ../FL/mac.H ../FL/win32.H
Fl_mac.o: ../FL/mac.H ../FL/win32.H
Fl_cocoa.o: ../FL/mac.H ../FL/win32.H
+Fl_Native_File_Chooser_MAC.o: ../FL/Fl_Native_File_Chooser.H ../FL/Fl_Native_File_Chooser_MAC.H
+Fl_Native_File_Chooser_WIN32.o: ../FL/Fl_Native_File_Chooser.H ../FL/Fl_Native_File_Chooser_WIN32.H
+Fl_Native_File_Chooser_FLTK.o: ../FL/Fl_Native_File_Chooser.H ../FL/Fl_Native_File_Chooser_FLTK.H
Fl_Menu_Window.o: ../FL/mac.H ../FL/win32.H
fl_overlay.o: ../FL/mac.H ../FL/win32.H
fl_overlay_visual.o: ../FL/mac.H ../FL/win32.H
diff --git a/src/makedepend b/src/makedepend
index 39a259f75..7a39ebd35 100644
--- a/src/makedepend
+++ b/src/makedepend
@@ -215,6 +215,8 @@ Fl_Multi_Label.o: ../FL/fl_types.h ../FL/Xutf8.h ../FL/Enumerations.H
Fl_Multi_Label.o: ../FL/Fl_Export.H ../FL/fl_types.h ../FL/Fl_Widget.H
Fl_Multi_Label.o: ../FL/Fl_Menu_Item.H ../FL/Fl_Widget.H ../FL/Fl_Image.H
Fl_Multi_Label.o: ../FL/Fl_Multi_Label.H
+Fl_Native_File_Chooser.o: ../config.h Fl_Native_File_Chooser_common.cxx \
+ ../FL/Fl_Native_File_Chooser.H ../FL/Fl.H ../FL/filename.H
Fl_Overlay_Window.o: ../config.h ../FL/Fl.H ../FL/fl_utf8.h ../FL/Fl_Export.H
Fl_Overlay_Window.o: ../FL/fl_types.h ../FL/Xutf8.h ../FL/Enumerations.H
Fl_Overlay_Window.o: ../FL/Fl_Export.H ../FL/fl_types.h
diff --git a/src/makefile.wat b/src/makefile.wat
index 87ae4d3c3..637474137 100644
--- a/src/makefile.wat
+++ b/src/makefile.wat
@@ -61,6 +61,7 @@ CPPFILES = &
Fl_Menu_add.obj &
Fl_Menu_global.obj &
Fl_Multi_Label.obj &
+ Fl_Native_File_Chooser.obj &
Fl_Overlay_Window.obj &
Fl_Pack.obj &
Fl_Pixmap.obj &
diff --git a/test/Makefile b/test/Makefile
index 1f8b91aad..6479e2c61 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -74,6 +74,7 @@ CPPFILES =\
menubar.cxx \
message.cxx \
minimum.cxx \
+ native-filechooser.cxx \
navigation.cxx \
output.cxx \
overlay.cxx \
@@ -139,6 +140,7 @@ ALL = \
menubar$(EXEEXT) \
message$(EXEEXT) \
minimum$(EXEEXT) \
+ native-filechooser$(EXEEXT) \
navigation$(EXEEXT) \
output$(EXEEXT) \
overlay$(EXEEXT) \
@@ -377,6 +379,8 @@ message$(EXEEXT): message.o
minimum$(EXEEXT): minimum.o
+native-filechooser$(EXEEXT): native-filechooser.o
+
navigation$(EXEEXT): navigation.o
output$(EXEEXT): output.o $(FLLIBNAME)
diff --git a/test/makefile.wat b/test/makefile.wat
index c1e83b9c2..44d3d4821 100644
--- a/test/makefile.wat
+++ b/test/makefile.wat
@@ -62,6 +62,7 @@ ALL = &
$(ODIR)/menubar$(EXEEXT) &
$(ODIR)/message$(EXEEXT) &
$(ODIR)/minimum$(EXEEXT) &
+ $(ODIR)/native-filechooser$(EXEEXT) &
$(ODIR)/navigation$(EXEEXT) &
$(ODIR)/output$(EXEEXT) &
$(ODIR)/overlay$(EXEEXT) &
@@ -179,6 +180,8 @@ $(ODIR)/message$(EXEEXT) : $(ODIR)/message.obj
$(ODIR)/minimum$(EXEEXT) : $(ODIR)/minimum.obj
+$(ODIR)/native-filechooser$(EXEEXT) : $(ODIR)/native-filechooser.obj
+
$(ODIR)/navigation$(EXEEXT) : $(ODIR)/navigation.obj
$(ODIR)/output$(EXEEXT) : $(ODIR)/output.obj
diff --git a/test/native-filechooser.cxx b/test/native-filechooser.cxx
new file mode 100644
index 000000000..e4655e6e6
--- /dev/null
+++ b/test/native-filechooser.cxx
@@ -0,0 +1,83 @@
+//
+// "$Id$"
+//
+// Simple test of the Fl_Native_File_Chooser.
+//
+// Copyright 1998-2009 by Bill Spitzak and others.
+// Copyright 2004 Greg Ercolano.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+#include <stdio.h>
+#include <FL/Fl.H>
+#include <FL/fl_ask.H> // fl_beep()
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Input.H>
+#include <FL/Fl_Native_File_Chooser.H>
+
+// GLOBALS
+Fl_Input *G_filename = NULL;
+
+void Butt_CB(Fl_Widget*, void*) {
+ // Create native chooser
+ Fl_Native_File_Chooser native;
+ native.title("Pick a file");
+ native.type(Fl_Native_File_Chooser::BROWSE_FILE);
+ native.filter("Text\t*.txt\n"
+ "C Files\t*.{cxx,h,c}\n"
+ "Apps\t*.{app}\n"); // TODO: need to add kNavSupportPackages to non-cocoa <FNFC>_MAC.cxx
+ native.preset_file(G_filename->value());
+ // Show native chooser
+ switch ( native.show() ) {
+ case -1: fprintf(stderr, "ERROR: %s\n", native.errmsg()); break; // ERROR
+ case 1: fprintf(stderr, "*** CANCEL\n"); fl_beep(); break; // CANCEL
+ default: // PICKED FILE
+ if ( native.filename() ) {
+ G_filename->value(native.filename());
+ } else {
+ G_filename->value("NULL");
+ }
+ break;
+ }
+}
+
+int main(int argc, char **argv) {
+ //// For a nicer looking browser under linux, uncomment the following line.
+ //// (If you do this, you'll need to link with fltk_images)
+ ////
+ //// Fl_File_Icon::load_system_icons();
+
+ Fl_Window *win = new Fl_Window(600, 100, "FLTK Window");
+ win->begin();
+ {
+ int y = 10;
+ G_filename = new Fl_Input(80, y, win->w()-80-10, 25, "Filename");
+ G_filename->value(argc < 2 ? "." : argv[1]);
+ G_filename->tooltip("Default filename");
+ y += G_filename->h() + 5;
+ Fl_Button *but = new Fl_Button(win->w()-80-10, win->h()-25-10, 80, 25, "Pick File");
+ but->callback(Butt_CB);
+ }
+ win->end();
+ win->resizable(win);
+ win->show();
+ return(Fl::run());
+}