summaryrefslogtreecommitdiff
path: root/src/Fl_mac.cxx
diff options
context:
space:
mode:
authorMichael R Sweet <michael.r.sweet@gmail.com>2001-11-27 17:44:08 +0000
committerMichael R Sweet <michael.r.sweet@gmail.com>2001-11-27 17:44:08 +0000
commit2b85bf81680e2243ef5a5daf85d9eb04321c7278 (patch)
treedc7d3e1cdbd44ed10b358412098b73d24b64d143 /src/Fl_mac.cxx
parent4dc5732a3e0f376786d1d6b788e5cf601439e890 (diff)
Preliminary commit of my MacOS X work.
**** THIS CODE COMPILES BUT DOES NOT WORK. **** TODO: fix event handling - getting blank windows, etc. TODO: re-port OpenGL code. TODO: add support for images with alpha. TODO: add support for more then just beeps in fl_beep(). TODO: other stuff I'm sure... git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1765 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_mac.cxx')
-rw-r--r--src/Fl_mac.cxx1158
1 files changed, 1158 insertions, 0 deletions
diff --git a/src/Fl_mac.cxx b/src/Fl_mac.cxx
new file mode 100644
index 000000000..087795a27
--- /dev/null
+++ b/src/Fl_mac.cxx
@@ -0,0 +1,1158 @@
+//
+// "$Id: Fl_mac.cxx,v 1.1.2.1 2001/11/27 17:44:06 easysw Exp $"
+//
+// MacOS specific code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2001 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 to "fltk-bugs@fltk.org".
+//
+
+// 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.
+#define CONSOLIDATE_MOTION 0
+
+#include <config.h>
+#include <FL/Fl.H>
+#include <FL/x.H>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Sys_Menu_Bar.H>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+int fl_handle(const EventRef event);
+
+int fl_screen;
+Handle fl_system_menu;
+Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0;
+CursHandle fl_default_cursor;
+static CursPtr default_cursor_ptr;
+static Cursor default_cursor;
+
+#if CONSOLIDATE_MOTION
+static Fl_Window* send_motion;
+extern Fl_Window* fl_xmousewin;
+#endif
+
+/**
+ * we need these as temporary regions for correct subwindow clipping
+ */
+static RgnHandle flmFullRgn = 0L, flmSubRgn = 0L;
+static Window flmFullXid = 0;
+static SysEnvRec MacWorld;
+
+
+/**
+ * Performance timer start
+ * - not finished, don't use
+ */
+static UnsignedWide _perfStart;
+static void _startPerf()
+{
+ Microseconds( &_perfStart );
+}
+
+/**
+ * Performance timer end
+ * - not finished, don't use
+ */
+static unsigned int _endPerf()
+{
+ UnsignedWide _perfEnd;
+ Microseconds( &_perfEnd );
+ // display the difference somehow - probably averaged
+ // if (msStart.hi==msEnd.hi)
+ // s1->value( (msEnd.lo-msStart.lo)/100.0 );
+
+ // get delta:
+ if ( _perfEnd.lo >= _perfStart.lo )
+ _perfEnd.hi = _perfEnd.hi - _perfStart.hi;
+ else
+ _perfEnd.hi = (_perfEnd.hi - 1) - _perfStart.hi;
+ _perfEnd.lo = _perfEnd.lo - _perfStart.lo;
+
+ // convert to double in micro seconds
+
+// static double kTwoPower32 = 4294967296.0;
+// double t = (((double) _perfEnd.hi) * kTwoPower32) + _perfEnd.lo;
+// UpTime();
+/*
+AbsoluteTime startTime;
+AbsoluteTime endTime;
+AbsoluteTime elapsedTime;
+Nanoseconds elapsedNanoseconds; // This is an UnsignedWide integer
+
+startTime = UpTime();
+DoMyOperation();
+endTime = UpTime();
+elapsedTime = SubAbsoluteFromAbsolute(endTime, startTime);
+elapsedNanoseconds = AbsoluteToNanoseconds(elapsedTime);
+*/
+ return 0;
+}
+
+
+/**
+ * \todo This funtion is not yet implemented!
+ */
+void Fl::add_fd( int n, int events, void (*cb)(int, void*), void *v )
+{
+#pragma unused ( n )
+#pragma unused ( events )
+#pragma unused ( cb )
+#pragma unused ( v )
+}
+
+
+/**
+ * \todo This funtion is not yet implemented!
+ */
+void Fl::add_fd(int fd, void (*cb)(int, void*), void* v)
+{
+#pragma unused ( fd )
+#pragma unused ( cb )
+#pragma unused ( v )
+}
+
+
+/**
+ * \todo This funtion is not yet implemented!
+ */
+void Fl::remove_fd(int n, int events)
+{
+#pragma unused ( n )
+#pragma unused ( events )
+}
+
+
+/**
+ * \todo This funtion is not yet implemented!
+ */
+void Fl::remove_fd(int n)
+{
+ remove_fd(n, -1);
+}
+
+
+/**
+ * \todo check if there is actually a message pending!
+ */
+int fl_ready()
+{
+ return 1;
+}
+
+
+/**
+ * This function iss 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 )
+{
+ static bool been_here = 0;
+ static RgnHandle rgn;
+
+ // initialize events and a region that enables mouse move events
+ if (!been_here) {
+ rgn = NewRgn();
+ Point mp;
+ GetMouse(&mp);
+ SetRectRgn(rgn, mp.h, mp.v, mp.h, mp.v);
+ SetEventMask(everyEvent);
+ //++ SystemEventMask ( MouseUp )
+ been_here = 1;
+ }
+
+ EventRef ev;
+ while ( ReceiveNextEvent(0, NULL, time, true, &ev) )
+ {
+ fl_handle(ev); //: handle the nullEvent to get mouse up events
+// SetRectRgn(rgn, ev.where.h, ev.where.v, ev.where.h+1, ev.where.v+1 );
+ }
+
+#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' secods for an event. It returns the same time that was given
+ * in the argument!
+ *
+ * \TODO: there is no socket handling in this code whatsoever
+ */
+double fl_wait( double time )
+{
+ return do_queued_events( time );
+}
+
+
+/**
+ * \todo not yet implemented!
+ */
+static void fd_callback(int,void *)
+{
+ do_queued_events();
+}
+
+
+/**
+ * Handle the mac typical topline menubar
+ */
+static void HandleMenu( long mResult )
+{
+ short item, menu ;
+ MenuHandle mHandle ;
+// Str255 itemName;
+ UInt32 ref;
+
+ item = LoWord( mResult ) ;
+ menu = HiWord( mResult ) ;
+ mHandle = GetMenuHandle( menu ) ;
+
+ switch (menu)
+ {
+ case 0:
+ break;
+ case 1: // Apple (this menu should be defined in the resource of your application)
+// GetMenuItemText( GetMenuHandle( 1 ), item, itemName );
+// OpenDeskAcc( itemName );
+ break;
+ default:
+ if ( !item ) break;
+ GetMenuItemRefCon( mHandle, item, &ref );
+ if ( ref && fl_sys_menu_bar )
+ {
+ Fl_Menu_Item *m = (Fl_Menu_Item*)ref;
+ fl_sys_menu_bar->picked( m );
+ if ( m->flags & FL_MENU_TOGGLE )
+ SetItemMark( mHandle, item, ( m->flags & FL_MENU_VALUE ) ? 0x12 : 0 );
+ if ( m->flags & FL_MENU_RADIO )
+ {
+ Fl_Menu_Item* j = m;
+ int i = item;
+ for (;;) {
+ if (j->flags & FL_MENU_DIVIDER) break; // stop on divider lines
+ j++; i++;
+ if (!j->text || !j->radio()) break; // stop after group
+ SetItemMark( mHandle, i, ( j->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
+ }
+ j = m-1; i = item-1;
+ for (;i>0;j--,i--) {
+ if (!j->text || (j->flags&FL_MENU_DIVIDER) || !j->radio()) break;
+ SetItemMark( mHandle, i, ( j->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
+ }
+ SetItemMark( mHandle, item, ( m->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
+ }
+ }
+ }
+ HiliteMenu( 0 );
+}
+
+
+/**
+ * initialize the Mac toolboxes and set the default menubar
+ */
+void fl_open_display() {
+ static char beenHereDoneThat = 0;
+ if ( !beenHereDoneThat ) {
+ beenHereDoneThat = 1;
+
+ //++ open all macintosh services
+// InitGraf(&qd.thePort); /* init Quickdraw and global variables */
+// InitFonts();
+// InitWindows();
+// InitMenus();
+// InitCursor();
+// TEInit();
+ FlushEvents(everyEvent, 0);
+// InitDialogs( nil );
+
+ MoreMasters();
+// MaxApplZone();
+
+// SysEnvirons( 1, &MacWorld );
+
+ // OK, this is just ridiculous...
+ GetQDGlobalsArrow(&default_cursor);
+ default_cursor_ptr = &default_cursor;
+ fl_default_cursor = &default_cursor_ptr;
+
+ FlushEvents(everyEvent,0);
+
+ flmFullRgn = NewRgn(); // here we remember our overall damage
+ flmSubRgn = NewRgn(); // used to clip subwindows out of the parent windows redraw
+
+ // create a minimal menu bar (\todo "about app", "FLTK settings")
+ // Any FLTK application may replace this menu later with its own bar.
+ fl_system_menu = GetNewMBar( 1 );
+ if ( fl_system_menu ) {
+ SetMenuBar( fl_system_menu );
+ AppendResMenu( GetMenuHandle( 1 ), 'DRVR' );
+ }
+
+ DrawMenuBar();
+ }
+}
+
+
+/**
+ * get rid of allocated resources
+ */
+void fl_close_display() {
+ DisposeRgn( flmFullRgn );
+ DisposeRgn( flmSubRgn );
+ //++ close all mac services
+}
+
+
+/**
+ * smallest x ccordinate in screen space
+ */
+int Fl::x() {
+ BitMap r;
+ GetQDGlobalsScreenBits(&r);
+ return r.bounds.left;
+}
+
+
+/**
+ * smallest y ccordinate in screen space
+ */
+int Fl::y() {
+ BitMap r;
+ GetQDGlobalsScreenBits(&r);
+ return r.bounds.top + 20; // 20 pixel menu bar?
+}
+
+
+/**
+ * screen width (single monitor!?)
+ */
+int Fl::w() {
+ BitMap r;
+ GetQDGlobalsScreenBits(&r);
+ return r.bounds.right - r.bounds.left;
+}
+
+
+/**
+ * screen height (single monitor!?)
+ */
+int Fl::h() {
+ BitMap r;
+ GetQDGlobalsScreenBits(&r);
+ return r.bounds.bottom - r.bounds.top - 20;
+}
+
+
+/**
+ * get the current mouse pointer world coordinates
+ */
+void Fl::get_mouse(int &x, int &y)
+{
+ fl_open_display();
+ Point loc;
+ GetMouse( &loc );
+ LocalToGlobal( &loc );
+ x = loc.h;
+ y = loc.v;
+}
+
+
+/************************** event conversion stuff ***********************/
+
+const EventRecord* fl_macevent; // the current mac event
+ulong fl_event_time; // the last timestamp from an x event
+char fl_key_vector[32]; // used by Fl::get_key()
+
+// Record event mouse position and state from an XEvent:
+
+static int px, py;
+static ulong ptime;
+
+/**
+ * convert Mac modifiers to FLTK
+ */
+static void set_shift_states(const EventRecord &macevent)
+{
+ ulong state = Fl::e_state & 0xff000000;
+ if (macevent.modifiers&shiftKey) state |= FL_SHIFT;
+ if ( (macevent.modifiers&controlKey) && (macevent.modifiers&btnState) ) state |= FL_META; // try to fetch the right mouse button
+ if (macevent.modifiers&optionKey) state |= FL_ALT;
+ if (macevent.modifiers&cmdKey) state |= FL_CTRL;
+ if (macevent.modifiers&alphaLock) state |= FL_CAPS_LOCK;
+ state |= FL_NUM_LOCK; //++ always num keypad on Mac?
+ Fl::e_state = state;
+}
+
+/**
+ * set the FLTK mouse status variables
+ */
+static void set_event_xy(const EventRecord &macevent)
+{
+#if CONSOLIDATE_MOTION
+ send_motion = 0;
+#endif
+ Fl::e_x_root = macevent.where.h;
+ Fl::e_y_root = macevent.where.v;
+ Point g = macevent.where;
+ GlobalToLocal(&g);
+ Fl::e_x = g.h;
+ Fl::e_y = g.v;
+ if (macevent.what!=osEvt) set_shift_states(macevent);
+ fl_event_time = macevent.when;
+ if (abs(Fl::e_x_root-px)+abs(Fl::e_y_root-py) > 3
+ || fl_event_time >= ptime+GetDblTime())
+ Fl::e_is_click = 0;
+}
+
+/**
+ * Mac keyboard lookup table
+ */
+static unsigned short macKeyLookUp[128] =
+{
+ 'a', 's', 'd', 'f', 'h', 'g', 'z', 'x',
+ 'c', 'v', 0, '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, 0, FL_Escape, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, FL_KP+'.', 0, FL_KP+'*', 0, FL_KP+'+', 0, FL_Num_Lock,
+ 0, 0, 0, FL_KP+'/', FL_KP_Enter, 0, 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, 0, 0, 0, FL_F+10, 0, FL_F+12,
+
+ 0, 0, FL_Pause, FL_Home, FL_Page_Up, 0, FL_F+4, 0,
+ FL_F+2, FL_Page_Down, FL_F+1, FL_Left, FL_Right, FL_Down, FL_Up, 0,
+};
+
+
+/**
+ * convert Mac keystrokes to FLTK
+ */
+unsigned short mac2fltk(ulong macKey)
+{
+ unsigned short cc = macKeyLookUp[(macKey>>8)&0x7f];
+ if (cc) return cc;
+ return macKey&0xff;
+}
+
+
+/**
+ * handle double and triple clicks
+ */
+static inline void checkdouble()
+{
+ if (Fl::e_is_click == Fl::e_keysym)
+ Fl::e_clicks++;
+ else {
+ Fl::e_clicks = 0;
+ Fl::e_is_click = Fl::e_keysym;
+ }
+ px = Fl::e_x_root;
+ py = Fl::e_y_root;
+ ptime = fl_event_time;
+}
+
+/************************** Mac Window System stuff ***********************/
+
+static Fl_Window* resize_from_system;
+Fl_Window* fl_find(Window);
+
+
+/**
+ * user is in the process of resizing the window
+ */
+void Fl_X::MacGrowWindow(WindowPtr xid, const EventRecord &macevent)
+{
+ Fl_Window *win = fl_find(xid);
+ if (!win) return;
+ while ( win->window() ) win = (Fl_Window*)win->window();
+ Rect limit;
+ limit.top = win->minh; limit.left = win->minw;
+ limit.bottom = win->maxh?win->maxh:Fl::h(); limit.right = win->maxw?win->maxw:Fl::w();
+ unsigned int grow = GrowWindow(xid, macevent.where, &limit);
+ if (grow==0) return;
+ win->resize(win->x(), win->y(), grow&0xffff, grow>>16);
+}
+
+
+/**
+ * user is in the process of resizing the window
+ */
+void Fl_X::MacDragWindow(WindowPtr xid, const EventRecord &macevent)
+{
+ BitMap bm;
+
+ GetQDGlobalsScreenBits(&bm);
+ DragWindow(xid, macevent.where, &(bm.bounds));
+ Fl_Window *win = fl_find(xid);
+ if (!win) return;
+ Point pt; pt.h = 0; pt.v = 0;
+ SetPort((GrafPtr)xid); SetOrigin(0, 0); LocalToGlobal(&pt);
+ win->resize( pt.h, pt.v, win->w(), win->h() );
+ //++ win->x(pt.h); win->y(pt.v);
+}
+
+
+//++ actually this function should be part of 'set_shift_states'
+//++ because pressing down SHIFT, then another key while the event queue is full
+//++ while actually generate the SHIFT event AFTER the key event!
+//++ (at least no events are lost in the process)
+int Fl_X::MacModifiers(const EventRecord &macevent, unsigned short prev)
+{
+ Fl_Window *window = fl_find(FrontWindow());
+ if (!window) return 0;
+ Fl::e_length = 0;
+ unsigned short now = macevent.modifiers;
+ set_shift_states(macevent); //++ will 'break' if multiple keys are released between 0 events
+ unsigned short m = now^prev;
+ if (m&cmdKey && now&cmdKey) { Fl::e_keysym = FL_Control_L; Fl::handle(FL_KEYBOARD, window); }
+ if (m&shiftKey && now&shiftKey) { Fl::e_keysym = FL_Shift_L; Fl::handle(FL_KEYBOARD, window); }
+ if (m&optionKey && now&optionKey) { Fl::e_keysym = FL_Alt_L; Fl::handle(FL_KEYBOARD, window); }
+ if ( ((m&controlKey)&&(m&btnState)) && ((now&controlKey)&&(now&btnState)) ) { Fl::e_keysym = FL_Meta_L; Fl::handle(FL_KEYBOARD, window); }
+ //: caps lock generates keyboard event only on key-down
+ if (m&alphaLock) { Fl::e_keysym = FL_Caps_Lock; Fl::handle(FL_KEYBOARD, window); }
+ return 1;
+}
+
+
+/**
+ * Initialize the given port for redraw and call the windw's flush() to actually draw the content
+ */
+void Fl_X::flush()
+{
+ w->flush();
+ SetOrigin( 0, 0 );
+}
+
+
+/**
+ * Handle all clipping and redraw for the given port
+ * There are two different callers for this event:
+ * 1: the OS can request a redraw and provides all clipping itself
+ * 2: Fl::flush() wants all redraws now
+ */
+void handleUpdateEvent( WindowPtr xid )
+{
+ Fl_Window *window = fl_find( xid );
+ if ( !window ) return;
+ SetPort( (GrafPtr)xid );
+ Fl_X *i = Fl_X::i( window );
+ i->wait_for_expose = 0; //++ what about this flag?!
+ if ( window->damage() ) {
+ if ( i->region ) {
+ InvalWindowRgn( xid, i->region );
+ }
+ }
+ if ( i->region ) { // no region, so the sytem will take the update region from the OS
+ DisposeRgn( i->region );
+ i->region = 0;
+ }
+ BeginUpdate( xid );
+
+ for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext )
+ {
+ cx->w->clear_damage(window->damage()|FL_DAMAGE_EXPOSE);
+ cx->flush();
+ cx->w->clear_damage();
+ }
+ window->clear_damage(window->damage()|FL_DAMAGE_EXPOSE);
+ i->flush();
+ window->clear_damage();
+
+ EndUpdate( xid );
+}
+
+
+/**
+ * dispatch all mac events
+ */
+int fl_handle(const EventRef event)
+{
+ UInt32 eventclass, eventkind;
+ static char buffer[5];
+ static unsigned short prevMod = 0;
+ static WindowPtr prevMouseDownXid;
+ WindowPtr xid;
+// int event = 0;
+ Fl_Window *window = 0L;
+ eventclass = GetEventClass(event);
+ eventkind = GetEventKind(event);
+ memcpy(buffer, &eventclass, 4);
+ buffer[4] = '\0';
+ printf("fl_event(): class = %s, kind = %d\n", buffer, eventkind);
+#if 0
+ switch (macevent.what)
+ {
+ case mouseDown: {
+ // handle the differnt mouseDown events in various areas of the screen
+ int part = FindWindow(macevent.where, &xid);
+ prevMouseDownXid = xid;
+ switch (part) {
+ case inDesk: break;
+ case inMenuBar: HandleMenu(MenuSelect(macevent.where)); break;
+// case inSysWindow: SystemClick(&macevent, xid); break;
+ case inContent: {
+ if (xid!=FrontWindow()) SelectWindow( xid ); //{ SelectWindow(xid); return 1; }
+ window = fl_find(xid);
+ if (!window) break;
+ SetPort((GrafPtr)xid); SetOrigin(0, 0);
+ Fl::e_keysym = FL_Button+((macevent.modifiers&controlKey)?3:1); //++ simulate three button using modifiers
+ set_event_xy(macevent); checkdouble();
+ Fl::e_state |= ((macevent.modifiers&controlKey)?FL_BUTTON3:FL_BUTTON1);
+ return Fl::handle(FL_PUSH, window); }
+ case inDrag: Fl_X::MacDragWindow(xid, macevent); break;
+ case inGrow: Fl_X::MacGrowWindow(xid, macevent); break;
+ case inGoAway:
+ if (TrackGoAway(xid, macevent.where)) Fl::handle(FL_CLOSE, fl_find(xid));
+ break;
+ case inZoomIn: case inZoomOut:
+// if (TrackBox(xid, event.where, part)) DoZoomWindow(xid, part);
+ break;
+ }
+ break; }
+ case mouseUp: {
+ xid = FrontWindow();
+ window = fl_find( xid );
+ if (!window) break;
+ SetPort((GrafPtr)xid);
+ SetOrigin(0, 0);
+ Fl::e_keysym = FL_Button+((Fl::e_state&FL_BUTTON1)?1:3); // macevent.modifiers ...
+ set_event_xy(macevent);
+ Fl::e_state &= ~(FL_BUTTON1|FL_BUTTON3);
+// if (!Fl::grab()) ReleaseCapture();
+ return Fl::handle(FL_RELEASE, window); }
+ case nullEvent: { //: idle events - who came up with that idea?
+ if (macevent.modifiers&0xff00 == prevMod) break;
+ int ret = Fl_X::MacModifiers(macevent, prevMod);
+ prevMod = macevent.modifiers&0xff00;
+ return ret; }
+ case keyUp:
+ //: bit0..7 message = keycode, 8..15 virtual, 16..23 ADB
+ //:: keyup does NOT GET CALLED in CW debug mode!!
+ case keyDown:
+ case autoKey: {
+ window = fl_find(FrontWindow());
+ if (!window) break;
+ unsigned short cc = mac2fltk(macevent.message);
+ unsigned char cm = macevent.message;
+ Fl::e_keysym = cc;
+ set_shift_states(macevent);
+ if (macevent.what==keyUp) {
+ Fl::e_length = 0; buffer[0] = 0;
+ } else {
+ Fl::e_text = buffer;
+ if (cc<0x100) {
+ //++ please check the Mac specific 'option+key' special characters
+ //++ handle the control key to generate control characters
+ //if (Fl::e_state&FL_CTRL && cm>=32 && cm<64) buffer[0] = cm-32; else
+ buffer[0] = cm;
+ } else if (cc>=FL_KP && cc<=FL_KP_Last) {
+ buffer[0] = cc-FL_KP; //++ remapped num keys: macevent.message;
+ } else {
+ buffer[0] = 0;
+ }
+ if (cc==FL_Escape) buffer[0]=27;
+ else if (cc==FL_BackSpace) buffer[0]=0x08;
+ else if (cc==FL_Tab) buffer[0]=0x09;
+ Fl::e_length = (buffer[0]?1:0);
+ return Fl::handle(FL_KEYBOARD, window);
+ }
+ break;
+ }
+ case activateEvt:
+ window = fl_find((WindowPtr)(macevent.message));
+ if (!window) break;
+ if (macevent.modifiers & activeFlag) {
+ return Fl::handle(FL_FOCUS, window);
+ } else {
+ return Fl::handle(FL_UNFOCUS, window);
+ }
+ break;
+ case updateEvt:
+ xid = (WindowPtr)macevent.message;
+ handleUpdateEvent( xid );
+ break;
+ case diskEvt:
+ break;
+ case osEvt: //: contains mouse move events
+ switch ( (macevent.message>>24)&0xff ) {
+ case suspendResumeMessage:
+ window = fl_find(FrontWindow());
+ if (!window) break;
+ SetEventMask(everyEvent); //++ currentMask | keyUpEvent
+ //++ mac users will expect that all windows switch to inactive
+ if (macevent.message & resumeFlag) {
+ return Fl::handle(FL_FOCUS, window);
+ } else {
+ return Fl::handle(FL_UNFOCUS, window);
+ }
+ break;
+ case mouseMovedMessage:
+ if (Fl::e_x_root==macevent.where.h && Fl::e_y_root==macevent.where.v) break;
+ xid = FrontWindow();
+ window = fl_find( xid );
+ if (!window) break;
+ SetPort((GrafPtr)xid); SetOrigin(0, 0);
+ set_event_xy(macevent);
+ #if CONSOLIDATE_MOTION
+ send_motion = fl_xmousewin = window;
+ return 0;
+ #else
+ return Fl::handle( (macevent.modifiers & btnState)?FL_MOVE:FL_DRAG, window);
+ #endif
+// if (!Fl::grab()) ReleaseCapture();
+ }
+ break;
+ //++ get null events to grab changes in the modifier keys (shift down, etc.)
+ case kHighLevelEvent:
+ AEProcessAppleEvent(&macevent);
+ break;
+ }
+#endif // 0
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////
+// This function gets the dimensions of the top/left borders and
+// the title bar, if there is one, based on the FL_BORDER, FL_MODAL
+// and FL_NONMODAL flags, and on the window's size range.
+// It returns the following values:
+//
+// value | border | title bar
+// 0 | none | no
+// 1 | fix | yes
+// 2 | size | yes
+// 3 | dialog | dialog (currently not used)
+
+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;
+ bx = 6; //++ GetSystemMetrics(SM_CXSIZEFRAME);
+ by = 6; //++ get Mac window frame size GetSystemMetrics(SM_CYSIZEFRAME);
+ } else {
+ ret = 1;
+ bx = 6; //++ GetSystemMetrics(SM_CXFIXEDFRAME);
+ by = 6; //++ GetSystemMetrics(SM_CYFIXEDFRAME);
+ }
+ bt = 22; //++ GetSystemMetrics(SM_CYCAPTION);
+ }
+ //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
+ //Make border's lower right corner visible
+ if (Fl::w() < X+W) X = Fl::w() - W;
+ if (Fl::h() < Y+H) Y = Fl::h() - H;
+ //Make border's upper left corner visible
+ if (X<0) X = 0;
+ if (Y<0) Y = 0;
+ //Make client area's lower right corner visible
+ if (Fl::w() < X+dx+ w->w()) X = Fl::w() - w->w() - dx;
+ if (Fl::h() < Y+dy+ w->h()) Y = Fl::h() - w->h() - dy;
+ //Make client area's upper left corner visible
+ if (X+xoff < 0) X = -xoff;
+ if (Y+yoff < 0) Y = -yoff;
+ //Return the client area's top left corner in (X,Y)
+ X+=xoff;
+ Y+=yoff;
+
+ return ret;
+}
+
+
+////////////////////////////////////////////////////////////////
+// Innards of Fl_Window::create()
+
+bool fl_show_iconic; // true if called from iconize()
+int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
+const Fl_Window* fl_modal_for; // parent of modal() window
+
+/**
+ * go ahead, create that (sub)window
+ */
+void Fl_X::make(Fl_Window* w)
+{
+ static int xyPos = 24;
+ if ( w->parent() ) // create a subwindow
+ {
+ Fl_Group::current(0);
+// int xp = w->x();
+// int yp = w->y();
+// int wp = w->w();
+// int hp = w->h();
+ //++ now we have to do completely different stuff here!
+ //++ mac has no concept of a window in a window!
+
+ 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;
+ Fl_Window *win = w->window();
+ Fl_X *xo = Fl_X::i(win);
+ x->xidNext = xo->xidChildren;
+ x->xidChildren = 0L;
+ xo->xidChildren = x;
+ x->xid = fl_xid(win);
+ x->w = w; w->i = x;
+ x->wait_for_expose = 0;
+ x->next = Fl_X::first; // must be in the list for ::flush()
+ Fl_X::first = x;
+ w->set_visible();
+ w->handle(FL_SHOW);
+ w->redraw(); // force draw to happen
+ fl_show_iconic = 0;
+ //++ hmmm, this should maybe set by the activate event?!
+ Fl::handle(FL_FOCUS, w);
+ //++ if (w->modal()) { Fl::modal_ = w; fl_fix_focus(); }
+ }
+ else // create a desktop window
+ {
+ Fl_Group::current(0);
+ fl_open_display();
+ int winclass = kDocumentWindowClass;
+// int winattr = kCloseBoxAttribute | kCollapseBoxAttribute | kWindowStandardHandlerAttribute;
+// int winattr = kWindowStandardHandlerAttribute;
+ int winattr = 0;
+ int xp = w->x();
+ int yp = w->y();
+ int wp = w->w();
+ int hp = w->h();
+ if (!w->size_range_set) {
+ 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);
+// winattr |= kWindowFullZoomAttribute | kWindowResizeableAttribute;
+ winattr |= kWindowFullZoomAttribute;
+ } 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)) winclass = kFloatingWindowClass;
+ else if (w->modal()) winclass = kModalWindowClass;
+ else if (w->non_modal()) winclass = kToolbarWindowClass;
+ if (by+bt) {
+ //++ if (!w->non_modal()) style |= WS_SYSMENU | WS_MINIMIZEBOX;
+ wp += 2*bx;
+ hp += 2*by+bt;
+ }
+ if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) {
+ w->x(xyPos+Fl::x()); w->y(xyPos+Fl::y());
+ xyPos += 24;
+ if (xyPos>200) xyPos = 24;
+ } 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();
+ //++parent = fl_xid(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();
+ Str255 pTitle;
+ if (name) { pTitle[0] = strlen(name); memcpy(pTitle+1, name, pTitle[0]); }
+ else pTitle[0]=0;
+
+ Fl_X* x = new Fl_X;
+ x->other_xid = 0; // room for doublebuffering image map //++ OS X: the OS always doublebuffers!
+ x->region = 0;
+ x->subRegion = 0;
+ x->cursor = fl_default_cursor;
+ x->xidChildren = 0;
+ x->xidNext = 0;
+ CreateNewWindow(winclass, winattr, &wRect, &(x->xid));
+ SetWTitle(x->xid, pTitle);
+ x->w = w; w->i = x;
+ x->wait_for_expose = 1;
+ x->next = Fl_X::first;
+ Fl_X::first = x;
+ if (w->resizable()) DrawGrowIcon(x->xid);
+ w->set_visible();
+ w->handle(FL_SHOW);
+ w->redraw(); // force draw to happen
+ TransitionWindow( x->xid, kWindowZoomTransitionEffect, kWindowShowTransitionAction, 0 );
+ ShowWindow( x->xid );
+ fl_show_iconic = 0;
+ //++ hmmm, this should maybe set by the activate event?!
+ Fl::handle(FL_FOCUS, w);
+ //++ if (w->modal()) { Fl::modal_ = w; fl_fix_focus(); }
+ }
+}
+
+void Fl_Window::size_range_() {
+ size_range_set = 1;
+}
+
+////////////////////////////////////////////////////////////////
+
+//++ make this run with Unix filenames
+// returns pointer to the filename, or null if name ends with ':'
+const char *filename_name( const char *name )
+{
+ const char *p, *q;
+ 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);
+ Str255 pTitle;
+
+ if (name) { pTitle[0] = strlen(name); memcpy(pTitle+1, name, pTitle[0]); }
+ else pTitle[0] = 0;
+
+ if (shown() || i) SetWTitle(fl_xid(this), pTitle);
+}
+
+////////////////////////////////////////////////////////////////
+// Implement the virtual functions for the base Fl_Window class:
+
+// Display can *look* faster (it isn't really faster) if X's background
+// color is used to erase the window. In fltk 2.0 the only way to
+// prevent this is to set the box to FL_NO_BOX.
+//
+// Drawing should really be faster if FL_FRAME_ONLY is passed to the
+// box drawing function, since X has already erased the interior. But
+// on XFree86 (and prehaps all X's) this has a problem if the window
+// is resized while a save-behind window is atop it. The previous
+// contents are restored to the area, but this assummes the area is
+// cleared to background color. So I had to give up on this...
+/*
+void Fl_Window::create() {
+ Fl_X::create(this);
+}
+*/
+Window fl_window;
+Fl_Window *Fl_Window::current_;
+
+
+void Fl_Window::show() {
+ if (!shown() || !i) {
+ Fl_X::make(this);
+ } else {
+ //++ do we need to do grab and icon handling here?
+ /*if (!fl_capture)*/ BringToFront(i->xid);
+ }
+}
+
+
+void Fl_Window::resize(int X,int Y,int W,int H) {
+ int is_a_resize = (W != w() || H != h());
+ if (X != x() || Y != y()) set_flag(FL_FORCE_POSITION);
+ else if (!is_a_resize) return;
+ // change the viewport first, so children (namely OpenGL) can resize correctly
+ if ( (!parent()) && shown()) {
+ MoveWindow(i->xid, X, Y, 0);
+ if (is_a_resize) {
+ SizeWindow(i->xid, W>0 ? W : 1, H>0 ? H : 1, 1);
+// Rect all; all.top=-32000; all.bottom=32000; all.left=-32000; all.right=32000;
+// InvalRect(&all);
+ }
+ }
+ if (is_a_resize) {
+ Fl_Group::resize(X,Y,W,H);
+ if (shown()) {redraw(); if (!parent()) i->wait_for_expose = 1; }
+ } else {
+ x(X); y(Y);
+ }
+}
+
+Fl_Region fl_window_region = 0;
+
+/**
+ * make all drawing go into this window (called by subclass flush() impl.)
+ */
+void Fl_Window::make_current()
+{
+ if ( !fl_window_region )
+ fl_window_region = NewRgn();
+ //- printf(" make current: 0x%08x\n", this);
+ fl_window = i->xid;
+ current_ = this;
+
+ SetPort((GrafPtr)(i->xid));
+
+ 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();
+ }
+ SetOrigin( -xp, -yp ); //++ how do we handle doublebuffering here?
+
+ //+++ here we should set the clip to all except the subwindows
+ //++ first of all, there seems to be some leftovers from an old operation
+ SetRectRgn( fl_window_region, 0, 0, w(), h() );
+ // remove all subwindows from the clip
+
+ //+++ for performance reasons: we don't have to create this unless the child windows moved
+ for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext )
+ {
+ Fl_Region r = NewRgn();
+ Fl_Window *cw = cx->w;
+ SetRectRgn( r, cw->x() - xp, cw->y() - yp,
+ cw->x() + cw->w() - xp, cw->y() + cw->h() - yp );
+ DiffRgn( fl_window_region, r, fl_window_region );
+ DisposeRgn( r );
+ }
+
+ fl_clip_region( 0 );
+ CopyRgn( fl_window_region, GetPortClipRegion((GrafPtr)(i->xid), 0) ); // for Fl_GL_Window
+ return;
+}
+
+
+/**
+ * This block contains a collection of ideas to improve and carbonize the Mac port
+ *
+ * I found a note stating that in order to receive the
+ * MouseUp event I need to set some SystemEvent Mask.
+ * Although I do receive them, it might still be smart to look into this!
+ *
+ * I have to solve the subwindow linking problem (links
+ * get corrupted when widows get reparented or closed)
+ *
+ * The current subwindow inking allows only one level of
+ * subwindowing (which was correct for the first layout).
+ * I have to change it for arbitrary depths.
+ *
+ * There is supposedly a nice library out for Berkeley sockets.
+ * Check out www.iis.ee.ethz.ch/~neeri/macintosh/gusi-qa.html
+ * (Those Swiss people in Zuerich have the longest links :-)
+ *
+ * Alternative timers:
+ * - GetTicks(): TickCount(): simple, unreliable, 60th of a second
+ * - Microseconds(): about 1ms
+ * - UpTime(): nano second resultion, only PCI machines (ah well)
+ */
+
+/* ---- sample hires timer (up to 20 microseconds!)
+double MicrosecondToDouble(register const UnsignedWide *epochPtr)
+{
+ register double result;
+
+ result = (((double) epochPtr->hi) * kTwoPower32) + epochPtr->lo;
+ return (result);
+}
+
+void MicrosecondDelta(register const UnsignedWide *startPtr,
+ register const UnsignedWide *endPtr,
+ register SignedWide *resultPtr)
+{
+ if (endPtr->lo >= startPtr->lo)
+ resultPtr->hi = endPtr->hi - startPtr->hi;
+ else
+ resultPtr->hi = (endPtr->hi - 1) - startPtr->hi;
+
+ resultPtr->lo = endPtr->lo - startPtr->lo;
+}
+*/
+
+/* ---- sample UpTime() timer
+AbsoluteTime startTime;
+AbsoluteTime endTime;
+AbsoluteTime elapsedTime;
+Nanoseconds elapsedNanoseconds;
+
+startTime = UpTime();
+DoMyOperation();
+endTime = UpTime();
+elapsedTime = SubAbsoluteFromAbsolute(endTime, startTime);
+elapsedNanoseconds = AbsoluteToNanoseconds(elapsedTime);
+*/
+
+//
+// End of "$Id: Fl_mac.cxx,v 1.1.2.1 2001/11/27 17:44:06 easysw Exp $".
+//
+