summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Fl.cxx52
-rw-r--r--src/Fl_Bitmap.cxx4
-rw-r--r--src/Fl_Font.H3
-rw-r--r--src/Fl_Gl_Choice.cxx62
-rw-r--r--src/Fl_Gl_Window.cxx29
-rw-r--r--src/Fl_Input.cxx606
-rw-r--r--src/Fl_Sys_Menu_Bar.cxx193
-rw-r--r--src/Fl_Window.cxx5
-rw-r--r--src/Fl_Window_iconize.cxx4
-rw-r--r--src/Fl_arg.cxx7
-rw-r--r--src/Fl_cocoa.mm3105
-rw-r--r--src/Fl_compose.cxx12
-rw-r--r--src/Fl_grab.cxx18
-rw-r--r--src/cgdebug.h1
-rw-r--r--src/fl_arci.cxx12
-rw-r--r--src/fl_ask.cxx3
-rw-r--r--src/fl_cursor.cxx111
-rw-r--r--src/fl_dnd_mac.cxx6
-rw-r--r--src/fl_font_mac.cxx199
-rw-r--r--src/fl_line_style.cxx11
-rw-r--r--src/fl_read_image_mac.cxx32
-rw-r--r--src/fl_rect.cxx202
-rw-r--r--src/fl_scroll_area.cxx12
-rw-r--r--src/fl_set_fonts_mac.cxx31
-rw-r--r--src/fl_vertex.cxx37
-rw-r--r--src/gl_draw.cxx111
-rw-r--r--src/makedepend8
-rw-r--r--src/screen_xywh.cxx5
28 files changed, 4453 insertions, 428 deletions
diff --git a/src/Fl.cxx b/src/Fl.cxx
index 1c39c0323..87379ed4f 100644
--- a/src/Fl.cxx
+++ b/src/Fl.cxx
@@ -40,6 +40,10 @@
#include <stdlib.h>
#include "flstring.h"
+#if defined(__APPLE__) && defined(__APPLE_COCOA__)
+#import <Cocoa/Cocoa.h>
+#endif
+
#ifdef DEBUG
# include <stdio.h>
#endif // DEBUG
@@ -406,10 +410,17 @@ double Fl::wait(double time_to_wait) {
// the idle function may turn off idle, we can then wait:
if (idle) time_to_wait = 0.0;
}
+#ifdef __APPLE_COCOA__
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+#endif
flush();
if (idle && !in_idle) // 'idle' may have been set within flush()
time_to_wait = 0.0;
- return fl_wait(time_to_wait);
+ double retval = fl_wait(time_to_wait);
+#ifdef __APPLE_COCOA__
+ [pool release];
+#endif
+ return retval;
#else
@@ -586,12 +597,13 @@ Fl_Window* fl_find(Window xid) {
Fl_X *window;
for (Fl_X **pp = &Fl_X::first; (window = *pp); pp = &window->next)
#if defined(WIN32) || defined(USE_X11)
- if (window->xid == xid) {
+ if (window->xid == xid)
#elif defined(__APPLE_QUARTZ__)
- if (window->xid == xid && !window->w->window()) {
+ if (window->xid == xid && !window->w->window())
#else
# error unsupported platform
#endif // __APPLE__
+ {
if (window != Fl_X::first && !Fl::modal()) {
// make this window be first to speed up searches
// this is not done if modal is true to avoid messing up modal stack
@@ -1278,7 +1290,11 @@ int Fl_Window::handle(int ev)
#if defined(USE_X11) || defined(WIN32)
XMapWindow(fl_display, fl_xid(this)); // extra map calls are harmless
#elif defined(__APPLE_QUARTZ__)
- MacMapWindow(this, fl_xid(this));
+#ifdef __APPLE_COCOA__
+ MacMapWindow(this, i->xid);
+#else
+ MacMapWindow(this, fl_xid(this));
+#endif
#else
# error unsupported platform
#endif // __APPLE__
@@ -1300,7 +1316,11 @@ int Fl_Window::handle(int ev)
#if defined(USE_X11) || defined(WIN32)
XUnmapWindow(fl_display, fl_xid(this));
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ MacUnmapWindow(this, i->xid);
+#else
MacUnmapWindow(this, fl_xid(this));
+#endif
#else
# error platform unsupported
#endif
@@ -1453,10 +1473,22 @@ void Fl_Widget::damage(uchar fl, int X, int Y, int W, int H) {
CombineRgn(i->region, i->region, R, RGN_OR);
XDestroyRegion(R);
#elif defined(__APPLE_QUARTZ__)
- Fl_Region R = NewRgn();
- SetRectRgn(R, X, Y, X+W, Y+H);
- UnionRgn(R, i->region, i->region);
- DisposeRgn(R);
+#ifdef __APPLE_COCOA__
+ CGRect arg = CGRectMake(X,Y,W - 1,H - 1);
+ int j;//don't add a rectangle totally inside the Fl_Region
+ for(j = 0; j < i->region->count; j++) {
+ if(CGRectContainsRect(i->region->rects[j], arg)) break;
+ }
+ if( j >= i->region->count) {
+ i->region->rects = (CGRect*)realloc(i->region->rects, (++(i->region->count)) * sizeof(CGRect));
+ i->region->rects[i->region->count - 1] = arg;
+ }
+#else
+ Fl_Region R = NewRgn();
+ SetRectRgn(R, X, Y, X+W, Y+H);
+ UnionRgn(R, i->region, i->region);
+ DisposeRgn(R);
+#endif
#else
# error unsupported platform
#endif
@@ -1480,8 +1512,12 @@ void Fl_Window::flush() {
#ifdef WIN32
# include "Fl_win32.cxx"
#elif defined(__APPLE__)
+#ifdef __APPLE_COCOA__
+# include "Fl_cocoa.mm"
+#else
# include "Fl_mac.cxx"
#endif
+#endif
//
// The following methods allow callbacks to schedule the deletion of
diff --git a/src/Fl_Bitmap.cxx b/src/Fl_Bitmap.cxx
index 76a10a589..26019091b 100644
--- a/src/Fl_Bitmap.cxx
+++ b/src/Fl_Bitmap.cxx
@@ -325,7 +325,11 @@ Fl_Bitmap::~Fl_Bitmap() {
void Fl_Bitmap::uncache() {
if (id) {
+#if defined(__APPLE__) && defined(__APPLE_COCOA__)
+ fl_delete_bitmask((Fl_Bitmask)id);
+#else
fl_delete_bitmask((Fl_Offscreen)id);
+#endif
id = 0;
}
}
diff --git a/src/Fl_Font.H b/src/Fl_Font.H
index 6bb2e724e..3a4408cb5 100644
--- a/src/Fl_Font.H
+++ b/src/Fl_Font.H
@@ -67,6 +67,9 @@ public:
# elif defined(__APPLE_QUARTZ__)
FL_EXPORT Fl_Font_Descriptor(const char* fontname, Fl_Fontsize size);
ATSUTextLayout layout;
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ CTFontRef fontref;
+#endif
ATSUStyle style;
short ascent, descent, q_width;
// short width[256];
diff --git a/src/Fl_Gl_Choice.cxx b/src/Fl_Gl_Choice.cxx
index 476bb08d8..a831eb4b6 100644
--- a/src/Fl_Gl_Choice.cxx
+++ b/src/Fl_Gl_Choice.cxx
@@ -295,21 +295,35 @@ GLContext fl_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int lay
}
# elif defined(__APPLE_QUARTZ__)
- // warning: the Quartz version should probably use Core GL (CGL) instead of AGL
- GLContext fl_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) {
- GLContext context, shared_ctx = 0;
- if (context_list && nContext) shared_ctx = context_list[0];
- context = aglCreateContext( g->pixelformat, shared_ctx);
- if (!context) return 0;
- add_context((GLContext)context);
- if ( window->parent() ) {
- Rect wrect; GetWindowPortBounds( fl_xid(window), &wrect );
- GLint rect[] = { window->x(), wrect.bottom-window->h()-window->y(), window->w(), window->h() };
- aglSetInteger( (GLContext)context, AGL_BUFFER_RECT, rect );
- aglEnable( (GLContext)context, AGL_BUFFER_RECT );
- }
- aglSetDrawable( context, GetWindowPort( fl_xid(window) ) );
- return (context);
+// warning: the Quartz version should probably use Core GL (CGL) instead of AGL
+GLContext fl_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) {
+ GLContext context, shared_ctx = 0;
+ if (context_list && nContext) shared_ctx = context_list[0];
+ context = aglCreateContext( g->pixelformat, shared_ctx);
+ if (!context) return 0;
+ add_context((GLContext)context);
+ if ( window->parent() ) {
+#ifdef __APPLE_COCOA__
+ int H = window->window()->h();
+ GLint rect[] = { window->x(), H-window->h()-window->y(), window->w(), window->h() };
+#else
+ Rect wrect;
+ GetWindowPortBounds( fl_xid(window), &wrect );
+ GLint rect[] = { window->x(), wrect.bottom-window->h()-window->y(), window->w(), window->h() };
+#endif
+ aglSetInteger( (GLContext)context, AGL_BUFFER_RECT, rect );
+ aglEnable( (GLContext)context, AGL_BUFFER_RECT );
+ }
+#if defined(__APPLE_COCOA__)
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ aglSetWindowRef(context, MACwindowRef(window) );
+#else
+ aglSetDrawable( context, GetWindowPort( MACwindowRef(window) ) );
+#endif
+#else
+ aglSetDrawable( context, GetWindowPort( fl_xid(window) ) );
+#endif
+ return (context);
}
# else
# error unsupported platform
@@ -329,12 +343,26 @@ void fl_set_gl_context(Fl_Window* w, GLContext context) {
# elif defined(__APPLE_QUARTZ__)
// warning: the Quartz version should probably use Core GL (CGL) instead of AGL
if ( w->parent() ) { //: resize our GL buffer rectangle
- Rect wrect; GetWindowPortBounds( fl_xid(w), &wrect );
+#ifdef __APPLE_COCOA__
+ int H = w->window()->h();
+ GLint rect[] = { w->x(), H-w->h()-w->y(), w->w(), w->h() };
+#else
+ Rect wrect;
+ GetWindowPortBounds( fl_xid(w), &wrect );
GLint rect[] = { w->x(), wrect.bottom-w->h()-w->y(), w->w(), w->h() };
+#endif
aglSetInteger( context, AGL_BUFFER_RECT, rect );
aglEnable( context, AGL_BUFFER_RECT );
}
- aglSetDrawable(context, GetWindowPort( fl_xid(w) ) );
+#if defined(__APPLE_COCOA__)
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ aglSetWindowRef(context, MACwindowRef(w) );
+#else
+ aglSetDrawable( context, GetWindowPort( MACwindowRef(w) ) );
+#endif
+#else
+ aglSetDrawable( context, GetWindowPort( fl_xid(w) ) );
+#endif
aglSetCurrentContext(context);
# else
# error unsupported platform
diff --git a/src/Fl_Gl_Window.cxx b/src/Fl_Gl_Window.cxx
index ae84f38de..b5b052075 100644
--- a/src/Fl_Gl_Window.cxx
+++ b/src/Fl_Gl_Window.cxx
@@ -66,6 +66,9 @@ int Fl_Gl_Window::can_do(int a, const int *b) {
}
void Fl_Gl_Window::show() {
+#if defined(__APPLE__) && defined(__APPLE_COCOA__)
+ int need_redraw = 0;
+#endif
if (!shown()) {
if (!g) {
g = Fl_Gl_Choice::find(mode_,alist);
@@ -83,12 +86,19 @@ void Fl_Gl_Window::show() {
#if !defined(WIN32) && !defined(__APPLE__)
Fl_X::make_xid(this, g->vis, g->colormap);
if (overlay && overlay != this) ((Fl_Gl_Window*)overlay)->show();
+#elif defined(__APPLE__) && defined(__APPLE_COCOA__)
+ extern void MACsetContainsGLsubwindow(Fl_Window *);
+ if( ! parent() ) need_redraw=1;
+ else MACsetContainsGLsubwindow( window() );
#endif
}
Fl_Window::show();
#ifdef __APPLE__
set_visible();
+#ifdef __APPLE_COCOA__
+ if(need_redraw) redraw();//necessary only after creation of a top-level GL window
+#endif
#endif /* __APPLE__ */
}
@@ -154,6 +164,7 @@ int Fl_Gl_Window::mode(int m, const int *a) {
being called and can also be used to implement feedback and/or
selection within the handle() method.
*/
+
void Fl_Gl_Window::make_current() {
// puts("Fl_Gl_Window::make_current()");
// printf("make_current: context_=%p\n", context_);
@@ -237,6 +248,15 @@ void Fl_Gl_Window::swap_buffers() {
# endif
#elif defined(__APPLE_QUARTZ__)
// warning: the Quartz version should probably use Core GL (CGL) instead of AGL
+#ifdef __APPLE_COCOA__
+ if(overlay != NULL) {
+ //aglSwapBuffers does not work well with overlays under cocoa
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_FRONT);
+ glCopyPixels(0,0,w(),h(),GL_COLOR);
+ }
+ else
+#endif
aglSwapBuffers((AGLContext)context_);
#else
# error unsupported platform
@@ -248,6 +268,7 @@ uchar fl_overlay; // changes how fl_color() works
int fl_overlay_depth = 0;
#endif
+
void Fl_Gl_Window::flush() {
uchar save_valid = valid_f_ & 1;
#if HAVE_GL_OVERLAY && defined(WIN32)
@@ -257,13 +278,19 @@ void Fl_Gl_Window::flush() {
#if defined(__APPLE_QUARTZ__)
// warning: the Quartz version should probably use Core GL (CGL) instead of AGL
//: clear previous clipping in this shared port
+#if ! __LP64__
+#ifdef __APPLE_COCOA__
+ GrafPtr port = GetWindowPort( MACwindowRef(this) );
+#else
GrafPtr port = GetWindowPort( fl_xid(this) );
+#endif
Rect rect; SetRect( &rect, 0, 0, 0x7fff, 0x7fff );
GrafPtr old; GetPort( &old );
SetPort( port );
ClipRect( &rect );
SetPort( old );
#endif
+#endif
#if HAVE_GL_OVERLAY && defined(WIN32)
@@ -327,7 +354,7 @@ void Fl_Gl_Window::flush() {
// don't draw if only the overlay is damaged:
if (damage() != FL_DAMAGE_OVERLAY || !save_valid) draw();
- swap_buffers();
+ swap_buffers();
} else { // SWAP_TYPE == UNDEFINED
diff --git a/src/Fl_Input.cxx b/src/Fl_Input.cxx
index 67b5f2357..92d3e1d36 100644
--- a/src/Fl_Input.cxx
+++ b/src/Fl_Input.cxx
@@ -82,18 +82,18 @@ static const char *legal_fp_chars = ".eE+-";
#endif
int Fl_Input::handle_key() {
-
+
char ascii = Fl::event_text()[0];
-
+
int repeat_num=1;
-
+
int del;
if (Fl::compose(del)) {
-
+
// Insert characters into numeric fields after checking for legality:
if (input_type() == FL_FLOAT_INPUT || input_type() == FL_INT_INPUT) {
Fl::compose_reset(); // ignore any foreign letters...
-
+
// initialize the list of legal characters inside a floating point number
#ifdef HAVE_LOCALECONV
if (!legal_fp_chars) {
@@ -108,7 +108,7 @@ int Fl_Input::handle_key() {
// the following line is not a true memory leak because the array is only
// allocated once if required, and automatically freed when the program quits
char *chars = (char*)malloc(len+1);
- legal_fp_chars = chars;
+ legal_fp_chars = chars;
strcpy(chars, standard_fp_chars);
if (lc) {
if (lc->decimal_point) strcat(chars, lc->decimal_point);
@@ -118,7 +118,7 @@ int Fl_Input::handle_key() {
}
}
#endif // HAVE_LOCALECONV
-
+
// find the insert position
int ip = position()<mark() ? position() : mark();
// This is complex to allow "0xff12" hex to be typed:
@@ -129,353 +129,353 @@ int Fl_Input::handle_key() {
&& (ascii>='A'&& ascii<='F' || ascii>='a'&& ascii<='f'))
|| input_type()==FL_FLOAT_INPUT && ascii && strchr(legal_fp_chars, ascii))
{
- if (readonly()) fl_beep();
- else replace(position(), mark(), &ascii, 1);
+ if (readonly()) fl_beep();
+ else replace(position(), mark(), &ascii, 1);
}
return 1;
}
-
+
if (del || Fl::event_length()) {
if (readonly()) fl_beep();
else replace(position(), del ? position()-del : mark(),
- Fl::event_text(), Fl::event_length());
+ Fl::event_text(), Fl::event_length());
}
return 1;
}
-
+
unsigned int mods = Fl::event_state() & (FL_META|FL_CTRL|FL_ALT);
switch (Fl::event_key()) {
- case FL_Insert:
- if (Fl::event_state() & FL_CTRL) ascii = ctrl('C');
- else if (Fl::event_state() & FL_SHIFT) ascii = ctrl('V');
- break;
- case FL_Delete:
+ case FL_Insert:
+ if (Fl::event_state() & FL_CTRL) ascii = ctrl('C');
+ else if (Fl::event_state() & FL_SHIFT) ascii = ctrl('V');
+ break;
+ case FL_Delete:
#ifdef __APPLE__
- if (mods==0 || mods==FL_CTRL) { // delete next char
- ascii = ctrl('D');
- } else if (mods==FL_ALT) { // delete next word
- if (mark() != position()) return cut();
- cut(position(), word_end(position()));
- return 1;
- } else if (mods==FL_META) { // delete to the end of the line
- if (mark() != position()) return cut();
- cut(position(), line_end(position()));
- return 1;
- } else return 1;
+ if (mods==0 || mods==FL_CTRL) { // delete next char
+ ascii = ctrl('D');
+ } else if (mods==FL_ALT) { // delete next word
+ if (mark() != position()) return cut();
+ cut(position(), word_end(position()));
+ return 1;
+ } else if (mods==FL_META) { // delete to the end of the line
+ if (mark() != position()) return cut();
+ cut(position(), line_end(position()));
+ return 1;
+ } else return 1;
#else
- if (mods==0) {
- ascii = ctrl('D');
- } else if (mods==FL_SHIFT) {
- ascii = ctrl('X');
- } else return 1;
+ if (mods==0) {
+ ascii = ctrl('D');
+ } else if (mods==FL_SHIFT) {
+ ascii = ctrl('X');
+ } else return 1;
#endif
- break;
- case FL_Left:
+ break;
+ case FL_Left:
#ifdef __APPLE__
- if (mods==0) { // char left
- ascii = ctrl('B');
- } else if (mods==FL_ALT) { // word left
- shift_position(word_start(position()));
- return 1;
- } else if (mods==FL_CTRL || mods==FL_META) { // start of line
- shift_position(line_start(position()));
- return 1;
- } else return 1;
+ if (mods==0) { // char left
+ ascii = ctrl('B');
+ } else if (mods==FL_ALT) { // word left
+ shift_position(word_start(position()));
+ return 1;
+ } else if (mods==FL_CTRL || mods==FL_META) { // start of line
+ shift_position(line_start(position()));
+ return 1;
+ } else return 1;
#else
- if (mods==0) { // char left
- ascii = ctrl('B');
- } else if (mods==FL_CTRL) { // word left
- shift_position(word_start(position()));
- return 1;
- } else return 1;
+ if (mods==0) { // char left
+ ascii = ctrl('B');
+ } else if (mods==FL_CTRL) { // word left
+ shift_position(word_start(position()));
+ return 1;
+ } else return 1;
#endif
- break;
- case FL_Right:
+ break;
+ case FL_Right:
#ifdef __APPLE__
- if (mods==0) { // char right
- ascii = ctrl('F');
- } else if (mods==FL_ALT) { // word right
- shift_position(word_end(position()));
- return 1;
- } else if (mods==FL_CTRL || mods==FL_META) { // end of line
- shift_position(line_end(position()));
- return 1;
- } else return 1;
+ if (mods==0) { // char right
+ ascii = ctrl('F');
+ } else if (mods==FL_ALT) { // word right
+ shift_position(word_end(position()));
+ return 1;
+ } else if (mods==FL_CTRL || mods==FL_META) { // end of line
+ shift_position(line_end(position()));
+ return 1;
+ } else return 1;
#else
- if (mods==0) { // char right
- ascii = ctrl('F');
- } else if (mods==FL_CTRL) { // word right
- shift_position(word_end(position()));
- return 1;
- } else return 1;
+ if (mods==0) { // char right
+ ascii = ctrl('F');
+ } else if (mods==FL_CTRL) { // word right
+ shift_position(word_end(position()));
+ return 1;
+ } else return 1;
#endif // __APPLE__
- break;
- case FL_Page_Up:
+ break;
+ case FL_Page_Up:
#ifdef __APPLE__
- if (mods==0) { // scroll text one page
- // OS X scrolls the view, but does not move the cursor
- // Fl_Input has no scroll control, so instead we move the cursor by one page
- repeat_num = linesPerPage();
- ascii = ctrl('P');
- } else if (mods==FL_ALT) { // move cursor one page
- repeat_num = linesPerPage();
- ascii = ctrl('P');
- } else return 1;
- break;
-#else
+ if (mods==0) { // scroll text one page
+ // OS X scrolls the view, but does not move the cursor
+ // Fl_Input has no scroll control, so instead we move the cursor by one page
+ repeat_num = linesPerPage();
+ ascii = ctrl('P');
+ } else if (mods==FL_ALT) { // move cursor one page
repeat_num = linesPerPage();
- // fall through
+ ascii = ctrl('P');
+ } else return 1;
+ break;
+#else
+ repeat_num = linesPerPage();
+ // fall through
#endif
- case FL_Up:
+ case FL_Up:
#ifdef __APPLE__
- if (mods==0) { // line up
- ascii = ctrl('P');
- } else if (mods==FL_CTRL) { // scroll text down one page
- // OS X scrolls the view, but does not move the cursor
- // Fl_Input has no scroll control, so instead we move the cursor by one page
- repeat_num = linesPerPage();
- ascii = ctrl('P');
- } else if (mods==FL_ALT) { // line start and up
- if (line_start(position())==position() && position()>0)
- return shift_position(line_start(position()-1)) + NORMAL_INPUT_MOVE;
- else
- return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
- } else if (mods==FL_META) { // start of document
- shift_position(0);
- return 1;
- } else return 1;
+ if (mods==0) { // line up
+ ascii = ctrl('P');
+ } else if (mods==FL_CTRL) { // scroll text down one page
+ // OS X scrolls the view, but does not move the cursor
+ // Fl_Input has no scroll control, so instead we move the cursor by one page
+ repeat_num = linesPerPage();
+ ascii = ctrl('P');
+ } else if (mods==FL_ALT) { // line start and up
+ if (line_start(position())==position() && position()>0)
+ return shift_position(line_start(position()-1)) + NORMAL_INPUT_MOVE;
+ else
+ return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
+ } else if (mods==FL_META) { // start of document
+ shift_position(0);
+ return 1;
+ } else return 1;
#else
- if (mods==0) { // line up
- ascii = ctrl('P');
- } else if (mods==FL_CTRL) { // scroll text down one line
- // Fl_Input has no scroll control, so instead we move the cursor by one page
- ascii = ctrl('P');
- } else return 1;
+ if (mods==0) { // line up
+ ascii = ctrl('P');
+ } else if (mods==FL_CTRL) { // scroll text down one line
+ // Fl_Input has no scroll control, so instead we move the cursor by one page
+ ascii = ctrl('P');
+ } else return 1;
#endif
- break;
- case FL_Page_Down:
+ break;
+ case FL_Page_Down:
#ifdef __APPLE__
- if (mods==0) { // scroll text one page
- // OS X scrolls the view, but does not move the cursor
- // Fl_Input has no scroll control, so instead we move the cursor by one page
- repeat_num = linesPerPage();
- ascii = ctrl('N');
- } else if (mods==FL_ALT) { // move cursor one page
- repeat_num = linesPerPage();
- ascii = ctrl('N');
- } else return 1;
- break;
-#else
+ if (mods==0) { // scroll text one page
+ // OS X scrolls the view, but does not move the cursor
+ // Fl_Input has no scroll control, so instead we move the cursor by one page
+ repeat_num = linesPerPage();
+ ascii = ctrl('N');
+ } else if (mods==FL_ALT) { // move cursor one page
repeat_num = linesPerPage();
- // fall through
+ ascii = ctrl('N');
+ } else return 1;
+ break;
+#else
+ repeat_num = linesPerPage();
+ // fall through
#endif
- case FL_Down:
+ case FL_Down:
#ifdef __APPLE__
- if (mods==0) { // line down
- ascii = ctrl('N');
- } else if (mods==FL_CTRL) {
- // OS X scrolls the view, but does not move the cursor
- // Fl_Input has no scroll control, so instead we move the cursor by one page
- repeat_num = linesPerPage();
- ascii = ctrl('N');
- } else if (mods==FL_ALT) { // line end and down
- if (line_end(position())==position() && position()<size())
- return shift_position(line_end(position()+1)) + NORMAL_INPUT_MOVE;
- else
- return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
- } else if (mods==FL_META) { // end of document
- shift_position(size());
- return 1;
- } else return 1;
+ if (mods==0) { // line down
+ ascii = ctrl('N');
+ } else if (mods==FL_CTRL) {
+ // OS X scrolls the view, but does not move the cursor
+ // Fl_Input has no scroll control, so instead we move the cursor by one page
+ repeat_num = linesPerPage();
+ ascii = ctrl('N');
+ } else if (mods==FL_ALT) { // line end and down
+ if (line_end(position())==position() && position()<size())
+ return shift_position(line_end(position()+1)) + NORMAL_INPUT_MOVE;
+ else
+ return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
+ } else if (mods==FL_META) { // end of document
+ shift_position(size());
+ return 1;
+ } else return 1;
#else
- if (mods==0) { // line down
- ascii = ctrl('N');
- } else if (mods==FL_CTRL) { // scroll text up one line
- // Fl_Input has no scroll control, so instead we move the cursor by one page
- ascii = ctrl('N');
- } else return 1;
+ if (mods==0) { // line down
+ ascii = ctrl('N');
+ } else if (mods==FL_CTRL) { // scroll text up one line
+ // Fl_Input has no scroll control, so instead we move the cursor by one page
+ ascii = ctrl('N');
+ } else return 1;
#endif
- break;
- case FL_Home:
+ break;
+ case FL_Home:
#ifdef __APPLE__
- if (mods==0) { // scroll display to the top
- // OS X scrolls the view, but does not move the cursor
- // Fl_Input has no scroll control, so instead we move the cursor by one page
- shift_position(0);
- return 1;
- } else return 1;
+ if (mods==0) { // scroll display to the top
+ // OS X scrolls the view, but does not move the cursor
+ // Fl_Input has no scroll control, so instead we move the cursor by one page
+ shift_position(0);
+ return 1;
+ } else return 1;
#else
- if (mods==0) {
- ascii = ctrl('A');
- } else if (mods==FL_CTRL) {
- shift_position(0);
- return 1;
- }
+ if (mods==0) {
+ ascii = ctrl('A');
+ } else if (mods==FL_CTRL) {
+ shift_position(0);
+ return 1;
+ }
#endif
- break;
- case FL_End:
+ break;
+ case FL_End:
#ifdef __APPLE__
- if (mods==0) { // scroll display to the bottom
- // OS X scrolls the view, but does not move the cursor
- // Fl_Input has no scroll control, so instead we move the cursor by one page
- shift_position(size());
- return 1;
- } else return 1;
+ if (mods==0) { // scroll display to the bottom
+ // OS X scrolls the view, but does not move the cursor
+ // Fl_Input has no scroll control, so instead we move the cursor by one page
+ shift_position(size());
+ return 1;
+ } else return 1;
#else
- if (mods==0) {
- ascii = ctrl('E');
- } else if (mods==FL_CTRL) {
- shift_position(size());
- return 1;
- } else return 1;
+ if (mods==0) {
+ ascii = ctrl('E');
+ } else if (mods==FL_CTRL) {
+ shift_position(size());
+ return 1;
+ } else return 1;
#endif
- break;
- case FL_BackSpace:
+ break;
+ case FL_BackSpace:
#ifdef __APPLE__
- if (mods==0 || mods==FL_CTRL) { // delete previous char
- ascii = ctrl('H');
- } else if (mods==FL_ALT) { // delete previous word
- if (mark() != position()) return cut();
- cut(word_start(position()), position());
- return 1;
- } else if (mods==FL_META) { // delete to the beginning of the line
- if (mark() != position()) return cut();
- cut(line_start(position()), position());
- return 1;
- } else return 1;
+ if (mods==0 || mods==FL_CTRL) { // delete previous char
+ ascii = ctrl('H');
+ } else if (mods==FL_ALT) { // delete previous word
+ if (mark() != position()) return cut();
+ cut(word_start(position()), position());
+ return 1;
+ } else if (mods==FL_META) { // delete to the beginning of the line
+ if (mark() != position()) return cut();
+ cut(line_start(position()), position());
+ return 1;
+ } else return 1;
#else
- ascii = ctrl('H');
+ ascii = ctrl('H');
#endif
- break;
- case FL_Enter:
- case FL_KP_Enter:
- if (when() & FL_WHEN_ENTER_KEY) {
- position(size(), 0);
- maybe_do_callback();
- return 1;
- } else if (input_type() == FL_MULTILINE_INPUT && !readonly())
- return replace(position(), mark(), "\n", 1);
- else
- return 0; // reserved for shortcuts
- case FL_Tab:
- if (Fl::event_state(FL_CTRL|FL_SHIFT) || input_type()!=FL_MULTILINE_INPUT || readonly()) return 0;
- return replace(position(), mark(), &ascii, 1);
+ break;
+ case FL_Enter:
+ case FL_KP_Enter:
+ if (when() & FL_WHEN_ENTER_KEY) {
+ position(size(), 0);
+ maybe_do_callback();
+ return 1;
+ } else if (input_type() == FL_MULTILINE_INPUT && !readonly())
+ return replace(position(), mark(), "\n", 1);
+ else
+ return 0; // reserved for shortcuts
+ case FL_Tab:
+ if (Fl::event_state(FL_CTRL|FL_SHIFT) || input_type()!=FL_MULTILINE_INPUT || readonly()) return 0;
+ return replace(position(), mark(), &ascii, 1);
#ifdef __APPLE__
- case 'c' :
- case 'v' :
- case 'x' :
- case 'z' :
- // printf("'%c' (0x%02x) pressed with%s%s%s%s\n", ascii, ascii,
- // Fl::event_state(FL_SHIFT) ? " FL_SHIFT" : "",
- // Fl::event_state(FL_CTRL) ? " FL_CTRL" : "",
- // Fl::event_state(FL_ALT) ? " FL_ALT" : "",
- // Fl::event_state(FL_META) ? " FL_META" : "");
- if (Fl::event_state(FL_META)) ascii -= 0x60;
- // printf("using '%c' (0x%02x)...\n", ascii, ascii);
- break;
+ case 'c' :
+ case 'v' :
+ case 'x' :
+ case 'z' :
+// printf("'%c' (0x%02x) pressed with%s%s%s%s\n", ascii, ascii,
+// Fl::event_state(FL_SHIFT) ? " FL_SHIFT" : "",
+// Fl::event_state(FL_CTRL) ? " FL_CTRL" : "",
+// Fl::event_state(FL_ALT) ? " FL_ALT" : "",
+// Fl::event_state(FL_META) ? " FL_META" : "");
+ if (Fl::event_state(FL_META)) ascii -= 0x60;
+// printf("using '%c' (0x%02x)...\n", ascii, ascii);
+ break;
#endif // __APPLE__
}
-
+
int i;
switch (ascii) {
- case ctrl('A'): // go to the beginning of the current line
- return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
- case ctrl('B'): // go one character backward
- return shift_position(position()-1) + NORMAL_INPUT_MOVE;
- case ctrl('C'): // copy
- return copy(1);
- case ctrl('D'): // cut the next character
- case ctrl('?'):
- if (readonly()) {
- fl_beep();
- return 1;
- }
- if (mark() != position()) return cut();
- else return cut(1);
- case ctrl('E'): // go to the end of the line
- return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
- case ctrl('F'): // go to the next character
- return shift_position(position()+1) + NORMAL_INPUT_MOVE;
- case ctrl('H'): // cut the previous character
- if (readonly()) {
- fl_beep();
- return 1;
- }
- if (mark() != position()) cut();
- else cut(-1);
+ case ctrl('A'): // go to the beginning of the current line
+ return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
+ case ctrl('B'): // go one character backward
+ return shift_position(position()-1) + NORMAL_INPUT_MOVE;
+ case ctrl('C'): // copy
+ return copy(1);
+ case ctrl('D'): // cut the next character
+ case ctrl('?'):
+ if (readonly()) {
+ fl_beep();
return 1;
- case ctrl('K'): // cut to the end of the line
- if (readonly()) {
- fl_beep();
- return 1;
- }
- if (position()>=size()) return 0;
- i = line_end(position());
- if (i == position() && i < size()) i++;
- cut(position(), i);
- return copy_cuts();
- case ctrl('N'): // go down one line
- i = position();
- if (line_end(i) >= size()) return NORMAL_INPUT_MOVE;
- while (repeat_num--) {
- i = line_end(i);
- if (i >= size()) break;
- i++;
- }
- shift_up_down_position(i);
+ }
+ if (mark() != position()) return cut();
+ else return cut(1);
+ case ctrl('E'): // go to the end of the line
+ return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
+ case ctrl('F'): // go to the next character
+ return shift_position(position()+1) + NORMAL_INPUT_MOVE;
+ case ctrl('H'): // cut the previous character
+ if (readonly()) {
+ fl_beep();
return 1;
- case ctrl('P'): // go up one line
- i = position();
- if (!line_start(i)) return NORMAL_INPUT_MOVE;
- while(repeat_num--) {
- i = line_start(i);
- if (!i) break;
- i--;
- }
- shift_up_down_position(line_start(i));
+ }
+ if (mark() != position()) cut();
+ else cut(-1);
+ return 1;
+ case ctrl('K'): // cut to the end of the line
+ if (readonly()) {
+ fl_beep();
return 1;
- case ctrl('U'): // clear the whole document?
- if (readonly()) {
- fl_beep();
- return 1;
- }
- return cut(0, size());
- case ctrl('V'): // paste text
- case ctrl('Y'):
- if (readonly()) {
- fl_beep();
- return 1;
- }
- Fl::paste(*this, 1);
+ }
+ if (position()>=size()) return 0;
+ i = line_end(position());
+ if (i == position() && i < size()) i++;
+ cut(position(), i);
+ return copy_cuts();
+ case ctrl('N'): // go down one line
+ i = position();
+ if (line_end(i) >= size()) return NORMAL_INPUT_MOVE;
+ while (repeat_num--) {
+ i = line_end(i);
+ if (i >= size()) break;
+ i++;
+ }
+ shift_up_down_position(i);
+ return 1;
+ case ctrl('P'): // go up one line
+ i = position();
+ if (!line_start(i)) return NORMAL_INPUT_MOVE;
+ while(repeat_num--) {
+ i = line_start(i);
+ if (!i) break;
+ i--;
+ }
+ shift_up_down_position(line_start(i));
+ return 1;
+ case ctrl('U'): // clear the whole document?
+ if (readonly()) {
+ fl_beep();
return 1;
- case ctrl('X'): // cut the selected text
- case ctrl('W'):
- if (readonly()) {
- fl_beep();
- return 1;
- }
- copy(1);
- return cut();
- case ctrl('Z'): // undo
- case ctrl('_'):
- if (readonly()) {
- fl_beep();
- return 1;
- }
- return undo();
- case ctrl('I'): // insert literal
- case ctrl('J'):
- case ctrl('L'):
- case ctrl('M'):
- if (readonly()) {
- fl_beep();
- return 1;
- }
- // insert a few selected control characters literally:
- if (input_type() != FL_FLOAT_INPUT && input_type() != FL_INT_INPUT)
- return replace(position(), mark(), &ascii, 1);
+ }
+ return cut(0, size());
+ case ctrl('V'): // paste text
+ case ctrl('Y'):
+ if (readonly()) {
+ fl_beep();
+ return 1;
+ }
+ Fl::paste(*this, 1);
+ return 1;
+ case ctrl('X'): // cut the selected text
+ case ctrl('W'):
+ if (readonly()) {
+ fl_beep();
+ return 1;
+ }
+ copy(1);
+ return cut();
+ case ctrl('Z'): // undo
+ case ctrl('_'):
+ if (readonly()) {
+ fl_beep();
+ return 1;
+ }
+ return undo();
+ case ctrl('I'): // insert literal
+ case ctrl('J'):
+ case ctrl('L'):
+ case ctrl('M'):
+ if (readonly()) {
+ fl_beep();
+ return 1;
+ }
+ // insert a few selected control characters literally:
+ if (input_type() != FL_FLOAT_INPUT && input_type() != FL_INT_INPUT)
+ return replace(position(), mark(), &ascii, 1);
}
-
+
return 0;
}
diff --git a/src/Fl_Sys_Menu_Bar.cxx b/src/Fl_Sys_Menu_Bar.cxx
index 6092f75bb..da0451582 100644
--- a/src/Fl_Sys_Menu_Bar.cxx
+++ b/src/Fl_Sys_Menu_Bar.cxx
@@ -61,6 +61,12 @@
#include "flstring.h"
#include <stdio.h>
#include <ctype.h>
+#include <stdarg.h>
+
+#ifdef __APPLE_COCOA__
+extern void *MACMenuOrItemOperation(const char *operation, ...);
+#define MenuHandle void *
+#endif
typedef const Fl_Menu_Item *pFl_Menu_Item;
@@ -69,7 +75,9 @@ typedef const Fl_Menu_Item *pFl_Menu_Item;
* Skip all '&' which would mark the shortcut in FLTK
* Skip all Mac control characters ('(', '<', ';', '^', '!' )
*/
-static void catMenuText( const char *src, char *dst )
+
+#ifndef __APPLE_COCOA__
+ static void catMenuText( const char *src, char *dst )
{
char c;
while ( *dst )
@@ -88,6 +96,7 @@ static void catMenuText( const char *src, char *dst )
* append a marker to identify the menu font style
* <B, I, U, O, and S
*/
+
static void catMenuFont( const Fl_Menu_Item *m, char *dst )
{
if ( !m->labeltype_ && !m->labelfont_ )
@@ -110,11 +119,11 @@ static void catMenuFont( const Fl_Menu_Item *m, char *dst )
strcat( dst, "<S" );
//else if ( m->labeltype_ == FL_SYMBOL_LABEL )
; // not supported
-}
+}
/**
* append a marker to identify the menu shortcut
- * <B, I, U, O, and S
+ * <B, I, U, O, and S
enum {
kMenuNoModifiers = 0,
kMenuShiftModifier = (1 << 0),
@@ -122,7 +131,9 @@ enum {
kMenuControlModifier = (1 << 2),
kMenuNoCommandModifier = (1 << 3)
};
- */
+*/
+#endif
+
static void setMenuShortcut( MenuHandle mh, int miCnt, const Fl_Menu_Item *m )
{
if ( !m->shortcut_ )
@@ -135,6 +146,11 @@ static void setMenuShortcut( MenuHandle mh, int miCnt, const Fl_Menu_Item *m )
if ( !isalnum( key ) )
return;
+#ifdef __APPLE_COCOA__
+ void *menuItem = MACMenuOrItemOperation("itemAtIndex", mh, miCnt);
+ MACMenuOrItemOperation("setKeyEquivalent", menuItem, key );
+ MACMenuOrItemOperation("setKeyEquivalentModifierMask", menuItem, m->shortcut_ );
+#else
long macMod = kMenuNoCommandModifier;
if ( m->shortcut_ & FL_META ) macMod = kMenuNoModifiers;
if ( m->shortcut_ & FL_SHIFT || isupper(key) ) macMod |= kMenuShiftModifier;
@@ -144,8 +160,10 @@ static void setMenuShortcut( MenuHandle mh, int miCnt, const Fl_Menu_Item *m )
//SetMenuItemKeyGlyph( mh, miCnt, key );
SetItemCmd( mh, miCnt, toupper(key) );
SetMenuItemModifiers( mh, miCnt, macMod );
+#endif
}
+
#if 0
// this function needs to be verified before we compile it back in.
static void catMenuShortcut( const Fl_Menu_Item *m, char *dst )
@@ -166,16 +184,113 @@ static void catMenuShortcut( const Fl_Menu_Item *m, char *dst )
}
#endif
+
static void setMenuFlags( MenuHandle mh, int miCnt, const Fl_Menu_Item *m )
{
if ( m->flags & FL_MENU_TOGGLE )
{
- SetItemMark( mh, miCnt, ( m->flags & FL_MENU_VALUE ) ? 0x12 : 0 );
+#ifdef __APPLE_COCOA__
+ void *menuItem = MACMenuOrItemOperation("itemAtIndex", mh, miCnt);
+ MACMenuOrItemOperation("setState", menuItem, m->flags & FL_MENU_VALUE );
+#else
+ SetItemMark( mh, miCnt, ( m->flags & FL_MENU_VALUE ) ? 0x12 : 0 );
+#endif
+ }
+ else if ( m->flags & FL_MENU_RADIO ) {
+#ifndef __APPLE_COCOA__
+ SetItemMark( mh, miCnt, ( m->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
+#endif
}
- else if ( m->flags & FL_MENU_RADIO )
- SetItemMark( mh, miCnt, ( m->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
}
+
+#ifdef __APPLE_COCOA__
+
+/**
+ * create a sub menu for a specific menu handle
+ */
+static void createSubMenu( void * mh, pFl_Menu_Item &mm )
+{
+ void *submenu;
+ int miCnt, flags;
+
+ void *menuItem;
+ submenu = MACMenuOrItemOperation("initWithTitle", mm->text);
+ int cnt;
+ MACMenuOrItemOperation("numberOfItems", mh, &cnt);
+ cnt--;
+ menuItem = MACMenuOrItemOperation("itemAtIndex", mh, cnt);
+ MACMenuOrItemOperation("setSubmenu", menuItem, submenu);
+ if ( mm->flags & FL_MENU_INACTIVE ) {
+ MACMenuOrItemOperation("setEnabled", menuItem, 0);
+ }
+ mm++;
+
+ while ( mm->text )
+ {
+ MACMenuOrItemOperation("addNewItem", submenu, mm->text, mm->callback_, mm->user_data_, &miCnt);
+ setMenuFlags( submenu, miCnt, mm );
+ setMenuShortcut( submenu, miCnt, mm );
+ if ( mm->flags & FL_MENU_INACTIVE ) {
+ void *item = MACMenuOrItemOperation("itemAtIndex", submenu, miCnt);
+ MACMenuOrItemOperation("setEnabled", item, 0);
+ }
+ flags = mm->flags;
+ if ( mm->flags & FL_SUBMENU )
+ {
+ createSubMenu( submenu, mm );
+ }
+ else if ( mm->flags & FL_SUBMENU_POINTER )
+ {
+ const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_;
+ createSubMenu( submenu, smm );
+ }
+ if ( flags & FL_MENU_DIVIDER ) {
+ MACMenuOrItemOperation("addSeparatorItem", submenu);
+ }
+ mm++;
+ }
+}
+
+
+/**
+ * create a system menu bar using the given list of menu structs
+ *
+ * \author Matthias Melcher
+ *
+ * @param m list of Fl_Menu_Item
+ */
+extern void *MACmainMenu(void);
+void Fl_Sys_Menu_Bar::menu(const Fl_Menu_Item *m)
+{
+ fl_open_display();
+ Fl_Menu_Bar::menu( m );
+ fl_sys_menu_bar = this;
+
+
+ const Fl_Menu_Item *mm = m;
+ for (;;)
+ {
+ if ( !mm || !mm->text )
+ break;
+ char visible = mm->visible() ? 1 : 0;
+ MACMenuOrItemOperation("addNewItem", MACmainMenu(), mm->text, NULL, NULL, NULL);
+
+ if ( mm->flags & FL_SUBMENU )
+ createSubMenu( MACmainMenu(), mm );
+ else if ( mm->flags & FL_SUBMENU_POINTER ) {
+ const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_;
+ createSubMenu( MACmainMenu(), smm );
+ }
+ if ( visible ) {
+// InsertMenu( mh, 0 );
+ }
+ mm++;
+ }
+}
+
+#else
+
static void catMenuFlags( const Fl_Menu_Item *m, char *dst )
{
if ( !m->flags )
@@ -184,6 +299,7 @@ static void catMenuFlags( const Fl_Menu_Item *m, char *dst )
strcat( dst, "(" );
}
+
/**
* create a sub menu for a specific menu handle
*/
@@ -229,7 +345,7 @@ static void createSubMenu( MenuHandle mh, int &cnt, pFl_Menu_Item &mm )
}
InsertMenu( mh, -1 );
}
-
+
/**
* create a system menu bar using the given list of menu structs
@@ -243,9 +359,9 @@ void Fl_Sys_Menu_Bar::menu(const Fl_Menu_Item *m)
fl_open_display();
Fl_Menu_Bar::menu( m );
fl_sys_menu_bar = this;
-
+
char buf[255];
-
+
int cnt = 1; // first menu is no 2. no 1 is the Apple Menu
const Fl_Menu_Item *mm = m;
for (;;)
@@ -276,6 +392,8 @@ void Fl_Sys_Menu_Bar::menu(const Fl_Menu_Item *m)
DrawMenuBar();
}
+#endif //__APPLE_COCOA__
+
/*
const Fl_Menu_Item* Fl_Sys_Menu_Bar::picked(const Fl_Menu_Item* v) {
Fl_menu_Item *ret = Fl_Menu_Bar::picked( v );
@@ -290,42 +408,31 @@ const Fl_Menu_Item* Fl_Sys_Menu_Bar::picked(const Fl_Menu_Item* v) {
*/
void Fl_Sys_Menu_Bar::draw() {
-/* -- nothing to do, system should take care of this
- draw_box();
- if (!menu() || !menu()->text) return;
- const Fl_Menu_Item* m;
- int X = x()+6;
- for (m=menu(); m->text; m = m->next()) {
- int W = m->measure(0,this) + 16;
- m->draw(X, y(), W, h(), this);
- X += W;
- }
- */
}
/*
-int Fl_Menu_Bar::handle(int event) {
- const Fl_Menu_Item* v;
- if (menu() && menu()->text) switch (event) {
- case FL_ENTER:
- case FL_LEAVE:
- return 1;
- case FL_PUSH:
- v = 0;
- J1:
- v = menu()->pulldown(x(), y(), w(), h(), v, this, 0, 1);
- picked(v);
- return 1;
- case FL_SHORTCUT:
- if (visible_r()) {
- v = menu()->find_shortcut();
- if (v && v->submenu()) goto J1;
- }
- return test_shortcut() != 0;
- }
- return 0;
-}
-*/
+ int Fl_Menu_Bar::handle(int event) {
+ const Fl_Menu_Item* v;
+ if (menu() && menu()->text) switch (event) {
+ case FL_ENTER:
+ case FL_LEAVE:
+ return 1;
+ case FL_PUSH:
+ v = 0;
+ J1:
+ v = menu()->pulldown(x(), y(), w(), h(), v, this, 0, 1);
+ picked(v);
+ return 1;
+ case FL_SHORTCUT:
+ if (visible_r()) {
+ v = menu()->find_shortcut();
+ if (v && v->submenu()) goto J1;
+ }
+ return test_shortcut() != 0;
+ }
+ return 0;
+ }
+ */
#endif /* __APPLE__ */
diff --git a/src/Fl_Window.cxx b/src/Fl_Window.cxx
index 4f54e7ebc..692aa255e 100644
--- a/src/Fl_Window.cxx
+++ b/src/Fl_Window.cxx
@@ -31,6 +31,7 @@
// equivalent (but totally different) crap for MSWindows is in Fl_win32.cxx
#include "config.h"
#include <FL/Fl.H>
+#include <FL/x.H>
#include <FL/Fl_Window.H>
#include <stdlib.h>
#include "flstring.h"
@@ -125,6 +126,10 @@ void Fl_Window::draw() {
int i;
for (i=dx; i<12; i++) {
fl_color(c[i&3]);
+#ifdef __APPLE_COCOA__
+ extern CGContextRef fl_gc;
+ if(fl_gc)
+#endif
fl_line(x1--, y1, x2, y2--);
}
}
diff --git a/src/Fl_Window_iconize.cxx b/src/Fl_Window_iconize.cxx
index 83a1b810c..2341a95fe 100644
--- a/src/Fl_Window_iconize.cxx
+++ b/src/Fl_Window_iconize.cxx
@@ -37,7 +37,11 @@ void Fl_Window::iconize() {
#ifdef WIN32
ShowWindow(i->xid, SW_SHOWMINNOACTIVE);
#elif defined(__APPLE__)
+#ifdef __APPLE_COCOA__
+ MacCollapseWindow((Window)i->xid);
+#else
CollapseWindow( i->xid, true );
+#endif
#else
XIconifyWindow(fl_display, i->xid, fl_screen);
#endif
diff --git a/src/Fl_arg.cxx b/src/Fl_arg.cxx
index 253857a1c..b1476faa9 100644
--- a/src/Fl_arg.cxx
+++ b/src/Fl_arg.cxx
@@ -88,13 +88,6 @@ int Fl::arg(int argc, char **argv, int &i) {
if (s[0] != '-' || s[1] == '-' || !s[1]) {return_i = 1; return 0;}
s++; // point after the dash
-#ifdef __APPLE__
- if (!strncmp(s, "psn", 3)) {
- // Skip process serial number...
- i++;
- }
- else
-#endif // __APPLE__
if (fl_match(s, "iconic")) {
fl_show_iconic = 1;
i++;
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm
new file mode 100644
index 000000000..e20b5c76d
--- /dev/null
+++ b/src/Fl_cocoa.mm
@@ -0,0 +1,3105 @@
+//
+// "$Id: Fl_mac.cxx 6758 2009-04-13 07:32:01Z matt $"
+//
+// MacOS specific code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2009 by Bill Spitzak and others.
+//
+// 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
+//
+
+//// From the inner edge of a MetroWerks CodeWarrior CD:
+// (without permission)
+//
+// "Three Compiles for 68Ks under the sky,
+// Seven Compiles for PPCs in their fragments of code,
+// Nine Compiles for Mortal Carbon doomed to die,
+// One Compile for Mach-O Cocoa on its Mach-O throne,
+// in the Land of MacOS X where the Drop-Shadows lie.
+//
+// One Compile to link them all, One Compile to merge them,
+// One Compile to copy them all and in the bundle bind them,
+// in the Land of MacOS X where the Drop-Shadows lie."
+
+// we don't need the following definition because we deliver only
+// true mouse moves. On very slow systems however, this flag may
+// still be useful.
+#ifndef FL_DOXYGEN
+
+#define CONSOLIDATE_MOTION 0
+extern "C" {
+#include <pthread.h>
+}
+
+
+#include <FL/Fl.H>
+#include <FL/x.H>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Tooltip.H>
+#include <FL/Fl_Sys_Menu_Bar.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include "flstring.h"
+#include <unistd.h>
+#include <stdarg.h>
+
+#import <Cocoa/Cocoa.h>
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+#endif
+
+
+// #define DEBUG_SELECT // UNCOMMENT FOR SELECT()/THREAD DEBUGGING
+#ifdef DEBUG_SELECT
+#include <stdio.h> // testing
+#define DEBUGMSG(msg) if ( msg ) fprintf(stderr, msg);
+#define DEBUGPERRORMSG(msg) if ( msg ) perror(msg)
+#define DEBUGTEXT(txt) txt
+#else
+#define DEBUGMSG(msg)
+#define DEBUGPERRORMSG(msg)
+#define DEBUGTEXT(txt) NULL
+#endif /*DEBUG_SELECT*/
+
+// external functions
+extern void fl_fix_focus();
+extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h);
+extern CGContextRef CreateWatchImage(void);
+extern CGContextRef CreateHelpImage(void);
+extern CGContextRef CreateNESWImage(void);
+extern CGContextRef CreateNWSEImage(void);
+extern CGContextRef CreateNoneImage(void);
+
+// forward definition of functions in this file
+// converting cr lf converter function
+static void convert_crlf(char * string, size_t len);
+static void createAppleMenu(void);
+Fl_Region MacRegionMinusRect(Fl_Region r, int x,int y,int w,int h);
+static void cocoaMouseHandler(NSEvent *theEvent);
+
+// public variables
+int fl_screen;
+CGContextRef fl_gc = 0;
+void *fl_system_menu; // this is really a NSMenu*
+Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0;
+void *fl_default_cursor; // this is really a NSCursor*
+void *fl_capture = 0; // (NSWindow*) we need this to compensate for a missing(?) mouse capture
+//ulong fl_event_time; // the last timestamp from an x event
+char fl_key_vector[32]; // used by Fl::get_key()
+bool fl_show_iconic; // true if called from iconize() - shows the next created window in collapsed state
+int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
+//const Fl_Window* fl_modal_for; // parent of modal() window
+Fl_Region fl_window_region = 0;
+Window fl_window;
+Fl_Window *Fl_Window::current_;
+//EventRef fl_os_event; // last (mouse) event
+
+// forward declarations of variables in this file
+static int got_events = 0;
+static Fl_Window* resize_from_system;
+static NSView *viewWithLockedFocus = nil;
+static SInt32 MACsystemVersion;
+
+#if CONSOLIDATE_MOTION
+static Fl_Window* send_motion;
+extern Fl_Window* fl_xmousewin;
+#endif
+
+enum { FLTKTimerEvent = 1, FLTKDataReadyEvent };
+
+
+/* fltk-utf8 placekeepers */
+void fl_reset_spot()
+{
+}
+
+void fl_set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win)
+{
+}
+
+void fl_set_status(int x, int y, int w, int h)
+{
+}
+
+/**
+ * Mac keyboard lookup table
+ */
+static unsigned short macKeyLookUp[128] =
+{
+ 'a', 's', 'd', 'f', 'h', 'g', 'z', 'x',
+ 'c', 'v', '^', 'b', 'q', 'w', 'e', 'r',
+
+ 'y', 't', '1', '2', '3', '4', '6', '5',
+ '=', '9', '7', '-', '8', '0', ']', 'o',
+
+ 'u', '[', 'i', 'p', FL_Enter, 'l', 'j', '\'',
+ 'k', ';', '\\', ',', '/', 'n', 'm', '.',
+
+ FL_Tab, ' ', '`', FL_BackSpace,
+ FL_KP_Enter, FL_Escape, 0, 0/*FL_Meta_L*/,
+ 0/*FL_Shift_L*/, 0/*FL_Caps_Lock*/, 0/*FL_Alt_L*/, 0/*FL_Control_L*/,
+ 0/*FL_Shift_R*/, 0/*FL_Alt_R*/, 0/*FL_Control_R*/, 0,
+
+ 0, FL_KP+'.', FL_Right, FL_KP+'*', 0, FL_KP+'+', FL_Left, FL_Delete,
+ FL_Down, 0, 0, FL_KP+'/', FL_KP_Enter, FL_Up, FL_KP+'-', 0,
+
+ 0, FL_KP+'=', FL_KP+'0', FL_KP+'1', FL_KP+'2', FL_KP+'3', FL_KP+'4', FL_KP+'5',
+ FL_KP+'6', FL_KP+'7', 0, FL_KP+'8', FL_KP+'9', 0, 0, 0,
+
+ FL_F+5, FL_F+6, FL_F+7, FL_F+3, FL_F+8, FL_F+9, 0, FL_F+11,
+ 0, 0/*FL_F+13*/, FL_Print, FL_Scroll_Lock, 0, FL_F+10, FL_Menu, FL_F+12,
+
+ 0, FL_Pause, FL_Help, FL_Home, FL_Page_Up, FL_Delete, FL_F+4, FL_End,
+ 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 )
+{
+ long state = 0;
+ if ( mods & NSNumericPadKeyMask ) state |= FL_NUM_LOCK;
+ if ( mods & NSCommandKeyMask ) state |= FL_META;
+ if ( mods & NSAlternateKeyMask ) state |= FL_ALT;
+ if ( mods & NSControlKeyMask ) state |= FL_CTRL;
+ if ( mods & NSShiftKeyMask ) state |= FL_SHIFT;
+ if ( mods & NSAlphaShiftKeyMask ) state |= FL_CAPS_LOCK;
+ unsigned int ret = ( Fl::e_state & 0xff000000 ) | state;
+ Fl::e_state = ret;
+ //printf( "State 0x%08x (%04x)\n", Fl::e_state, mods );
+ return ret;
+}
+
+
+/**
+ * convert the current mouse chord into the FLTK keysym
+ */
+/*
+ static void mods_to_e_keysym( NSUInteger mods )
+ {
+ if ( mods & NSCommandKeyMask ) Fl::e_keysym = FL_Meta_L;
+ else if ( mods & NSNumericPadKeyMask ) Fl::e_keysym = FL_Num_Lock;
+ else if ( mods & NSAlternateKeyMask ) Fl::e_keysym = FL_Alt_L;
+ else if ( mods & NSControlKeyMask ) Fl::e_keysym = FL_Control_L;
+ else if ( mods & NSShiftKeyMask ) Fl::e_keysym = FL_Shift_L;
+ 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;
+void (*fl_unlock_function)() = nothing;
+
+//
+// Select interface -- how it's implemented:
+// When the user app configures one or more file descriptors to monitor
+// with Fl::add_fd(), we start a separate thread to select() the data,
+// sending a custom OSX 'FLTK data ready event' to the parent thread's
+// RunApplicationLoop(), so that it triggers the data ready callbacks
+// in the parent thread. -erco 04/04/04
+//
+#define POLLIN 1
+#define POLLOUT 4
+#define POLLERR 8
+
+// Class to handle select() 'data ready'
+class DataReady
+{
+ struct FD
+ {
+ int fd;
+ short events;
+ void (*cb)(int, void*);
+ void* arg;
+ };
+ int nfds, fd_array_size;
+ FD *fds;
+ pthread_t tid; // select()'s thread id
+
+ // Data that needs to be locked (all start with '_')
+ pthread_mutex_t _datalock; // data lock
+ fd_set _fdsets[3]; // r/w/x sets user wants to monitor
+ int _maxfd; // max fd count to monitor
+ int _cancelpipe[2]; // pipe used to help cancel thread
+ void *_userdata; // thread's userdata
+
+public:
+ DataReady()
+ {
+ nfds = 0;
+ fd_array_size = 0;
+ fds = 0;
+ tid = 0;
+
+ pthread_mutex_init(&_datalock, NULL);
+ FD_ZERO(&_fdsets[0]); FD_ZERO(&_fdsets[1]); FD_ZERO(&_fdsets[2]);
+ _cancelpipe[0] = _cancelpipe[1] = 0;
+ _userdata = 0;
+ _maxfd = 0;
+ }
+
+ ~DataReady()
+ {
+ CancelThread(DEBUGTEXT("DESTRUCTOR\n"));
+ if (fds) { free(fds); fds = 0; }
+ nfds = 0;
+ }
+
+ // Locks
+ // The convention for locks: volatile vars start with '_',
+ // and must be locked before use. Locked code is prefixed
+ // with /*LOCK*/ to make painfully obvious esp. in debuggers. -erco
+ //
+ void DataLock() { pthread_mutex_lock(&_datalock); }
+ void DataUnlock() { pthread_mutex_unlock(&_datalock); }
+
+ // Accessors
+ int IsThreadRunning() { return(tid ? 1 : 0); }
+ int GetNfds() { return(nfds); }
+ int GetCancelPipe(int ix) { return(_cancelpipe[ix]); }
+ fd_set GetFdset(int ix) { return(_fdsets[ix]); }
+
+ // Methods
+ void AddFD(int n, int events, void (*cb)(int, void*), void *v);
+ void RemoveFD(int n, int events);
+ int CheckData(fd_set& r, fd_set& w, fd_set& x);
+ void HandleData(fd_set& r, fd_set& w, fd_set& x);
+ static void* DataReadyThread(void *self);
+ void StartThread(void *userdata);
+ void CancelThread(const char *reason);
+};
+
+static DataReady dataready;
+
+void DataReady::AddFD(int n, int events, void (*cb)(int, void*), void *v)
+{
+ RemoveFD(n, events);
+ int i = nfds++;
+ if (i >= fd_array_size)
+ {
+ FD *temp;
+ fd_array_size = 2*fd_array_size+1;
+ if (!fds) { temp = (FD*)malloc(fd_array_size*sizeof(FD)); }
+ else { temp = (FD*)realloc(fds, fd_array_size*sizeof(FD)); }
+ if (!temp) return;
+ fds = temp;
+ }
+ fds[i].cb = cb;
+ fds[i].arg = v;
+ fds[i].fd = n;
+ fds[i].events = events;
+ DataLock();
+ /*LOCK*/ if (events & POLLIN) FD_SET(n, &_fdsets[0]);
+ /*LOCK*/ if (events & POLLOUT) FD_SET(n, &_fdsets[1]);
+ /*LOCK*/ if (events & POLLERR) FD_SET(n, &_fdsets[2]);
+ /*LOCK*/ if (n > _maxfd) _maxfd = n;
+ DataUnlock();
+}
+
+// Remove an FD from the array
+void DataReady::RemoveFD(int n, int events)
+{
+ int i,j;
+ 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]; }
+ j++;
+ }
+ nfds = j;
+ DataLock();
+ /*LOCK*/ if (events & POLLIN) FD_CLR(n, &_fdsets[0]);
+ /*LOCK*/ if (events & POLLOUT) FD_CLR(n, &_fdsets[1]);
+ /*LOCK*/ if (events & POLLERR) FD_CLR(n, &_fdsets[2]);
+ /*LOCK*/ if (n == _maxfd) _maxfd--;
+ DataUnlock();
+}
+
+// CHECK IF USER DATA READY, RETURNS r/w/x INDICATING WHICH IF ANY
+int DataReady::CheckData(fd_set& r, fd_set& w, fd_set& x)
+{
+ int ret;
+ DataLock();
+ /*LOCK*/ timeval t = { 0, 1 }; // quick check
+ /*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()"); }
+ 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++)
+ {
+ 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)
+ {
+ DEBUGMSG("DOING CALLBACK: ");
+ fds[i].cb(f, fds[i].arg);
+ DEBUGMSG("DONE\n");
+ }
+ }
+}
+
+// DATA READY THREAD
+// This thread watches for changes in user's file descriptors.
+// Sends a 'data ready event' to the main thread if any change.
+//
+void* DataReady::DataReadyThread(void *o)
+{
+ DataReady *self = (DataReady*)o;
+ NSAutoreleasePool *localPool;
+ localPool = [[NSAutoreleasePool alloc] init];
+ while ( 1 ) // loop until thread cancel or error
+ {
+ // Thread safe local copies of data before each select()
+ self->DataLock();
+ /*LOCK*/ int maxfd = self->_maxfd;
+ /*LOCK*/ fd_set r = self->GetFdset(0);
+ /*LOCK*/ fd_set w = self->GetFdset(1);
+ /*LOCK*/ fd_set x = self->GetFdset(2);
+ // /*LOCK*/ void *userdata = self->_userdata;
+ /*LOCK*/ int cancelpipe = self->GetCancelPipe(0);
+ /*LOCK*/ if ( cancelpipe > maxfd ) maxfd = cancelpipe;
+ /*LOCK*/ FD_SET(cancelpipe, &r); // add cancelpipe to fd's to watch
+ /*LOCK*/ FD_SET(cancelpipe, &x);
+ self->DataUnlock();
+ // timeval t = { 1000, 0 }; // 1000 seconds;
+ 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 )
+ {
+ case 0: // NO DATA
+ continue;
+ case -1: // ERROR
+ {
+ DEBUGPERRORMSG("CHILD THREAD: select() failed");
+ return(NULL); // error? exit thread
+ }
+ default: // DATA READY
+ {
+ if (FD_ISSET(cancelpipe, &r) || FD_ISSET(cancelpipe, &x)) // cancel?
+ { return(NULL); } // just exit
+ DEBUGMSG("CHILD THREAD: DATA IS READY\n");
+ NSPoint pt={0,0};
+ NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:pt modifierFlags:0
+ timestamp:0
+ windowNumber:0 context:NULL subtype:FLTKDataReadyEvent data1:0 data2:0];
+ [NSApp postEvent:event atStart:NO];
+ return(NULL); // done with thread
+ }
+ }
+ }
+}
+
+// START 'DATA READY' THREAD RUNNING, CREATE INTER-THREAD PIPE
+void DataReady::StartThread(void *new_userdata)
+{
+ CancelThread(DEBUGTEXT("STARTING NEW THREAD\n"));
+ DataLock();
+ /*LOCK*/ pipe(_cancelpipe); // pipe for sending cancel msg to thread
+ /*LOCK*/ _userdata = new_userdata;
+ DataUnlock();
+ DEBUGMSG("*** START THREAD\n");
+ pthread_create(&tid, NULL, DataReadyThread, (void*)this);
+}
+
+// CANCEL 'DATA READY' THREAD, CLOSE PIPE
+void DataReady::CancelThread(const char *reason)
+{
+ if ( tid )
+ {
+ DEBUGMSG("*** CANCEL THREAD: ");
+ DEBUGMSG(reason);
+ if ( pthread_cancel(tid) == 0 ) // cancel first
+ {
+ DataLock();
+ /*LOCK*/ write(_cancelpipe[1], "x", 1); // wake thread from select
+ DataUnlock();
+ pthread_join(tid, NULL); // wait for thread to finish
+ }
+ tid = 0;
+ DEBUGMSG("(JOINED) OK\n");
+ }
+ // Close pipe if open
+ DataLock();
+ /*LOCK*/ if ( _cancelpipe[0] ) { close(_cancelpipe[0]); _cancelpipe[0] = 0; }
+ /*LOCK*/ if ( _cancelpipe[1] ) { close(_cancelpipe[1]); _cancelpipe[1] = 0; }
+ DataUnlock();
+}
+
+void Fl::add_fd( int n, int events, void (*cb)(int, void*), void *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); }
+
+void Fl::remove_fd(int n, int events)
+{ dataready.RemoveFD(n, events); }
+
+void Fl::remove_fd(int n)
+{ 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;
+}
+
+
+static void processFLTKEvent(void) {
+ dataready.CancelThread(DEBUGTEXT("DATA READY EVENT\n"));
+
+ // CHILD THREAD TELLS US DATA READY
+ // Check to see what's ready, and invoke user's cb's
+ //
+ fd_set r,w,x;
+ switch(dataready.CheckData(r,w,x))
+ {
+ case 0: // NO DATA
+ break;
+ case -1: // ERROR
+ break;
+ default: // DATA READY
+ dataready.HandleData(r,w,x);
+ break;
+ }
+ return;
+}
+
+
+/**
+ * break the current event loop
+ */
+static void breakMacEventLoop()
+{
+ fl_lock_function();
+
+ NSPoint pt={0,0};
+ NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:pt modifierFlags:0
+ timestamp:0
+ windowNumber:0 context:NULL subtype:FLTKTimerEvent data1:0 data2:0];
+ [NSApp postEvent:event atStart:NO];
+ fl_unlock_function();
+}
+
+//
+// MacOS X timers
+//
+
+struct MacTimeout {
+ Fl_Timeout_Handler callback;
+ void* data;
+ EventLoopTimerRef timer;
+ EventLoopTimerUPP upp;
+ char pending;
+};
+static MacTimeout* mac_timers;
+static int mac_timer_alloc;
+static int mac_timer_used;
+
+
+static void realloc_timers()
+{
+ if (mac_timer_alloc == 0) {
+ mac_timer_alloc = 8;
+ }
+ mac_timer_alloc *= 2;
+ MacTimeout* new_timers = new MacTimeout[mac_timer_alloc];
+ memset(new_timers, 0, sizeof(MacTimeout)*mac_timer_alloc);
+ memcpy(new_timers, mac_timers, sizeof(MacTimeout) * mac_timer_used);
+ MacTimeout* delete_me = mac_timers;
+ mac_timers = new_timers;
+ delete [] delete_me;
+}
+
+static void delete_timer(MacTimeout& t)
+{
+ if (t.timer) {
+ RemoveEventLoopTimer(t.timer);
+ DisposeEventLoopTimerUPP(t.upp);
+ memset(&t, 0, sizeof(MacTimeout));
+ }
+}
+
+
+static void do_timer(EventLoopTimerRef timer, void* data)
+{
+ for (int i = 0; i < mac_timer_used; ++i) {
+ MacTimeout& t = mac_timers[i];
+ if (t.timer == timer && t.data == data) {
+ t.pending = 0;
+ (*t.callback)(data);
+ if (t.pending==0)
+ delete_timer(t);
+ break;
+ }
+ }
+ breakMacEventLoop();
+}
+
+
+@interface FLWindow : NSWindow {
+ Fl_Window *w;
+ BOOL containsGLsubwindow;
+}
+- (FLWindow*)initWithFl_W:(Fl_Window *)flw;
+- (Fl_Window *)getFl_Window;
+- (BOOL)windowShouldClose:(FLWindow *)w;
+- (BOOL)containsGLsubwindow;
+- (void)setContainsGLsubwindow:(BOOL)contains;
+@end
+
+@implementation FLWindow
+- (FLWindow*)initWithFl_W:(Fl_Window *)flw;
+{
+ w = flw;
+ containsGLsubwindow = NO;
+ return self;
+}
+- (Fl_Window *)getFl_Window;
+{
+ return w;
+}
+- (BOOL)windowShouldClose:(FLWindow *)fl
+{
+ Fl::handle( FL_CLOSE, [fl getFl_Window] ); // this might or might not close the window
+ if (!Fl_X::first) return YES;
+ Fl_Window *l = Fl::first_window();
+ while( l != NULL && l != [fl getFl_Window]) l = Fl::next_window(l);
+ return (l == NULL ? YES : NO);
+}
+- (BOOL)containsGLsubwindow
+{
+ return containsGLsubwindow;
+}
+- (void)setContainsGLsubwindow:(BOOL)contains
+{
+ containsGLsubwindow = contains;
+}
+@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.
+ */
+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")); }
+
+ // Start thread to watch for data ready
+ 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 main again
+ 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];
+ }
+ if(![cw isMainWindow]) {//always make Fl::first_window() the main window
+ [cw makeMainWindow];
+ }
+ }
+ }
+ 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);
+ }
+ }
+ else if([event type] == NSApplicationDefined) {
+ if([event subtype] == FLTKDataReadyEvent) {
+ processFLTKEvent();
+ }
+ needSendEvent = NO;
+ }
+ if(needSendEvent) [NSApp sendEvent:event];
+ fl_lock_function();
+
+#if CONSOLIDATE_MOTION
+ if (send_motion && send_motion == fl_xmousewin) {
+ send_motion = 0;
+ Fl::handle(FL_MOVE, fl_xmousewin);
+ }
+#endif
+
+ 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.
+ *
+ * \todo there is no socket handling in this code whatsoever
+ */
+int fl_wait( double time )
+{
+ do_queued_events( time );
+ return (got_events);
+}
+
+
+
+
+/**
+ * Cocoa Mousewheel handler
+ */
+void cocoaMouseWheelHandler(NSEvent *theEvent)
+{
+ // Handle the new "MightyMouse" mouse wheel events. Please, someone explain
+ // to me why Apple changed the API on this even though the current API
+ // supports two wheels just fine. Matthias,
+ fl_lock_function();
+
+ Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window];
+ if ( !window->shown() )
+ {
+ fl_unlock_function();
+ return;
+ }
+ Fl::first_window(window);
+
+ if([theEvent deltaX] != 0) {
+ Fl::e_dx = -[theEvent deltaX];
+ Fl::e_dy = 0;
+ if ( Fl::e_dx) Fl::handle( FL_MOUSEWHEEL, window );
+ } else if([theEvent deltaY] != 0) {
+ Fl::e_dx = 0;
+ Fl::e_dy = -[theEvent deltaY];
+ if ( Fl::e_dy) Fl::handle( FL_MOUSEWHEEL, window );
+ } else {
+ fl_unlock_function();
+
+ return;
+ }
+
+ fl_unlock_function();
+
+ // return noErr;
+}
+
+
+/**
+ * Cocoa Mouse Button Handler
+ */
+static void cocoaMouseHandler(NSEvent *theEvent)
+{
+ static int keysym[] = { 0, FL_Button+1, FL_Button+3, FL_Button+2 };
+ static int px, py;
+ static char suppressed = 0;
+
+ fl_lock_function();
+
+ Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window];
+ 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);
+ NSPoint pos = [theEvent locationInWindow];
+ pos.y = window->h() - pos.y;
+ NSInteger btn = [theEvent buttonNumber] + 1;
+ int clickCount = [theEvent clickCount];
+ NSUInteger mods = [theEvent modifierFlags];
+ int sendEvent = 0;
+
+ 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;
+ if (clickCount>1)
+ Fl::e_clicks++;
+ else
+ Fl::e_clicks = 0;
+ // fall through
+ case NSLeftMouseUp:
+ case NSRightMouseUp:
+ case NSOtherMouseUp:
+ Fl::e_state &= 0xff0000;
+ if (suppressed) {
+ suppressed = 0;
+ break;
+ }
+ if ( !window ) break;
+ if ( !sendEvent ) {
+ sendEvent = FL_RELEASE;
+ }
+ Fl::e_keysym = keysym[ btn ];
+ // fall through
+ case NSMouseMoved:
+ suppressed = 0;
+ if ( !sendEvent ) {
+ sendEvent = FL_MOVE;
+ }
+ // fall through
+ 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)
+ Fl::e_is_click = 0;
+ }
+ mods_to_e_state( mods );
+ NSPoint screen = [[theEvent window] convertBaseToScreen:[theEvent locationInWindow]];
+ Fl::e_x_root = screen.x;
+ Fl::e_y_root = [[[theEvent window] screen] frame].size.height - screen.y;
+ Fl::e_x = pos.x;
+ Fl::e_y = pos.y;
+ Fl::handle( sendEvent, window );
+ break;
+ }
+
+ fl_unlock_function();
+
+ return;
+}
+
+
+/*
+ * keycode_function for post-10.5 systems, allows more sophisticated decoding of keys
+ */
+/*
+ static int keycodeToUnicode(
+ char * uniChars, int maxChars,
+ EventKind eKind,
+ UInt32 keycode, UInt32 modifiers,
+ UInt32 * deadKeyStatePtr,
+ 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;
+ }
+ */
+
+/*
+ * keycode_function for pre-10.5 systems, this is the "historic" fltk Mac key handling
+ */
+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) {
+ buffer[0] = key;
+ return 1;
+ } else {
+ buffer[0] = 0;
+ 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
+ * intended to allow us to utilise 10.5 services dynamically to improve Unicode handling, whilst still
+ * allowing code to run satisfactorily on older systems.
+ */
+static int (*keycode_function)(char*, int, EventKind, UInt32, UInt32, UInt32*, unsigned char, unsigned short) = keycode_wrap_old;
+
+
+// EXPERIMENTAL!
+//this gets called by CJK character palette input
+OSStatus carbonTextHandler( EventHandlerCallRef nextHandler, EventRef event, void *unused )
+{
+ //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] == NSKeyDown) return noErr;
+ if( [NSApp keyWindow] == nil) return noErr;
+ Fl_Window *window = [(FLWindow*)[NSApp keyWindow] getFl_Window];
+ fl_lock_function();
+ //int kind = GetEventKind(event);
+ unsigned short buf[200];
+ ByteCount size;
+ GetEventParameter( event, kEventParamTextInputSendText, typeUnicodeText,
+ NULL, 100, &size, &buf );
+ // printf("TextEvent: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
+ // FIXME: oversimplified!
+ unsigned ucs = buf[0];
+ char utf8buf[20];
+ int len = fl_utf8encode(ucs, utf8buf);
+
+ Fl::e_length = len;
+ Fl::e_text = utf8buf;
+ while (window->parent()) window = window->window();
+ Fl::handle(FL_KEYBOARD, window);
+ fl_unlock_function();
+ fl_lock_function();
+ Fl::handle(FL_KEYUP, window);
+ fl_unlock_function();
+ // for some reason, the window does not redraw until the next mouse move or button push
+ // sending a 'redraw()' or 'awake()' does not solve the issue!
+ Fl::flush();
+ return noErr;
+}
+
+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)
+{
+ //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;
+ char buffer[10];
+ char text[10];
+ UniChar first = CFStringGetCharacterAtIndex(s, 0);
+ CFStringGetCString(s, buffer, sizeof(buffer), kCFStringEncodingUTF8);
+ for(unsigned int i = 0; i < sizeof(asciis)/sizeof(char); i++) {
+ if(first == unicodes[i]) {
+ //replace the 2-byte utf8 of a non-ascii unicode by the corresponding 1-byte ascii
+ memmove(buffer+1, buffer+2, 2);
+ *buffer = asciis[i];
+ break;
+ }
+ }
+ Fl::e_keysym = 0;
+ Fl::e_state = 0;
+ Fl::e_length = 1;
+ Fl::e_text = text;
+ Fl::e_text[0] = buffer[0];
+ Fl::handle(FL_KEYBOARD, window);
+ Fl::e_keysym = 0;
+ Fl::e_state = 0;
+ Fl::e_length = 1;
+ Fl::e_text[0] = buffer[1];
+ Fl::handle(FL_KEYBOARD, window);
+}
+
+
+/**
+ * handle cocoa keyboard events
+ */
+OSStatus cocoaKeyboardHandler(NSEvent *theEvent)
+{
+ static char buffer[32];
+ int sendEvent = 0;
+ Fl_Window *window = (Fl_Window*)[(FLWindow*)[theEvent window] getFl_Window];
+ Fl::first_window(window);
+ NSUInteger mods;
+
+ fl_lock_function();
+
+ int kind = 0;
+
+ // get the modifiers for any of the events
+ mods = [theEvent modifierFlags];
+
+ // get the key code only for key events
+ UInt32 keyCode = 0, maskedKeyCode = 0;
+ unichar key = 0;
+ unsigned char keychar = 0;
+ unsigned short sym = 0;
+ keyCode = [theEvent keyCode];
+ NSString *s = [theEvent characters];
+ 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
+ compose = NO;
+ [edit setString:@""];
+ CFRelease(sequence);
+ fl_unlock_function();
+ return noErr;
+ }
+ [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+ countevents++;
+ UniChar deadkey;
+ CFRange range = {0, 1};
+ CFStringGetCharacters((CFStringRef)s, range, &deadkey);
+ 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
+ }
+ 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
+ while (window->parent()) window = window->window();
+ Fl::e_keysym = FL_Control_R;//first simulate pressing of the compose key (FL_Control_R)
+ Fl::e_text = "";
+ 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
+ edit = [[theEvent window] fieldEditor:YES forObject:nil];
+ [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+ countevents = 1;
+ sequence = CFStringCreateMutable(NULL, 2);
+ fl_unlock_function();
+ return noErr;
+ }
+ 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);
+ */
+ switch([theEvent type])
+ {
+ case NSKeyDown:
+ sendEvent = FL_KEYBOARD;
+ // fall through
+ case NSKeyUp:
+ if ( !sendEvent ) {
+ sendEvent = FL_KEYUP;
+ Fl::e_state &= 0xbfffffff; // clear the deadkey flag
+ }
+ 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];
+ if ( isalpha(key) )
+ 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
+ sym = maskedKeyCode;*/
+ 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) {
+ 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;
+ }
+ while (window->parent()) window = window->window();
+ if (sendEvent && Fl::handle(sendEvent,window)) {
+ fl_unlock_function();
+ return noErr; // return noErr if FLTK handled the event
+ } else {
+ fl_unlock_function();
+ return eventNotHandledErr;
+ }
+}
+
+
+
+/**
+ * Open callback function to call...
+ */
+
+static void (*open_cb)(const char *) = 0;
+
+
+/**
+ * Install an open documents event handler...
+ */
+@interface FLAppleEventHandler : NSObject
+{
+}
+- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent;
+@end
+@implementation FLAppleEventHandler
+- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent
+{
+ NSAppleEventDescriptor *single = [event descriptorAtIndex:1];
+ const AEDesc *document = [single aeDesc];
+ long i, n;
+ FSRef fileRef;
+ AEKeyword keyWd;
+ DescType typeCd;
+ Size actSz;
+ char filename[1024];
+ // Lock access to FLTK in this thread...
+ fl_lock_function();
+
+ // Open the documents via the callback...
+ if (AECountItems(document, &n) == noErr) {
+ for (i = 1; i <= n; i ++) {
+ AEGetNthPtr(document, i, typeFSRef, &keyWd, &typeCd,
+ (Ptr)&fileRef, sizeof(fileRef),
+ (actSz = sizeof(fileRef), &actSz));
+ FSRefMakePath( &fileRef, (UInt8*)filename, sizeof(filename) );
+
+ (*open_cb)(filename);
+ }
+ }
+
+ // Unlock access to FLTK for all threads...
+ fl_unlock_function();
+}
+@end
+
+void fl_open_callback(void (*cb)(const char *)) {
+ static NSAppleEventManager *aeventmgr = nil;
+ static FLAppleEventHandler *handler;
+ fl_open_display();
+ if(!aeventmgr) {
+ aeventmgr = [NSAppleEventManager sharedAppleEventManager];
+ handler = [[FLAppleEventHandler alloc] init];
+ }
+
+ open_cb = cb;
+ if (cb) {
+ [aeventmgr setEventHandler:handler andSelector: @selector(handleAppleEvent:withReplyEvent:)
+ forEventClass:kCoreEventClass andEventID:kAEOpenDocuments];
+ } else {
+ [aeventmgr removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEOpenDocuments];
+ }
+}
+
+
+/**
+ * initialize the Mac toolboxes, dock status, and set the default menubar
+ */
+
+extern "C" {
+ extern OSErr CPSEnableForegroundOperation(ProcessSerialNumber *psn, UInt32 _arg2,
+ UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
+}
+
+@interface FLDelegate : NSObject {
+}
+- (void)windowDidMove:(NSNotification *)notif;
+- (void)windowDidResize:(NSNotification *)notif;
+- (void)windowDidBecomeKey:(NSNotification *)notif;
+- (void)windowDidBecomeMain:(NSNotification *)notif;
+- (void)windowDidDeminiaturize:(NSNotification *)notif;
+- (void)windowDidMiniaturize:(NSNotification *)notif;
+- (void)windowWillClose:(NSNotification *)notif;
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender;
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
+
+@end
+@implementation FLDelegate
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
+ fl_system_menu = [NSApp mainMenu];
+}
+- (void)windowDidMove:(NSNotification *)notif
+{
+ FLWindow *nsw = (FLWindow*)[notif object];
+ Fl_Window *window = [nsw getFl_Window];
+ NSPoint pt, pt2;
+ 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
+ }
+}
+- (void)windowDidResize:(NSNotification *)notif
+{
+ FLWindow *nsw = (FLWindow*)[notif object];
+ Fl_Window *window = [nsw getFl_Window];
+ NSRect r = [[nsw contentView] frame];
+ NSPoint pt, pt2;
+ pt.x = 0;
+ 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);
+}
+- (void)windowDidBecomeKey:(NSNotification *)notif
+{
+ FLWindow *nsw = (FLWindow*)[notif object];
+ Fl_Window *window = [nsw getFl_Window];
+ Fl::handle( FL_FOCUS, window);
+}
+- (void)windowDidBecomeMain:(NSNotification *)notif
+{
+ FLWindow *nsw = (FLWindow*)[notif object];
+ Fl_Window *window = [nsw getFl_Window];
+ Fl::first_window(window);
+}
+- (void)windowDidDeminiaturize:(NSNotification *)notif
+{
+ FLWindow *nsw = (FLWindow*)[notif object];
+ Fl_Window *window = [nsw getFl_Window];
+ window->set_visible();
+}
+- (void)windowDidMiniaturize:(NSNotification *)notif
+{
+ FLWindow *nsw = (FLWindow*)[notif object];
+ Fl_Window *window = [nsw getFl_Window];
+ window->clear_visible();
+}
+- (void)windowWillClose:(NSNotification *)notif
+{
+ Fl_Window *w = Fl::first_window();
+ 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
+ [cw makeKeyAndOrderFront:nil];
+ }
+ if(![cw isMainWindow]) {//always make Fl::first_window() the main widow
+ [cw makeMainWindow];
+ }
+ }
+}
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
+{
+ fl_lock_function();
+ NSApplicationTerminateReply reply = NSTerminateNow;
+ while ( Fl_X::first ) {
+ Fl_X *x = Fl_X::first;
+ Fl::handle( FL_CLOSE, x->w );
+ if ( Fl_X::first == x ) {
+ reply = NSTerminateCancel; // FLTK has not closed all windows, so we return to the main program now
+ break;
+ }
+ }
+ fl_unlock_function();
+ return reply;
+}
+@end
+
+static FLDelegate *mydelegate;
+
+void fl_open_display() {
+ static char beenHereDoneThat = 0;
+ if ( !beenHereDoneThat ) {
+ beenHereDoneThat = 1;
+
+ [NSApplication sharedApplication];
+ NSAutoreleasePool *localPool;
+ localPool = [[NSAutoreleasePool alloc] init];
+ mydelegate = [[FLDelegate alloc] init];
+ [NSApp setDelegate:mydelegate];
+ [NSApp finishLaunching];
+
+ FlushEvents(everyEvent,0);
+
+ fl_default_cursor = [NSCursor arrowCursor];
+ Gestalt(gestaltSystemVersion, &MACsystemVersion);
+
+ // 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 )
+ {
+ // only transform the application type for unbundled apps
+ CFBundleRef bundle = CFBundleGetMainBundle();
+ if( bundle )
+ {
+ FSRef execFs;
+ CFURLRef execUrl = CFBundleCopyExecutableURL( bundle );
+ CFURLGetFSRef( execUrl, &execFs );
+
+ FSRef bundleFs;
+ GetProcessBundleLocation( &cur_psn, &bundleFs );
+
+ if( !FSCompareFSRefs( &execFs, &bundleFs ) )
+ bundle = NULL;
+
+ CFRelease(execUrl);
+ }
+
+ 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
+ }*/
+
+ 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
+ // both TransformProcessType and CPSEnableForegroundOperation, the following
+ // conditional code compiled on 10.2 will still work on newer releases...
+ OSErr err;
+#if __LP64__
+ err = TransformProcessType(&cur_psn, kProcessTransformToForegroundApplication);
+#else
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
+ if (TransformProcessType != NULL) {
+ err = TransformProcessType(&cur_psn, kProcessTransformToForegroundApplication);
+ } else
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
+ err = CPSEnableForegroundOperation(&cur_psn, 0x03, 0x3C, 0x2C, 0x1103);
+#endif // __LP64__
+ if (err == noErr) {
+ SetFrontProcess( &cur_psn );
+ }
+ }
+ }
+ createAppleMenu();
+ // Install Carbon Event handler for character palette input
+ static EventTypeSpec textEvents[] = {
+ { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } };
+ EventHandlerUPP textHandler = NewEventHandlerUPP( carbonTextHandler );
+ InstallEventHandler(GetEventDispatcherTarget(), textHandler, 1, textEvents, NULL, 0L);
+ }
+}
+
+
+/**
+ * get rid of allocated resources
+ */
+void fl_close_display() {
+}
+
+
+// Gets the border sizes and the titlebar size
+static void get_window_frame_sizes(int &bx, int &by, int &bt) {
+ fl_open_display();
+ NSRect inside = { {20,20}, {100,100} };
+ NSRect outside = [NSWindow frameRectForContentRect:inside styleMask:NSTitledWindowMask];
+ bx = outside.origin.x - inside.origin.x;
+ by = outside.origin.y - inside.origin.y;
+ bt = outside.size.height - inside.size.height - by;
+}
+
+/**
+ * smallest x ccordinate in screen space
+ */
+int Fl::x() {
+ return [[NSScreen mainScreen] frame].origin.x;
+}
+
+
+/**
+ * smallest y coordinate in screen space
+ */
+int Fl::y() {
+ NSRect all = [[NSScreen mainScreen] frame];
+ NSRect visible = [[NSScreen mainScreen] visibleFrame];
+ return all.size.height - (visible.origin.y + visible.size.height);
+}
+
+
+/**
+ * screen width (single monitor!?)
+ */
+int Fl::w() {
+ return [[NSScreen mainScreen] visibleFrame].size.width;
+}
+
+
+/**
+ * screen height (single monitor!?)
+ */
+int Fl::h() {
+ int bx, by, bt;
+ get_window_frame_sizes(bx, by, bt);
+ return [[NSScreen mainScreen] frame].size.height - bt;
+}
+
+
+/**
+ * get the current mouse pointer world coordinates
+ */
+void Fl::get_mouse(int &x, int &y)
+{
+ fl_open_display();
+ NSPoint pt = [NSEvent mouseLocation];
+ x = pt.x;
+ y = [[NSScreen mainScreen] frame].size.height - pt.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;
+ }
+ */
+
+/**
+ * Initialize the given port for redraw and call the window's flush() to actually draw the content
+ */
+void Fl_X::flush()
+{
+ w->flush();
+ if (fl_gc) {
+ CGContextFlush(fl_gc);
+ if(viewWithLockedFocus) {
+ [viewWithLockedFocus unlockFocus];
+ viewWithLockedFocus = nil;
+ }
+ }
+}
+
+
+/**
+ * Gets called when a window is created, resized, or deminiaturized
+ */
+static void handleUpdateEvent( Fl_Window *window )
+{
+ if ( !window ) return;
+ Fl_X *i = Fl_X::i( window );
+ i->wait_for_expose = 0;
+ if ( i->region ) {
+ XDestroyRegion(i->region);
+ i->region = 0;
+ }
+
+ for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext )
+ {
+ if ( cx->region ) {
+ XDestroyRegion(cx->region);
+ cx->region = 0;
+ }
+ cx->w->clear_damage(FL_DAMAGE_ALL);
+ cx->flush();
+ cx->w->clear_damage();
+ }
+ window->clear_damage(FL_DAMAGE_ALL);
+ i->flush();
+ window->clear_damage();
+}
+
+int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) {
+ int W, H, xoff, yoff, dx, dy;
+ int ret = bx = by = bt = 0;
+ if (w->border() && !w->parent()) {
+ if (w->maxw != w->minw || w->maxh != w->minh) {
+ ret = 2;
+ get_window_frame_sizes(bx, by, bt);
+ } else {
+ ret = 1;
+ get_window_frame_sizes(bx, by, bt);
+ }
+ }
+ //The coordinates of the whole window, including non-client area
+ xoff = bx;
+ yoff = by + bt;
+ dx = 2*bx;
+ dy = 2*by + bt;
+ X = w->x()-xoff;
+ Y = w->y()-yoff;
+ W = w->w()+dx;
+ H = w->h()+dy;
+
+ //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
+ // top menu bar (and even more stuff in 10.4 Tiger). So we will go through the
+ // list of all available screens and find the one that this window is most
+ // likely to go to, and then reposition it to fit withing the 'good' area.
+ // Rect r;
+ // find the screen, that the center of this window will fall into
+ int R = X+W, B = Y+H; // right and bottom
+ int cx = (X+R)/2, cy = (Y+B)/2; // center of window;
+ NSScreen *gd = NULL;
+ NSArray *a = [NSScreen screens]; int count = (int)[a count]; NSRect r; int i;
+ for( i = 0; i < count; i++) {
+ r = [[a objectAtIndex:i] frame];
+ cy = r.size.height - cy;
+ if ( cx >= r.origin.x && cx <= r.origin.x + r.size.width
+ && cy >= r.origin.y && cy <= r.origin.y + r.size.height)
+ break;
+ }
+ if(i < count) gd = [a objectAtIndex:i];
+
+ // if the center doesn't fall on a screen, try the top left
+ if (!gd) {
+ for( i = 0; i < count; i++) {
+ r = [[a objectAtIndex:i] frame];
+ if ( X >= r.origin.x && X <= r.origin.x + r.size.width
+ && 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 that doesn't fall on a screen, try the top right
+ if (!gd) {
+ for( i = 0; i < count; i++) {
+ r = [[a objectAtIndex:i] frame];
+ if ( R >= r.origin.x && R <= r.origin.x + r.size.width
+ && 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 that doesn't fall on a screen, try the bottom left
+ if (!gd) {
+ for( i = 0; i < count; i++) {
+ r = [[a objectAtIndex:i] frame];
+ if ( X >= r.origin.x && X <= r.origin.x + r.size.width
+ && Y-H >= r.origin.y && Y-H <= r.origin.y + r.size.height)
+ break;
+ }
+ if(i < count) gd = [a objectAtIndex:i];
+ }
+ // last resort, try the bottom right
+ if (!gd) {
+ for( i = 0; i < count; i++) {
+ r = [[a objectAtIndex:i] frame];
+ if ( R >= r.origin.x && R <= r.origin.x + r.size.width
+ && Y-H >= r.origin.y && Y-H <= r.origin.y + r.size.height)
+ break;
+ }
+ 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.
+ if (!gd) gd = [a objectAtIndex:0];
+ if (gd) {
+ r = [gd visibleFrame];
+ int sh = [gd frame].size.height;
+ if ( R > r.origin.x + r.size.width ) X -= R - (r.origin.x + r.size.width);
+ if ( B > sh - r.origin.y ) Y -= B - (sh - r.origin.y);
+ if ( X < r.origin.x ) X = r.origin.x;
+ 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)
+ X+=xoff;
+ Y+=yoff;
+
+ return ret;
+}
+
+
+Fl_Window *fl_dnd_target_window = 0;
+
+static void q_set_window_title(NSWindow *nsw, const char * name ) {
+ CFStringRef utf8_title = CFStringCreateWithCString(NULL, (name ? name : ""), kCFStringEncodingUTF8);
+ [nsw setTitle:(NSString*)utf8_title ];
+ CFRelease(utf8_title);
+}
+
+
+@interface FLView : NSView {
+}
+- (void)drawRect:(NSRect)rect;
+- (BOOL)acceptsFirstResponder;
+- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent;
+- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
+- (void)mouseUp:(NSEvent *)theEvent;
+- (void)rightMouseUp:(NSEvent *)theEvent;
+- (void)otherMouseUp:(NSEvent *)theEvent;
+- (void)mouseDown:(NSEvent *)theEvent;
+- (void)rightMouseDown:(NSEvent *)theEvent;
+- (void)otherMouseDown:(NSEvent *)theEvent;
+- (void)mouseDragged:(NSEvent *)theEvent;
+- (void)scrollWheel:(NSEvent *)theEvent;
+- (void)keyDown:(NSEvent *)theEvent;
+- (void)keyUp:(NSEvent *)theEvent;
+- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender;
+- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender;
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+- (void)draggingExited:(id < NSDraggingInfo >)sender;
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;
+@end
+
+@implementation FLView
+- (void)drawRect:(NSRect)rect
+{
+ FLWindow *cw = (FLWindow*)[self window];
+ Fl_Window *w = [cw getFl_Window];
+ handleUpdateEvent(w);
+}
+
+- (BOOL)acceptsFirstResponder
+{
+ 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];
+ Fl_Window *first = Fl::first_window();
+ return (first == w || !first->modal());
+}
+- (void)mouseUp:(NSEvent *)theEvent {
+ cocoaMouseHandler(theEvent);
+}
+- (void)rightMouseUp:(NSEvent *)theEvent {
+ cocoaMouseHandler(theEvent);
+}
+- (void)otherMouseUp:(NSEvent *)theEvent {
+ cocoaMouseHandler(theEvent);
+}
+- (void)mouseDown:(NSEvent *)theEvent {
+ cocoaMouseHandler(theEvent);
+}
+- (void)rightMouseDown:(NSEvent *)theEvent {
+ cocoaMouseHandler(theEvent);
+}
+- (void)otherMouseDown:(NSEvent *)theEvent {
+ cocoaMouseHandler(theEvent);
+}
+- (void)mouseMoved:(NSEvent *)theEvent {
+ cocoaMouseHandler(theEvent);
+}
+- (void)mouseDragged:(NSEvent *)theEvent {
+ cocoaMouseHandler(theEvent);
+}
+- (void)scrollWheel:(NSEvent *)theEvent {
+ cocoaMouseWheelHandler(theEvent);
+}
+- (void)keyDown:(NSEvent *)theEvent {
+ cocoaKeyboardHandler(theEvent);
+}
+- (void)keyUp:(NSEvent *)theEvent {
+ cocoaKeyboardHandler(theEvent);
+}
+- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender
+{
+ Fl_Window *target = [(FLWindow*)[self window] getFl_Window];
+ NSPoint pt = [sender draggingLocation];
+ Fl::e_x = pt.x;
+ Fl::e_y = [self frame].size.height - pt.y;
+ 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;
+ fl_dnd_target_window = target;
+ Fl::handle( FL_DND_ENTER, target );
+ return NSDragOperationGeneric;
+}
+- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
+{
+ Fl_Window *target = [(FLWindow*)[self window] getFl_Window];
+ NSPoint pt = [sender draggingLocation];
+ Fl::e_x = pt.x;
+ Fl::e_y = [self frame].size.height - pt.y;
+ 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;
+ fl_dnd_target_window = target;
+ Fl::handle( FL_DND_DRAG, target );
+ return NSDragOperationGeneric;
+}
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ static char *DragData = NULL;
+ Fl_Window *target = [(FLWindow*)[self window] getFl_Window];
+ if ( !Fl::handle( FL_DND_RELEASE, target ) ) { return NO; }
+ NSPasteboard *pboard;
+ //NSDragOperation sourceDragMask;
+ //sourceDragMask = [sender draggingSourceOperationMask];
+ pboard = [sender draggingPasteboard];
+ NSPoint pt = [sender draggingLocation];
+ Fl::e_x = pt.x;
+ Fl::e_y = [self frame].size.height - pt.y;
+ 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 ( [[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);
+ }
+ 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));
+ }
+ else return NO;
+ Fl::e_text = DragData;
+ Fl::e_length = strlen(DragData);
+ 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; }
+ Fl::e_text = NULL;
+ Fl::e_length = 0;
+ fl_dnd_target_window = NULL;
+ return YES;
+}
+- (void)draggingExited:(id < NSDraggingInfo >)sender
+{
+ if ( fl_dnd_target_window )
+ {
+ Fl::handle( FL_DND_LEAVE, fl_dnd_target_window );
+ fl_dnd_target_window = 0;
+ }
+}
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
+{
+ return NSDragOperationGeneric;
+}
+@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
+ {
+ Fl_Group::current(0);
+ Rect wRect;
+ wRect.top = w->y();
+ wRect.left = w->x();
+ wRect.bottom = w->y() + w->h(); if (wRect.bottom<=wRect.top) wRect.bottom = wRect.top+1;
+ wRect.right = w->x() + w->w(); if (wRect.right<=wRect.left) wRect.right = wRect.left+1;
+ // our subwindow needs this structure to know about its clipping.
+ Fl_X* x = new Fl_X;
+ x->other_xid = 0;
+ x->region = 0;
+ x->subRegion = 0;
+ x->cursor = fl_default_cursor;
+ 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->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;
+ int old_event = Fl::e_number;
+ w->handle(Fl::e_number = FL_SHOW);
+ Fl::e_number = old_event;
+ w->redraw(); // force draw to happen
+ }
+ fl_show_iconic = 0;
+ }
+ 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;
+ 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)
+ 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;
+ } else {
+ w->size_range(w->w(), w->h(), w->w(), w->h());
+ }
+ }
+ int xwm = xp, ywm = yp, bt, bx, by;
+
+ if (!fake_X_wm(w, xwm, ywm, bt, bx, by)) {
+ // menu windows and tooltips
+ if (w->modal()||w->override()) {
+ winstyle = NSBorderlessWindowMask;
+ winlevel = NSMainMenuWindowLevel;
+ } else {
+ winstyle = NSBorderlessWindowMask;
+ }
+ } else if (w->modal()) {
+ winstyle &= ~(NSResizableWindowMask | NSMiniaturizableWindowMask);
+ // winlevel = NSModalPanelWindowLevel;
+ }
+ else if (w->non_modal()) {
+ winlevel = NSFloatingWindowLevel;
+ }
+
+ if (by+bt) {
+ wp += 2*bx;
+ hp += 2*by+bt;
+ }
+ if (!(w->flags() & Fl_Window::FORCE_POSITION)) {
+ // use the Carbon functions below for default window positioning
+ w->x(xyPos+Fl::x());
+ w->y(xyPos+Fl::y());
+ xyPos += 25;
+ if (xyPos>200) xyPos = 100;
+ } else {
+ if (!Fl::grab()) {
+ xp = xwm; yp = ywm;
+ w->x(xp);w->y(yp);
+ }
+ xp -= bx;
+ yp -= by+bt;
+ }
+
+ if (w->non_modal() && Fl_X::first && !fl_disable_transient_for) {
+ // find some other window to be "transient for":
+ Fl_Window* w = Fl_X::first->w;
+ while (w->parent()) w = w->window(); // todo: this code does not make any sense! (w!=w??)
+ }
+
+ Rect wRect;
+ wRect.top = w->y();
+ wRect.left = w->x();
+ wRect.bottom = w->y() + w->h(); if (wRect.bottom<=wRect.top) wRect.bottom = wRect.top+1;
+ wRect.right = w->x() + w->w(); if (wRect.right<=wRect.left) wRect.right = wRect.left+1;
+
+ const char *name = w->label();
+
+ Fl_X* x = new Fl_X;
+ x->other_xid = 0; // room for doublebuffering image map. On OS X this is only used by overlay windows
+ x->region = 0;
+ x->subRegion = 0;
+ x->cursor = fl_default_cursor;
+ x->xidChildren = 0;
+ x->xidNext = 0;
+ x->gc = 0;
+
+ FLWindow *cw = [[FLWindow alloc] initWithFl_W:w];
+ NSRect srect = [[NSScreen mainScreen] frame];
+ NSRect crect;
+ crect.origin.x = w->x();
+ crect.origin.y = srect.size.height - (w->y() + w->h());
+ crect.size.width=w->w();
+ crect.size.height=w->h();
+ [cw initWithContentRect:crect styleMask:winstyle backing:NSBackingStoreBuffered defer:NO];
+ [cw setAcceptsMouseMovedEvents:YES];
+ x->xid = cw;
+ FLView *myview = [[FLView alloc] init];
+ [cw setContentView:myview];
+ [cw setLevel:winlevel];
+
+ q_set_window_title(cw, name);
+ if (!(w->flags() & Fl_Window::FORCE_POSITION))
+ {
+ if (w->modal()) {
+ [cw center];
+ } else if (w->non_modal()) {
+ [cw center];
+ } else {
+ static NSPoint delta = NSZeroPoint;
+ delta = [cw cascadeTopLeftFromPoint:delta];
+ }
+ }
+ x->w = w; w->i = x;
+ x->wait_for_expose = 1;
+ x->next = Fl_X::first;
+ Fl_X::first = x;
+ // 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
+ {
+ ProcessSerialNumber psn;
+ OSErr err = GetCurrentProcess( &psn );
+ if ( err==noErr ) SetFrontProcess( &psn );
+ }
+
+ if (w->size_range_set) w->size_range_();
+
+ if(winlevel != NSMainMenuWindowLevel) {
+ Fl_Tooltip::enter(0);
+ }
+ [cw makeKeyAndOrderFront:nil];
+ Fl::first_window(w);
+ [cw setDelegate:mydelegate];
+ if (fl_show_iconic) {
+ fl_show_iconic = 0;
+ [cw miniaturize:nil];
+ } else {
+ w->set_visible();
+ }
+
+ crect = [[cw contentView] frame];
+ w->w(crect.size.width);
+ w->h(crect.size.height);
+ crect = [cw frame];
+ w->x(crect.origin.x);
+ srect = [[cw screen] frame];
+ w->y(srect.size.height - (crect.origin.y + w->h()));
+
+ int old_event = Fl::e_number;
+ w->handle(Fl::e_number = FL_SHOW);
+ Fl::e_number = old_event;
+
+ if (w->modal()) { Fl::modal_ = w; fl_fix_focus(); }
+ [localPool release];
+ }
+}
+
+
+/**
+ * Tell the OS what window sizes we want to allow
+ */
+void Fl_Window::size_range_() {
+ int bx, by, bt;
+ get_window_frame_sizes(bx, by, bt);
+ size_range_set = 1;
+ 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];
+ }
+}
+
+
+/**
+ * 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] == ':' ) )
+ {
+ q = p+2;
+ p++;
+ }
+ else if (p[0] == '/')
+ q = p + 1;
+ p++;
+ }
+ return q;
+}
+
+
+/**
+ * set the window title bar
+ * \todo make the titlebar icon work!
+ */
+void Fl_Window::label(const char *name,const char */*iname*/) {
+ Fl_Widget::label(name);
+ if (shown() || i) {
+ q_set_window_title((NSWindow*)i->xid, name);
+ }
+}
+
+
+/**
+ * make a window visible
+ */
+void Fl_Window::show() {
+ image(Fl::scheme_bg_);
+ if (Fl::scheme_bg_) {
+ labeltype(FL_NORMAL_LABEL);
+ align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
+ } else {
+ labeltype(FL_NO_LABEL);
+ }
+ Fl_Tooltip::exit(this);
+ 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];
+ }
+ }
+ }
+}
+
+
+/**
+ * resize a window
+ */
+void Fl_Window::resize(int X,int Y,int W,int H) {
+ int bx, by, bt;
+ 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;
+ int is_a_resize = (W != w() || H != h());
+ // printf("Fl_Window::resize(X=%d, Y=%d, W=%d, H=%d), is_a_resize=%d, resize_from_system=%p, this=%p\n",
+ // X, Y, W, H, is_a_resize, resize_from_system, this);
+ if (X != x() || Y != y()) set_flag(FORCE_POSITION);
+ else if (!is_a_resize) return;
+ if ( (resize_from_system!=this) && (!parent()) && shown()) {
+ if (is_a_resize) {
+ if (resizable()) {
+ if (W<minw) minw = W; // user request for resize takes priority
+ if (W>maxw) maxw = W; // over a previously set size_range
+ if (H<minh) minh = H;
+ if (H>maxh) maxh = H;
+ size_range(minw, minh, maxw, maxh);
+ } else {
+ size_range(W, H, W, H);
+ }
+ NSRect dim;
+ dim.origin.x = X;
+ dim.origin.y = [[(NSWindow*)i->xid screen] frame].size.height - (Y + H);
+ dim.size.width = W;
+ dim.size.height = H + bt;
+ [(NSWindow*)i->xid setFrame:dim display:YES];
+ } else {
+ NSPoint pt;
+ pt.x = X;
+ pt.y = [[(NSWindow*)i->xid screen] frame].size.height - (Y + h());
+ [(NSWindow*)i->xid setFrameOrigin:pt];
+ }
+ }
+ resize_from_system = 0;
+ if (is_a_resize) {
+ Fl_Group::resize(X,Y,W,H);
+ if (shown()) {
+ redraw();
+ }
+ } else {
+ x(X); y(Y);
+ }
+}
+
+
+/**
+ * make all drawing go into this window (called by subclass flush() impl.)
+ */
+void Fl_Window::make_current()
+{
+ Fl_X::q_release_context();
+ fl_window = i->xid;
+ current_ = this;
+
+ int xp = 0, yp = 0;
+ Fl_Window *win = this;
+ while ( win )
+ {
+ if ( !win->window() )
+ break;
+ xp += win->x();
+ yp += win->y();
+ win = (Fl_Window*)win->window();
+ }
+
+ viewWithLockedFocus = [(NSWindow*)i->xid contentView];
+ [viewWithLockedFocus lockFocusIfCanDraw];//important
+ i->gc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+ fl_gc = i->gc;
+ if ( fl_window_region ) XDestroyRegion(fl_window_region);
+ if(this->window()) {
+ fl_window_region = XRectangleRegion(0,0,w(),h());
+ }
+ 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);
+ }
+ }
+
+ //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
+ 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
+#endif
+ fl_clip_region( 0 );
+
+#if defined(USE_CAIRO)
+ // update the cairo_t context
+ if (Fl::cairo_autolink_context()) Fl::cairo_make_current(this);
+#endif
+}
+
+// helper function to manage the current CGContext fl_gc
+extern Fl_Color fl_color_;
+extern class Fl_Font_Descriptor *fl_fontsize;
+extern void fl_font(class Fl_Font_Descriptor*);
+extern void fl_quartz_restore_line_style_();
+
+// FLTK has only one global graphics state. This function copies the FLTK state into the
+// current Quartz context
+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;
+ } else {
+ hgt = CGBitmapContextGetHeight(fl_gc);
+ }
+ CGContextTranslateCTM(fl_gc, 0.5, hgt-0.5f);
+ CGContextScaleCTM(fl_gc, 1.0f, -1.0f); // now 0,0 is top-left point of the 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
+ 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
+// state and restore the global state.
+void Fl_X::q_clear_clipping() {
+ if (!fl_gc) return;
+ CGContextRestoreGState(fl_gc);
+ CGContextSaveGState(fl_gc);
+}
+
+// Give the Quartz context back to the system
+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
+ 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
+#endif
+}
+
+void Fl_X::q_begin_image(CGRect &rect, int cx, int cy, int w, int h) {
+ CGContextSaveGState(fl_gc);
+ CGAffineTransform mx = CGContextGetCTM(fl_gc);
+ CGRect r2 = rect;
+ r2.origin.x -= 0.5f;
+ r2.origin.y -= 0.5f;
+ CGContextClipToRect(fl_gc, r2);
+ mx.d = -1.0; mx.tx = -mx.tx;
+ CGContextConcatCTM(fl_gc, mx);
+ rect.origin.x = -(mx.tx+0.5f) + rect.origin.x - cx;
+ rect.origin.y = (mx.ty+0.5f) - rect.origin.y - h + cy;
+ rect.size.width = w;
+ rect.size.height = h;
+}
+
+void Fl_X::q_end_image() {
+ CGContextRestoreGState(fl_gc);
+}
+
+
+////////////////////////////////////////////////////////////////
+// Copy & Paste fltk implementation.
+////////////////////////////////////////////////////////////////
+
+static void convert_crlf(char * s, size_t len)
+{
+ // turn all \r characters into \n:
+ for (size_t x = 0; x < len; x++) if (s[x] == '\r') s[x] = '\n';
+}
+
+// fltk 1.3 clipboard support constant definitions:
+const CFStringRef flavorNames[] = {
+ CFSTR("public.utf16-plain-text"),
+ CFSTR("public.utf8-plain-text"),
+ CFSTR("com.apple.traditional-mac-plain-text") };
+const CFStringEncoding encodings[] = {
+ kCFStringEncodingUnicode,
+ kCFStringEncodingUTF8,
+ kCFStringEncodingMacRoman};
+const size_t handledFlavorsCount = sizeof(encodings)/sizeof(CFStringEncoding);
+
+// clipboard variables definitions :
+Fl_Widget *fl_selection_requestor = 0;
+char *fl_selection_buffer[2];
+int fl_selection_length[2];
+static int fl_selection_buffer_length[2];
+
+static PasteboardRef myPasteboard = 0;
+static void allocatePasteboard() {
+ if (!myPasteboard)
+ PasteboardCreate(kPasteboardClipboard, &myPasteboard);
+}
+
+
+/**
+ * create a selection
+ * owner: widget that created the selection
+ * stuff: pointer to selected data
+ * size of selected data
+ */
+void Fl::copy(const char *stuff, int len, int clipboard) {
+ if (!stuff || len<0) return;
+ if (len+1 > fl_selection_buffer_length[clipboard]) {
+ delete[] fl_selection_buffer[clipboard];
+ fl_selection_buffer[clipboard] = new char[len+100];
+ fl_selection_buffer_length[clipboard] = len+100;
+ }
+ memcpy(fl_selection_buffer[clipboard], stuff, len);
+ fl_selection_buffer[clipboard][len] = 0; // needed for direct paste
+ fl_selection_length[clipboard] = len;
+ if (clipboard) {
+ allocatePasteboard();
+ OSStatus err = PasteboardClear(myPasteboard);
+ if (err!=noErr) return; // clear did not work, maybe not owner of clipboard.
+ PasteboardSynchronize(myPasteboard);
+ CFDataRef text = CFDataCreate(kCFAllocatorDefault, (UInt8*)fl_selection_buffer[1], len);
+ if (text==NULL) return; // there was a pb creating the object, abort.
+ err=PasteboardPutItemFlavor(myPasteboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), text, 0);
+ CFRelease(text);
+ }
+}
+
+// Call this when a "paste" operation happens:
+void Fl::paste(Fl_Widget &receiver, int clipboard) {
+ if (clipboard) {
+ // see if we own the selection, if not go get it:
+ fl_selection_length[1] = 0;
+ OSStatus err = noErr;
+ Boolean found = false;
+ CFDataRef flavorData = NULL;
+ CFStringEncoding encoding = 0;
+
+ allocatePasteboard();
+ PasteboardSynchronize(myPasteboard);
+ ItemCount nFlavor = 0, i, j;
+ err = PasteboardGetItemCount(myPasteboard, &nFlavor);
+ if (err==noErr) {
+ for (i=1; i<=nFlavor; i++) {
+ PasteboardItemID itemID = 0;
+ CFArrayRef flavorTypeArray = NULL;
+ found = false;
+ err = PasteboardGetItemIdentifier(myPasteboard, i, &itemID);
+ if (err!=noErr) continue;
+ err = PasteboardCopyItemFlavors(myPasteboard, itemID, &flavorTypeArray);
+ if (err!=noErr) {
+ if (flavorTypeArray) {CFRelease(flavorTypeArray); flavorTypeArray = NULL;}
+ continue;
+ }
+ CFIndex flavorCount = CFArrayGetCount(flavorTypeArray);
+ for (j = 0; j < handledFlavorsCount; j++) {
+ for (CFIndex flavorIndex=0; flavorIndex<flavorCount; flavorIndex++) {
+ CFStringRef flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex);
+ if (UTTypeConformsTo(flavorType, flavorNames[j])) {
+ err = PasteboardCopyItemFlavorData( myPasteboard, itemID, flavorNames[j], &flavorData );
+ if(err != noErr) continue;
+ encoding = encodings[j];
+ found = true;
+ break;
+ }
+ }
+ if(found) break;
+ }
+ if (flavorTypeArray) {CFRelease(flavorTypeArray); flavorTypeArray = NULL;}
+ if (found) break;
+ }
+ if(found) {
+ CFIndex len = CFDataGetLength(flavorData);
+ CFStringRef mycfs = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(flavorData), len, encoding, false);
+ CFRelease(flavorData);
+ len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(mycfs), kCFStringEncodingUTF8) + 1;
+ if ( len >= fl_selection_buffer_length[1] ) {
+ fl_selection_buffer_length[1] = len;
+ delete[] fl_selection_buffer[1];
+ fl_selection_buffer[1] = new char[len];
+ }
+ CFStringGetCString(mycfs, fl_selection_buffer[1], len, kCFStringEncodingUTF8);
+ CFRelease(mycfs);
+ 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];
+ Fl::e_length = fl_selection_length[clipboard];
+ if (!Fl::e_text) Fl::e_text = (char *)"";
+ receiver.handle(FL_PASTE);
+}
+
+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) {
+ MacTimeout& t = mac_timers[i];
+ // if so, simply change the fire interval
+ if (t.callback == cb && t.data == data) {
+ SetEventLoopTimerNextFireTime(t.timer, (EventTimerInterval)time);
+ t.pending = 1;
+ return;
+ }
+ }
+ // 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) {
+ if ( !mac_timers[i].timer ) {
+ timer_id = i;
+ break;
+ }
+ }
+ // if there was no empty slot, append a new timer
+ if (timer_id == -1) {
+ // make space if needed
+ if (mac_timer_used == mac_timer_alloc) {
+ realloc_timers();
+ }
+ timer_id = mac_timer_used++;
+ }
+ // now install a brand new timer
+ MacTimeout& t = mac_timers[timer_id];
+ EventTimerInterval fireDelay = (EventTimerInterval)time;
+ EventLoopTimerUPP timerUPP = NewEventLoopTimerUPP(do_timer);
+ EventLoopTimerRef timerRef = 0;
+ OSStatus err = InstallEventLoopTimer(GetMainEventLoop(), fireDelay, 0, timerUPP, data, &timerRef);
+ if (err == noErr) {
+ t.callback = cb;
+ t.data = data;
+ t.timer = timerRef;
+ t.upp = timerUPP;
+ t.pending = 1;
+ } else {
+ if (timerRef)
+ RemoveEventLoopTimer(timerRef);
+ if (timerUPP)
+ DisposeEventLoopTimerUPP(timerUPP);
+ }
+}
+
+void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data)
+{
+ // currently, repeat_timeout does not subtract the trigger time of the previous timer event as it should.
+ add_timeout(time, cb, data);
+}
+
+int Fl::has_timeout(Fl_Timeout_Handler cb, void* data)
+{
+ 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;
+ }
+ }
+ return 0;
+}
+
+void Fl::remove_timeout(Fl_Timeout_Handler cb, void* data)
+{
+ 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);
+ }
+ }
+ breakMacEventLoop();
+}
+
+int MacUnlinkWindow(Fl_X *ip, Fl_X *start) {
+ if (!ip) return 0;
+ if (start) {
+ Fl_X *pc = start;
+ while (pc) {
+ if (pc->xidNext == ip) {
+ pc->xidNext = ip->xidNext;
+ return 1;
+ }
+ if (pc->xidChildren) {
+ if (pc->xidChildren == ip) {
+ pc->xidChildren = ip->xidNext;
+ return 1;
+ }
+ if (MacUnlinkWindow(ip, pc->xidChildren))
+ return 1;
+ }
+ pc = pc->xidNext;
+ }
+ } else {
+ for ( Fl_X *pc = Fl_X::first; pc; pc = pc->next ) {
+ if (MacUnlinkWindow(ip, pc))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void MacRelinkWindow(Fl_X *x, Fl_X *p) {
+ if (!x || !p) return;
+ // first, check if 'x' is already registered as a child of 'p'
+ for (Fl_X *i = p->xidChildren; i; i=i->xidNext) {
+ if (i == x) return;
+ }
+ // now add 'x' as the first child of 'p'
+ x->xidNext = p->xidChildren;
+ p->xidChildren = x;
+}
+
+void MacDestroyWindow(Fl_Window *w, void *p) {
+ MacUnmapWindow(w, 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()));
+ w->redraw();
+ }
+}
+
+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));
+}
+
+Fl_Region MacRegionMinusRect(Fl_Region r, int x,int y,int w,int h)
+/* removes x,y,w,h rectangle from region r and returns result as a new Fl_Region
+ */
+{
+ Fl_Region outr = (Fl_Region)malloc(sizeof(*outr));
+ outr->rects = (CGRect*)malloc(4 * r->count * sizeof(CGRect));
+ outr->count = 0;
+ CGRect rect = CGRectMake(x,y,w - 1,h - 1);
+ for( int i = 0; i < r->count; i++) {
+ CGRect A = r->rects[i];
+ CGRect test = CGRectIntersection(A, rect);
+ if(CGRectIsEmpty(test)) {
+ outr->rects[(outr->count)++] = A;
+ }
+ else {
+ const CGFloat verylarge = 100000.;
+ CGRect side = CGRectMake(0,0,rect.origin.x,verylarge);//W side
+ test = CGRectIntersection(A, side);
+ if( ! CGRectIsEmpty(test)) {
+ outr->rects[(outr->count)++] = test;
+ }
+ side = CGRectMake(0,rect.origin.y + rect.size.height,verylarge,verylarge);//N side
+ test = CGRectIntersection(A, side);
+ if( ! CGRectIsEmpty(test)) {
+ outr->rects[(outr->count)++] = test;
+ }
+ side = CGRectMake(rect.origin.x + rect.size.width, 0, verylarge, verylarge);//E side
+ test = CGRectIntersection(A, side);
+ if( ! CGRectIsEmpty(test)) {
+ outr->rects[(outr->count)++] = test;
+ }
+ side = CGRectMake(0, 0, verylarge, rect.origin.y);//S side
+ test = CGRectIntersection(A, side);
+ if( ! CGRectIsEmpty(test)) {
+ outr->rects[(outr->count)++] = test;
+ }
+ }
+ }
+ 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;
+}
+
+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);
+ 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;
+ }
+ if(j) {
+ outr->count = j;
+ outr->rects = (CGRect*)realloc(outr->rects, outr->count * sizeof(CGRect));
+ }
+ else {
+ XDestroyRegion(outr);
+ outr = XRectangleRegion(0,0,0,0);
+ }
+ return outr;
+}
+
+void MacCollapseWindow(Window w)
+{
+ [(NSWindow*)w miniaturize:nil];
+}
+
+static NSImage *CGBitmapContextToNSImage(CGContextRef c)
+//the returned NSImage is autoreleased
+{
+ unsigned char *pdata = (unsigned char *)CGBitmapContextGetData(c);
+ NSBitmapImageRep *imagerep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&pdata
+ pixelsWide:CGBitmapContextGetWidth(c)
+ pixelsHigh:CGBitmapContextGetHeight(c)
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:CGBitmapContextGetBytesPerRow(c)
+ bitsPerPixel:CGBitmapContextGetBitsPerPixel(c)];
+ NSImage* image = [[NSImage alloc] initWithData: [imagerep TIFFRepresentation]];
+ [imagerep release];
+ return [image autorelease];
+}
+
+static NSCursor *PrepareCursor(NSCursor *cursor, CGContextRef (*f)() )
+{
+ if(cursor == nil) {
+ CGContextRef c = f();
+ NSImage *image = CGBitmapContextToNSImage(c);
+ fl_delete_offscreen( (Fl_Offscreen)c );
+ NSPoint pt = {[image size].width/2, [image size].height/2};
+ cursor = [[NSCursor alloc] initWithImage:image hotSpot:pt];
+ }
+ return cursor;
+}
+
+void *MACSetCursor(Fl_Cursor c)
+{
+ NSCursor *icrsr;
+ switch (c) {
+ case FL_CURSOR_CROSS: icrsr = [NSCursor crosshairCursor]; break;
+ case FL_CURSOR_WAIT:
+ static NSCursor *watch = nil;
+ watch = PrepareCursor(watch, CreateWatchImage);
+ icrsr = watch;
+ break;
+ case FL_CURSOR_INSERT: icrsr = [NSCursor IBeamCursor]; break;
+ case FL_CURSOR_N: icrsr = [NSCursor resizeUpCursor]; break;
+ case FL_CURSOR_S: icrsr = [NSCursor resizeDownCursor]; break;
+ case FL_CURSOR_NS: icrsr = [NSCursor resizeUpDownCursor]; break;
+ case FL_CURSOR_HELP:
+ static NSCursor *help = nil;
+ help = PrepareCursor(help, CreateHelpImage);
+ icrsr = help;
+ break;
+ case FL_CURSOR_HAND: icrsr = [NSCursor pointingHandCursor]; break;
+ case FL_CURSOR_MOVE: icrsr = [NSCursor openHandCursor]; break;
+ case FL_CURSOR_NE:
+ case FL_CURSOR_SW:
+ case FL_CURSOR_NESW:
+ static NSCursor *nesw = nil;
+ nesw = PrepareCursor(nesw, CreateNESWImage);
+ icrsr = nesw;
+ break;
+ case FL_CURSOR_E: icrsr = [NSCursor resizeRightCursor]; break;
+ case FL_CURSOR_W: icrsr = [NSCursor resizeLeftCursor]; break;
+ case FL_CURSOR_WE: icrsr = [NSCursor resizeLeftRightCursor]; break;
+ case FL_CURSOR_SE:
+ case FL_CURSOR_NW:
+ case FL_CURSOR_NWSE:
+ static NSCursor *nwse = nil;
+ nwse = PrepareCursor(nwse, CreateNWSEImage);
+ icrsr = nwse;
+ break;
+ case FL_CURSOR_NONE:
+ static NSCursor *none = nil;
+ none = PrepareCursor(none, CreateNoneImage);
+ icrsr = none;
+ break;
+ case FL_CURSOR_ARROW:
+ case FL_CURSOR_DEFAULT:
+ default: icrsr = [NSCursor arrowCursor];
+ break;
+ }
+ [icrsr set];
+ return icrsr;
+}
+
+int MACscreen_init(XRectangle screens[])
+{
+ NSAutoreleasePool *localPool;
+ localPool = [[NSAutoreleasePool alloc] init];
+ NSArray *a = [NSScreen screens];
+ int count = (int)[a count];
+ NSRect r;
+ int i, num_screens = 0;
+ for( i = 0; i < count; i++) {
+ 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;
+}
+
+static NSMenu *appleMenu;
+static void createAppleMenu(void)
+{
+ static BOOL donethat = NO;
+ if(donethat) return;
+ donethat = YES;
+ NSMenu *mainmenu, *services;
+ NSMenuItem *menuItem;
+ NSString *title;
+ CFStringRef nsappname;
+
+ ProcessSerialNumber psn;
+ GetCurrentProcess(&psn);
+ CopyProcessName(&psn, &nsappname);
+ appleMenu = [[NSMenu alloc] initWithTitle:@""];
+ /* Add menu items */
+ title = [@"About " stringByAppendingString:(NSString*)nsappname];
+ [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+ // Services Menu
+ services = [[[NSMenu alloc] init] autorelease];
+ [appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
+ [appleMenu setSubmenu: services forItem: [appleMenu itemWithTitle: @"Services"]];
+ // Hide AppName
+ title = [@"Hide " stringByAppendingString:(NSString*)nsappname];
+ [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
+ // Hide Others
+ menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:)
+ keyEquivalent:@"h"];
+ [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
+ // Show All
+ [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
+ [appleMenu addItem:[NSMenuItem separatorItem]];
+ // Quit AppName
+ title = [@"Quit " stringByAppendingString:(NSString*)nsappname];
+ [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
+ /* Put menu into the menubar */
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+ [menuItem setSubmenu:appleMenu];
+ mainmenu = [[NSMenu alloc] initWithTitle:@""];
+ [mainmenu addItem:menuItem];
+ if(MACsystemVersion < 0x1060) {
+ // [NSApp setAppleMenu:appleMenu];
+ // to avoid compiler warning raised by use of undocumented setAppleMenu :
+ [NSApp performSelector:@selector(setAppleMenu:) withObject:appleMenu];
+ }
+ [NSApp setServicesMenu:services];
+ [NSApp setMainMenu:mainmenu];
+ CFRelease(nsappname);
+ [services release];
+ [mainmenu release];
+ [appleMenu release];
+ [menuItem release];
+}
+
+@interface FLMenuItem : NSMenuItem {
+ Fl_Callback *cb;
+ void *data;
+}
+- (FLMenuItem*) putData:(Fl_Callback*)callback pter:(void*)d;
+- (void) doCallback:(id)obj;
+- (void*)getItemData;
+@end
+@implementation FLMenuItem
+- (FLMenuItem*) putData:(Fl_Callback*)callback pter:(void*)d
+{
+ cb = callback;
+ data = d;
+ return self;
+}
+- (void) doCallback:(id)obj
+{
+ cb((Fl_Widget*)obj, data);
+}
+- (void*)getItemData
+{
+ return data;
+}
+@end
+
+void *MACmainMenu(void)
+{
+ return (void *)[NSApp mainMenu];
+}
+
+void *MACcreateMenu(const char *name)
+// to create a new top-level menu in the apple menu bar
+// returns the created menu (NSMenu*)
+{
+ fl_open_display();
+ NSMenu *mymenu;
+ NSMenuItem *menuItem;
+ CFStringRef cfname = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+ mymenu = [[NSMenu alloc] initWithTitle:(NSString*)cfname];
+ CFRelease(cfname);
+ // Put menu into the menubar
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+ [menuItem setSubmenu:mymenu];
+ [[NSApp mainMenu] addItem:menuItem];
+ [menuItem release];
+ [mymenu setAutoenablesItems:NO];
+ [mymenu release];
+ return (void *)mymenu;
+}
+
+void MACsetAboutMenu( Fl_Callback *cb, void *data )
+// attaches a callback to the "About myprog" item of the application menu
+{
+ fl_open_display();
+ CFStringRef cfname = CFStringCreateCopy(NULL, (CFStringRef)[[appleMenu itemAtIndex:0] title]);
+ [appleMenu removeItemAtIndex:0];
+ FLMenuItem *item = [[FLMenuItem alloc] autorelease];
+ [item initWithTitle:(NSString*)cfname action:@selector(doCallback:) keyEquivalent:@""];
+ [item putData:cb pter:data];
+ [appleMenu insertItem:item atIndex:0];
+ CFRelease(cfname);
+ [item setTarget:item];
+}
+
+void *MACMenuOrItemOperation(const char *operation, ...)
+/* these operations apply to menus, submenus, or menu items
+ */
+{
+ NSMenu *menu;
+ NSMenuItem *item;
+ int value;
+ void *pter;
+ void *retval = NULL;
+ va_list ap;
+ va_start(ap, operation);
+
+ if(strcmp(operation, "itemAtIndex") == 0) {//arguments: NSMenu*, int. Returns the item
+ menu = va_arg(ap, NSMenu*);
+ value = va_arg(ap, int);
+ retval = (void *)[menu itemAtIndex:value];
+ }
+ else if(strcmp(operation, "setKeyEquivalent") == 0) {//arguments: NSMenuItem*, int
+ item = va_arg(ap, NSMenuItem*);
+ value = va_arg(ap, int);
+ NSString *equiv = [[NSString alloc] initWithBytes:&value length:1 encoding:NSASCIIStringEncoding];
+ [item setKeyEquivalent:equiv];
+ [equiv release];
+ }
+ else if(strcmp(operation, "setKeyEquivalentModifierMask") == 0) {//arguments: NSMenuItem*, int
+ item = va_arg(ap, NSMenuItem*);
+ value = va_arg(ap, int);
+ NSUInteger macMod = 0;
+ if ( value & FL_META ) macMod = NSCommandKeyMask;
+ if ( value & FL_SHIFT || isupper(value) ) macMod |= NSShiftKeyMask;
+ if ( value & FL_ALT ) macMod |= NSAlternateKeyMask;
+ if ( value & FL_CTRL ) macMod |= NSControlKeyMask;
+ [item setKeyEquivalentModifierMask:macMod];
+ }
+ else if(strcmp(operation, "setState") == 0) {//arguments: NSMenuItem*, int
+ item = va_arg(ap, NSMenuItem*);
+ value = va_arg(ap, int);
+ [item setState:(value ? NSOnState : NSOffState)];
+ }
+ else if(strcmp(operation, "initWithTitle") == 0) {//arguments: const char*title. Returns the newly created menu
+ //creates a new (sub)menu
+ pter = va_arg(ap, void *);
+ CFStringRef title = CFStringCreateWithCString(NULL, (const char *)pter, kCFStringEncodingUTF8);
+ NSMenu *menu = [[NSMenu alloc] initWithTitle:(NSString*)title];
+ CFRelease(title);
+ [menu setAutoenablesItems:NO];
+ retval = (void *)menu;
+ [menu autorelease];
+ }
+ else if(strcmp(operation, "numberOfItems") == 0) {//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(strcmp(operation, "setSubmenu") == 0) {//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];
+ }
+ else if(strcmp(operation, "setEnabled") == 0) {//arguments: NSMenuItem*, int
+ item = va_arg(ap, NSMenuItem*);
+ value = va_arg(ap, int);
+ [item setEnabled:(value ? YES : NO)];
+ }
+ else if(strcmp(operation, "addSeparatorItem") == 0) {//arguments: NSMenu*
+ menu = va_arg(ap, NSMenu*);
+ [menu addItem:[NSMenuItem separatorItem]];
+ }
+ else if(strcmp(operation, "setTitle") == 0) {//arguments: NSMenuItem*, const char *
+ item = va_arg(ap, NSMenuItem*);
+ pter = va_arg(ap, void *);
+ CFStringRef title = CFStringCreateWithCString(NULL, (const char *)pter, kCFStringEncodingUTF8);
+ [item setTitle:(NSString*)title];
+ CFRelease(title);
+ }
+ else if(strcmp(operation, "removeItem") == 0) {//arguments: NSMenu*, int
+ menu = va_arg(ap, NSMenu*);
+ value = va_arg(ap, int);
+ [menu removeItem:[menu itemAtIndex:value]];
+ }
+ else if(strcmp(operation, "getItemData") == 0) {//arguments: NSMenu*, int. Returns the item's data
+ //items can have a callback and a data pointer attached to them. This returns the data pointer
+ menu = va_arg(ap, NSMenu*);
+ value = va_arg(ap, int);
+ retval = [(FLMenuItem *)[menu itemAtIndex:value] getItemData];
+ }
+ else if(strcmp(operation, "addNewItem") == 0) {
+ //arguments: NSMenu *menu, const char *name, Fl_Callback *cb, void *data, int *prank
+ //creates a new menu item named 'name' at the end of 'menu'
+ //attaches callback 'cb' and data pointer 'data' to it
+ //upon return, puts the rank of the new item in *prank unless prank is NULL
+ menu = va_arg(ap, NSMenu*);
+ const char *name = va_arg(ap, const char*);
+ Fl_Callback *cb = va_arg(ap, Fl_Callback*);
+ pter = va_arg(ap, void *);
+ int *prank = va_arg(ap, int*);
+ CFStringRef cfname = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+ FLMenuItem *item = [FLMenuItem alloc];
+ [item initWithTitle:(NSString*)cfname action:@selector(doCallback:) keyEquivalent:@""];
+ [item putData:cb pter:pter];
+ [menu addItem:item];
+ CFRelease(cfname);
+ [item setTarget:item];
+ if(prank != NULL) *prank = [menu indexOfItem:item];
+ [item release];
+ }
+ va_end(ap);
+ return retval;
+}
+
+void MACsetkeywindow(void *nsw)
+{
+ [(NSWindow*)nsw makeKeyAndOrderFront:nil];
+}
+
+int MACpreparedrag(void)
+{
+ CFDataRef text = CFDataCreate(kCFAllocatorDefault, (UInt8*)fl_selection_buffer[0], fl_selection_length[0]);
+ if (text==NULL) return false;
+ NSAutoreleasePool *localPool;
+ localPool = [[NSAutoreleasePool alloc] init];
+ NSPasteboard *mypasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ [mypasteboard declareTypes:[NSArray arrayWithObjects:@"public.utf8-plain-text", nil] owner:nil];
+ [mypasteboard setData:(NSData*)text forType:@"public.utf8-plain-text"];
+ CFRelease(text);
+ Fl_Widget *w = Fl::pushed();
+ Fl_Window *win = w->window();
+ while(win->window()) win = win->window();
+ NSView *myview = [(NSWindow*)Fl_X::i(win)->xid contentView];
+ NSEvent *theEvent = [NSApp currentEvent];
+
+ char *p, *q;
+ int width = 0, height, w2;
+ fl_font(FL_HELVETICA, 10);
+ fl_selection_buffer[0][ fl_selection_length[0] ] = 0;
+ p = fl_selection_buffer[0];
+ int nl = 0;
+ while((q=strchr(p, '\n')) != NULL) {
+ nl++;
+ w2 = fl_width(p, q - p);
+ if(w2 > width) width = w2;
+ p = q + 1;
+ }
+ if(fl_selection_buffer[0][ fl_selection_length[0] - 1] != '\n') {
+ nl++;
+ w2 = fl_width(p);
+ if(w2 > width) width = w2;
+ }
+ height = nl * fl_height() + 3;
+ width += 6;
+ Fl_Offscreen off = fl_create_offscreen_with_alpha(width, height);
+ fl_begin_offscreen(off);
+ CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
+ fl_rectf(0,0,width,height);
+ fl_color(FL_BLACK);
+ p = fl_selection_buffer[0];
+ int y = fl_height();
+ while(TRUE) {
+ q = strchr(p, '\n');
+ if(q) fl_draw(p, q - p, 3, y);
+ else {
+ fl_draw(p, 3, y);
+ break;
+ }
+ y += fl_height();
+ p = q + 1;
+ }
+ fl_end_offscreen();
+ NSImage* image = CGBitmapContextToNSImage( (CGContextRef)off );
+ fl_delete_offscreen( off );
+ static NSSize offset={0,0};
+ NSPoint pt = [theEvent locationInWindow];
+ pt.x -= width/2;
+ pt.y -= height/2;
+ [myview dragImage:image at:pt offset:offset
+ event:theEvent pasteboard:mypasteboard
+ source:myview slideBack:YES];
+ if ( w )
+ {
+ int old_event = Fl::e_number;
+ w->handle(Fl::e_number = FL_RELEASE);
+ Fl::e_number = old_event;
+ Fl::pushed( 0 );
+ }
+ [localPool release];
+ return true;
+}
+
+unsigned char *MACbitmapFromRectOfWindow(Fl_Window *win, int x, int y, int w, int h, int *bytesPerPixel)
+//delete the returned pointer after use
+{
+ while(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.
+ NSRect rect = NSMakeRect(x - epsilon, y - epsilon, w, h);
+ NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:rect];
+ [myview unlockFocus];
+ *bytesPerPixel = [bitmap bitsPerPixel]/8;
+ unsigned char *data = new unsigned char[w * h * *bytesPerPixel];
+ memcpy(data, [bitmap bitmapData], w * h * *bytesPerPixel);
+ [bitmap release];
+ return data;
+}
+
+void imgProviderReleaseData (void *info, const void *data, size_t size)
+{
+ delete (unsigned char *)data;
+}
+
+CGImageRef MAC_CGImageFromRectOfWindow(Fl_Window *win, int x, int y, int w, int h)
+//CFRelease the returned CGImageRef after use
+{
+ int bpp;
+ unsigned char *bitmap = MACbitmapFromRectOfWindow(win, x, y, w, h, &bpp);
+ CGImageRef img;
+ CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
+ CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bitmap, w*h*bpp, imgProviderReleaseData);
+ img = CGImageCreate(w, h, 8, 8*bpp, w*bpp, lut,
+ bpp == 3 ? kCGImageAlphaNone : kCGImageAlphaLast,
+ provider, NULL, false, kCGRenderingIntentDefault);
+ CGColorSpaceRelease(lut);
+ CGDataProviderRelease(provider);
+ return img;
+}
+
+void MACsetContainsGLsubwindow(Fl_Window *w)
+{
+ [(FLWindow*)Fl_X::i(w)->xid setContainsGLsubwindow:YES];
+}
+
+WindowRef MACwindowRef(Fl_Window *w)
+{
+ return (WindowRef)[(FLWindow*)Fl_X::i(w)->xid windowRef];
+}
+#endif // FL_DOXYGEN
+
+//
+// End of "$Id: Fl_mac.cxx 6758 2009-04-13 07:32:01Z matt $".
+//
diff --git a/src/Fl_compose.cxx b/src/Fl_compose.cxx
index a24fa8a85..a272c055e 100644
--- a/src/Fl_compose.cxx
+++ b/src/Fl_compose.cxx
@@ -26,6 +26,7 @@
//
#include <FL/Fl.H>
+#include <FL/x.H>
//
// MRS: Uncomment the following define to get the original (pre-1.1.2)
@@ -38,6 +39,15 @@
#ifdef __APPLE__
+#ifdef __APPLE_COCOA__
+
+static const char* const compose_pairs =
+" ! % # $ y=| & : c a <<~ - r _ * +-2 3 ' u p . , 1 o >>141234? "//00A0 ...
+"`A'A^A~A:A*AAE,C`E'E^E:E`I'I^I:I-D~N`O'O^O~O:Ox O/`U'U^U:U'YTHss" //00C0 ...
+"`a'a^a~a:a*aae,c`e'e^e:e`i'i^i:i-d~n`o'o^o~o:o-:o/`u'u^u:u'yth:y";//00E0 ...
+
+#else
+
static const char* const compose_pairs =
":A*A,C'E~N:O:U'a`a^a:a~a*a,c'e`e"
"^e:e'i`i^i:i~n'o`o^o:o~o'u`u^u:u"
@@ -48,6 +58,8 @@ static const char* const compose_pairs =
"++..,,_\"%%^A^E'A:E`E'I^I:I`I'O^O"
"mc`O'U^U`U||^ ~^_ u . * , ~-; v ";
+#endif
+
#else
static const char* const compose_pairs =
diff --git a/src/Fl_grab.cxx b/src/Fl_grab.cxx
index b16ee536f..b6d49f8a5 100644
--- a/src/Fl_grab.cxx
+++ b/src/Fl_grab.cxx
@@ -48,7 +48,12 @@ extern HWND fl_capture;
#ifdef __APPLE__
// MacOS Carbon does not seem to have a mechanism to grab the mouse pointer
-extern WindowRef fl_capture;
+#ifdef __APPLE_COCOA__
+extern void MACsetkeywindow(void *nsw);
+extern void *fl_capture;
+#else
+extern Window fl_capture;
+#endif
#endif
void Fl::grab(Fl_Window* win) {
@@ -58,8 +63,13 @@ void Fl::grab(Fl_Window* win) {
SetActiveWindow(fl_capture = fl_xid(first_window()));
SetCapture(fl_capture);
#elif defined(__APPLE__)
- fl_capture = fl_xid( first_window() );
- SetUserFocusWindow( fl_capture );
+#ifdef __APPLE_COCOA__
+ fl_capture = Fl_X::i(first_window())->xid;
+ MACsetkeywindow(fl_capture);
+#else
+ fl_capture = fl_xid( first_window() );
+ SetUserFocusWindow( fl_capture );
+#endif
#else
XGrabPointer(fl_display,
fl_xid(first_window()),
@@ -87,7 +97,9 @@ void Fl::grab(Fl_Window* win) {
ReleaseCapture();
#elif defined(__APPLE__)
fl_capture = 0;
+#ifndef __APPLE_COCOA__
SetUserFocusWindow( (WindowRef)kUserFocusAuto );
+#endif
#else
XUngrabKeyboard(fl_display, fl_event_time);
XUngrabPointer(fl_display, fl_event_time);
diff --git a/src/cgdebug.h b/src/cgdebug.h
index ab7e9330b..bc3924f11 100644
--- a/src/cgdebug.h
+++ b/src/cgdebug.h
@@ -212,3 +212,4 @@ inline void dbgCGContextRestoreGState(CGContextRef context)
//
// End of "$Id$".
//
+
diff --git a/src/fl_arci.cxx b/src/fl_arci.cxx
index a9d25f0ed..47db7b3fc 100644
--- a/src/fl_arci.cxx
+++ b/src/fl_arci.cxx
@@ -86,6 +86,9 @@ void fl_arc(int x,int y,int w,int h,double a1,double a2) {
#elif defined(__APPLE_QUARTZ__)
a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI;
float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f;
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
if (w!=h) {
CGContextSaveGState(fl_gc);
CGContextTranslateCTM(fl_gc, cx, cy);
@@ -97,6 +100,9 @@ void fl_arc(int x,int y,int w,int h,double a1,double a2) {
CGContextAddArc(fl_gc, cx, cy, r, a1, a2, 1);
}
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
@@ -136,6 +142,9 @@ void fl_pie(int x,int y,int w,int h,double a1,double a2) {
#elif defined(__APPLE_QUARTZ__)
a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI;
float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f;
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
if (w!=h) {
CGContextSaveGState(fl_gc);
CGContextTranslateCTM(fl_gc, cx, cy);
@@ -151,6 +160,9 @@ void fl_pie(int x,int y,int w,int h,double a1,double a2) {
CGContextClosePath(fl_gc);
}
CGContextFillPath(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
diff --git a/src/fl_ask.cxx b/src/fl_ask.cxx
index 4397d3859..4496c48bf 100644
--- a/src/fl_ask.cxx
+++ b/src/fl_ask.cxx
@@ -273,7 +273,8 @@ void fl_beep(int type) {
switch (type) {
case FL_BEEP_DEFAULT :
case FL_BEEP_ERROR :
- SysBeep(30);
+// SysBeep(30);
+ AlertSoundPlay();
break;
default :
break;
diff --git a/src/fl_cursor.cxx b/src/fl_cursor.cxx
index 2cdf8d41b..14b3cbb85 100644
--- a/src/fl_cursor.cxx
+++ b/src/fl_cursor.cxx
@@ -134,6 +134,113 @@ void Fl_Window::cursor(Fl_Cursor c, Fl_Color c1, Fl_Color c2) {
# error "Either __LITTLE_ENDIAN__ or __BIG_ENDIAN__ must be defined"
#endif
+#ifdef __APPLE_COCOA__
+extern void *MACSetCursor(Fl_Cursor c);
+extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h);
+
+
+CGContextRef CreateHelpImage(void)
+{
+ int w = 20, h = 20;
+ Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
+ fl_begin_offscreen(off);
+ CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
+ fl_rectf(0,0,w,h);
+ fl_color(FL_BLACK);
+ fl_font(FL_COURIER_BOLD, 20);
+ fl_draw("?", 1, h-1);
+ fl_end_offscreen();
+ return (CGContextRef)off;
+}
+
+CGContextRef CreateNoneImage(void)
+{
+ int w = 20, h = 20;
+ Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
+ fl_begin_offscreen(off);
+ CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
+ fl_rectf(0,0,w,h);
+ fl_end_offscreen();
+ return (CGContextRef)off;
+}
+
+CGContextRef CreateWatchImage(void)
+{
+ int w, h, r = 5;
+ w = 2*r+6;
+ h = 4*r;
+ Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
+ fl_begin_offscreen(off);
+ CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
+ fl_rectf(0,0,w,h);
+ CGContextTranslateCTM( (CGContextRef)off, w/2, h/2);
+ fl_color(FL_WHITE);
+ fl_circle(0, 0, r+1);
+ fl_color(FL_BLACK);
+ fl_rectf(-r*0.7, -r*1.7, 1.4*r, 3.4*r);
+ fl_rectf(r-1, -1, 3, 3);
+ fl_color(FL_WHITE);
+ fl_pie(-r, -r, 2*r, 2*r, 0, 360);
+ fl_color(FL_BLACK);
+ fl_circle(0,0,r);
+ fl_xyline(0, 0, -r*.7);
+ fl_xyline(0, 0, 0, -r*.7);
+ fl_end_offscreen();
+ return (CGContextRef)off;
+}
+
+CGContextRef CreateNESWImage(void)
+{
+ int c = 7, r = 2*c;
+ int w = r, h = r;
+ Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
+ fl_begin_offscreen(off);
+ CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
+ fl_rectf(0,0,w,h);
+ CGContextTranslateCTM( (CGContextRef)off, 0, h);
+ CGContextScaleCTM( (CGContextRef)off, 1, -1);
+ fl_color(FL_BLACK);
+ fl_polygon(0, 0, c, 0, 0, c);
+ fl_polygon(r, r, r, r-c, r-c, r);
+ fl_line_style(FL_SOLID, 2, 0);
+ fl_line(0,1, r,r+1);
+ fl_line_style(FL_SOLID, 0, 0);
+ fl_end_offscreen();
+ return (CGContextRef)off;
+}
+
+CGContextRef CreateNWSEImage(void)
+{
+ int c = 7, r = 2*c;
+ int w = r, h = r;
+ Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
+ fl_begin_offscreen(off);
+ CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
+ fl_rectf(0,0,w,h);
+ CGContextTranslateCTM( (CGContextRef)off, 0, h);
+ CGContextScaleCTM( (CGContextRef)off, 1, -1);
+ fl_color(FL_BLACK);
+ fl_polygon(r-1, 0, r-1, c, r-1-c, 0);
+ fl_polygon(-1, r, c-1, r, -1, r-c);
+ fl_line_style(FL_SOLID, 2, 0);
+ fl_line(r-1,1, -1,r+1);
+ fl_line_style(FL_SOLID, 0, 0);
+ fl_end_offscreen();
+ return (CGContextRef)off;
+}
+
+void Fl_Window::cursor(Fl_Cursor c, Fl_Color, Fl_Color) {
+ if (c == FL_CURSOR_DEFAULT) {
+ c = cursor_default;
+ }
+ void *cursor = MACSetCursor( c );
+ if (i) {
+ i->cursor = cursor;
+ }
+}
+
+#else
+
static Cursor crsrHAND =
{
{ E(0x0600), E(0x0900), E(0x0900), E(0x0900), E(0x09C0), E(0x0938), E(0x6926), E(0x9805),
@@ -214,7 +321,7 @@ void Fl_Window::cursor(Fl_Cursor c, Fl_Color, Fl_Color) {
c = cursor_default;
}
CursHandle icrsr = fl_default_cursor;
- switch (c) {
+ switch (c) {
case FL_CURSOR_CROSS: icrsr = GetCursor( crossCursor ); break;
case FL_CURSOR_WAIT: icrsr = GetCursor( watchCursor ); break;
case FL_CURSOR_INSERT: icrsr = GetCursor( iBeamCursor ); break;
@@ -246,6 +353,8 @@ void Fl_Window::cursor(Fl_Cursor c, Fl_Color, Fl_Color) {
}
}
+#endif //__APPLE_COCOA__
+
#else
// I like the MSWindows resize cursors, so I duplicate them here:
diff --git a/src/fl_dnd_mac.cxx b/src/fl_dnd_mac.cxx
index af8cf1c58..9928e4b9f 100644
--- a/src/fl_dnd_mac.cxx
+++ b/src/fl_dnd_mac.cxx
@@ -46,6 +46,11 @@ extern int fl_selection_length;
*/
int Fl::dnd()
{
+#ifdef __APPLE_COCOA__
+ extern int MACpreparedrag(void);
+ return MACpreparedrag();
+#else
+
OSErr result;
DragReference dragRef;
result = NewDrag( &dragRef );
@@ -82,6 +87,7 @@ int Fl::dnd()
DisposeRgn( region );
DisposeDrag( dragRef );
return true;
+#endif //__APPLE_COCOA__
}
diff --git a/src/fl_font_mac.cxx b/src/fl_font_mac.cxx
index 3e9db0763..552a579ad 100644
--- a/src/fl_font_mac.cxx
+++ b/src/fl_font_mac.cxx
@@ -33,6 +33,8 @@ extern unsigned fl_utf8toUtf16(const char* src, unsigned srclen, unsigned short*
// if no font has been selected yet by the user, get one.
#define check_default_font() {if (!fl_fontsize) fl_font(0, 12);}
+static const CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 };
+
Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) {
next = 0;
# if HAVE_GL
@@ -43,13 +45,39 @@ Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) {
// OpenGL needs those for its font handling
q_name = strdup(name);
size = Size;
+ minsize = maxsize = Size;
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+if(CTFontCreateWithName != NULL) {
+ CFStringRef str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+ fontref = CTFontCreateWithName(str, size, NULL);
+ CGGlyph glyph[2];
+ const UniChar A[2]={'W','.'};
+ CTFontGetGlyphsForCharacters(fontref, A, glyph, 2);
+ CGSize advances[2];
+ double w;
+ CTFontGetAdvancesForGlyphs(fontref, kCTFontHorizontalOrientation, glyph, advances, 2);
+ w = advances[0].width;
+ if( abs(advances[0].width - advances[1].width) < 1E-2 ) {//this is a fixed-width font
+ //slightly rescale fixed-width fonts so the character width has an integral value
+ CFRelease(fontref);
+ CGFloat fsize = size / ( w/floor(w + 0.5) );
+ fontref = CTFontCreateWithName(str, fsize, NULL);
+ w = CTFontGetAdvancesForGlyphs(fontref, kCTFontHorizontalOrientation, glyph, NULL, 1);
+ }
+ CFRelease(str);
+ ascent = (short)(CTFontGetAscent(fontref) + 0.5);
+ descent = (short)(CTFontGetDescent(fontref) + 0.5);
+ q_width = w + 0.5;
+ }
+else {
+#endif
+#if ! __LP64__
OSStatus err;
// fill our structure with a few default values
ascent = Size*3/4;
descent = Size-ascent;
q_width = Size*2/3;
- minsize = maxsize = Size;
- // now use ATS to get the actual Glyph size information
+ // now use ATS to get the actual Glyph size information
// say that our passed-in name is encoded as UTF-8, since this works for plain ASCII names too...
CFStringRef cfname = CFStringCreateWithCString(0L, name, kCFStringEncodingUTF8);
ATSFontRef font = ATSFontFindFromName(cfname, kATSOptionFlagsDefault);
@@ -112,6 +140,10 @@ Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize Size) {
// cause ATSU to find a suitable font to render any chars the current font can't do...
ATSUSetTransientFontMatching (layout, true);
# endif
+#endif//__LP64__
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ }
+#endif
}
Fl_Font_Descriptor* fl_fontsize = 0L;
@@ -132,8 +164,12 @@ Fl_Font_Descriptor::~Fl_Font_Descriptor() {
#endif
*/
if (this == fl_fontsize) fl_fontsize = 0;
- ATSUDisposeTextLayout(layout);
- ATSUDisposeStyle(style);
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ if(CTFontCreateWithName != NULL) CFRelease(fontref);
+#else
+ /* ATSUDisposeTextLayout(layout);
+ ATSUDisposeStyle(style); */
+#endif
}
////////////////////////////////////////////////////////////////
@@ -235,7 +271,25 @@ double fl_width(const UniChar* txt, int n) {
if (!fl_fontsize)
return 8*n; // user must select a font first!
}
- OSStatus err;
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+if(CTFontCreateWithName != NULL) {
+ CTFontRef fontref = fl_fontsize->fontref;
+ CFStringRef str = CFStringCreateWithBytes(NULL, (const UInt8*)txt, n * sizeof(UniChar), kCFStringEncodingUTF16, false);
+ CFAttributedStringRef astr = CFAttributedStringCreate(NULL, str, NULL);
+ CFMutableAttributedStringRef mastr = CFAttributedStringCreateMutableCopy(NULL, 0, astr);
+ CFRelease(astr);
+ CFAttributedStringSetAttribute(mastr, CFRangeMake(0, CFStringGetLength(str)), kCTFontAttributeName, fontref);
+ CFRelease(str);
+ CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
+ CFRelease(mastr);
+ double retval = CTLineGetTypographicBounds(ctline, NULL, NULL, NULL);
+ CFRelease(ctline);
+ return retval;
+ }
+else {
+#endif
+#if ! __LP64__
+ OSStatus err;
Fixed bBefore, bAfter, bAscent, bDescent;
ATSUTextLayout layout;
ByteCount iSize;
@@ -256,6 +310,10 @@ double fl_width(const UniChar* txt, int n) {
// If err is OK then return length, else return 0. Or something...
int len = FixedToInt(bAfter);
return len;
+#endif
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ }
+#endif
}
double fl_width(const char* txt, int n) {
@@ -281,6 +339,30 @@ void fl_text_extents(const UniChar* txt, int n, int &dx, int &dy, int &w, int &h
h = 8.0;
return;
}
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+if(CTFontCreateWithName != NULL) {
+ CTFontRef fontref = fl_fontsize->fontref;
+ CFStringRef str16 = CFStringCreateWithBytes(NULL, (const UInt8*)txt, n *sizeof(UniChar), kCFStringEncodingUTF16, false);
+ CFAttributedStringRef astr = CFAttributedStringCreate(NULL, str16, NULL);
+ CFMutableAttributedStringRef mastr = CFAttributedStringCreateMutableCopy(NULL, 0, astr);
+ CFRelease(astr);
+ CFAttributedStringSetAttribute(mastr, CFRangeMake(0, CFStringGetLength(str16)), kCTFontAttributeName, fontref);
+ CFRelease(str16);
+ CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
+ CFRelease(mastr);
+ CGContextSetTextPosition(fl_gc, 0, 0);
+ CGContextSetShouldAntialias(fl_gc, true);
+ CGRect rect = CTLineGetImageBounds(ctline, fl_gc);
+ CGContextSetShouldAntialias(fl_gc, false);
+ CFRelease(ctline);
+ dx = floor(rect.origin.x + 0.5);
+ dy = floor(- rect.origin.y - rect.size.height + 0.5);
+ w = rect.size.width + 0.5;
+ h = rect.size.height + 0.5;
+ }
+else {
+#endif
+#if ! __LP64__
OSStatus err;
ATSUTextLayout layout;
ByteCount iSize;
@@ -304,6 +386,10 @@ void fl_text_extents(const UniChar* txt, int n, int &dx, int &dy, int &w, int &h
dx = bbox.left;
dy = -bbox.bottom;
//printf("r: %d l: %d t: %d b: %d w: %d h: %d\n", bbox.right, bbox.left, bbox.top, bbox.bottom, w, h);
+#endif
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ }
+#endif
return;
} // fl_text_extents
@@ -320,13 +406,76 @@ void fl_draw(const char* str, int n, int x, int y) {
fl_draw(str, n, (float)x-0.0f, (float)y-0.5f);
}
+
+#if defined(__APPLE_COCOA__)
+static unsigned fl_cmap[256] = {
+#include "fl_cmap.h" // this is a file produced by "cmap.cxx":
+};
+CGColorRef flcolortocgcolor(Fl_Color i)
+{
+ int index;
+ uchar r, g, b;
+ if (i & 0xFFFFFF00) {
+ // translate rgb colors into color index
+ r = i>>24;
+ g = i>>16;
+ b = i>> 8;
+ } else {
+ // translate index into rgb:
+ index = i;
+ unsigned c = fl_cmap[i];
+ r = c>>24;
+ g = c>>16;
+ b = c>> 8;
+ }
+ CGFloat components[4] = {r/255.0f, g/255.0f, b/255.0f, 1.};
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
+ return CGColorCreate(CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), components);
+#else
+ return CGColorCreate(CGColorSpaceCreateWithName(kCGColorSpaceUserRGB), components);
+#endif
+}
+#endif
+
void fl_draw(const char *str, int n, float x, float y) {
- OSStatus err;
- // convert to UTF-16 first
- UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n);
// avoid a crash if no font has been selected by user yet !
check_default_font();
+ // convert to UTF-16 first
+ UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n);
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+if(CTFontCreateWithName != NULL) {
+ CFStringRef keys[2];
+ CFTypeRef values[2];
+ CFStringRef str16 = CFStringCreateWithBytes(NULL, (const UInt8*)uniStr, n * sizeof(UniChar), kCFStringEncodingUTF16, false);
+ CGColorRef color = flcolortocgcolor(fl_color());
+ keys[0] = kCTFontAttributeName;
+ keys[1] = kCTForegroundColorAttributeName;
+ values[0] = fl_fontsize->fontref;
+ values[1] = color;
+ CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void**)&keys,
+ (const void**)&values,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFAttributedStringRef mastr = CFAttributedStringCreate(kCFAllocatorDefault, str16, attributes);
+ CFRelease(str16);
+ CFRelease(attributes);
+ CFRelease(color);
+ CTLineRef ctline = CTLineCreateWithAttributedString(mastr);
+ CFRelease(mastr);
+ CGContextSetTextMatrix(fl_gc, font_mx);
+ CGContextSetTextPosition(fl_gc, x, y);
+ CGContextSetShouldAntialias(fl_gc, true);
+ CTLineDraw(ctline, fl_gc);
+ CGContextSetShouldAntialias(fl_gc, false);
+ CFRelease(ctline);
+ }
+else {
+#endif
+#if ! __LP64__
+ OSStatus err;
// now collect our ATSU resources
ATSUTextLayout layout = fl_fontsize->layout;
@@ -337,10 +486,25 @@ void fl_draw(const char *str, int n, float x, float y) {
err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n);
err = ATSUDrawText(layout, kATSUFromTextBeginning, n, FloatToFixed(x), FloatToFixed(y));
+#endif
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ }
+#endif
}
void fl_draw(int angle, const char *str, int n, int x, int y) {
- OSStatus err;
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+if(CTFontCreateWithName != NULL) {
+ CGContextSaveGState(fl_gc);
+ CGContextTranslateCTM(fl_gc, x, y);
+ CGContextRotateCTM(fl_gc, - angle*(M_PI/180) );
+ fl_draw(str, n, (float)0., (float)0.);
+ CGContextRestoreGState(fl_gc);
+ }
+else {
+#endif
+#if ! __LP64__
+ OSStatus err;
// convert to UTF-16 first
UniChar *uniStr = mac_Utf8_to_Utf16(str, n, &n);
@@ -360,10 +524,21 @@ void fl_draw(int angle, const char *str, int n, int x, int y) {
//restore layout baseline
ang = IntToFixed(0);
ATSUSetLayoutControls(layout, 2, iTag, iSize, aAttr);
+#endif
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ }
+#endif
}
void fl_rtl_draw(const char* c, int n, int x, int y) {
-// I guess with ATSU the thing to do is force the layout mode to RTL and let ATSU draw the text...
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+if(CTFontCreateWithName != NULL) {
+ fl_draw(c, n, x - fl_width(c, n), y); //to check;
+ }
+else {
+#endif
+#if ! __LP64__
+ // I guess with ATSU the thing to do is force the layout mode to RTL and let ATSU draw the text...
double offs = fl_width(c, n);
OSStatus err;
// convert to UTF-16 first
@@ -379,6 +554,10 @@ void fl_rtl_draw(const char* c, int n, int x, int y) {
err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n);
err = ATSUDrawText(layout, kATSUFromTextBeginning, n, FloatToFixed(x-offs), FloatToFixed(y));
+#endif
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ }
+#endif
}
//
diff --git a/src/fl_line_style.cxx b/src/fl_line_style.cxx
index 287a2eaf7..bf299bbc7 100644
--- a/src/fl_line_style.cxx
+++ b/src/fl_line_style.cxx
@@ -40,7 +40,7 @@
float fl_quartz_line_width_ = 1.0f;
static enum CGLineCap fl_quartz_line_cap_ = kCGLineCapButt;
static enum CGLineJoin fl_quartz_line_join_ = kCGLineJoinMiter;
-static float *fl_quartz_line_pattern = 0;
+static CGFloat *fl_quartz_line_pattern = 0;
static int fl_quartz_line_pattern_size = 0;
void fl_quartz_restore_line_style_() {
CGContextSetLineWidth(fl_gc, fl_quartz_line_width_);
@@ -145,9 +145,9 @@ void fl_line_style(int style, int width, char* dashes) {
fl_quartz_line_cap_ = Cap[(style>>8)&3];
fl_quartz_line_join_ = Join[(style>>12)&3];
char *d = dashes;
- static float pattern[16];
+ static CGFloat pattern[16];
if (d && *d) {
- float *p = pattern;
+ CGFloat *p = pattern;
while (*d) { *p++ = (float)*d++; }
fl_quartz_line_pattern = pattern;
fl_quartz_line_pattern_size = d-dashes;
@@ -162,7 +162,7 @@ void fl_line_style(int style, int width, char* dashes) {
dash = char(3*width);
dot = gap = char(width);
}
- float *p = pattern;
+ CGFloat *p = pattern;
switch (style & 0xff) {
case FL_DASH: *p++ = dash; *p++ = gap; break;
case FL_DOT: *p++ = dot; *p++ = gap; break;
@@ -172,7 +172,8 @@ void fl_line_style(int style, int width, char* dashes) {
fl_quartz_line_pattern_size = p-pattern;
fl_quartz_line_pattern = pattern;
} else {
- fl_quartz_line_pattern = 0; fl_quartz_line_pattern_size = 0;
+ fl_quartz_line_pattern = 0;
+ fl_quartz_line_pattern_size = 0;
}
fl_quartz_restore_line_style_();
#else
diff --git a/src/fl_read_image_mac.cxx b/src/fl_read_image_mac.cxx
index 3df921173..08e4361f7 100644
--- a/src/fl_read_image_mac.cxx
+++ b/src/fl_read_image_mac.cxx
@@ -26,9 +26,9 @@
//
#include <config.h>
-
-// warning: this function is only implemented in Quickdraw. The function
-// below may not work If FLTK is compiled with Quartz enabled
+#ifdef __APPLE_COCOA__
+extern unsigned char *MACbitmapFromRectOfWindow(Fl_Window *win, int x, int y, int w, int h, int *bytesPerPixel);
+#endif
//
// 'fl_read_image()' - Read an image from the current window.
@@ -41,6 +41,29 @@ fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate
int w, // I - Width of area to read
int h, // I - Height of area to read
int alpha) { // I - Alpha value for image (0 for none)
+#if defined(__APPLE_COCOA__)
+ Fl_Window *window = Fl_Window::current();
+ while(window->window()) window = window->window();
+ int delta;
+ uchar *base = MACbitmapFromRectOfWindow(window,x,y,w,h,&delta);
+ int rowBytes = delta*w;
+ // Allocate the image data array as needed...
+ int d = alpha ? 4 : 3;
+ if (!p) p = new uchar[w * h * d];
+ // Initialize the default colors/alpha in the whole image...
+ memset(p, alpha, w * h * d);
+ // Copy the image from the off-screen buffer to the memory buffer.
+ int idx, idy; // Current X & Y in image
+ uchar *pdst, *psrc;
+ for (idy = 0, pdst = p; idy < h; idy ++) {
+ for (idx = 0, psrc = base + idy * rowBytes; idx < w; idx ++, psrc += delta, pdst += d) {
+/*R*/ pdst[0] = psrc[0];
+/*G*/ pdst[1] = psrc[1];
+/*B*/ pdst[2] = psrc[2];
+ }
+ }
+delete base;
+#else
Rect src, // Source rectangle
dst; // Destination rectangle
GWorldPtr osbuffer; // Temporary off-screen buffer for copy
@@ -128,7 +151,8 @@ fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate
DisposeGWorld(osbuffer);
SetPort(srcPort);
- return p;
+#endif
+return p;
}
diff --git a/src/fl_rect.cxx b/src/fl_rect.cxx
index fb7fe0f05..0709f2ff9 100644
--- a/src/fl_rect.cxx
+++ b/src/fl_rect.cxx
@@ -59,10 +59,18 @@ void fl_rect(int x, int y, int w, int h) {
LineTo(fl_gc, x, y+h-1);
LineTo(fl_gc, x, y);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGRect rect = CGRectMake(x, y, w-1, h-1);
CGContextStrokeRect(fl_gc, rect);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -81,10 +89,18 @@ void fl_rectf(int x, int y, int w, int h) {
rect.right = x + w; rect.bottom = y + h;
FillRect(fl_gc, &rect, fl_brush());
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGRect rect = CGRectMake(x, y, w-1, h-1);
CGContextFillRect(fl_gc, rect);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -99,11 +115,19 @@ void fl_xyline(int x, int y, int x1) {
#elif defined(WIN32)
MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x1+1, y);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x1, y);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -125,12 +149,20 @@ void fl_xyline(int x, int y, int x1, int y2) {
LineTo(fl_gc, x1, y);
LineTo(fl_gc, x1, y2);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x1, y);
CGContextAddLineToPoint(fl_gc, x1, y2);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
#error unsupported platform
#endif
@@ -155,13 +187,21 @@ void fl_xyline(int x, int y, int x1, int y2, int x3) {
LineTo(fl_gc, x1, y2);
LineTo(fl_gc, x3, y2);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x1, y);
CGContextAddLineToPoint(fl_gc, x1, y2);
CGContextAddLineToPoint(fl_gc, x3, y2);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -178,11 +218,19 @@ void fl_yxline(int x, int y, int y1) {
else y1++;
MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x, y1);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x, y1);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -204,12 +252,20 @@ void fl_yxline(int x, int y, int y1, int x2) {
LineTo(fl_gc, x, y1);
LineTo(fl_gc, x2, y1);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x, y1);
CGContextAddLineToPoint(fl_gc, x2, y1);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -234,13 +290,21 @@ void fl_yxline(int x, int y, int y1, int x2, int y3) {
LineTo(fl_gc, x2, y1);
LineTo(fl_gc, x2, y3);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x, y1);
CGContextAddLineToPoint(fl_gc, x2, y1);
CGContextAddLineToPoint(fl_gc, x2, y3);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -259,11 +323,19 @@ void fl_line(int x, int y, int x1, int y1) {
// functions will not draw the last point ("it's a feature!"...)
SetPixel(fl_gc, x1, y1, fl_RGB());
#elif defined(__APPLE_QUARTZ__)
- if (fl_quartz_line_width_==1.0f ) CGContextSetShouldAntialias(fl_gc, false);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
+ if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x1, y1);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -287,12 +359,20 @@ void fl_line(int x, int y, int x1, int y1, int x2, int y2) {
// functions will not draw the last point ("it's a feature!"...)
SetPixel(fl_gc, x2, y2, fl_RGB());
#elif defined(__APPLE_QUARTZ__)
- if (fl_quartz_line_width_==1.0f ) CGContextSetShouldAntialias(fl_gc, false);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
+ if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x1, y1);
CGContextAddLineToPoint(fl_gc, x2, y2);
CGContextStrokePath(fl_gc);
- if (fl_quartz_line_width_==1.0f ) CGContextSetShouldAntialias(fl_gc, true);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
+ if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -315,11 +395,17 @@ void fl_loop(int x, int y, int x1, int y1, int x2, int y2) {
LineTo(fl_gc, x2, y2);
LineTo(fl_gc, x, y);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x1, y1);
CGContextAddLineToPoint(fl_gc, x2, y2);
CGContextClosePath(fl_gc);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
@@ -344,12 +430,18 @@ void fl_loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
LineTo(fl_gc, x3, y3);
LineTo(fl_gc, x, y);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x1, y1);
CGContextAddLineToPoint(fl_gc, x2, y2);
CGContextAddLineToPoint(fl_gc, x3, y3);
CGContextClosePath(fl_gc);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
@@ -371,11 +463,17 @@ void fl_polygon(int x, int y, int x1, int y1, int x2, int y2) {
SelectObject(fl_gc, fl_brush());
Polygon(fl_gc, p, 3);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x1, y1);
CGContextAddLineToPoint(fl_gc, x2, y2);
CGContextClosePath(fl_gc);
CGContextFillPath(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
@@ -398,12 +496,18 @@ void fl_polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
SelectObject(fl_gc, fl_brush());
Polygon(fl_gc, p, 4);
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
CGContextMoveToPoint(fl_gc, x, y);
CGContextAddLineToPoint(fl_gc, x1, y1);
CGContextAddLineToPoint(fl_gc, x2, y2);
CGContextAddLineToPoint(fl_gc, x3, y3);
CGContextClosePath(fl_gc);
CGContextFillPath(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
@@ -418,11 +522,19 @@ void fl_point(int x, int y) {
#elif defined(WIN32)
SetPixel(fl_gc, x, y, fl_RGB());
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
CGContextMoveToPoint(fl_gc, x-.5, y); // Quartz needs a line that is one pixel long, or it will not draw anything
CGContextAddLineToPoint(fl_gc, x+.5, y);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -467,7 +579,17 @@ void fl_restore_clip() {
#elif defined(__APPLE_QUARTZ__)
if ( fl_window ) // clipping for a true window
{
- GrafPtr port = GetWindowPort( fl_window );
+#ifdef __APPLE_COCOA__
+ Fl_X::q_clear_clipping();
+ Fl_X::q_fill_context();//flip coords and translate if subwindow
+ //apply window's clip
+ CGContextClipToRects(fl_gc, fl_window_region->rects, fl_window_region->count );
+ //apply additional program clip
+ if(r) {
+ CGContextClipToRects(fl_gc, r->rects, r->count);
+ }
+#else
+ GrafPtr port = GetWindowPort( fl_window );
if ( port ) {
RgnHandle portClip = NewRgn();
CopyRgn( fl_window_region, portClip ); // changed
@@ -479,16 +601,22 @@ void fl_restore_clip() {
Fl_X::q_fill_context();
DisposeRgn( portClip );
}
+#endif
} else if (fl_gc) { // clipping for an offscreen drawing world (CGBitmap)
- Rect portRect;
- portRect.top = 0;
- portRect.left = 0;
- portRect.bottom = CGBitmapContextGetHeight(fl_gc);
- portRect.right = CGBitmapContextGetWidth(fl_gc);
- Fl_X::q_clear_clipping();
- if (r)
- ClipCGContextToRegion(fl_gc, &portRect, r);
- Fl_X::q_fill_context();
+ Rect portRect;
+ portRect.top = 0;
+ portRect.left = 0;
+ portRect.bottom = CGBitmapContextGetHeight(fl_gc);
+ portRect.right = CGBitmapContextGetWidth(fl_gc);
+ Fl_X::q_clear_clipping();
+ if (r) {
+#ifdef __APPLE_COCOA__
+ CGContextClipToRects(fl_gc, r->rects, r->count);
+#else
+ ClipCGContextToRegion(fl_gc, &portRect, r);
+#endif
+ }
+ Fl_X::q_fill_context();
}
#else
# error unsupported platform
@@ -534,19 +662,33 @@ void fl_push_clip(int x, int y, int w, int h) {
#elif defined(WIN32)
CombineRgn(r,r,current,RGN_AND);
#elif defined(__APPLE_QUARTZ__)
- SectRgn(r, current, r);
+#ifdef __APPLE_COCOA__
+ XDestroyRegion(r);
+ r = MacRectRegionIntersect(current, x,y,w,h);
+#else
+ SectRgn(r, current, r);
+#endif
#else
# error unsupported platform
#endif
}
+#if defined(__APPLE_QUARTZ__)
+ else {
+ r = XRectangleRegion(x,y,w,h);
+ }
+#endif
} else { // make empty clip region:
#if defined(USE_X11)
r = XCreateRegion();
#elif defined(WIN32)
r = CreateRectRgn(0,0,0,0);
#elif defined(__APPLE_QUARTZ__)
- r = NewRgn();
- SetEmptyRgn(r);
+#ifdef __APPLE_COCOA__
+ r = NULL;
+#else
+ r = NewRgn();
+ SetEmptyRgn(r);
+#endif
#else
# error unsupported platform
#endif
@@ -604,9 +746,18 @@ int fl_not_clipped(int x, int y, int w, int h) {
return RectInRegion(r,&rect);
#elif defined(__APPLE_QUARTZ__)
if (!r) return 1;
+#ifdef __APPLE_COCOA__
+ CGRect arg = CGRectMake(x,y,w - 1,h - 1);
+ for(int i = 0; i < r->count; i++) {
+ CGRect test = CGRectIntersection(r->rects[i], arg);
+ if( ! CGRectIsEmpty(test)) return 1;
+ }
+ return 0;
+#else
Rect rect;
rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h;
return RectInRgn(&rect, r);
+#endif
#else
# error unsupported platform
#endif
@@ -673,6 +824,24 @@ int fl_clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){
DeleteObject(rr);
return ret;
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ CGRect arg = CGRectMake(x,y,w - 1,h - 1);
+ CGRect u = CGRectMake(0,0,0,0);
+ CGRect test;
+ for(int i = 0; i < r->count; i++) {
+ test = CGRectIntersection(r->rects[i], arg);
+ if( ! CGRectIsEmpty(test) ) {
+ if(CGRectIsEmpty(u)) u = test;
+ else u = CGRectUnion(u, test);
+ }
+ }
+ X = u.origin.x;
+ Y = u.origin.y;
+ W = u.size.width;
+ H = u.size.height;
+ if(CGRectIsEmpty(u)) W = H = 0;
+ return ! CGRectEqualToRect(arg, u);
+#else
RgnHandle rr = NewRgn();
SetRectRgn( rr, x, y, x+w, y+h );
SectRgn( r, rr, rr );
@@ -685,6 +854,7 @@ int fl_clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){
if ( H==0 ) return 2;
if ( h==H && w==W ) return 0;
return 0;
+#endif
#else
# error unsupported platform
#endif
diff --git a/src/fl_scroll_area.cxx b/src/fl_scroll_area.cxx
index 40609bc51..ff07ef3b4 100644
--- a/src/fl_scroll_area.cxx
+++ b/src/fl_scroll_area.cxx
@@ -151,6 +151,16 @@ void fl_scroll(int X, int Y, int W, int H, int dx, int dy,
BitBlt(fl_gc, dest_x, dest_y, src_w, src_h, fl_gc, src_x, src_y,SRCCOPY);
#elif defined(__APPLE_QUARTZ__)
+
+#if defined(__APPLE_COCOA__)
+ extern CGImageRef MAC_CGImageFromRectOfWindow(Fl_Window*, int x, int y, int w, int h);
+ CGImageRef img = MAC_CGImageFromRectOfWindow(Fl_Window::current(), src_x, src_y, src_w, src_h);
+ CGRect rect = { { dest_x, dest_y }, { src_w, src_h } };
+ Fl_X::q_begin_image(rect, 0, 0, src_w, src_h);
+ CGContextDrawImage(fl_gc, rect, img);
+ Fl_X::q_end_image();
+ CFRelease(img);
+#else
// warning: there does not seem to be an equivalent to this function in Quartz
// ScrollWindowRect is a QuickDraw function and won't work here.
// Since on OS X all windows are fully double buffered, we need not
@@ -161,6 +171,8 @@ void fl_scroll(int X, int Y, int W, int H, int dx, int dy,
static RGBColor fg = { 0x0000, 0x0000, 0x0000 }; RGBForeColor( &fg );
CopyBits( GetPortBitMapForCopyBits( GetWindowPort(fl_window) ),
GetPortBitMapForCopyBits( GetWindowPort(fl_window) ), &src, &dst, srcCopy, 0L);
+#endif
+
#else
# error unsupported platform
#endif
diff --git a/src/fl_set_fonts_mac.cxx b/src/fl_set_fonts_mac.cxx
index bb54f5631..84715f1b2 100644
--- a/src/fl_set_fonts_mac.cxx
+++ b/src/fl_set_fonts_mac.cxx
@@ -60,6 +60,33 @@ static int fl_free_font = FL_FREE_FONT;
Fl_Font Fl::set_fonts(const char* xstarname) {
#pragma unused ( xstarname )
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+if(CTFontCreateWithFontDescriptor != NULL) {
+ int value[1] = {1};
+ CFDictionaryRef dict = CFDictionaryCreate(NULL, (const void **)kCTFontCollectionRemoveDuplicatesOption,
+ (const void **)&value, 1, NULL, NULL);
+ CTFontCollectionRef fcref = CTFontCollectionCreateFromAvailableFonts(dict);
+ CFRelease(dict);
+ CFArrayRef arrayref = CTFontCollectionCreateMatchingFontDescriptors(fcref);
+ CFRelease(fcref);
+ CFIndex count = CFArrayGetCount(arrayref);
+ CFIndex i;
+ for (i = 0; i < count; i++) {
+ CTFontDescriptorRef fdesc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(arrayref, i);
+ CTFontRef font = CTFontCreateWithFontDescriptor(fdesc, 0., NULL);
+ CFStringRef cfname = CTFontCopyPostScriptName(font);
+ CFRelease(font);
+ static char fname[100];
+ CFStringGetCString(cfname, fname, sizeof(fname), kCFStringEncodingUTF8);
+ CFRelease(cfname);
+ Fl::set_font((Fl_Font)(fl_free_font++), strdup(fname));
+ }
+ CFRelease(arrayref);
+ return (Fl_Font)fl_free_font;
+}
+else {
+#endif
+#if ! __LP64__
#if defined(OLD__APPLE_QUARTZ__)
ATSFontIterator it;
ATSFontIteratorCreate(kATSFontContextGlobal, 0L, 0L, kATSOptionFlagsUnRestrictedScope, &it);
@@ -114,6 +141,10 @@ Fl_Font Fl::set_fonts(const char* xstarname) {
}
free(oFontIDs);
return (Fl_Font)fl_free_font;
+#endif //OLD__APPLE_QUARTZ__
+#endif //__LP64__
+#if defined(__APPLE_COCOA__) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ }
#endif
}
diff --git a/src/fl_vertex.cxx b/src/fl_vertex.cxx
index 66e5102de..36e0aaae9 100644
--- a/src/fl_vertex.cxx
+++ b/src/fl_vertex.cxx
@@ -229,13 +229,21 @@ void fl_end_points() {
#elif defined(WIN32)
for (int i=0; i<n; i++) SetPixel(fl_gc, p[i].x, p[i].y, fl_RGB());
#elif defined(__APPLE_QUARTZ__)
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
+#else
if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#endif
for (int i=0; i<n; i++) {
CGContextMoveToPoint(fl_gc, p[i].x, p[i].y);
CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y);
CGContextStrokePath(fl_gc);
}
- if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false);
+#ifdef __APPLE_COCOA__
+ if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
+#else
+ if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true);
+#endif
#else
# error unsupported platform
#endif
@@ -255,10 +263,16 @@ void fl_end_line() {
if (n>1) Polyline(fl_gc, p, n);
#elif defined(__APPLE_QUARTZ__)
if (n<=1) return;
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
CGContextMoveToPoint(fl_gc, p[0].x, p[0].y);
for (int i=1; i<n; i++)
CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y);
CGContextStrokePath(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
@@ -295,11 +309,17 @@ void fl_end_polygon() {
}
#elif defined(__APPLE_QUARTZ__)
if (n<=1) return;
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
CGContextMoveToPoint(fl_gc, p[0].x, p[0].y);
for (int i=1; i<n; i++)
CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y);
CGContextClosePath(fl_gc);
CGContextFillPath(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
@@ -370,11 +390,17 @@ void fl_end_complex_polygon() {
}
#elif defined(__APPLE_QUARTZ__)
if (n<=1) return;
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
CGContextMoveToPoint(fl_gc, p[0].x, p[0].y);
for (int i=1; i<n; i++)
CGContextAddLineToPoint(fl_gc, p[i].x, p[i].y);
CGContextClosePath(fl_gc);
CGContextFillPath(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
@@ -412,8 +438,15 @@ void fl_circle(double x, double y,double r) {
Arc(fl_gc, llx, lly, llx+w, lly+h, 0,0, 0,0);
#elif defined(__APPLE_QUARTZ__)
// Quartz warning : circle won't scale to current matrix!
- CGContextAddArc(fl_gc, xt, yt, (w+h)*0.25f, 0, 2.0f*M_PI, 1);
+//last argument must be 0 (counterclockwise) or it draws nothing under __LP64__ !!!!
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, true);
+#endif
+ CGContextAddArc(fl_gc, xt, yt, (w+h)*0.25f, 0, 2.0f*M_PI, 0);
(what == POLYGON ? CGContextFillPath : CGContextStrokePath)(fl_gc);
+#ifdef __APPLE_COCOA__
+ CGContextSetShouldAntialias(fl_gc, false);
+#endif
#else
# error unsupported platform
#endif
diff --git a/src/gl_draw.cxx b/src/gl_draw.cxx
index edb5f0855..4d4e8ef76 100644
--- a/src/gl_draw.cxx
+++ b/src/gl_draw.cxx
@@ -110,6 +110,9 @@ void gl_font(int fontid, int size) {
wglUseFontBitmaps(fl_gc, base, count, fl_fontsize->listbase+base);
SelectObject(fl_gc, oldFid);
# elif defined(__APPLE_QUARTZ__)
+#if ! __LP64__
+//AGL is not supported for use in 64-bit applications:
+//http://developer.apple.com/mac/library/documentation/Carbon/Conceptual/Carbon64BitGuide/OtherAPIChanges/OtherAPIChanges.html
short font, face, size;
uchar fn[256];
fn[0]=strlen(fl_fontsize->q_name);
@@ -118,8 +121,9 @@ void gl_font(int fontid, int size) {
face = 0;
size = fl_fontsize->size;
fl_fontsize->listbase = glGenLists(256);
- aglUseFont(aglGetCurrentContext(), font, face,
+ aglUseFont(aglGetCurrentContext(), font, face,
size, 0, 256, fl_fontsize->listbase);
+#endif
# else
# error unsupported platform
# endif
@@ -128,7 +132,9 @@ void gl_font(int fontid, int size) {
}
gl_fontsize = fl_fontsize;
+#if !( defined(__APPLE__) && __LP64__ )
glListBase(fl_fontsize->listbase);
+#endif
}
#ifndef __APPLE__
@@ -204,10 +210,20 @@ void gl_remove_displaylist_fonts()
Draws an array of n characters of the string in the current font
at the current position.
*/
+#if defined(__APPLE__) && __LP64__
+static void gl_draw_cocoa(const char* str, int n);
+#endif
+
void gl_draw(const char* str, int n) {
#ifdef __APPLE__
+
+#if __LP64__
+ gl_draw_cocoa(str, n);
+#else
// Should be converting the text here, as for other platforms???
glCallLists(n, GL_UNSIGNED_BYTE, str);
+#endif
+
#else
static xchar *buf = NULL;
static int l = 0;
@@ -236,7 +252,7 @@ void gl_draw(const char* str, int n) {
}
/**
- Draws n charachters of the string in the current font at the given position
+ Draws n characters of the string in the current font at the given position
*/
void gl_draw(const char* str, int n, int x, int y) {
glRasterPos2i(x, y);
@@ -244,7 +260,7 @@ void gl_draw(const char* str, int n, int x, int y) {
}
/**
- Draws n charachters of the string in the current font at the given position
+ Draws n characters of the string in the current font at the given position
*/
void gl_draw(const char* str, int n, float x, float y) {
glRasterPos2f(x, y);
@@ -351,6 +367,95 @@ void gl_draw_image(const uchar* b, int x, int y, int w, int h, int d, int ld) {
glDrawPixels(w,h,d<4?GL_RGB:GL_RGBA,GL_UNSIGNED_BYTE,(const ulong*)b);
}
+#if defined(__APPLE__) && defined(__APPLE_COCOA__) && __LP64__
+
+#include <FL/glu.h>
+
+static void gl_draw_cocoa(const char* str, int n)
+{
+//setup matrices
+ GLint matrixMode;
+ glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
+ glMatrixMode (GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity ();
+ glMatrixMode (GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity ();
+ float winw = Fl_Window::current()->w();
+ float winh = Fl_Window::current()->h();
+ glScalef (2.0f / winw, 2.0f / winh, 1.0f);
+ glTranslatef (-winw / 2.0f, -winh / 2.0f, 0.0f);
+//write str to a bitmap just big enough
+ int w = 0, h = 0;
+ fl_measure(str, w, h, 0);
+ CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
+ void *base = calloc(4*w, h);
+ if(base == NULL) return;
+ fl_gc = CGBitmapContextCreate(base, w, h, 8, w*4, lut, kCGImageAlphaPremultipliedLast);
+ CGColorSpaceRelease(lut);
+ fl_fontsize = gl_fontsize;
+ fl_draw(str, 0, h - fl_descent());
+//put this bitmap in a texture
+ static GLuint texName = 0;
+ glPushAttrib(GL_TEXTURE_BIT);
+ if (0 == texName) glGenTextures (1, &texName);
+ glBindTexture (GL_TEXTURE_RECTANGLE_EXT, texName);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, base);
+ glPopAttrib();
+ CGContextRelease(fl_gc);
+ fl_gc = NULL;
+ free(base);
+ GLfloat pos[4];
+ glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
+ if (texName) {//write the texture on screen
+ CGRect bounds = CGRectMake (pos[0], pos[1] - fl_descent(), w, h);
+ glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); // GL_COLOR_BUFFER_BIT for glBlendFunc, GL_ENABLE_BIT for glEnable / glDisable
+
+ glDisable (GL_DEPTH_TEST); // ensure text is not removed by depth buffer test.
+ glEnable (GL_BLEND); // for text fading
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // ditto
+ glEnable (GL_TEXTURE_RECTANGLE_EXT);
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_EXT, texName);
+ glBegin (GL_QUADS);
+ glTexCoord2f (0.0f, 0.0f); // draw lower left in world coordinates
+ glVertex2f (bounds.origin.x, bounds.origin.y);
+
+ glTexCoord2f (0.0f, h); // draw upper left in world coordinates
+ glVertex2f (bounds.origin.x, bounds.origin.y + bounds.size.height);
+
+ glTexCoord2f (w, h); // draw upper right in world coordinates
+ glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height);
+
+ glTexCoord2f (w, 0.0f); // draw lower right in world coordinates
+ glVertex2f (bounds.origin.x + bounds.size.width, bounds.origin.y);
+ glEnd ();
+
+ glPopAttrib();
+ glDeleteTextures(1, &texName);
+ }
+ // reset original matrices
+ glPopMatrix(); // GL_MODELVIEW
+ glMatrixMode (GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode (matrixMode);
+//set the raster position to end of string
+ pos[0] += w;
+ GLdouble modelmat[16];
+ glGetDoublev (GL_MODELVIEW_MATRIX, modelmat);
+ GLdouble projmat[16];
+ glGetDoublev (GL_PROJECTION_MATRIX, projmat);
+ GLdouble objX, objY, objZ;
+ GLint viewport[4];
+ glGetIntegerv (GL_VIEWPORT, viewport);
+ gluUnProject(pos[0], pos[1], pos[2], modelmat, projmat, viewport, &objX, &objY, &objZ);
+ glRasterPos2d(objX, objY);
+}
+#endif
+
#endif
//
diff --git a/src/makedepend b/src/makedepend
index 425f4cf12..5ab041c44 100644
--- a/src/makedepend
+++ b/src/makedepend
@@ -383,9 +383,9 @@ Fl_Widget.o: ../FL/Fl_Tooltip.H ../FL/fl_draw.H ../FL/Fl_Window.H flstring.h
Fl_Widget.o: ../config.h
Fl_Window.o: ../config.h ../FL/Fl.H ../FL/fl_utf8.h ../FL/Fl_Export.H
Fl_Window.o: ../FL/fl_types.h ../FL/Xutf8.h ../FL/Enumerations.H
-Fl_Window.o: ../FL/Fl_Export.H ../FL/fl_types.h ../FL/Fl_Window.H
-Fl_Window.o: ../FL/Fl_Group.H ../FL/Fl_Widget.H flstring.h ../FL/fl_draw.H
-Fl_Window.o: ../FL/Fl_Window.H
+Fl_Window.o: ../FL/Fl_Export.H ../FL/fl_types.h ../FL/x.H ../FL/Fl_Window.H
+Fl_Window.o: ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H flstring.h
+Fl_Window.o: ../FL/fl_draw.H
Fl_Window_fullscreen.o: ../FL/Fl.H ../FL/fl_utf8.h ../FL/Fl_Export.H
Fl_Window_fullscreen.o: ../FL/fl_types.h ../FL/Xutf8.h ../FL/Enumerations.H
Fl_Window_fullscreen.o: ../FL/Fl_Export.H ../FL/fl_types.h ../FL/x.H
@@ -423,7 +423,7 @@ Fl_arg.o: ../FL/Fl_Widget.H ../FL/filename.H ../FL/fl_draw.H flstring.h
Fl_arg.o: ../config.h
Fl_compose.o: ../FL/Fl.H ../FL/fl_utf8.h ../FL/Fl_Export.H ../FL/fl_types.h
Fl_compose.o: ../FL/Xutf8.h ../FL/Enumerations.H ../FL/Fl_Export.H
-Fl_compose.o: ../FL/fl_types.h
+Fl_compose.o: ../FL/fl_types.h ../FL/x.H ../FL/Fl_Window.H
Fl_display.o: ../FL/Fl.H ../FL/fl_utf8.h ../FL/Fl_Export.H ../FL/fl_types.h
Fl_display.o: ../FL/Xutf8.h ../FL/Enumerations.H ../FL/Fl_Export.H
Fl_display.o: ../FL/fl_types.h flstring.h ../config.h
diff --git a/src/screen_xywh.cxx b/src/screen_xywh.cxx
index 66f05778d..3ef2aa970 100644
--- a/src/screen_xywh.cxx
+++ b/src/screen_xywh.cxx
@@ -107,7 +107,11 @@ static void screen_init() {
#elif defined(__APPLE__)
XRectangle screens[16];
+extern int MACscreen_init(XRectangle screens[]);
static void screen_init() {
+#ifdef __APPLE_COCOA__
+ num_screens = MACscreen_init(screens);
+#else
GDHandle gd;
for (gd = GetDeviceList(), num_screens = 0; gd; gd = GetNextDevice(gd)) {
@@ -120,6 +124,7 @@ static void screen_init() {
num_screens ++;
if (num_screens >= 16) break;
}
+#endif
}
#elif HAVE_XINERAMA
# include <X11/extensions/Xinerama.h>