2001-11-27 20:44:08 +03:00
|
|
|
//
|
2005-02-25 00:55:12 +03:00
|
|
|
// "$Id$"
|
2001-11-27 20:44:08 +03:00
|
|
|
//
|
|
|
|
// MacOS specific code for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2010-11-29 21:18:27 +03:00
|
|
|
// Copyright 1998-2010 by Bill Spitzak and others.
|
2001-11-27 20:44:08 +03:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2005-04-16 04:13:17 +04:00
|
|
|
// Please report all bugs and problems on the following page:
|
|
|
|
//
|
|
|
|
// http://www.fltk.org/str.php
|
2001-11-27 20:44:08 +03:00
|
|
|
//
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
//// From the inner edge of a MetroWerks CodeWarrior CD:
|
|
|
|
// (without permission)
|
|
|
|
//
|
2006-05-30 11:35:58 +04:00
|
|
|
// "Three Compiles for 68Ks under the sky,
|
2002-01-03 11:08:21 +03:00
|
|
|
// 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,
|
2006-05-30 11:35:58 +04:00
|
|
|
// in the Land of MacOS X where the Drop-Shadows lie."
|
2001-12-20 08:27:14 +03:00
|
|
|
|
2004-09-10 01:34:48 +04:00
|
|
|
// warning: the Apple Quartz version still uses some Quickdraw calls,
|
|
|
|
// mostly to get around the single active context in QD and
|
|
|
|
// to implement clipping. This should be changed into pure
|
|
|
|
// Quartz calls in the near future.
|
2001-12-20 08:27:14 +03:00
|
|
|
|
2008-12-21 03:44:55 +03:00
|
|
|
// FIXME moving away from Carbon, I am replacing the Scrap manager calls with Pasteboard
|
2010-02-18 16:03:10 +03:00
|
|
|
// calls that support utf8 encoding. As soon as these function haven proven working
|
2008-12-21 03:44:55 +03:00
|
|
|
// the Scrap manager calls should be removed
|
|
|
|
#define USE_PASTEBOARD 1
|
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
// 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.
|
2008-09-18 23:09:34 +04:00
|
|
|
#ifndef FL_DOXYGEN
|
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
#define CONSOLIDATE_MOTION 0
|
2003-06-09 22:53:06 +04:00
|
|
|
extern "C" {
|
|
|
|
#include <pthread.h>
|
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
|
2004-08-25 04:20:27 +04:00
|
|
|
#include <config.h>
|
2001-11-27 20:44:08 +03:00
|
|
|
#include <FL/Fl.H>
|
|
|
|
#include <FL/x.H>
|
|
|
|
#include <FL/Fl_Window.H>
|
2006-06-14 14:48:36 +04:00
|
|
|
#include <FL/Fl_Tooltip.H>
|
2001-11-27 20:44:08 +03:00
|
|
|
#include <FL/Fl_Sys_Menu_Bar.H>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2002-04-11 15:52:43 +04:00
|
|
|
#include "flstring.h"
|
2001-11-27 20:44:08 +03:00
|
|
|
#include <unistd.h>
|
2002-06-28 03:18:12 +04:00
|
|
|
|
|
|
|
// #define DEBUG_SELECT // UNCOMMENT FOR SELECT()/THREAD DEBUGGING
|
|
|
|
#ifdef DEBUG_SELECT
|
2004-04-06 21:38:36 +04:00
|
|
|
#include <stdio.h> // testing
|
|
|
|
#define DEBUGMSG(msg) if ( msg ) fprintf(stderr, msg);
|
|
|
|
#define DEBUGPERRORMSG(msg) if ( msg ) perror(msg)
|
|
|
|
#define DEBUGTEXT(txt) txt
|
2002-06-28 03:18:12 +04:00
|
|
|
#else
|
|
|
|
#define DEBUGMSG(msg)
|
|
|
|
#define DEBUGPERRORMSG(msg)
|
2004-04-06 21:38:36 +04:00
|
|
|
#define DEBUGTEXT(txt) NULL
|
|
|
|
#endif /*DEBUG_SELECT*/
|
2001-11-27 20:44:08 +03:00
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
// external functions
|
|
|
|
extern Fl_Window* fl_find(Window);
|
|
|
|
extern void fl_fix_focus();
|
2001-11-27 20:44:08 +03:00
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
// forward definition of functions in this file
|
|
|
|
static void handleUpdateEvent( WindowPtr xid );
|
2002-02-26 03:34:55 +03:00
|
|
|
//+ int fl_handle(const EventRecord &event);
|
2003-05-30 11:03:09 +04:00
|
|
|
static int FSSpec2UnixPath( FSSpec *fs, char *dst );
|
2009-01-12 19:45:55 +03:00
|
|
|
// converting cr lf converter function
|
|
|
|
static void convert_crlf(char * string, size_t len);
|
2001-11-27 20:44:08 +03:00
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
// public variables
|
2001-11-27 20:44:08 +03:00
|
|
|
int fl_screen;
|
2004-08-26 04:18:43 +04:00
|
|
|
CGContextRef fl_gc = 0;
|
2001-11-27 20:44:08 +03:00
|
|
|
Handle fl_system_menu;
|
|
|
|
Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0;
|
|
|
|
CursHandle fl_default_cursor;
|
2002-01-03 11:08:21 +03:00
|
|
|
WindowRef fl_capture = 0; // 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_;
|
2002-02-26 03:34:55 +03:00
|
|
|
EventRef fl_os_event; // last (mouse) event
|
2002-01-03 11:08:21 +03:00
|
|
|
|
|
|
|
// forward declarations of variables in this file
|
2002-06-11 20:17:41 +04:00
|
|
|
static int got_events = 0;
|
2002-01-03 11:08:21 +03:00
|
|
|
static Fl_Window* resize_from_system;
|
2001-11-27 20:44:08 +03:00
|
|
|
static CursPtr default_cursor_ptr;
|
|
|
|
static Cursor default_cursor;
|
2002-01-03 11:08:21 +03:00
|
|
|
static WindowRef fl_os_capture = 0; // the dispatch handler will redirect mose move and drag events to these windows
|
2002-06-03 20:09:27 +04:00
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
#if CONSOLIDATE_MOTION
|
|
|
|
static Fl_Window* send_motion;
|
|
|
|
extern Fl_Window* fl_xmousewin;
|
|
|
|
#endif
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
enum { kEventClassFLTK = 'fltk' };
|
2002-06-28 03:18:12 +04:00
|
|
|
enum { kEventFLTKBreakLoop = 1, kEventFLTKDataReady };
|
2001-11-27 20:44:08 +03:00
|
|
|
|
2008-09-11 03:56:49 +04:00
|
|
|
/* fltk-utf8 placekeepers */
|
|
|
|
void fl_reset_spot()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-12-27 22:22:30 +03:00
|
|
|
void fl_set_spot(int font, int size, int X, int Y, int W, int H, Fl_Window *win)
|
2008-09-11 03:56:49 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void fl_set_status(int x, int y, int w, int h)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2002-06-03 20:09:27 +04:00
|
|
|
/**
|
|
|
|
* Mac keyboard lookup table
|
|
|
|
*/
|
|
|
|
static unsigned short macKeyLookUp[128] =
|
|
|
|
{
|
|
|
|
'a', 's', 'd', 'f', 'h', 'g', 'z', 'x',
|
2006-04-04 15:44:20 +04:00
|
|
|
'c', 'v', '^', 'b', 'q', 'w', 'e', 'r',
|
2002-06-03 20:09:27 +04:00
|
|
|
|
|
|
|
'y', 't', '1', '2', '3', '4', '6', '5',
|
|
|
|
'=', '9', '7', '-', '8', '0', ']', 'o',
|
|
|
|
|
|
|
|
'u', '[', 'i', 'p', FL_Enter, 'l', 'j', '\'',
|
|
|
|
'k', ';', '\\', ',', '/', 'n', 'm', '.',
|
|
|
|
|
2006-06-07 13:46:03 +04:00
|
|
|
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,
|
2002-06-03 20:09:27 +04:00
|
|
|
|
2009-04-12 17:48:03 +04:00
|
|
|
0, FL_KP+'.', FL_Right, FL_KP+'*', 0, FL_KP+'+', FL_Left, FL_Delete,
|
2002-06-03 20:09:27 +04:00
|
|
|
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,
|
2006-06-07 13:46:03 +04:00
|
|
|
0, 0/*FL_F+13*/, FL_Print, FL_Scroll_Lock, 0, FL_F+10, FL_Menu, FL_F+12,
|
2002-06-03 20:09:27 +04:00
|
|
|
|
|
|
|
0, FL_Pause, FL_Help, FL_Home, FL_Page_Up, FL_Delete, FL_F+4, FL_End,
|
2006-06-07 13:46:03 +04:00
|
|
|
FL_F+2, FL_Page_Down, FL_F+1, FL_Left, FL_Right, FL_Down, FL_Up, 0/*FL_Power*/,
|
2002-06-03 20:09:27 +04:00
|
|
|
};
|
|
|
|
|
2005-11-28 17:38:38 +03:00
|
|
|
/**
|
|
|
|
* convert the current mouse chord into the FLTK modifier state
|
|
|
|
*/
|
2008-10-13 23:26:18 +04:00
|
|
|
static unsigned int mods_to_e_state( UInt32 mods )
|
2005-11-28 17:38:38 +03:00
|
|
|
{
|
|
|
|
long state = 0;
|
|
|
|
if ( mods & kEventKeyModifierNumLockMask ) state |= FL_NUM_LOCK;
|
|
|
|
if ( mods & cmdKey ) state |= FL_META;
|
|
|
|
if ( mods & (optionKey|rightOptionKey) ) state |= FL_ALT;
|
|
|
|
if ( mods & (controlKey|rightControlKey) ) state |= FL_CTRL;
|
|
|
|
if ( mods & (shiftKey|rightShiftKey) ) state |= FL_SHIFT;
|
|
|
|
if ( mods & alphaLock ) state |= FL_CAPS_LOCK;
|
2008-10-13 23:26:18 +04:00
|
|
|
unsigned int ret = ( Fl::e_state & 0xff000000 ) | state;
|
|
|
|
Fl::e_state = ret;
|
2005-11-28 17:38:38 +03:00
|
|
|
//printf( "State 0x%08x (%04x)\n", Fl::e_state, mods );
|
2008-10-13 23:26:18 +04:00
|
|
|
return ret;
|
2005-11-28 17:38:38 +03:00
|
|
|
}
|
2002-06-03 20:09:27 +04:00
|
|
|
|
2005-11-28 17:38:38 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* convert the current mouse chord into the FLTK keysym
|
|
|
|
*/
|
|
|
|
static void mods_to_e_keysym( UInt32 mods )
|
|
|
|
{
|
|
|
|
if ( mods & cmdKey ) Fl::e_keysym = FL_Meta_L;
|
|
|
|
else if ( mods & kEventKeyModifierNumLockMask ) Fl::e_keysym = FL_Num_Lock;
|
|
|
|
else if ( mods & optionKey ) Fl::e_keysym = FL_Alt_L;
|
|
|
|
else if ( mods & rightOptionKey ) Fl::e_keysym = FL_Alt_R;
|
|
|
|
else if ( mods & controlKey ) Fl::e_keysym = FL_Control_L;
|
|
|
|
else if ( mods & rightControlKey ) Fl::e_keysym = FL_Control_R;
|
|
|
|
else if ( mods & shiftKey ) Fl::e_keysym = FL_Shift_L;
|
|
|
|
else if ( mods & rightShiftKey ) Fl::e_keysym = FL_Shift_R;
|
|
|
|
else if ( mods & alphaLock ) Fl::e_keysym = FL_Caps_Lock;
|
|
|
|
else Fl::e_keysym = 0;
|
|
|
|
//printf( "to sym 0x%08x (%04x)\n", Fl::e_keysym, mods );
|
|
|
|
}
|
2002-04-16 19:49:06 +04:00
|
|
|
// these pointers are set by the Fl::lock() function:
|
|
|
|
static void nothing() {}
|
|
|
|
void (*fl_lock_function)() = nothing;
|
|
|
|
void (*fl_unlock_function)() = nothing;
|
|
|
|
|
2002-06-28 03:18:12 +04:00
|
|
|
//
|
2004-04-06 21:38:36 +04:00
|
|
|
// 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
|
|
|
|
//
|
2002-06-28 03:18:12 +04:00
|
|
|
#define POLLIN 1
|
|
|
|
#define POLLOUT 4
|
|
|
|
#define POLLERR 8
|
2004-04-06 21:38:36 +04:00
|
|
|
|
|
|
|
// Class to handle select() 'data ready'
|
|
|
|
class DataReady
|
2002-06-28 03:18:12 +04:00
|
|
|
{
|
2004-04-06 21:38:36 +04:00
|
|
|
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);
|
2002-06-28 03:18:12 +04:00
|
|
|
};
|
2001-11-27 20:44:08 +03:00
|
|
|
|
2004-04-06 21:38:36 +04:00
|
|
|
static DataReady dataready;
|
2001-11-27 20:44:08 +03:00
|
|
|
|
2004-04-06 21:38:36 +04:00
|
|
|
void DataReady::AddFD(int n, int events, void (*cb)(int, void*), void *v)
|
2002-06-28 03:18:12 +04:00
|
|
|
{
|
2004-04-06 21:38:36 +04:00
|
|
|
RemoveFD(n, events);
|
2002-06-28 03:18:12 +04:00
|
|
|
int i = nfds++;
|
2004-04-06 21:38:36 +04:00
|
|
|
if (i >= fd_array_size)
|
|
|
|
{
|
2002-06-28 03:18:12 +04:00
|
|
|
FD *temp;
|
|
|
|
fd_array_size = 2*fd_array_size+1;
|
2004-04-06 21:38:36 +04:00
|
|
|
if (!fds) { temp = (FD*)malloc(fd_array_size*sizeof(FD)); }
|
|
|
|
else { temp = (FD*)realloc(fds, fd_array_size*sizeof(FD)); }
|
2002-06-28 03:18:12 +04:00
|
|
|
if (!temp) return;
|
2004-04-06 21:38:36 +04:00
|
|
|
fds = temp;
|
2002-06-28 03:18:12 +04:00
|
|
|
}
|
2004-04-06 21:38:36 +04:00
|
|
|
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();
|
2002-06-28 03:18:12 +04:00
|
|
|
}
|
|
|
|
|
2004-04-06 21:38:36 +04:00
|
|
|
// Remove an FD from the array
|
|
|
|
void DataReady::RemoveFD(int n, int events)
|
2002-06-28 03:18:12 +04:00
|
|
|
{
|
|
|
|
int i,j;
|
2004-04-06 21:38:36 +04:00
|
|
|
for (i=j=0; i<nfds; i++)
|
|
|
|
{
|
|
|
|
if (fds[i].fd == n)
|
|
|
|
{
|
|
|
|
int e = fds[i].events & ~events;
|
2002-06-28 03:18:12 +04:00
|
|
|
if (!e) continue; // if no events left, delete this fd
|
2004-04-06 21:38:36 +04:00
|
|
|
fds[i].events = e;
|
2002-06-28 03:18:12 +04:00
|
|
|
}
|
|
|
|
// move it down in the array if necessary:
|
|
|
|
if (j<i)
|
2004-04-06 21:38:36 +04:00
|
|
|
{ fds[j] = fds[i]; }
|
2002-06-28 03:18:12 +04:00
|
|
|
j++;
|
|
|
|
}
|
|
|
|
nfds = j;
|
2004-04-06 21:38:36 +04:00
|
|
|
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();
|
2002-06-28 03:18:12 +04:00
|
|
|
}
|
|
|
|
|
2004-04-06 21:38:36 +04:00
|
|
|
// 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)
|
2001-11-27 20:44:08 +03:00
|
|
|
{
|
2004-04-06 21:38:36 +04:00
|
|
|
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();
|
2002-06-28 03:18:12 +04:00
|
|
|
if ( ret == -1 )
|
2004-04-06 21:38:36 +04:00
|
|
|
{ DEBUGPERRORMSG("CheckData(): select()"); }
|
2002-06-28 03:18:12 +04:00
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
// HANDLE DATA READY CALLBACKS
|
2004-04-06 21:38:36 +04:00
|
|
|
void DataReady::HandleData(fd_set& r, fd_set& w, fd_set& x)
|
2002-06-28 03:18:12 +04:00
|
|
|
{
|
|
|
|
for (int i=0; i<nfds; i++)
|
|
|
|
{
|
2004-04-06 21:38:36 +04:00
|
|
|
int f = fds[i].fd;
|
2002-06-28 03:18:12 +04:00
|
|
|
short revents = 0;
|
|
|
|
if (FD_ISSET(f, &r)) revents |= POLLIN;
|
|
|
|
if (FD_ISSET(f, &w)) revents |= POLLOUT;
|
|
|
|
if (FD_ISSET(f, &x)) revents |= POLLERR;
|
2004-04-06 21:38:36 +04:00
|
|
|
if (fds[i].events & revents)
|
2002-06-28 03:18:12 +04:00
|
|
|
{
|
|
|
|
DEBUGMSG("DOING CALLBACK: ");
|
2004-04-06 21:38:36 +04:00
|
|
|
fds[i].cb(f, fds[i].arg);
|
2002-06-28 03:18:12 +04:00
|
|
|
DEBUGMSG("DONE\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
|
2004-04-06 21:38:36 +04:00
|
|
|
// 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;
|
|
|
|
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");
|
|
|
|
EventRef drEvent;
|
|
|
|
CreateEvent( 0, kEventClassFLTK, kEventFLTKDataReady,
|
|
|
|
0, kEventAttributeUserEvent, &drEvent);
|
|
|
|
EventQueueRef eventqueue = (EventQueueRef)userdata;
|
|
|
|
PostEventToQueue(eventqueue, drEvent, kEventPriorityStandard );
|
|
|
|
ReleaseEvent( drEvent );
|
|
|
|
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()
|
|
|
|
{
|
2005-09-26 01:48:43 +04:00
|
|
|
EventRef event;
|
|
|
|
return !ReceiveNextEvent(0, NULL, 0.0, false, &event);
|
2004-04-06 21:38:36 +04:00
|
|
|
}
|
2002-07-11 08:11:41 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* handle Apple Menu items (can be created using the Fl_Sys_Menu_Bar
|
|
|
|
* returns eventNotHandledErr if the menu item could not be handled
|
|
|
|
*/
|
|
|
|
OSStatus HandleMenu( HICommand *cmd )
|
|
|
|
{
|
|
|
|
OSStatus ret = eventNotHandledErr;
|
|
|
|
// attributes, commandIDm menu.menuRef, menu.menuItemIndex
|
|
|
|
UInt32 ref;
|
|
|
|
OSErr rrc = GetMenuItemRefCon( cmd->menu.menuRef, cmd->menu.menuItemIndex, &ref );
|
|
|
|
//printf( "%d, %08x, %08x, %d, %d, %8x\n", rrc, cmd->attributes, cmd->commandID, cmd->menu.menuRef, cmd->menu.menuItemIndex, rrc );
|
|
|
|
if ( rrc==noErr && ref )
|
|
|
|
{
|
|
|
|
Fl_Menu_Item *m = (Fl_Menu_Item*)ref;
|
|
|
|
//printf( "Menu: %s\n", m->label() );
|
|
|
|
fl_sys_menu_bar->picked( m );
|
|
|
|
if ( m->flags & FL_MENU_TOGGLE ) // update the menu toggle symbol
|
|
|
|
SetItemMark( cmd->menu.menuRef, cmd->menu.menuItemIndex, (m->flags & FL_MENU_VALUE ) ? 0x12 : 0 );
|
|
|
|
if ( m->flags & FL_MENU_RADIO ) // update all radio buttons in this menu
|
|
|
|
{
|
|
|
|
Fl_Menu_Item *j = m;
|
|
|
|
int i = cmd->menu.menuItemIndex;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if ( j->flags & FL_MENU_DIVIDER )
|
|
|
|
break;
|
|
|
|
j++; i++;
|
|
|
|
if ( !j->text || !j->radio() )
|
|
|
|
break;
|
|
|
|
SetItemMark( cmd->menu.menuRef, i, ( j->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
|
|
|
|
}
|
|
|
|
j = m-1; i = cmd->menu.menuItemIndex-1;
|
|
|
|
for ( ; i>0; j--, i-- )
|
|
|
|
{
|
|
|
|
if ( !j->text || j->flags&FL_MENU_DIVIDER || !j->radio() )
|
|
|
|
break;
|
|
|
|
SetItemMark( cmd->menu.menuRef, i, ( j->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
|
|
|
|
}
|
|
|
|
SetItemMark( cmd->menu.menuRef, cmd->menu.menuItemIndex, ( m->flags & FL_MENU_VALUE ) ? 0x13 : 0 );
|
|
|
|
}
|
|
|
|
ret = noErr; // done handling this event
|
|
|
|
}
|
|
|
|
HiliteMenu(0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-20 08:27:14 +03:00
|
|
|
/**
|
|
|
|
* We can make every event pass through this function
|
|
|
|
* - mouse events need to be manipulated to use a mouse focus window
|
|
|
|
* - keyboard, mouse and some window events need to quit the Apple Event Loop
|
|
|
|
* so FLTK can continue its own management
|
|
|
|
*/
|
2002-01-03 11:08:21 +03:00
|
|
|
static pascal OSStatus carbonDispatchHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData )
|
2001-12-20 08:27:14 +03:00
|
|
|
{
|
|
|
|
OSStatus ret = eventNotHandledErr;
|
2002-07-11 08:11:41 +04:00
|
|
|
HICommand cmd;
|
2002-04-16 19:49:06 +04:00
|
|
|
|
|
|
|
fl_lock_function();
|
|
|
|
|
2002-06-11 22:44:07 +04:00
|
|
|
got_events = 1;
|
2002-06-11 20:17:41 +04:00
|
|
|
|
2001-12-20 08:27:14 +03:00
|
|
|
switch ( GetEventClass( event ) )
|
|
|
|
{
|
|
|
|
case kEventClassMouse:
|
|
|
|
switch ( GetEventKind( event ) )
|
|
|
|
{
|
|
|
|
case kEventMouseUp:
|
|
|
|
case kEventMouseMoved:
|
|
|
|
case kEventMouseDragged:
|
|
|
|
if ( fl_capture )
|
|
|
|
ret = SendEventToEventTarget( event, GetWindowEventTarget( fl_capture ) );
|
2004-03-11 08:17:12 +03:00
|
|
|
else if ( fl_os_capture ){
|
2001-12-20 08:27:14 +03:00
|
|
|
ret = SendEventToEventTarget( event, GetWindowEventTarget( fl_os_capture ) );
|
2004-03-11 08:17:12 +03:00
|
|
|
fl_os_capture = 0;
|
|
|
|
}
|
2001-12-20 08:27:14 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2002-07-11 08:11:41 +04:00
|
|
|
case kEventClassCommand:
|
|
|
|
switch (GetEventKind( event ) )
|
|
|
|
{
|
|
|
|
case kEventCommandProcess:
|
2009-04-13 00:00:45 +04:00
|
|
|
ret = GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd );
|
|
|
|
if (ret == noErr && (cmd.attributes & kHICommandFromMenu) != 0)
|
|
|
|
ret = HandleMenu( &cmd );
|
|
|
|
else
|
|
|
|
ret = eventNotHandledErr;
|
2002-07-11 08:11:41 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2002-01-03 11:08:21 +03:00
|
|
|
case kEventClassFLTK:
|
|
|
|
switch ( GetEventKind( event ) )
|
|
|
|
{
|
|
|
|
case kEventFLTKBreakLoop:
|
|
|
|
ret = noErr;
|
|
|
|
break;
|
2002-06-28 03:18:12 +04:00
|
|
|
case kEventFLTKDataReady:
|
|
|
|
{
|
2004-04-06 21:38:36 +04:00
|
|
|
dataready.CancelThread(DEBUGTEXT("DATA READY EVENT\n"));
|
2002-06-28 03:18:12 +04:00
|
|
|
|
|
|
|
// CHILD THREAD TELLS US DATA READY
|
|
|
|
// Check to see what's ready, and invoke user's cb's
|
|
|
|
//
|
2004-04-06 21:38:36 +04:00
|
|
|
fd_set r,w,x;
|
|
|
|
switch(dataready.CheckData(r,w,x))
|
2002-06-28 03:18:12 +04:00
|
|
|
{
|
2004-04-06 21:38:36 +04:00
|
|
|
case 0: // NO DATA
|
|
|
|
break;
|
|
|
|
case -1: // ERROR
|
|
|
|
break;
|
|
|
|
default: // DATA READY
|
|
|
|
dataready.HandleData(r,w,x);
|
|
|
|
break;
|
2002-06-28 03:18:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = noErr;
|
|
|
|
break;
|
2002-01-03 11:08:21 +03:00
|
|
|
}
|
2001-12-20 08:27:14 +03:00
|
|
|
}
|
|
|
|
if ( ret == eventNotHandledErr )
|
|
|
|
ret = CallNextEventHandler( nextHandler, event ); // let the OS handle the activation, but continue to get a click-through effect
|
2002-04-16 19:49:06 +04:00
|
|
|
|
|
|
|
fl_unlock_function();
|
|
|
|
|
2001-12-20 08:27:14 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
|
2002-02-26 03:34:55 +03:00
|
|
|
/**
|
|
|
|
* break the current event loop
|
|
|
|
*/
|
|
|
|
static void breakMacEventLoop()
|
|
|
|
{
|
|
|
|
EventRef breakEvent;
|
2002-04-16 19:49:06 +04:00
|
|
|
|
|
|
|
fl_lock_function();
|
|
|
|
|
2002-02-26 03:34:55 +03:00
|
|
|
CreateEvent( 0, kEventClassFLTK, kEventFLTKBreakLoop, 0, kEventAttributeUserEvent, &breakEvent );
|
|
|
|
PostEventToQueue( GetCurrentEventQueue(), breakEvent, kEventPriorityStandard );
|
|
|
|
ReleaseEvent( breakEvent );
|
2002-04-16 19:49:06 +04:00
|
|
|
|
|
|
|
fl_unlock_function();
|
2002-02-26 03:34:55 +03:00
|
|
|
}
|
|
|
|
|
2006-01-02 13:31:59 +03:00
|
|
|
//
|
|
|
|
// MacOS X timers
|
|
|
|
//
|
|
|
|
|
|
|
|
struct MacTimeout {
|
|
|
|
Fl_Timeout_Handler callback;
|
|
|
|
void* data;
|
|
|
|
EventLoopTimerRef timer;
|
2006-04-20 07:02:37 +04:00
|
|
|
EventLoopTimerUPP upp;
|
|
|
|
char pending;
|
2006-01-02 13:31:59 +03:00
|
|
|
};
|
|
|
|
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;
|
|
|
|
}
|
2006-08-20 00:09:33 +04:00
|
|
|
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);
|
2006-01-02 13:31:59 +03:00
|
|
|
MacTimeout* delete_me = mac_timers;
|
|
|
|
mac_timers = new_timers;
|
|
|
|
delete [] delete_me;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void delete_timer(MacTimeout& t)
|
|
|
|
{
|
2006-04-20 07:02:37 +04:00
|
|
|
if (t.timer) {
|
|
|
|
RemoveEventLoopTimer(t.timer);
|
|
|
|
DisposeEventLoopTimerUPP(t.upp);
|
|
|
|
memset(&t, 0, sizeof(MacTimeout));
|
|
|
|
}
|
2006-01-02 13:31:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static pascal 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) {
|
2006-04-20 07:02:37 +04:00
|
|
|
t.pending = 0;
|
2006-01-02 13:31:59 +03:00
|
|
|
(*t.callback)(data);
|
2006-04-20 07:02:37 +04:00
|
|
|
if (t.pending==0)
|
|
|
|
delete_timer(t);
|
2006-01-02 13:31:59 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
breakMacEventLoop();
|
|
|
|
}
|
2002-02-26 03:34:55 +03:00
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
/**
|
2002-07-11 05:10:15 +04:00
|
|
|
* This function is the central event handler.
|
2001-11-27 20:44:08 +03:00
|
|
|
* 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 )
|
|
|
|
{
|
2008-10-14 03:10:43 +04:00
|
|
|
static bool been_here = false;
|
2001-11-27 20:44:08 +03:00
|
|
|
static RgnHandle rgn;
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
// initialize events and a region that enables mouse move events
|
2001-11-27 20:44:08 +03:00
|
|
|
if (!been_here) {
|
|
|
|
rgn = NewRgn();
|
|
|
|
Point mp;
|
|
|
|
GetMouse(&mp);
|
|
|
|
SetRectRgn(rgn, mp.h, mp.v, mp.h, mp.v);
|
|
|
|
SetEventMask(everyEvent);
|
2008-10-14 03:10:43 +04:00
|
|
|
been_here = true;
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
2001-12-12 10:50:37 +03:00
|
|
|
OSStatus ret;
|
|
|
|
static EventTargetRef target = 0;
|
2001-12-20 08:27:14 +03:00
|
|
|
if ( !target )
|
|
|
|
{
|
|
|
|
target = GetEventDispatcherTarget();
|
|
|
|
|
|
|
|
EventHandlerUPP dispatchHandler = NewEventHandlerUPP( carbonDispatchHandler ); // will not be disposed by Carbon...
|
|
|
|
static EventTypeSpec dispatchEvents[] = {
|
|
|
|
{ kEventClassWindow, kEventWindowShown },
|
|
|
|
{ kEventClassWindow, kEventWindowHidden },
|
|
|
|
{ kEventClassWindow, kEventWindowActivated },
|
|
|
|
{ kEventClassWindow, kEventWindowDeactivated },
|
|
|
|
{ kEventClassWindow, kEventWindowClose },
|
|
|
|
{ kEventClassKeyboard, kEventRawKeyDown },
|
|
|
|
{ kEventClassKeyboard, kEventRawKeyRepeat },
|
|
|
|
{ kEventClassKeyboard, kEventRawKeyUp },
|
|
|
|
{ kEventClassKeyboard, kEventRawKeyModifiersChanged },
|
|
|
|
{ kEventClassMouse, kEventMouseDown },
|
|
|
|
{ kEventClassMouse, kEventMouseUp },
|
|
|
|
{ kEventClassMouse, kEventMouseMoved },
|
2005-11-04 13:24:42 +03:00
|
|
|
{ kEventClassMouse, 11 }, // MightyMouse wheels
|
2001-12-20 08:27:14 +03:00
|
|
|
{ kEventClassMouse, kEventMouseWheelMoved },
|
2002-01-03 11:08:21 +03:00
|
|
|
{ kEventClassMouse, kEventMouseDragged },
|
2002-06-28 03:18:12 +04:00
|
|
|
{ kEventClassFLTK, kEventFLTKBreakLoop },
|
|
|
|
{ kEventClassFLTK, kEventFLTKDataReady } };
|
2002-07-11 08:11:41 +04:00
|
|
|
ret = InstallEventHandler( target, dispatchHandler, GetEventTypeCount(dispatchEvents), dispatchEvents, 0, 0L );
|
|
|
|
static EventTypeSpec appEvents[] = {
|
|
|
|
{ kEventClassCommand, kEventCommandProcess } };
|
|
|
|
ret = InstallApplicationEventHandler( dispatchHandler, GetEventTypeCount(appEvents), appEvents, 0, 0L );
|
2001-12-20 08:27:14 +03:00
|
|
|
}
|
2002-04-16 19:49:06 +04:00
|
|
|
|
2002-06-11 22:44:07 +04:00
|
|
|
got_events = 0;
|
2002-06-11 20:17:41 +04:00
|
|
|
|
2004-04-06 21:38:36 +04:00
|
|
|
// Check for re-entrant condition
|
|
|
|
if ( dataready.IsThreadRunning() )
|
|
|
|
{ dataready.CancelThread(DEBUGTEXT("AVOID REENTRY\n")); }
|
2002-06-28 03:18:12 +04:00
|
|
|
|
2004-04-06 21:38:36 +04:00
|
|
|
// Start thread to watch for data ready
|
|
|
|
if ( dataready.GetNfds() )
|
|
|
|
{ dataready.StartThread((void*)GetCurrentEventQueue()); }
|
2002-06-28 03:18:12 +04:00
|
|
|
|
2002-06-11 20:17:41 +04:00
|
|
|
fl_unlock_function();
|
|
|
|
|
2005-09-26 01:48:43 +04:00
|
|
|
EventRef event;
|
|
|
|
EventTimeout timeout = time;
|
|
|
|
if (!ReceiveNextEvent(0, NULL, timeout, true, &event)) {
|
|
|
|
got_events = 1;
|
2005-10-10 16:47:49 +04:00
|
|
|
OSErr ret = SendEventToEventTarget( event, target );
|
2005-11-02 13:39:06 +03:00
|
|
|
if (ret!=noErr) {
|
|
|
|
EventRecord clevent;
|
|
|
|
ConvertEventRefToEventRecord(event, &clevent);
|
|
|
|
if (clevent.what==kHighLevelEvent) {
|
|
|
|
ret = AEProcessAppleEvent(&clevent);
|
|
|
|
}
|
|
|
|
}
|
2005-10-10 16:47:49 +04:00
|
|
|
if ( ret==eventNotHandledErr
|
|
|
|
&& GetEventClass(event)==kEventClassMouse
|
|
|
|
&& GetEventKind(event)==kEventMouseDown ) {
|
|
|
|
WindowRef win; Point pos;
|
|
|
|
GetEventParameter(event, kEventParamMouseLocation, typeQDPoint,
|
|
|
|
NULL, sizeof(pos), NULL, &pos);
|
|
|
|
if (MacFindWindow(pos, &win)==inMenuBar) {
|
|
|
|
MenuSelect(pos);
|
|
|
|
}
|
|
|
|
}
|
2005-09-26 01:48:43 +04:00
|
|
|
ReleaseEvent( event );
|
|
|
|
}
|
2002-09-20 21:56:56 +04:00
|
|
|
|
2002-06-11 20:17:41 +04:00
|
|
|
fl_lock_function();
|
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
#if CONSOLIDATE_MOTION
|
2002-04-16 19:49:06 +04:00
|
|
|
if (send_motion && send_motion == fl_xmousewin) {
|
|
|
|
send_motion = 0;
|
|
|
|
Fl::handle(FL_MOVE, fl_xmousewin);
|
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
#endif
|
2002-04-16 19:49:06 +04:00
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
return time;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This public function handles all events. It wait a maximum of
|
2002-06-11 20:17:41 +04:00
|
|
|
* 'time' secods for an event. This version returns 1 if events
|
|
|
|
* other than the timeout timer were processed.
|
2001-11-27 20:44:08 +03:00
|
|
|
*
|
2002-01-03 11:08:21 +03:00
|
|
|
* \todo there is no socket handling in this code whatsoever
|
2001-11-27 20:44:08 +03:00
|
|
|
*/
|
2002-06-11 20:17:41 +04:00
|
|
|
int fl_wait( double time )
|
2001-11-27 20:44:08 +03:00
|
|
|
{
|
2002-06-11 20:17:41 +04:00
|
|
|
do_queued_events( time );
|
|
|
|
return (got_events);
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2002-01-03 11:08:21 +03:00
|
|
|
* event handler for Apple-Q key combination
|
|
|
|
* this is also called from the Carbon Window handler after all windows were closed
|
2001-11-27 20:44:08 +03:00
|
|
|
*/
|
2001-12-04 06:03:17 +03:00
|
|
|
static OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon )
|
|
|
|
{
|
2002-04-16 19:49:06 +04:00
|
|
|
fl_lock_function();
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
while ( Fl_X::first ) {
|
|
|
|
Fl_X *x = Fl_X::first;
|
|
|
|
Fl::handle( FL_CLOSE, x->w );
|
2002-04-16 19:49:06 +04:00
|
|
|
if ( Fl_X::first == x ) {
|
|
|
|
fl_unlock_function();
|
2002-01-03 11:08:21 +03:00
|
|
|
return noErr; // FLTK has not close all windows, so we return to the main program now
|
2002-04-16 19:49:06 +04:00
|
|
|
}
|
2002-01-03 11:08:21 +03:00
|
|
|
}
|
2002-04-16 19:49:06 +04:00
|
|
|
|
|
|
|
fl_unlock_function();
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
return noErr;
|
2001-12-04 06:03:17 +03:00
|
|
|
}
|
|
|
|
|
2001-12-19 12:10:00 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Carbon Window handler
|
|
|
|
* This needs to be linked into all new window event handlers
|
|
|
|
*/
|
2002-01-03 11:08:21 +03:00
|
|
|
static pascal OSStatus carbonWindowHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData )
|
2001-12-19 12:10:00 +03:00
|
|
|
{
|
|
|
|
UInt32 kind = GetEventKind( event );
|
|
|
|
OSStatus ret = eventNotHandledErr;
|
|
|
|
Fl_Window *window = (Fl_Window*)userData;
|
2007-02-02 19:10:19 +03:00
|
|
|
Fl::first_window(window);
|
2001-12-19 12:10:00 +03:00
|
|
|
|
|
|
|
Rect currentBounds, originalBounds;
|
2001-12-22 10:16:12 +03:00
|
|
|
WindowClass winClass;
|
|
|
|
static Fl_Window *activeWindow = 0;
|
2001-12-19 12:10:00 +03:00
|
|
|
|
2002-04-16 19:49:06 +04:00
|
|
|
fl_lock_function();
|
|
|
|
|
2001-12-19 12:10:00 +03:00
|
|
|
switch ( kind )
|
|
|
|
{
|
2003-08-02 09:54:43 +04:00
|
|
|
case kEventWindowBoundsChanging:
|
|
|
|
GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, ¤tBounds );
|
|
|
|
GetEventParameter( event, kEventParamOriginalBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &originalBounds );
|
|
|
|
break;
|
2001-12-19 12:10:00 +03:00
|
|
|
case kEventWindowDrawContent:
|
|
|
|
handleUpdateEvent( fl_xid( window ) );
|
|
|
|
ret = noErr;
|
|
|
|
break;
|
|
|
|
case kEventWindowBoundsChanged: {
|
|
|
|
GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, ¤tBounds );
|
|
|
|
GetEventParameter( event, kEventParamOriginalBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &originalBounds );
|
|
|
|
int X = currentBounds.left, W = currentBounds.right-X;
|
|
|
|
int Y = currentBounds.top, H = currentBounds.bottom-Y;
|
|
|
|
resize_from_system = window;
|
|
|
|
window->resize( X, Y, W, H );
|
|
|
|
if ( ( originalBounds.right - originalBounds.left != W )
|
|
|
|
|| ( originalBounds.bottom - originalBounds.top != H ) )
|
|
|
|
{
|
|
|
|
if ( window->shown() )
|
|
|
|
handleUpdateEvent( fl_xid( window ) );
|
|
|
|
}
|
|
|
|
break; }
|
|
|
|
case kEventWindowShown:
|
2002-06-27 08:29:39 +04:00
|
|
|
if ( !window->parent() )
|
|
|
|
{
|
|
|
|
GetWindowClass( fl_xid( window ), &winClass );
|
|
|
|
if ( winClass != kHelpWindowClass ) { // help windows can't get the focus!
|
|
|
|
Fl::handle( FL_FOCUS, window);
|
|
|
|
activeWindow = window;
|
|
|
|
}
|
|
|
|
Fl::handle( FL_SHOW, window);
|
2005-11-28 17:38:38 +03:00
|
|
|
mods_to_e_state(GetCurrentKeyModifiers());
|
2002-06-27 08:29:39 +04:00
|
|
|
}
|
2001-12-19 12:10:00 +03:00
|
|
|
break;
|
|
|
|
case kEventWindowHidden:
|
|
|
|
if ( !window->parent() ) Fl::handle( FL_HIDE, window);
|
|
|
|
break;
|
|
|
|
case kEventWindowActivated:
|
2008-02-20 21:17:34 +03:00
|
|
|
if ( window->shown() && window!=activeWindow )
|
2001-12-22 10:16:12 +03:00
|
|
|
{
|
|
|
|
GetWindowClass( fl_xid( window ), &winClass );
|
|
|
|
if ( winClass != kHelpWindowClass ) { // help windows can't get the focus!
|
|
|
|
Fl::handle( FL_FOCUS, window);
|
|
|
|
activeWindow = window;
|
|
|
|
}
|
|
|
|
}
|
2001-12-19 12:10:00 +03:00
|
|
|
break;
|
|
|
|
case kEventWindowDeactivated:
|
2001-12-22 10:16:12 +03:00
|
|
|
if ( window==activeWindow )
|
|
|
|
{
|
|
|
|
Fl::handle( FL_UNFOCUS, window);
|
|
|
|
activeWindow = 0;
|
|
|
|
}
|
2001-12-19 12:10:00 +03:00
|
|
|
break;
|
|
|
|
case kEventWindowClose:
|
2001-12-20 08:27:14 +03:00
|
|
|
Fl::handle( FL_CLOSE, window ); // this might or might not close the window
|
2002-01-03 11:08:21 +03:00
|
|
|
// if there are no more windows, send a high-level quit event
|
2001-12-19 12:10:00 +03:00
|
|
|
if (!Fl_X::first) QuitAppleEventHandler( 0, 0, 0 );
|
2001-12-20 08:27:14 +03:00
|
|
|
ret = noErr; // returning noErr tells Carbon to stop following up on this event
|
2001-12-19 12:10:00 +03:00
|
|
|
break;
|
2006-07-17 00:37:41 +04:00
|
|
|
case kEventWindowCollapsed:
|
|
|
|
window->clear_visible();
|
|
|
|
break;
|
|
|
|
case kEventWindowExpanded:
|
|
|
|
window->set_visible();
|
|
|
|
break;
|
2001-12-19 12:10:00 +03:00
|
|
|
}
|
2002-04-16 19:49:06 +04:00
|
|
|
|
|
|
|
fl_unlock_function();
|
|
|
|
|
2001-12-19 12:10:00 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-12 10:50:37 +03:00
|
|
|
/**
|
|
|
|
* Carbon Mousewheel handler
|
|
|
|
* This needs to be linked into all new window event handlers
|
|
|
|
*/
|
2005-11-29 21:06:46 +03:00
|
|
|
static pascal OSStatus carbonMousewheelHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData )
|
2001-12-12 10:50:37 +03:00
|
|
|
{
|
2005-11-04 14:17:31 +03:00
|
|
|
// 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,
|
2002-04-16 19:49:06 +04:00
|
|
|
fl_lock_function();
|
2005-11-25 17:50:22 +03:00
|
|
|
|
2005-11-04 13:24:42 +03:00
|
|
|
fl_os_event = event;
|
|
|
|
Fl_Window *window = (Fl_Window*)userData;
|
2008-02-20 21:17:34 +03:00
|
|
|
if ( !window->shown() )
|
|
|
|
{
|
|
|
|
fl_unlock_function();
|
|
|
|
return noErr;
|
|
|
|
}
|
2007-02-02 19:10:19 +03:00
|
|
|
Fl::first_window(window);
|
2005-11-04 13:24:42 +03:00
|
|
|
|
|
|
|
EventMouseWheelAxis axis;
|
2001-12-12 10:50:37 +03:00
|
|
|
GetEventParameter( event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(EventMouseWheelAxis), NULL, &axis );
|
|
|
|
long delta;
|
|
|
|
GetEventParameter( event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(long), NULL, &delta );
|
2005-11-26 03:47:45 +03:00
|
|
|
// fprintf(stderr, "axis=%d, delta=%d\n", axis, delta);
|
2005-11-25 17:50:22 +03:00
|
|
|
if ( axis == kEventMouseWheelAxisX ) {
|
2005-11-29 21:06:46 +03:00
|
|
|
Fl::e_dx = -delta;
|
|
|
|
Fl::e_dy = 0;
|
2001-12-14 22:34:30 +03:00
|
|
|
if ( Fl::e_dx) Fl::handle( FL_MOUSEWHEEL, window );
|
2005-11-25 17:50:22 +03:00
|
|
|
} else if ( axis == kEventMouseWheelAxisY ) {
|
2005-11-29 21:06:46 +03:00
|
|
|
Fl::e_dx = 0;
|
2001-12-14 22:34:30 +03:00
|
|
|
Fl::e_dy = -delta;
|
2001-12-12 10:50:37 +03:00
|
|
|
if ( Fl::e_dy) Fl::handle( FL_MOUSEWHEEL, window );
|
2005-11-25 17:50:22 +03:00
|
|
|
} else {
|
2002-04-16 19:49:06 +04:00
|
|
|
fl_unlock_function();
|
|
|
|
|
|
|
|
return eventNotHandledErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
fl_unlock_function();
|
|
|
|
|
2001-12-12 10:50:37 +03:00
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
|
2001-12-12 10:50:37 +03:00
|
|
|
/**
|
|
|
|
* convert the current mouse chord into the FLTK modifier state
|
|
|
|
*/
|
|
|
|
static void chord_to_e_state( UInt32 chord )
|
|
|
|
{
|
|
|
|
static ulong state[] =
|
|
|
|
{
|
|
|
|
0, FL_BUTTON1, FL_BUTTON3, FL_BUTTON1|FL_BUTTON3, FL_BUTTON2,
|
2003-05-28 09:10:05 +04:00
|
|
|
FL_BUTTON2|FL_BUTTON1, FL_BUTTON2|FL_BUTTON3,
|
|
|
|
FL_BUTTON2|FL_BUTTON1|FL_BUTTON3
|
2001-12-12 10:50:37 +03:00
|
|
|
};
|
|
|
|
Fl::e_state = ( Fl::e_state & 0xff0000 ) | state[ chord & 0x07 ];
|
|
|
|
}
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
|
2001-12-12 10:50:37 +03:00
|
|
|
/**
|
|
|
|
* Carbon Mouse Button Handler
|
|
|
|
*/
|
2002-01-03 11:08:21 +03:00
|
|
|
static pascal OSStatus carbonMouseHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData )
|
2001-12-12 10:50:37 +03:00
|
|
|
{
|
|
|
|
static int keysym[] = { 0, FL_Button+1, FL_Button+3, FL_Button+2 };
|
|
|
|
static int px, py;
|
2006-08-17 13:01:56 +04:00
|
|
|
static char suppressed = 0;
|
2002-04-16 19:49:06 +04:00
|
|
|
|
|
|
|
fl_lock_function();
|
|
|
|
|
2002-02-26 03:34:55 +03:00
|
|
|
fl_os_event = event;
|
2001-12-12 10:50:37 +03:00
|
|
|
Fl_Window *window = (Fl_Window*)userData;
|
2008-02-20 21:17:34 +03:00
|
|
|
if ( !window->shown() )
|
|
|
|
{
|
|
|
|
fl_unlock_function();
|
|
|
|
return noErr;
|
|
|
|
}
|
2007-02-02 19:10:19 +03:00
|
|
|
Fl::first_window(window);
|
2001-12-12 10:50:37 +03:00
|
|
|
Point pos;
|
|
|
|
GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pos );
|
|
|
|
EventMouseButton btn;
|
|
|
|
GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &btn );
|
|
|
|
UInt32 clickCount;
|
|
|
|
GetEventParameter( event, kEventParamClickCount, typeUInt32, NULL, sizeof(UInt32), NULL, &clickCount );
|
|
|
|
UInt32 chord;
|
|
|
|
GetEventParameter( event, kEventParamMouseChord, typeUInt32, NULL, sizeof(UInt32), NULL, &chord );
|
2001-12-19 12:10:00 +03:00
|
|
|
WindowRef xid = fl_xid(window), tempXid;
|
2007-05-06 19:54:07 +04:00
|
|
|
int sendEvent = 0, part = 0;
|
2001-12-12 10:50:37 +03:00
|
|
|
switch ( GetEventKind( event ) )
|
|
|
|
{
|
|
|
|
case kEventMouseDown:
|
2001-12-19 12:10:00 +03:00
|
|
|
part = FindWindow( pos, &tempXid );
|
2007-02-01 23:13:57 +03:00
|
|
|
if (!(Fl::grab() && window!=Fl::grab())) {
|
|
|
|
if ( part == inGrow ) {
|
|
|
|
fl_unlock_function();
|
|
|
|
suppressed = 1;
|
|
|
|
Fl_Tooltip::current(0L);
|
|
|
|
return CallNextEventHandler( nextHandler, event ); // let the OS handle this for us
|
|
|
|
}
|
|
|
|
if ( part != inContent ) {
|
|
|
|
fl_unlock_function();
|
|
|
|
suppressed = 1;
|
|
|
|
Fl_Tooltip::current(0L);
|
|
|
|
// anything else to here?
|
|
|
|
return CallNextEventHandler( nextHandler, event ); // let the OS handle this for us
|
|
|
|
}
|
2002-04-16 19:49:06 +04:00
|
|
|
}
|
2006-08-17 13:01:56 +04:00
|
|
|
suppressed = 0;
|
2006-11-20 00:04:11 +03:00
|
|
|
if (part==inContent && !IsWindowActive( xid ) ) {
|
2001-12-19 12:10:00 +03:00
|
|
|
CallNextEventHandler( nextHandler, event ); // let the OS handle the activation, but continue to get a click-through effect
|
2006-11-20 00:04:11 +03:00
|
|
|
}
|
2001-12-18 14:00:09 +03:00
|
|
|
// normal handling of mouse-down follows
|
2001-12-20 08:27:14 +03:00
|
|
|
fl_os_capture = xid;
|
2001-12-12 10:50:37 +03:00
|
|
|
sendEvent = FL_PUSH;
|
|
|
|
Fl::e_is_click = 1; px = pos.h; py = pos.v;
|
2005-11-02 02:57:40 +03:00
|
|
|
if (clickCount>1)
|
|
|
|
Fl::e_clicks++;
|
|
|
|
else
|
|
|
|
Fl::e_clicks = 0;
|
2001-12-12 10:50:37 +03:00
|
|
|
// fall through
|
|
|
|
case kEventMouseUp:
|
2006-08-17 13:01:56 +04:00
|
|
|
if (suppressed) {
|
|
|
|
suppressed = 0;
|
|
|
|
break;
|
|
|
|
}
|
2001-12-20 08:27:14 +03:00
|
|
|
if ( !window ) break;
|
2001-12-22 10:16:12 +03:00
|
|
|
if ( !sendEvent ) {
|
|
|
|
sendEvent = FL_RELEASE;
|
|
|
|
}
|
2001-12-12 10:50:37 +03:00
|
|
|
Fl::e_keysym = keysym[ btn ];
|
|
|
|
// fall through
|
|
|
|
case kEventMouseMoved:
|
2006-08-17 13:01:56 +04:00
|
|
|
suppressed = 0;
|
2001-12-22 10:16:12 +03:00
|
|
|
if ( !sendEvent ) {
|
|
|
|
sendEvent = FL_MOVE; chord = 0;
|
|
|
|
}
|
2001-12-12 10:50:37 +03:00
|
|
|
// fall through
|
|
|
|
case kEventMouseDragged:
|
2006-08-17 13:01:56 +04:00
|
|
|
if (suppressed) break;
|
2001-12-12 10:50:37 +03:00
|
|
|
if ( !sendEvent ) {
|
2002-06-27 08:29:39 +04:00
|
|
|
sendEvent = FL_MOVE; // Fl::handle will convert into FL_DRAG
|
2001-12-22 10:16:12 +03:00
|
|
|
if (abs(pos.h-px)>5 || abs(pos.v-py)>5)
|
|
|
|
Fl::e_is_click = 0;
|
2001-12-12 10:50:37 +03:00
|
|
|
}
|
|
|
|
chord_to_e_state( chord );
|
2002-01-03 11:08:21 +03:00
|
|
|
GrafPtr oldPort;
|
|
|
|
GetPort( &oldPort );
|
|
|
|
SetPort( GetWindowPort(xid) ); // \todo replace this! There must be some GlobalToLocal call that has a port as an argument
|
2001-12-22 10:16:12 +03:00
|
|
|
SetOrigin(0, 0);
|
2001-12-12 10:50:37 +03:00
|
|
|
Fl::e_x_root = pos.h;
|
|
|
|
Fl::e_y_root = pos.v;
|
|
|
|
GlobalToLocal( &pos );
|
|
|
|
Fl::e_x = pos.h;
|
|
|
|
Fl::e_y = pos.v;
|
2002-01-03 11:08:21 +03:00
|
|
|
SetPort( oldPort );
|
2006-11-20 00:04:11 +03:00
|
|
|
if (GetEventKind(event)==kEventMouseDown && part!=inContent) {
|
2007-02-01 23:13:57 +03:00
|
|
|
int used = Fl::handle( sendEvent, window );
|
2006-11-20 00:04:11 +03:00
|
|
|
CallNextEventHandler( nextHandler, event ); // let the OS handle this for us
|
2007-02-01 23:13:57 +03:00
|
|
|
if (!used)
|
|
|
|
suppressed = 1;
|
2006-11-20 00:04:11 +03:00
|
|
|
} else {
|
|
|
|
Fl::handle( sendEvent, window );
|
|
|
|
}
|
2001-12-12 10:50:37 +03:00
|
|
|
break;
|
|
|
|
}
|
2002-04-16 19:49:06 +04:00
|
|
|
|
|
|
|
fl_unlock_function();
|
|
|
|
|
2001-12-12 10:50:37 +03:00
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
|
2002-10-30 04:01:53 +03:00
|
|
|
/**
|
|
|
|
* convert the keyboard return code into the symbol on the keycaps
|
|
|
|
*/
|
|
|
|
static unsigned short keycode_to_sym( UInt32 keyCode, UInt32 mods, unsigned short deflt )
|
|
|
|
{
|
|
|
|
static Ptr map = 0;
|
|
|
|
UInt32 state = 0;
|
|
|
|
if (!map) {
|
|
|
|
map = (Ptr)GetScriptManagerVariable(smKCHRCache);
|
|
|
|
if (!map) {
|
|
|
|
long kbID = GetScriptManagerVariable(smKeyScript);
|
|
|
|
map = *GetResource('KCHR', kbID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (map)
|
|
|
|
return KeyTranslate(map, keyCode|mods, &state );
|
|
|
|
return deflt;
|
|
|
|
}
|
2002-01-03 11:08:21 +03:00
|
|
|
|
2008-09-14 23:09:13 +04:00
|
|
|
/*
|
2008-12-21 00:09:59 +03:00
|
|
|
* keycode_function for post-10.5 systems, allows more sophisticated decoding of keys
|
2008-09-14 23:09:13 +04:00
|
|
|
*/
|
|
|
|
static int keycodeToUnicode(
|
|
|
|
char * uniChars, int maxChars,
|
|
|
|
EventKind eKind,
|
|
|
|
UInt32 keycode, UInt32 modifiers,
|
2008-12-21 00:09:59 +03:00
|
|
|
UInt32 * deadKeyStatePtr,
|
|
|
|
unsigned char, // not used in this function
|
|
|
|
unsigned short) // not used in this function
|
2008-09-14 23:09:13 +04:00
|
|
|
{
|
|
|
|
// 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;
|
2008-09-30 22:04:35 +04:00
|
|
|
// ScriptCode currentKeyScript;
|
2008-09-14 23:09:13 +04:00
|
|
|
|
|
|
|
KLGetCurrentKeyboardLayout(¤tLayout);
|
|
|
|
if (currentLayout) {
|
|
|
|
KLGetKeyboardLayoutProperty(currentLayout, kKLIdentifier, (const void**)¤tLayoutId);
|
|
|
|
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;
|
2008-12-28 14:32:54 +03:00
|
|
|
// not used yet: OptionBits options = kUCKeyTranslateNoDeadKeysMask;
|
2008-09-14 23:09:13 +04:00
|
|
|
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;
|
|
|
|
}
|
2008-12-21 00:09:59 +03:00
|
|
|
|
|
|
|
UInt32 deadKeyState = *deadKeyStatePtr;
|
|
|
|
if ((action==kUCKeyActionUp)&&(*deadKeyStatePtr))
|
|
|
|
deadKeyStatePtr = &deadKeyState;
|
|
|
|
|
2008-09-14 23:09:13 +04:00
|
|
|
status = UCKeyTranslate(
|
|
|
|
(const UCKeyboardLayout *) uchr,
|
|
|
|
keycode, action, modifiers, keyboardType,
|
2008-12-21 00:09:59 +03:00
|
|
|
0, deadKeyStatePtr,
|
2008-09-14 23:09:13 +04:00
|
|
|
10, &actuallength, utext);
|
2008-12-21 00:09:59 +03:00
|
|
|
|
2008-09-14 23:09:13 +04:00
|
|
|
if (noErr != status) {
|
2008-12-21 00:09:59 +03:00
|
|
|
fprintf(stderr,"UCKeyTranslate failed: %d\n", (int) status);
|
2008-09-14 23:09:13 +04:00
|
|
|
actuallength = 0;
|
|
|
|
}
|
2008-12-21 00:09:59 +03:00
|
|
|
|
|
|
|
// convert the list of unicode chars into utf8
|
2008-09-14 23:09:13 +04:00
|
|
|
// FIXME no bounds check (see maxchars)
|
2008-09-30 22:04:35 +04:00
|
|
|
unsigned i;
|
2008-09-14 23:09:13 +04:00
|
|
|
for (i=0; i<actuallength; ++i) {
|
|
|
|
len += fl_utf8encode(utext[i], uniChars+len);
|
|
|
|
}
|
|
|
|
uniChars[len] = 0;
|
2008-12-21 00:09:59 +03:00
|
|
|
return len;
|
2008-09-14 23:09:13 +04:00
|
|
|
}
|
|
|
|
|
2008-12-21 00:09:59 +03:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2008-09-14 23:09:13 +04:00
|
|
|
|
2009-04-12 17:48:03 +04:00
|
|
|
// EXPERIMENTAL!
|
|
|
|
pascal OSStatus carbonTextHandler(
|
|
|
|
EventHandlerCallRef nextHandler, EventRef event, void *userData )
|
|
|
|
{
|
|
|
|
Fl_Window *window = (Fl_Window*)userData;
|
|
|
|
Fl::first_window(window);
|
|
|
|
fl_lock_function();
|
2009-04-13 00:00:45 +04:00
|
|
|
//int kind = GetEventKind(event);
|
2009-04-12 17:48:03 +04:00
|
|
|
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();
|
2009-04-13 00:00:45 +04:00
|
|
|
// 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();
|
2009-04-12 17:48:03 +04:00
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
2001-12-12 10:50:37 +03:00
|
|
|
/**
|
|
|
|
* handle carbon keyboard events
|
|
|
|
*/
|
2004-06-19 05:50:31 +04:00
|
|
|
pascal OSStatus carbonKeyboardHandler(
|
|
|
|
EventHandlerCallRef nextHandler, EventRef event, void *userData )
|
2001-12-12 10:50:37 +03:00
|
|
|
{
|
2008-09-14 23:09:13 +04:00
|
|
|
static char buffer[32];
|
2001-12-12 10:50:37 +03:00
|
|
|
int sendEvent = 0;
|
|
|
|
Fl_Window *window = (Fl_Window*)userData;
|
2007-02-02 19:10:19 +03:00
|
|
|
Fl::first_window(window);
|
2001-12-12 10:50:37 +03:00
|
|
|
UInt32 mods;
|
2008-10-13 23:26:18 +04:00
|
|
|
static UInt32 prevMods = mods_to_e_state( GetCurrentKeyModifiers() );
|
2002-04-16 19:49:06 +04:00
|
|
|
|
|
|
|
fl_lock_function();
|
|
|
|
|
2004-06-19 05:50:31 +04:00
|
|
|
int kind = GetEventKind(event);
|
|
|
|
|
|
|
|
// get the modifiers for any of the events
|
|
|
|
GetEventParameter( event, kEventParamKeyModifiers, typeUInt32,
|
|
|
|
NULL, sizeof(UInt32), NULL, &mods );
|
|
|
|
|
|
|
|
// get the key code only for key events
|
2009-04-12 17:48:03 +04:00
|
|
|
UInt32 keyCode = 0, maskedKeyCode = 0;
|
2004-06-19 05:50:31 +04:00
|
|
|
unsigned char key = 0;
|
|
|
|
unsigned short sym = 0;
|
|
|
|
if (kind!=kEventRawKeyModifiersChanged) {
|
|
|
|
GetEventParameter( event, kEventParamKeyCode, typeUInt32,
|
|
|
|
NULL, sizeof(UInt32), NULL, &keyCode );
|
|
|
|
GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar,
|
|
|
|
NULL, sizeof(char), NULL, &key );
|
|
|
|
}
|
2009-04-12 17:48:03 +04:00
|
|
|
// 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;
|
2009-04-13 11:32:01 +04:00
|
|
|
/* output a human readable event identifier for debugging
|
2004-06-19 05:50:31 +04:00
|
|
|
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";
|
|
|
|
}
|
2009-04-13 11:32:01 +04:00
|
|
|
printf("%08x %08x %08x '%c' %s \n", mods, keyCode, key, key, ev);
|
|
|
|
*/
|
2004-06-19 05:50:31 +04:00
|
|
|
switch (kind)
|
2001-12-12 10:50:37 +03:00
|
|
|
{
|
|
|
|
case kEventRawKeyDown:
|
|
|
|
case kEventRawKeyRepeat:
|
2008-12-21 00:09:59 +03:00
|
|
|
/*
|
|
|
|
// FIXME Matt: For 10.5, the keycode_function will handle all this. This is untested for ealier versions of OS X.
|
2006-04-19 07:00:26 +04:00
|
|
|
// When the user presses a "dead key", no information is send about
|
|
|
|
// which dead key symbol was created. So we need to trick Carbon into
|
|
|
|
// giving us the code by sending a "space" after the "dead key".
|
|
|
|
if (key==0) {
|
|
|
|
UInt32 ktState = 0;
|
|
|
|
KeyboardLayoutRef klr;
|
|
|
|
KLGetCurrentKeyboardLayout(&klr);
|
|
|
|
const void *kchar = 0; KLGetKeyboardLayoutProperty(klr, kKLKCHRData, &kchar);
|
|
|
|
KeyTranslate(kchar, (mods&0xff00) | keyCode, &ktState); // send the dead key
|
|
|
|
key = KeyTranslate(kchar, 0x31, &ktState); // fake a space key press
|
|
|
|
Fl::e_state |= 0x40000000; // mark this as a dead key
|
|
|
|
} else {
|
|
|
|
Fl::e_state &= 0xbfffffff; // clear the deadkey flag
|
|
|
|
}
|
2008-12-21 00:09:59 +03:00
|
|
|
*/
|
2001-12-12 10:50:37 +03:00
|
|
|
sendEvent = FL_KEYBOARD;
|
|
|
|
// fall through
|
|
|
|
case kEventRawKeyUp:
|
2006-04-19 07:00:26 +04:00
|
|
|
if ( !sendEvent ) {
|
|
|
|
sendEvent = FL_KEYUP;
|
|
|
|
Fl::e_state &= 0xbfffffff; // clear the deadkey flag
|
|
|
|
}
|
2004-06-19 05:50:31 +04:00
|
|
|
// if the user pressed alt/option, event_key should have the keycap,
|
|
|
|
// but event_text should generate the international symbol
|
2009-04-13 11:32:01 +04:00
|
|
|
sym = macKeyLookUp[maskedKeyCode];
|
2002-10-30 04:01:53 +03:00
|
|
|
if ( isalpha(key) )
|
|
|
|
sym = tolower(key);
|
2009-04-13 11:32:01 +04:00
|
|
|
else if ( Fl::e_state&FL_CTRL && key<32 && sym<0xff00)
|
2002-10-30 04:01:53 +03:00
|
|
|
sym = key+96;
|
2009-04-13 11:32:01 +04:00
|
|
|
else if ( Fl::e_state&FL_ALT && sym<0xff00) // find the keycap of this key
|
2009-04-12 17:48:03 +04:00
|
|
|
sym = keycode_to_sym( maskedKeyCode, 0, macKeyLookUp[ maskedKeyCode ] );
|
2006-06-09 11:48:08 +04:00
|
|
|
Fl::e_keysym = Fl::e_original_keysym = sym;
|
2006-06-07 13:46:03 +04:00
|
|
|
// Handle FL_KP_Enter on regular keyboards and on Powerbooks
|
2009-04-12 17:48:03 +04:00
|
|
|
if ( maskedKeyCode==0x4c || maskedKeyCode==0x34) key=0x0d;
|
|
|
|
// Handle the Delete key on the keypad
|
2004-06-19 05:50:31 +04:00
|
|
|
// Matt: the Mac has no concept of a NumLock key, or at least not visible
|
|
|
|
// Matt: to Carbon. The kEventKeyModifierNumLockMask is only set when
|
|
|
|
// Matt: a numeric keypad key is pressed and does not correspond with
|
|
|
|
// Matt: the NumLock light in PowerBook keyboards.
|
2008-12-21 00:09:59 +03:00
|
|
|
|
|
|
|
// Matt: attempt to get the correct Unicode character(s) from our keycode
|
|
|
|
// imm: keycode_function function pointer added to allow us to use different functions
|
|
|
|
// imm: depending on which OS version we are running on (tested and set in fl_open_display)
|
2008-09-14 23:09:13 +04:00
|
|
|
static UInt32 deadKeyState = 0; // must be cleared when losing focus
|
2008-12-21 00:09:59 +03:00
|
|
|
Fl::e_length = (*keycode_function)(buffer, 31, kind, keyCode, mods, &deadKeyState, key, sym);
|
2001-12-12 10:50:37 +03:00
|
|
|
Fl::e_text = buffer;
|
2008-12-21 00:09:59 +03:00
|
|
|
buffer[Fl::e_length] = 0; // just in case...
|
2001-12-12 10:50:37 +03:00
|
|
|
break;
|
|
|
|
case kEventRawKeyModifiersChanged: {
|
|
|
|
UInt32 tMods = prevMods ^ mods;
|
|
|
|
if ( tMods )
|
|
|
|
{
|
|
|
|
mods_to_e_keysym( tMods );
|
|
|
|
if ( Fl::e_keysym )
|
|
|
|
sendEvent = ( prevMods<mods ) ? FL_KEYBOARD : FL_KEYUP;
|
|
|
|
Fl::e_length = 0;
|
|
|
|
buffer[0] = 0;
|
|
|
|
prevMods = mods;
|
|
|
|
}
|
|
|
|
mods_to_e_state( mods );
|
|
|
|
break; }
|
|
|
|
}
|
|
|
|
while (window->parent()) window = window->window();
|
2002-04-16 19:49:06 +04:00
|
|
|
if (sendEvent && Fl::handle(sendEvent,window)) {
|
2004-06-19 05:50:31 +04:00
|
|
|
fl_unlock_function();
|
2002-04-16 19:49:06 +04:00
|
|
|
return noErr; // return noErr if FLTK handled the event
|
|
|
|
} else {
|
|
|
|
fl_unlock_function();
|
2004-06-19 05:50:31 +04:00
|
|
|
//return CallNextEventHandler( nextHandler, event );;
|
|
|
|
// Matt: I had better results (no duplicate events) always returning
|
|
|
|
// Matt: 'noErr'. System keyboard events still seem to work just fine.
|
|
|
|
return noErr;
|
2002-04-16 19:49:06 +04:00
|
|
|
}
|
2001-12-12 10:50:37 +03:00
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
|
2003-05-30 11:03:09 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Open callback function to call...
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void (*open_cb)(const char *) = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Event handler for Apple-O key combination and also for file opens
|
|
|
|
* via the finder...
|
|
|
|
*/
|
|
|
|
|
|
|
|
static OSErr OpenAppleEventHandler(const AppleEvent *appleEvt,
|
|
|
|
AppleEvent *reply,
|
|
|
|
UInt32 refcon) {
|
|
|
|
OSErr err;
|
|
|
|
AEDescList documents;
|
|
|
|
long i, n;
|
|
|
|
FSSpec fileSpec;
|
|
|
|
AEKeyword keyWd;
|
|
|
|
DescType typeCd;
|
|
|
|
Size actSz;
|
|
|
|
char filename[1024];
|
|
|
|
|
|
|
|
if (!open_cb) return noErr;
|
|
|
|
|
|
|
|
// Initialize the document list...
|
|
|
|
AECreateDesc(typeNull, NULL, 0, &documents);
|
|
|
|
|
|
|
|
// Get the open parameter(s)...
|
|
|
|
err = AEGetParamDesc(appleEvt, keyDirectObject, typeAEList, &documents);
|
|
|
|
if (err != noErr) {
|
|
|
|
AEDisposeDesc(&documents);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lock access to FLTK in this thread...
|
|
|
|
fl_lock_function();
|
|
|
|
|
|
|
|
// Open the documents via the callback...
|
2003-06-01 04:23:57 +04:00
|
|
|
if (AECountItems(&documents, &n) == noErr) {
|
2003-05-30 11:03:09 +04:00
|
|
|
for (i = 1; i <= n; i ++) {
|
|
|
|
// Get the next FSSpec record...
|
2003-06-01 04:23:57 +04:00
|
|
|
AEGetNthPtr(&documents, i, typeFSS, &keyWd, &typeCd,
|
2003-05-30 11:03:09 +04:00
|
|
|
(Ptr)&fileSpec, sizeof(fileSpec),
|
|
|
|
(actSz = sizeof(fileSpec), &actSz));
|
|
|
|
|
|
|
|
// Convert to a UNIX path...
|
|
|
|
FSSpec2UnixPath(&fileSpec, filename);
|
|
|
|
|
|
|
|
// Call the callback with the filename...
|
|
|
|
(*open_cb)(filename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unlock access to FLTK for all threads...
|
|
|
|
fl_unlock_function();
|
|
|
|
|
|
|
|
// Get rid of the document list...
|
|
|
|
AEDisposeDesc(&documents);
|
|
|
|
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Install an open documents event handler...
|
|
|
|
*/
|
|
|
|
|
|
|
|
void fl_open_callback(void (*cb)(const char *)) {
|
|
|
|
open_cb = cb;
|
|
|
|
if (cb) {
|
|
|
|
AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
|
|
|
|
NewAEEventHandlerUPP((AEEventHandlerProcPtr)
|
|
|
|
OpenAppleEventHandler), 0, false);
|
|
|
|
} else {
|
|
|
|
AERemoveEventHandler(kCoreEventClass, kAEOpenDocuments,
|
|
|
|
NewAEEventHandlerUPP((AEEventHandlerProcPtr)
|
|
|
|
OpenAppleEventHandler), false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
/**
|
2007-01-20 18:28:11 +03:00
|
|
|
* initialize the Mac toolboxes, dock status, and set the default menubar
|
2001-11-27 20:44:08 +03:00
|
|
|
*/
|
2007-01-20 18:28:11 +03:00
|
|
|
|
|
|
|
extern "C" {
|
2007-01-23 13:27:44 +03:00
|
|
|
extern OSErr CPSEnableForegroundOperation(ProcessSerialNumber *psn, UInt32 _arg2,
|
2007-01-20 18:28:11 +03:00
|
|
|
UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
|
2007-01-23 13:27:44 +03:00
|
|
|
}
|
2007-01-20 18:28:11 +03:00
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
void fl_open_display() {
|
|
|
|
static char beenHereDoneThat = 0;
|
|
|
|
if ( !beenHereDoneThat ) {
|
|
|
|
beenHereDoneThat = 1;
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
FlushEvents(everyEvent,0);
|
2009-09-13 13:53:07 +04:00
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
MoreMasters(); // \todo Carbon suggests MoreMasterPointers()
|
2001-12-04 06:03:17 +03:00
|
|
|
AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false );
|
2009-09-13 13:53:07 +04:00
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
// create the Mac Handle for the default cursor (a pointer to a pointer)
|
2001-11-27 20:44:08 +03:00
|
|
|
GetQDGlobalsArrow(&default_cursor);
|
|
|
|
default_cursor_ptr = &default_cursor;
|
|
|
|
fl_default_cursor = &default_cursor_ptr;
|
|
|
|
|
2001-12-14 22:34:30 +03:00
|
|
|
ClearMenuBar();
|
|
|
|
AppendResMenu( GetMenuHandle( 1 ), 'DRVR' );
|
2001-11-27 20:44:08 +03:00
|
|
|
DrawMenuBar();
|
2009-09-13 13:53:07 +04:00
|
|
|
|
2007-01-20 18:28:11 +03:00
|
|
|
// bring the application into foreground without a 'CARB' resource
|
|
|
|
Boolean same_psn;
|
|
|
|
ProcessSerialNumber cur_psn, front_psn;
|
|
|
|
if( !GetCurrentProcess( &cur_psn ) && !GetFrontProcess( &front_psn ) &&
|
2009-09-13 13:53:07 +04:00
|
|
|
!SameProcess( &front_psn, &cur_psn, &same_psn ) && !same_psn )
|
2007-01-20 18:28:11 +03:00
|
|
|
{
|
|
|
|
// only transform the application type for unbundled apps
|
|
|
|
CFBundleRef bundle = CFBundleGetMainBundle();
|
|
|
|
if( bundle )
|
|
|
|
{
|
|
|
|
FSRef execFs;
|
|
|
|
CFURLRef execUrl = CFBundleCopyExecutableURL( bundle );
|
|
|
|
CFURLGetFSRef( execUrl, &execFs );
|
2009-09-13 13:53:07 +04:00
|
|
|
|
2007-01-20 18:28:11 +03:00
|
|
|
FSRef bundleFs;
|
|
|
|
GetProcessBundleLocation( &cur_psn, &bundleFs );
|
2009-09-13 13:53:07 +04:00
|
|
|
|
2007-01-20 18:28:11 +03:00
|
|
|
if( !FSCompareFSRefs( &execFs, &bundleFs ) )
|
|
|
|
bundle = NULL;
|
2009-09-13 13:53:07 +04:00
|
|
|
|
2007-01-20 18:28:11 +03:00
|
|
|
CFRelease(execUrl);
|
|
|
|
}
|
2009-09-13 13:53:07 +04:00
|
|
|
|
2007-01-20 18:28:11 +03:00
|
|
|
if( !bundle )
|
|
|
|
{
|
2007-01-24 00:48:17 +03:00
|
|
|
// Earlier versions of this code tried to use weak linking, however it
|
2008-12-21 00:09:59 +03:00
|
|
|
// 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...
|
2007-01-24 00:48:17 +03:00
|
|
|
OSErr err;
|
2009-09-13 13:53:07 +04:00
|
|
|
|
2007-01-24 00:48:17 +03:00
|
|
|
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
|
2007-01-21 17:57:42 +03:00
|
|
|
if (TransformProcessType != NULL) {
|
2009-09-13 13:53:07 +04:00
|
|
|
err = TransformProcessType(&cur_psn, kProcessTransformToForegroundApplication);
|
|
|
|
} else
|
2007-01-24 00:48:17 +03:00
|
|
|
#endif // MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
|
2009-09-13 13:53:07 +04:00
|
|
|
err = CPSEnableForegroundOperation(&cur_psn, 0x03, 0x3C, 0x2C, 0x1103);
|
|
|
|
|
2007-01-21 17:57:42 +03:00
|
|
|
if (err == noErr) {
|
2009-09-13 13:53:07 +04:00
|
|
|
SetFrontProcess( &cur_psn );
|
2007-01-21 17:57:42 +03:00
|
|
|
}
|
2007-01-20 18:28:11 +03:00
|
|
|
}
|
|
|
|
}
|
2009-09-13 13:53:07 +04:00
|
|
|
|
|
|
|
// imm: keycode handler stub setting - use Gestalt to determine the running system version,
|
|
|
|
// then set the keycode_function pointer accordingly
|
|
|
|
keycode_function = keycode_wrap_old; // default to pre-10.5 mechanism
|
|
|
|
SInt32 MacVersion;
|
|
|
|
if (Gestalt(gestaltSystemVersion, &MacVersion) == noErr)
|
|
|
|
{
|
|
|
|
if(MacVersion >= 0x1050) { // 10.5.0 or later
|
|
|
|
keycode_function = keycodeToUnicode;
|
|
|
|
}
|
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get rid of allocated resources
|
|
|
|
*/
|
|
|
|
void fl_close_display() {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
2002-01-03 11:08:21 +03:00
|
|
|
return r.bounds.top + 20; // \todo 20 pixel menu bar?
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 windw's flush() to actually draw the content
|
|
|
|
*/
|
|
|
|
void Fl_X::flush()
|
|
|
|
{
|
|
|
|
w->flush();
|
2004-09-01 02:00:49 +04:00
|
|
|
if (fl_gc)
|
|
|
|
CGContextFlush(fl_gc);
|
2001-11-27 20:44:08 +03:00
|
|
|
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;
|
2001-12-04 06:03:17 +03:00
|
|
|
GrafPtr oldPort;
|
|
|
|
GetPort( &oldPort );
|
|
|
|
SetPort( GetWindowPort(xid) );
|
2001-11-27 20:44:08 +03:00
|
|
|
Fl_X *i = Fl_X::i( window );
|
2002-01-03 11:08:21 +03:00
|
|
|
i->wait_for_expose = 0;
|
2001-11-27 20:44:08 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
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();
|
2001-12-04 06:03:17 +03:00
|
|
|
SetPort( oldPort );
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
|
2008-09-30 22:04:35 +04:00
|
|
|
// Gets the border sizes and the titlebar size
|
|
|
|
static void get_window_frame_sizes(int &bx, int &by, int &bt) {
|
|
|
|
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
|
2008-10-06 23:20:49 +04:00
|
|
|
static HIRect contentRect = { {50,50}, {100,100} }; // a rect to stand in for the content rect of a real window
|
|
|
|
static HIThemeWindowDrawInfo metrics= {0,
|
2008-09-30 22:04:35 +04:00
|
|
|
kThemeStateActive, kThemeDocumentWindow,
|
|
|
|
kThemeWindowHasFullZoom + kThemeWindowHasCloseBox +
|
|
|
|
kThemeWindowHasCollapseBox + kThemeWindowHasTitleText,
|
|
|
|
0, 0};
|
|
|
|
HIShapeRef shape1=0, shape2=0, shape3=0;
|
|
|
|
HIRect rect1, rect2, rect3;
|
|
|
|
OSStatus status;
|
|
|
|
status = HIThemeGetWindowShape(&contentRect, &metrics, kWindowStructureRgn, &shape1);
|
|
|
|
status |= HIThemeGetWindowShape(&contentRect, &metrics, kWindowContentRgn, &shape2);
|
|
|
|
status |= HIThemeGetWindowShape(&contentRect, &metrics, kWindowTitleBarRgn, &shape3);
|
|
|
|
|
|
|
|
if (!status)
|
|
|
|
{
|
|
|
|
HIShapeGetBounds(shape1, &rect1);
|
|
|
|
HIShapeGetBounds(shape2, &rect2);
|
|
|
|
HIShapeGetBounds(shape3, &rect3);
|
|
|
|
bt = rect3.size.height;
|
|
|
|
bx = rect2.origin.x - rect1.origin.x;
|
|
|
|
by = rect2.origin.y - rect1.origin.y - bt;
|
2008-10-06 23:20:49 +04:00
|
|
|
// fprintf(stderr, "HIThemeGetWindowShape succeeded bx=%d by=%d bt=%d\n", bx, by, bt);
|
2008-09-30 22:04:35 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif // MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
|
|
|
|
{
|
|
|
|
// sets default dimensions
|
|
|
|
bx = by = 6;
|
|
|
|
bt = 22;
|
2008-10-06 23:20:49 +04:00
|
|
|
// fprintf(stderr, "HIThemeGetWindowShape failed, bx=%d by=%d bt=%d\n", bx, by, bt);
|
2008-09-30 22:04:35 +04:00
|
|
|
}
|
|
|
|
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
|
2008-10-06 23:20:49 +04:00
|
|
|
CFRelease(shape1); // we must free HIThemeGetWindowShape() (copied) handles
|
|
|
|
CFRelease(shape2);
|
|
|
|
CFRelease(shape3);
|
2008-09-30 22:04:35 +04:00
|
|
|
#endif // MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
|
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
|
|
|
|
/**
|
2002-01-03 11:08:21 +03:00
|
|
|
* \todo this is a leftover from OS9 times. Please check how much applies to Carbon!
|
2001-11-27 20:44:08 +03:00
|
|
|
*/
|
|
|
|
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;
|
2008-09-30 22:04:35 +04:00
|
|
|
get_window_frame_sizes(bx, by, bt);
|
|
|
|
/*
|
|
|
|
bx = 6; // \todo Mac : GetSystemMetrics(SM_CXSIZEFRAME);
|
|
|
|
by = 6; // \todo Mac : get Mac window frame size GetSystemMetrics(SM_CYSIZEFRAME);
|
|
|
|
*/
|
2001-11-27 20:44:08 +03:00
|
|
|
} else {
|
|
|
|
ret = 1;
|
2008-09-30 22:04:35 +04:00
|
|
|
get_window_frame_sizes(bx, by, bt);
|
|
|
|
/*
|
|
|
|
bx = 6; // \todo Mac : GetSystemMetrics(SM_CXFIXEDFRAME);
|
|
|
|
by = 6; // \todo Mac : GetSystemMetrics(SM_CYFIXEDFRAME);
|
|
|
|
*/
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
//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
|
2004-11-23 03:28:35 +03:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
GDHandle gd = 0L;
|
|
|
|
for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) {
|
|
|
|
GDPtr gp = *gd;
|
|
|
|
if ( cx >= gp->gdRect.left && cx <= gp->gdRect.right
|
|
|
|
&& cy >= gp->gdRect.top && cy <= gp->gdRect.bottom)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// if the center doesn't fall on a screen, try the top left
|
|
|
|
if (!gd) {
|
|
|
|
for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) {
|
|
|
|
GDPtr gp = *gd;
|
|
|
|
if ( X >= gp->gdRect.left && X <= gp->gdRect.right
|
|
|
|
&& Y >= gp->gdRect.top && Y <= gp->gdRect.bottom)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if that doesn't fall on a screen, try the top right
|
|
|
|
if (!gd) {
|
|
|
|
for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) {
|
|
|
|
GDPtr gp = *gd;
|
|
|
|
if ( R >= gp->gdRect.left && R <= gp->gdRect.right
|
|
|
|
&& Y >= gp->gdRect.top && Y <= gp->gdRect.bottom)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if that doesn't fall on a screen, try the bottom left
|
|
|
|
if (!gd) {
|
|
|
|
for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) {
|
|
|
|
GDPtr gp = *gd;
|
|
|
|
if ( X >= gp->gdRect.left && X <= gp->gdRect.right
|
|
|
|
&& B >= gp->gdRect.top && B <= gp->gdRect.bottom)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// last resort, try the bottom right
|
|
|
|
if (!gd) {
|
|
|
|
for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) {
|
|
|
|
GDPtr gp = *gd;
|
|
|
|
if ( R >= gp->gdRect.left && R <= gp->gdRect.right
|
|
|
|
&& B >= gp->gdRect.top && B <= gp->gdRect.bottom)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 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 = GetMainDevice();
|
|
|
|
if (gd) {
|
|
|
|
GetAvailableWindowPositioningBounds(gd, &r);
|
|
|
|
if ( R > r.right ) X -= R - r.right;
|
|
|
|
if ( B > r.bottom ) Y -= B - r.bottom;
|
|
|
|
if ( X < r.left ) X = r.left;
|
|
|
|
if ( Y < r.top ) Y = r.top;
|
|
|
|
}
|
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
//Return the client area's top left corner in (X,Y)
|
|
|
|
X+=xoff;
|
|
|
|
Y+=yoff;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2002-02-26 03:34:55 +03:00
|
|
|
/**
|
|
|
|
* convert a Mac FSSpec structure into a Unix filename
|
|
|
|
*/
|
|
|
|
static int FSSpec2UnixPath( FSSpec *fs, char *dst )
|
|
|
|
{
|
|
|
|
FSRef fsRef;
|
|
|
|
FSpMakeFSRef( fs, &fsRef );
|
|
|
|
FSRefMakePath( &fsRef, (UInt8*)dst, 1024 );
|
|
|
|
return strlen(dst);
|
|
|
|
}
|
2009-01-12 19:45:55 +03:00
|
|
|
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';
|
|
|
|
}
|
|
|
|
|
2005-08-08 23:30:09 +04:00
|
|
|
|
|
|
|
static DragReference currDragRef = 0;
|
|
|
|
static char *currDragData = 0L;
|
|
|
|
static int currDragSize = 0;
|
|
|
|
static OSErr currDragErr = noErr;
|
2002-02-26 03:34:55 +03:00
|
|
|
Fl_Window *fl_dnd_target_window = 0;
|
2002-04-14 00:28:51 +04:00
|
|
|
#include <FL/fl_draw.H>
|
2005-08-08 23:30:09 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Fill the currDrag* variables with the current DnD ASCII text.
|
|
|
|
*/
|
|
|
|
static OSErr fillCurrentDragData(DragReference dragRef)
|
|
|
|
{
|
|
|
|
OSErr ret = noErr;
|
|
|
|
char *dst = 0L;
|
|
|
|
|
|
|
|
// shortcut through this whole procedure if this is still the same drag event
|
|
|
|
if (dragRef==currDragRef)
|
|
|
|
return currDragErr;
|
|
|
|
|
|
|
|
// clear currDrag* for a new drag event
|
|
|
|
currDragRef = dragRef;
|
|
|
|
if (currDragData) free(currDragData);
|
|
|
|
currDragData = 0;
|
|
|
|
currDragSize = 0;
|
|
|
|
|
|
|
|
// fill currDRag* with ASCII data, if available
|
|
|
|
UInt16 i, nItem;
|
|
|
|
ItemReference itemRef;
|
|
|
|
FlavorFlags flags;
|
|
|
|
Size itemSize, size = 0;
|
|
|
|
CountDragItems( dragRef, &nItem );
|
2009-04-12 17:48:03 +04:00
|
|
|
|
2005-08-08 23:30:09 +04:00
|
|
|
for ( i = 1; i <= nItem; i++ )
|
|
|
|
{
|
|
|
|
GetDragItemReferenceNumber( dragRef, i, &itemRef );
|
2009-04-12 17:48:03 +04:00
|
|
|
ret = GetFlavorFlags( dragRef, itemRef, 'utf8', &flags );
|
|
|
|
if ( ret == noErr )
|
|
|
|
{
|
|
|
|
GetFlavorDataSize( dragRef, itemRef, 'utf8', &itemSize );
|
|
|
|
size += itemSize;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ret = GetFlavorFlags( dragRef, itemRef, 'utxt', &flags );
|
|
|
|
if ( ret == noErr )
|
|
|
|
{
|
|
|
|
GetFlavorDataSize( dragRef, itemRef, 'utxt', &itemSize );
|
|
|
|
size += itemSize;
|
|
|
|
continue;
|
|
|
|
}
|
2005-08-08 23:30:09 +04:00
|
|
|
ret = GetFlavorFlags( dragRef, itemRef, 'TEXT', &flags );
|
|
|
|
if ( ret == noErr )
|
|
|
|
{
|
|
|
|
GetFlavorDataSize( dragRef, itemRef, 'TEXT', &itemSize );
|
|
|
|
size += itemSize;
|
2009-04-12 17:48:03 +04:00
|
|
|
continue;
|
2005-08-08 23:30:09 +04:00
|
|
|
}
|
|
|
|
ret = GetFlavorFlags( dragRef, itemRef, 'hfs ', &flags );
|
|
|
|
if ( ret == noErr )
|
|
|
|
{
|
|
|
|
size += 1024; //++ ouch! We should create the full pathname and figure out its length
|
2009-04-12 17:48:03 +04:00
|
|
|
continue;
|
2005-08-08 23:30:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !size )
|
|
|
|
{
|
|
|
|
currDragErr = userCanceledErr;
|
|
|
|
return currDragErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
currDragSize = size + nItem - 1;
|
|
|
|
currDragData = dst = (char*)malloc( size+nItem );;
|
|
|
|
|
|
|
|
for ( i = 1; i <= nItem; i++ )
|
|
|
|
{
|
|
|
|
GetDragItemReferenceNumber( dragRef, i, &itemRef );
|
2009-04-12 17:48:03 +04:00
|
|
|
ret = GetFlavorFlags( dragRef, itemRef, 'utf8', &flags );
|
|
|
|
if ( ret == noErr )
|
|
|
|
{
|
|
|
|
GetFlavorDataSize( dragRef, itemRef, 'utf8', &itemSize );
|
|
|
|
GetFlavorData( dragRef, itemRef, 'utf8', dst, &itemSize, 0L );
|
|
|
|
dst += itemSize;
|
|
|
|
*dst++ = '\n'; // add our element separator
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
GetDragItemReferenceNumber( dragRef, i, &itemRef );
|
|
|
|
ret = GetFlavorFlags( dragRef, itemRef, 'utxt', &flags );
|
|
|
|
if ( ret == noErr )
|
|
|
|
{
|
|
|
|
GetFlavorDataSize( dragRef, itemRef, 'utxt', &itemSize );
|
|
|
|
GetFlavorData( dragRef, itemRef, 'utxt', dst, &itemSize, 0L );
|
|
|
|
dst += itemSize;
|
|
|
|
*dst++ = '\n'; // add our element separator
|
|
|
|
continue;
|
|
|
|
}
|
2005-08-08 23:30:09 +04:00
|
|
|
ret = GetFlavorFlags( dragRef, itemRef, 'TEXT', &flags );
|
|
|
|
if ( ret == noErr )
|
|
|
|
{
|
|
|
|
GetFlavorDataSize( dragRef, itemRef, 'TEXT', &itemSize );
|
|
|
|
GetFlavorData( dragRef, itemRef, 'TEXT', dst, &itemSize, 0L );
|
|
|
|
dst += itemSize;
|
2008-12-13 21:31:54 +03:00
|
|
|
*dst++ = '\n'; // add our element separator
|
2009-04-12 17:48:03 +04:00
|
|
|
continue;
|
2005-08-08 23:30:09 +04:00
|
|
|
}
|
|
|
|
ret = GetFlavorFlags( dragRef, itemRef, 'hfs ', &flags );
|
|
|
|
if ( ret == noErr )
|
|
|
|
{
|
|
|
|
HFSFlavor hfs; itemSize = sizeof( hfs );
|
|
|
|
GetFlavorData( dragRef, itemRef, 'hfs ', &hfs, &itemSize, 0L );
|
2009-04-12 17:48:03 +04:00
|
|
|
itemSize = FSSpec2UnixPath( &hfs.fileSpec, dst ); // return the path name in UTF8
|
2005-08-08 23:30:09 +04:00
|
|
|
dst += itemSize;
|
|
|
|
if ( itemSize>1 && ( hfs.fileType=='fold' || hfs.fileType=='disk' ) )
|
|
|
|
*dst++ = '/';
|
2008-12-13 21:31:54 +03:00
|
|
|
*dst++ = '\n'; // add our element separator
|
2009-04-12 17:48:03 +04:00
|
|
|
continue;
|
2005-08-08 23:30:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dst[-1] = 0;
|
|
|
|
currDragSize = dst - currDragData - 1;
|
|
|
|
currDragErr = ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2002-02-26 03:34:55 +03:00
|
|
|
/**
|
|
|
|
* Drag'n'drop tracking handler
|
|
|
|
*/
|
2002-07-17 10:09:26 +04:00
|
|
|
static pascal OSErr dndTrackingHandler( DragTrackingMessage msg, WindowPtr w, void *userData, DragReference dragRef )
|
2002-02-26 03:34:55 +03:00
|
|
|
{
|
|
|
|
Fl_Window *target = (Fl_Window*)userData;
|
2007-02-02 19:10:19 +03:00
|
|
|
Fl::first_window(target);
|
2002-02-26 03:34:55 +03:00
|
|
|
Point mp;
|
|
|
|
static int px, py;
|
|
|
|
|
2005-08-08 23:30:09 +04:00
|
|
|
fillCurrentDragData(dragRef);
|
|
|
|
Fl::e_length = currDragSize;
|
|
|
|
Fl::e_text = currDragData;
|
|
|
|
|
2002-02-26 03:34:55 +03:00
|
|
|
switch ( msg )
|
|
|
|
{
|
|
|
|
case kDragTrackingEnterWindow:
|
|
|
|
// check if 'TEXT' is available
|
|
|
|
GetDragMouse( dragRef, &mp, 0 );
|
|
|
|
Fl::e_x_root = px = mp.h;
|
|
|
|
Fl::e_y_root = py = mp.v;
|
|
|
|
Fl::e_x = px - target->x();
|
|
|
|
Fl::e_y = py - target->y();
|
|
|
|
fl_dnd_target_window = target;
|
|
|
|
if ( Fl::handle( FL_DND_ENTER, target ) )
|
|
|
|
fl_cursor( FL_CURSOR_HAND ); //ShowDragHilite( ); // modify the mouse cursor?!
|
|
|
|
else
|
|
|
|
fl_cursor( FL_CURSOR_DEFAULT ); //HideDragHilite( dragRef );
|
|
|
|
breakMacEventLoop();
|
|
|
|
return noErr;
|
|
|
|
case kDragTrackingInWindow:
|
|
|
|
GetDragMouse( dragRef, &mp, 0 );
|
|
|
|
if ( mp.h==px && mp.v==py )
|
|
|
|
break; //+ return previous condition for dnd hiliting
|
|
|
|
Fl::e_x_root = px = mp.h;
|
|
|
|
Fl::e_y_root = py = mp.v;
|
|
|
|
Fl::e_x = px - target->x();
|
|
|
|
Fl::e_y = py - target->y();
|
|
|
|
fl_dnd_target_window = target;
|
|
|
|
if ( Fl::handle( FL_DND_DRAG, target ) )
|
|
|
|
fl_cursor( FL_CURSOR_HAND ); //ShowDragHilite( ); // modify the mouse cursor?!
|
|
|
|
else
|
|
|
|
fl_cursor( FL_CURSOR_DEFAULT ); //HideDragHilite( dragRef );
|
|
|
|
breakMacEventLoop();
|
|
|
|
return noErr;
|
|
|
|
break;
|
|
|
|
case kDragTrackingLeaveWindow:
|
|
|
|
// HideDragHilite()
|
|
|
|
fl_cursor( FL_CURSOR_DEFAULT ); //HideDragHilite( dragRef );
|
|
|
|
if ( fl_dnd_target_window )
|
|
|
|
{
|
|
|
|
Fl::handle( FL_DND_LEAVE, fl_dnd_target_window );
|
|
|
|
fl_dnd_target_window = 0;
|
|
|
|
}
|
|
|
|
breakMacEventLoop();
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Drag'n'drop receive handler
|
|
|
|
*/
|
2002-07-17 10:09:26 +04:00
|
|
|
static pascal OSErr dndReceiveHandler( WindowPtr w, void *userData, DragReference dragRef )
|
2002-02-26 03:34:55 +03:00
|
|
|
{
|
|
|
|
Point mp;
|
|
|
|
OSErr ret;
|
|
|
|
|
|
|
|
Fl_Window *target = fl_dnd_target_window = (Fl_Window*)userData;
|
2007-02-02 19:10:19 +03:00
|
|
|
Fl::first_window(target);
|
2002-02-26 03:34:55 +03:00
|
|
|
GetDragMouse( dragRef, &mp, 0 );
|
|
|
|
Fl::e_x_root = mp.h;
|
|
|
|
Fl::e_y_root = mp.v;
|
|
|
|
Fl::e_x = Fl::e_x_root - target->x();
|
|
|
|
Fl::e_y = Fl::e_y_root - target->y();
|
|
|
|
if ( !Fl::handle( FL_DND_RELEASE, target ) )
|
|
|
|
return userCanceledErr;
|
2005-08-08 23:30:09 +04:00
|
|
|
|
|
|
|
ret = fillCurrentDragData(dragRef);
|
|
|
|
if (ret==userCanceledErr)
|
2002-02-26 03:34:55 +03:00
|
|
|
return userCanceledErr;
|
|
|
|
|
2005-08-08 23:30:09 +04:00
|
|
|
Fl::e_length = currDragSize;
|
|
|
|
Fl::e_text = currDragData;
|
2003-05-26 18:19:50 +04:00
|
|
|
// printf("Sending following text to widget %p:\n%s\n", Fl::belowmouse(), Fl::e_text);
|
2004-12-03 06:14:17 +03:00
|
|
|
int old_event = Fl::e_number;
|
2005-08-11 14:36:51 +04:00
|
|
|
Fl::belowmouse()->handle(Fl::e_number = FL_PASTE);
|
2004-12-03 06:14:17 +03:00
|
|
|
Fl::e_number = old_event;
|
2005-08-08 23:30:09 +04:00
|
|
|
|
|
|
|
if (currDragData) {
|
|
|
|
free(currDragData);
|
|
|
|
}
|
|
|
|
currDragData = 0L;
|
|
|
|
currDragRef = 0;
|
|
|
|
Fl::e_text = 0L;
|
|
|
|
Fl::e_length = 0;
|
2002-02-26 03:34:55 +03:00
|
|
|
fl_dnd_target_window = 0L;
|
2005-08-08 23:30:09 +04:00
|
|
|
|
2002-02-26 03:34:55 +03:00
|
|
|
breakMacEventLoop();
|
|
|
|
return noErr;
|
|
|
|
}
|
2008-11-05 15:54:39 +03:00
|
|
|
// fc:
|
|
|
|
static void q_set_window_title(Window xid, const char * name ) {
|
|
|
|
#if 1
|
|
|
|
CFStringRef utf8_title = CFStringCreateWithCString(NULL, (name ? name : ""), kCFStringEncodingUTF8);
|
|
|
|
SetWindowTitleWithCFString(xid, utf8_title);
|
|
|
|
CFRelease(utf8_title);
|
|
|
|
#else // old non-utf8 code to remove after new utf8 code approval :
|
|
|
|
Str255 pTitle;
|
|
|
|
if (name) {
|
|
|
|
if (strlen(name) > 255) pTitle[0] = 255;
|
|
|
|
else pTitle[0] = strlen(name);
|
|
|
|
memcpy(pTitle+1, name, pTitle[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pTitle[0] = 0;
|
|
|
|
SetWTitle(xid, pTitle);
|
|
|
|
#endif
|
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* go ahead, create that (sub)window
|
2002-01-03 11:08:21 +03:00
|
|
|
* \todo we should make menu windows slightly transparent for the new Mac look
|
2001-11-27 20:44:08 +03:00
|
|
|
*/
|
|
|
|
void Fl_X::make(Fl_Window* w)
|
|
|
|
{
|
2004-09-01 02:00:49 +04:00
|
|
|
static int xyPos = 100;
|
2001-11-27 20:44:08 +03:00
|
|
|
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;
|
2004-08-26 04:18:43 +04:00
|
|
|
x->gc = 0; // stay 0 for Quickdraw; fill with CGContext for Quartz
|
2001-11-27 20:44:08 +03:00
|
|
|
Fl_Window *win = w->window();
|
|
|
|
Fl_X *xo = Fl_X::i(win);
|
2003-05-20 21:53:26 +04:00
|
|
|
if (xo) {
|
|
|
|
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;
|
2004-12-03 06:14:17 +03:00
|
|
|
int old_event = Fl::e_number;
|
|
|
|
w->handle(Fl::e_number = FL_SHOW);
|
|
|
|
Fl::e_number = old_event;
|
2003-05-20 21:53:26 +04:00
|
|
|
w->redraw(); // force draw to happen
|
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
fl_show_iconic = 0;
|
|
|
|
}
|
|
|
|
else // create a desktop window
|
|
|
|
{
|
|
|
|
Fl_Group::current(0);
|
|
|
|
fl_open_display();
|
|
|
|
int winclass = kDocumentWindowClass;
|
2002-06-27 08:29:39 +04:00
|
|
|
int winattr = kWindowStandardHandlerAttribute | kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute;
|
2001-11-27 20:44:08 +03:00
|
|
|
int xp = w->x();
|
|
|
|
int yp = w->y();
|
|
|
|
int wp = w->w();
|
|
|
|
int hp = w->h();
|
2001-12-06 03:17:47 +03:00
|
|
|
if (w->size_range_set) {
|
2002-10-29 22:23:55 +03:00
|
|
|
if ( w->minh != w->maxh || w->minw != w->maxw)
|
|
|
|
winattr |= kWindowFullZoomAttribute | kWindowResizableAttribute | kWindowLiveResizeAttribute;
|
2001-12-06 03:17:47 +03:00
|
|
|
} else {
|
2001-11-27 20:44:08 +03:00
|
|
|
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);
|
2002-04-16 00:30:06 +04:00
|
|
|
winattr |= kWindowFullZoomAttribute | kWindowResizableAttribute | kWindowLiveResizeAttribute;
|
2001-11-27 20:44:08 +03:00
|
|
|
} else {
|
|
|
|
w->size_range(w->w(), w->h(), w->w(), w->h());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int xwm = xp, ywm = yp, bt, bx, by;
|
2003-05-22 22:32:51 +04:00
|
|
|
|
|
|
|
if (!fake_X_wm(w, xwm, ywm, bt, bx, by)) {
|
|
|
|
// menu windows and tooltips
|
2005-12-30 14:11:54 +03:00
|
|
|
if (w->modal()||w->override()) {
|
|
|
|
winclass = kHelpWindowClass;
|
|
|
|
winattr = 0;
|
|
|
|
} else {
|
2006-01-02 16:37:56 +03:00
|
|
|
winattr = 512; // kWindowNoTitleBarAttribute;
|
2005-12-30 14:11:54 +03:00
|
|
|
}
|
2003-05-22 22:32:51 +04:00
|
|
|
} else if (w->modal()) {
|
2002-06-27 08:29:39 +04:00
|
|
|
winclass = kMovableModalWindowClass;
|
2003-05-22 22:32:51 +04:00
|
|
|
}
|
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
if (by+bt) {
|
|
|
|
wp += 2*bx;
|
|
|
|
hp += 2*by+bt;
|
|
|
|
}
|
2009-09-27 16:06:35 +04:00
|
|
|
if (!(w->flags() & Fl_Widget::FORCE_POSITION)) {
|
2003-05-22 22:32:51 +04:00
|
|
|
// use the Carbon functions below for default window positioning
|
|
|
|
w->x(xyPos+Fl::x());
|
|
|
|
w->y(xyPos+Fl::y());
|
2002-04-16 00:30:06 +04:00
|
|
|
xyPos += 25;
|
2004-09-01 02:00:49 +04:00
|
|
|
if (xyPos>200) xyPos = 100;
|
2001-11-27 20:44:08 +03:00
|
|
|
} else {
|
|
|
|
if (!Fl::grab()) {
|
2001-12-22 10:16:12 +03:00
|
|
|
xp = xwm; yp = ywm;
|
2001-11-27 20:44:08 +03:00
|
|
|
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;
|
2002-06-27 08:29:39 +04:00
|
|
|
while (w->parent()) w = w->window(); // todo: this code does not make any sense! (w!=w??)
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2002-01-03 11:08:21 +03:00
|
|
|
x->other_xid = 0; // room for doublebuffering image map. On OS X this is only used by overlay windows
|
2001-11-27 20:44:08 +03:00
|
|
|
x->region = 0;
|
|
|
|
x->subRegion = 0;
|
|
|
|
x->cursor = fl_default_cursor;
|
|
|
|
x->xidChildren = 0;
|
|
|
|
x->xidNext = 0;
|
2004-08-26 04:18:43 +04:00
|
|
|
x->gc = 0;
|
2002-06-27 08:29:39 +04:00
|
|
|
|
|
|
|
winattr &= GetAvailableWindowAttributes( winclass ); // make sure that the window will open
|
2001-12-06 03:17:47 +03:00
|
|
|
CreateNewWindow( winclass, winattr, &wRect, &(x->xid) );
|
2008-11-05 15:54:39 +03:00
|
|
|
q_set_window_title(x->xid, name);
|
2002-06-27 08:29:39 +04:00
|
|
|
MoveWindow(x->xid, wRect.left, wRect.top, 1); // avoid Carbon Bug on old OS
|
2003-05-22 22:32:51 +04:00
|
|
|
if (w->non_modal() && !w->modal()) {
|
|
|
|
// Major kludge: this is to have the regular look, but stay above the document windows
|
|
|
|
SetWindowClass(x->xid, kFloatingWindowClass);
|
2006-08-19 17:34:10 +04:00
|
|
|
SetWindowActivationScope(x->xid, kWindowActivationScopeAll);
|
2003-05-22 22:32:51 +04:00
|
|
|
}
|
2009-09-27 16:06:35 +04:00
|
|
|
if (!(w->flags() & Fl_Widget::FORCE_POSITION))
|
2002-06-27 08:29:39 +04:00
|
|
|
{
|
|
|
|
WindowRef pw = Fl_X::first ? Fl_X::first->xid : 0 ;
|
2003-05-22 22:32:51 +04:00
|
|
|
if (w->modal()) {
|
|
|
|
RepositionWindow(x->xid, pw, kWindowAlertPositionOnParentWindowScreen);
|
|
|
|
} else if (w->non_modal()) {
|
|
|
|
RepositionWindow(x->xid, pw, kWindowCenterOnParentWindowScreen);
|
|
|
|
} else {
|
|
|
|
RepositionWindow(x->xid, pw, kWindowCascadeOnParentWindowScreen);
|
|
|
|
}
|
2002-06-27 08:29:39 +04:00
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
x->w = w; w->i = x;
|
|
|
|
x->wait_for_expose = 1;
|
|
|
|
x->next = Fl_X::first;
|
|
|
|
Fl_X::first = x;
|
2001-12-12 10:50:37 +03:00
|
|
|
{ // Install Carbon Event handlers
|
|
|
|
OSStatus ret;
|
|
|
|
EventHandlerUPP mousewheelHandler = NewEventHandlerUPP( carbonMousewheelHandler ); // will not be disposed by Carbon...
|
2001-12-19 12:10:00 +03:00
|
|
|
static EventTypeSpec mousewheelEvents[] = {
|
|
|
|
{ kEventClassMouse, kEventMouseWheelMoved } };
|
2005-11-26 03:47:45 +03:00
|
|
|
ret = InstallWindowEventHandler( x->xid, mousewheelHandler,
|
|
|
|
(int)(sizeof(mousewheelEvents)/sizeof(mousewheelEvents[0])),
|
|
|
|
mousewheelEvents, w, 0L );
|
2001-12-12 10:50:37 +03:00
|
|
|
EventHandlerUPP mouseHandler = NewEventHandlerUPP( carbonMouseHandler ); // will not be disposed by Carbon...
|
2001-12-19 12:10:00 +03:00
|
|
|
static EventTypeSpec mouseEvents[] = {
|
|
|
|
{ kEventClassMouse, kEventMouseDown },
|
|
|
|
{ kEventClassMouse, kEventMouseUp },
|
|
|
|
{ kEventClassMouse, kEventMouseMoved },
|
|
|
|
{ kEventClassMouse, kEventMouseDragged } };
|
2001-12-12 10:50:37 +03:00
|
|
|
ret = InstallWindowEventHandler( x->xid, mouseHandler, 4, mouseEvents, w, 0L );
|
2009-04-12 17:48:03 +04:00
|
|
|
|
2001-12-12 10:50:37 +03:00
|
|
|
EventHandlerUPP keyboardHandler = NewEventHandlerUPP( carbonKeyboardHandler ); // will not be disposed by Carbon...
|
2001-12-19 12:10:00 +03:00
|
|
|
static EventTypeSpec keyboardEvents[] = {
|
|
|
|
{ kEventClassKeyboard, kEventRawKeyDown },
|
|
|
|
{ kEventClassKeyboard, kEventRawKeyRepeat },
|
|
|
|
{ kEventClassKeyboard, kEventRawKeyUp },
|
|
|
|
{ kEventClassKeyboard, kEventRawKeyModifiersChanged } };
|
2001-12-12 10:50:37 +03:00
|
|
|
ret = InstallWindowEventHandler( x->xid, keyboardHandler, 4, keyboardEvents, w, 0L );
|
2009-04-12 17:48:03 +04:00
|
|
|
|
|
|
|
EventHandlerUPP textHandler = NewEventHandlerUPP( carbonTextHandler ); // will not be disposed by Carbon...
|
|
|
|
static EventTypeSpec textEvents[] = {
|
|
|
|
{ kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } };
|
|
|
|
ret = InstallWindowEventHandler( x->xid, textHandler, 1, textEvents, w, 0L );
|
|
|
|
|
2001-12-19 12:10:00 +03:00
|
|
|
EventHandlerUPP windowHandler = NewEventHandlerUPP( carbonWindowHandler ); // will not be disposed by Carbon...
|
|
|
|
static EventTypeSpec windowEvents[] = {
|
|
|
|
{ kEventClassWindow, kEventWindowDrawContent },
|
|
|
|
{ kEventClassWindow, kEventWindowShown },
|
|
|
|
{ kEventClassWindow, kEventWindowHidden },
|
|
|
|
{ kEventClassWindow, kEventWindowActivated },
|
|
|
|
{ kEventClassWindow, kEventWindowDeactivated },
|
|
|
|
{ kEventClassWindow, kEventWindowClose },
|
2006-07-17 00:37:41 +04:00
|
|
|
{ kEventClassWindow, kEventWindowCollapsed },
|
|
|
|
{ kEventClassWindow, kEventWindowExpanded },
|
2003-08-02 09:54:43 +04:00
|
|
|
{ kEventClassWindow, kEventWindowBoundsChanging },
|
2001-12-19 12:10:00 +03:00
|
|
|
{ kEventClassWindow, kEventWindowBoundsChanged } };
|
2006-07-18 00:14:50 +04:00
|
|
|
ret = InstallWindowEventHandler( x->xid, windowHandler, 10, windowEvents, w, 0L );
|
2002-02-26 03:34:55 +03:00
|
|
|
ret = InstallTrackingHandler( dndTrackingHandler, x->xid, w );
|
|
|
|
ret = InstallReceiveHandler( dndReceiveHandler, x->xid, w );
|
2001-12-12 10:50:37 +03:00
|
|
|
}
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
if ( ! Fl_X::first->next ) // if this is the first window, we need to bring the application to the front
|
2001-12-19 12:10:00 +03:00
|
|
|
{
|
|
|
|
ProcessSerialNumber psn;
|
|
|
|
OSErr err = GetCurrentProcess( &psn );
|
|
|
|
if ( err==noErr ) SetFrontProcess( &psn );
|
|
|
|
}
|
2001-12-22 10:16:12 +03:00
|
|
|
|
2006-07-17 00:37:41 +04:00
|
|
|
if (w->size_range_set) w->size_range_();
|
|
|
|
|
2006-08-25 12:49:06 +04:00
|
|
|
if (winclass != kHelpWindowClass) {
|
2002-04-16 00:30:06 +04:00
|
|
|
Fl_Tooltip::enter(0);
|
2006-08-25 12:49:06 +04:00
|
|
|
}
|
|
|
|
if (w->size_range_set) w->size_range_();
|
|
|
|
ShowWindow(x->xid);
|
|
|
|
if (fl_show_iconic) {
|
|
|
|
fl_show_iconic = 0;
|
|
|
|
CollapseWindow( x->xid, true ); // \todo Mac ; untested
|
|
|
|
} else {
|
|
|
|
w->set_visible();
|
|
|
|
}
|
2002-04-16 00:30:06 +04:00
|
|
|
|
2003-08-02 09:54:43 +04:00
|
|
|
Rect rect;
|
|
|
|
GetWindowBounds(x->xid, kWindowContentRgn, &rect);
|
|
|
|
w->x(rect.left); w->y(rect.top);
|
|
|
|
w->w(rect.right-rect.left); w->h(rect.bottom-rect.top);
|
|
|
|
|
2004-12-03 06:14:17 +03:00
|
|
|
int old_event = Fl::e_number;
|
|
|
|
w->handle(Fl::e_number = FL_SHOW);
|
|
|
|
Fl::e_number = old_event;
|
2001-12-22 10:16:12 +03:00
|
|
|
w->redraw(); // force draw to happen
|
|
|
|
|
|
|
|
if (w->modal()) { Fl::modal_ = w; fl_fix_focus(); }
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
|
|
|
|
/**
|
2006-04-28 06:57:15 +04:00
|
|
|
* Tell the OS what window sizes we want to allow
|
2002-01-03 11:08:21 +03:00
|
|
|
*/
|
2001-11-27 20:44:08 +03:00
|
|
|
void Fl_Window::size_range_() {
|
|
|
|
size_range_set = 1;
|
2006-04-28 06:57:15 +04:00
|
|
|
HISize minSize = { minw, minh };
|
|
|
|
HISize maxSize = { maxw?maxw:32000, maxh?maxh:32000 };
|
|
|
|
if (i && i->xid)
|
|
|
|
SetWindowResizeLimits(i->xid, &minSize, &maxSize);
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
/**
|
|
|
|
* returns pointer to the filename, or null if name ends with ':'
|
|
|
|
*/
|
2002-03-26 00:08:42 +03:00
|
|
|
const char *fl_filename_name( const char *name )
|
2001-11-27 20:44:08 +03:00
|
|
|
{
|
|
|
|
const char *p, *q;
|
2002-04-07 22:31:55 +04:00
|
|
|
if (!name) return (0);
|
2001-11-27 20:44:08 +03:00
|
|
|
for ( p = q = name ; *p ; )
|
|
|
|
{
|
|
|
|
if ( ( p[0] == ':' ) && ( p[1] == ':' ) )
|
|
|
|
{
|
|
|
|
q = p+2;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
else if (p[0] == '/')
|
|
|
|
q = p + 1;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2008-11-05 15:54:39 +03:00
|
|
|
if (shown() || i) {
|
|
|
|
q_set_window_title(fl_xid(this), name);
|
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
/**
|
|
|
|
* make a window visible
|
|
|
|
*/
|
2001-11-27 20:44:08 +03:00
|
|
|
void Fl_Window::show() {
|
2002-01-03 21:28:37 +03:00
|
|
|
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);
|
|
|
|
}
|
2006-06-14 15:01:03 +04:00
|
|
|
Fl_Tooltip::exit(this);
|
2001-11-27 20:44:08 +03:00
|
|
|
if (!shown() || !i) {
|
|
|
|
Fl_X::make(this);
|
|
|
|
} else {
|
2001-12-18 14:00:09 +03:00
|
|
|
if ( !parent() )
|
|
|
|
{
|
|
|
|
if ( IsWindowCollapsed( i->xid ) ) CollapseWindow( i->xid, false );
|
2002-04-16 00:30:06 +04:00
|
|
|
if (!fl_capture) {
|
2001-12-18 14:00:09 +03:00
|
|
|
BringToFront(i->xid);
|
2002-04-16 00:30:06 +04:00
|
|
|
SelectWindow(i->xid);
|
|
|
|
}
|
2001-12-18 14:00:09 +03:00
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
/**
|
|
|
|
* resize a window
|
|
|
|
*/
|
2001-11-27 20:44:08 +03:00
|
|
|
void Fl_Window::resize(int X,int Y,int W,int H) {
|
2006-05-30 11:35:58 +04:00
|
|
|
if (W<=0) W = 1; // OS X does not like zero width windows
|
|
|
|
if (H<=0) H = 1;
|
2001-11-27 20:44:08 +03:00
|
|
|
int is_a_resize = (W != w() || H != h());
|
2003-06-15 10:10:54 +04:00
|
|
|
// printf("Fl_Winodw::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);
|
2009-09-27 16:06:35 +04:00
|
|
|
if (X != x() || Y != y()) set_flag(FORCE_POSITION);
|
2001-11-27 20:44:08 +03:00
|
|
|
else if (!is_a_resize) return;
|
2001-12-19 12:10:00 +03:00
|
|
|
if ( (resize_from_system!=this) && (!parent()) && shown()) {
|
2001-11-27 20:44:08 +03:00
|
|
|
if (is_a_resize) {
|
2006-05-30 11:35:58 +04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
Rect dim; dim.left=X; dim.top=Y; dim.right=X+W; dim.bottom=Y+H;
|
|
|
|
SetWindowBounds(i->xid, kWindowContentRgn, &dim);
|
2001-12-06 03:17:47 +03:00
|
|
|
Rect all; all.top=-32000; all.bottom=32000; all.left=-32000; all.right=32000;
|
|
|
|
InvalWindowRect( i->xid, &all );
|
2006-05-30 11:35:58 +04:00
|
|
|
} else {
|
|
|
|
MoveWindow(i->xid, X, Y, 0);
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
}
|
2001-12-19 12:10:00 +03:00
|
|
|
resize_from_system = 0;
|
2001-11-27 20:44:08 +03:00
|
|
|
if (is_a_resize) {
|
|
|
|
Fl_Group::resize(X,Y,W,H);
|
2005-12-30 16:04:48 +03:00
|
|
|
if (shown()) {
|
|
|
|
redraw();
|
|
|
|
}
|
2001-11-27 20:44:08 +03:00
|
|
|
} else {
|
|
|
|
x(X); y(Y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* make all drawing go into this window (called by subclass flush() impl.)
|
|
|
|
*/
|
|
|
|
void Fl_Window::make_current()
|
|
|
|
{
|
2006-06-06 12:00:56 +04:00
|
|
|
OSStatus err;
|
2004-08-28 00:02:45 +04:00
|
|
|
Fl_X::q_release_context();
|
2001-11-27 20:44:08 +03:00
|
|
|
if ( !fl_window_region )
|
|
|
|
fl_window_region = NewRgn();
|
|
|
|
fl_window = i->xid;
|
|
|
|
current_ = this;
|
|
|
|
|
2002-06-27 08:29:39 +04:00
|
|
|
SetPort( GetWindowPort(i->xid) ); // \todo check for the handling of doublebuffered windows
|
2001-11-27 20:44:08 +03:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
2002-01-03 11:08:21 +03:00
|
|
|
SetOrigin( -xp, -yp );
|
2001-11-27 20:44:08 +03:00
|
|
|
|
|
|
|
SetRectRgn( fl_window_region, 0, 0, w(), h() );
|
|
|
|
|
2002-01-03 11:08:21 +03:00
|
|
|
// \todo for performance reasons: we don't have to create this unless the child windows moved
|
2001-11-27 20:44:08 +03:00
|
|
|
for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext )
|
|
|
|
{
|
|
|
|
Fl_Window *cw = cx->w;
|
2005-07-23 16:21:58 +04:00
|
|
|
if (!cw->visible_r()) continue;
|
|
|
|
Fl_Region r = NewRgn();
|
2001-11-27 20:44:08 +03:00
|
|
|
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 );
|
|
|
|
}
|
2006-06-04 14:21:45 +04:00
|
|
|
|
2006-06-06 12:00:56 +04:00
|
|
|
err = QDBeginCGContext(GetWindowPort(i->xid), &i->gc);
|
|
|
|
if (err!=noErr)
|
|
|
|
fprintf(stderr, "Error %d in QDBeginCGContext\n", (int)err);
|
2004-08-28 00:02:45 +04:00
|
|
|
fl_gc = i->gc;
|
|
|
|
CGContextSaveGState(fl_gc);
|
|
|
|
Fl_X::q_fill_context();
|
2010-03-29 14:35:00 +04:00
|
|
|
#if defined(USE_CAIRO)
|
2008-09-25 22:26:33 +04:00
|
|
|
if (Fl::cairo_autolink_context()) Fl::cairo_make_current(this); // capture gc changes automatically to update the cairo context adequately
|
|
|
|
#endif
|
|
|
|
|
2006-06-04 14:21:45 +04:00
|
|
|
fl_clip_region( 0 );
|
|
|
|
SetPortClipRegion( GetWindowPort(i->xid), fl_window_region );
|
2008-09-25 22:26:33 +04:00
|
|
|
|
2010-03-29 14:35:00 +04:00
|
|
|
#if defined(USE_CAIRO)
|
2008-09-25 22:26:33 +04:00
|
|
|
// update the cairo_t context
|
|
|
|
if (Fl::cairo_autolink_context()) Fl::cairo_make_current(this);
|
|
|
|
#endif
|
2001-11-27 20:44:08 +03:00
|
|
|
}
|
|
|
|
|
2004-08-28 00:02:45 +04:00
|
|
|
// helper function to manage the current CGContext fl_gc
|
|
|
|
extern Fl_Color fl_color_;
|
2008-08-16 01:18:27 +04:00
|
|
|
extern class Fl_Font_Descriptor *fl_fontsize;
|
|
|
|
extern void fl_font(class Fl_Font_Descriptor*);
|
2004-08-31 04:27:40 +04:00
|
|
|
extern void fl_quartz_restore_line_style_();
|
2004-08-28 00:02:45 +04:00
|
|
|
|
2006-06-05 13:01:29 +04:00
|
|
|
// FLTK has only one global graphics state. This function copies the FLTK state into the
|
2004-08-28 00:02:45 +04:00
|
|
|
// current Quartz context
|
|
|
|
void Fl_X::q_fill_context() {
|
|
|
|
if (!fl_gc) return;
|
2004-08-31 04:27:40 +04:00
|
|
|
int hgt = 0;
|
|
|
|
if (fl_window) {
|
|
|
|
Rect portRect;
|
|
|
|
GetPortBounds(GetWindowPort( fl_window ), &portRect);
|
|
|
|
hgt = portRect.bottom-portRect.top;
|
|
|
|
} else {
|
|
|
|
hgt = CGBitmapContextGetHeight(fl_gc);
|
|
|
|
}
|
|
|
|
CGContextTranslateCTM(fl_gc, 0.5, hgt-0.5f);
|
2004-08-28 00:02:45 +04:00
|
|
|
CGContextScaleCTM(fl_gc, 1.0f, -1.0f);
|
|
|
|
fl_font(fl_fontsize);
|
|
|
|
fl_color(fl_color_);
|
2004-08-31 04:27:40 +04:00
|
|
|
fl_quartz_restore_line_style_();
|
2004-08-28 00:02:45 +04:00
|
|
|
}
|
|
|
|
|
2006-06-05 13:01:29 +04:00
|
|
|
// The only way to reset clipping to its original state is to pop the current graphics
|
2004-08-28 00:02:45 +04:00
|
|
|
// 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);
|
2006-06-06 12:00:56 +04:00
|
|
|
if (fl_window) {
|
|
|
|
OSStatus err = QDEndCGContext(GetWindowPort(fl_window), &fl_gc);
|
|
|
|
if (err!=noErr)
|
|
|
|
fprintf(stderr, "Error %d in QDEndCGContext\n", (int)err);
|
|
|
|
}
|
2004-08-28 00:02:45 +04:00
|
|
|
fl_gc = 0;
|
2010-03-29 14:35:00 +04:00
|
|
|
#if defined(USE_CAIRO)
|
Cairo increment 2: Finer cairo granularity, less deps, new fltk_cairo lib
+ added new USE_CAIRO config preprocessor def.
to differentiate from HAVE_CAIRO so that we can use the cairo lib
without forcing the full fltk lib to be linked against it.
In that case, cairo autolink context functionality which needs fltk lib
instrumentation is disabled.
+ added new --enable-cairoext, which correspond to previous --enable-cairo.
now, --enable-cairo only adds HAVE_CAIRO def. and keeps fltk lib
from referencing cairo.
In both cases (--enable-cairo & --enable-cairoext), a new fltk_cairo lib is
created. This lib, similarly to local versions of png,jpeg and zlib,
is not generated if cairo is not enabled.
+ added cairo to fltk-config : now new --use-cairo flag is available
+ modified all unix like makefiles to now generate minimum cairo deps and also
new libfltk_cairo lib.
+ added new cairo subdir to permit conditional fltk_cairo lib generation.
+ vc2005 project minimum update to compile without be broken, but still needs
to create a similar fltk_cairo independent lib. For now, it works as before
with a dedicated cairo env. similar to --enable-cairoext context in unix.
+ regression tested ok with cairo disabled on win32, mac osx, mingw.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6462 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
2008-10-19 05:42:35 +04:00
|
|
|
if (Fl::cairo_autolink_context()) Fl::cairo_make_current((Fl_Window*) 0); // capture gc changes automatically to update the cairo context adequately
|
2008-09-25 22:26:33 +04:00
|
|
|
#endif
|
2004-08-28 00:02:45 +04:00
|
|
|
}
|
|
|
|
|
2004-09-01 02:00:49 +04:00
|
|
|
void Fl_X::q_begin_image(CGRect &rect, int cx, int cy, int w, int h) {
|
2004-08-31 04:27:40 +04:00
|
|
|
CGContextSaveGState(fl_gc);
|
|
|
|
CGAffineTransform mx = CGContextGetCTM(fl_gc);
|
2004-09-01 02:00:49 +04:00
|
|
|
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;
|
2004-08-31 04:27:40 +04:00
|
|
|
CGContextConcatCTM(fl_gc, mx);
|
2007-12-18 12:41:12 +03:00
|
|
|
rect.origin.x = -(mx.tx+0.5f) + rect.origin.x - cx;
|
|
|
|
rect.origin.y = (mx.ty+0.5f) - rect.origin.y - h + cy;
|
2004-09-01 02:00:49 +04:00
|
|
|
rect.size.width = w;
|
|
|
|
rect.size.height = h;
|
2004-08-31 04:27:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Fl_X::q_end_image() {
|
|
|
|
CGContextRestoreGState(fl_gc);
|
|
|
|
}
|
|
|
|
|
2002-03-07 22:22:58 +03:00
|
|
|
////////////////////////////////////////////////////////////////
|
2009-01-14 17:49:17 +03:00
|
|
|
// Copy & Paste fltk implementation.
|
|
|
|
////////////////////////////////////////////////////////////////
|
2002-03-07 22:22:58 +03:00
|
|
|
|
2009-01-16 17:39:41 +03:00
|
|
|
// fltk 1.3 clipboard support constant definitions:
|
2009-01-14 17:49:17 +03:00
|
|
|
const CFStringRef flavorNames[] = {
|
|
|
|
CFSTR("public.utf16-plain-text"),
|
|
|
|
CFSTR("public.utf8-plain-text"),
|
|
|
|
CFSTR("com.apple.traditional-mac-plain-text") };
|
|
|
|
const CFStringEncoding encodings[] = {
|
|
|
|
kCFStringEncodingUTF16,
|
|
|
|
kCFStringEncodingUTF8,
|
|
|
|
kCFStringEncodingMacRoman};
|
|
|
|
const size_t handledFlavorsCount = sizeof(encodings)/sizeof(CFStringEncoding);
|
|
|
|
|
|
|
|
// clipboard variables definitions :
|
2002-03-26 20:35:18 +03:00
|
|
|
Fl_Widget *fl_selection_requestor = 0;
|
|
|
|
char *fl_selection_buffer[2];
|
|
|
|
int fl_selection_length[2];
|
2009-01-14 17:49:17 +03:00
|
|
|
static int fl_selection_buffer_length[2];
|
|
|
|
|
2008-12-21 03:44:55 +03:00
|
|
|
#ifdef USE_PASTEBOARD
|
|
|
|
static PasteboardRef myPasteboard = 0;
|
|
|
|
static void allocatePasteboard() {
|
|
|
|
if (!myPasteboard)
|
|
|
|
PasteboardCreate(kPasteboardClipboard, &myPasteboard);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#endif
|
2009-01-12 19:45:55 +03:00
|
|
|
|
|
|
|
#ifndef USE_PASTEBOARD
|
|
|
|
static ScrapRef myScrap = 0;
|
|
|
|
#endif
|
2002-03-07 22:22:58 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
2002-03-26 20:35:18 +03:00
|
|
|
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;
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
2002-03-26 20:35:18 +03:00
|
|
|
memcpy(fl_selection_buffer[clipboard], stuff, len);
|
|
|
|
fl_selection_buffer[clipboard][len] = 0; // needed for direct paste
|
|
|
|
fl_selection_length[clipboard] = len;
|
2002-03-07 22:22:58 +03:00
|
|
|
if (clipboard) {
|
2008-12-21 03:44:55 +03:00
|
|
|
#ifdef USE_PASTEBOARD
|
|
|
|
// FIXME no error checking done yet!
|
|
|
|
allocatePasteboard();
|
2009-01-14 17:49:17 +03:00
|
|
|
OSStatus err = PasteboardClear(myPasteboard);
|
|
|
|
if (err!=noErr) return; // clear did not work, maybe not owner of clipboard.
|
2008-12-21 03:44:55 +03:00
|
|
|
PasteboardSynchronize(myPasteboard);
|
|
|
|
CFDataRef text = CFDataCreate(kCFAllocatorDefault, (UInt8*)fl_selection_buffer[1], len);
|
2009-01-14 17:49:17 +03:00
|
|
|
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);
|
2008-12-21 03:44:55 +03:00
|
|
|
#else
|
2009-01-14 17:49:17 +03:00
|
|
|
OSStatus err = ClearCurrentScrap(); // whatever happens we should clear the current scrap.
|
|
|
|
if(err!=noErr) {myScrap=0; return;} // don't get current scrap if a prev err occured.
|
|
|
|
err = GetCurrentScrap( &myScrap );
|
|
|
|
if ( err != noErr ) {
|
2002-03-07 22:22:58 +03:00
|
|
|
myScrap = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Previous version changed \n to \r before sending the text, but I would
|
|
|
|
// prefer to leave the local buffer alone, so a copied buffer may be
|
|
|
|
// needed. Check to see if this is necessary on OS/X.
|
|
|
|
PutScrapFlavor( myScrap, kScrapFlavorTypeText, 0,
|
|
|
|
len, fl_selection_buffer[1] );
|
2008-12-21 03:44:55 +03:00
|
|
|
#endif
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call this when a "paste" operation happens:
|
|
|
|
void Fl::paste(Fl_Widget &receiver, int clipboard) {
|
2009-01-14 17:49:17 +03:00
|
|
|
if (clipboard) {
|
|
|
|
// see if we own the selection, if not go get it:
|
|
|
|
fl_selection_length[1] = 0;
|
2008-12-21 03:44:55 +03:00
|
|
|
#ifdef USE_PASTEBOARD
|
2009-01-14 17:49:17 +03:00
|
|
|
OSStatus err = noErr;
|
2009-01-17 12:18:46 +03:00
|
|
|
Boolean found = false;
|
|
|
|
CFDataRef flavorData = NULL;
|
|
|
|
CFStringEncoding encoding = 0;
|
2009-01-14 17:49:17 +03:00
|
|
|
|
|
|
|
allocatePasteboard();
|
|
|
|
PasteboardSynchronize(myPasteboard);
|
|
|
|
ItemCount nFlavor = 0, i, j;
|
|
|
|
err = PasteboardGetItemCount(myPasteboard, &nFlavor);
|
|
|
|
if (err==noErr) {
|
|
|
|
for (i=1; i<=nFlavor; i++) {
|
2009-01-17 12:18:46 +03:00
|
|
|
PasteboardItemID itemID = 0;
|
|
|
|
CFArrayRef flavorTypeArray = NULL;
|
2009-01-14 17:49:17 +03:00
|
|
|
found = false;
|
|
|
|
err = PasteboardGetItemIdentifier(myPasteboard, i, &itemID);
|
|
|
|
if (err!=noErr) continue;
|
|
|
|
err = PasteboardCopyItemFlavors(myPasteboard, itemID, &flavorTypeArray);
|
2009-01-16 17:39:41 +03:00
|
|
|
if (err!=noErr) {
|
2009-01-27 16:38:23 +03:00
|
|
|
if (flavorTypeArray) {CFRelease(flavorTypeArray); flavorTypeArray = NULL;}
|
2009-01-16 17:39:41 +03:00
|
|
|
continue;
|
|
|
|
}
|
2009-01-17 12:18:46 +03:00
|
|
|
CFIndex flavorCount = CFArrayGetCount(flavorTypeArray);
|
2009-01-16 17:39:41 +03:00
|
|
|
for (j = 0; j < handledFlavorsCount; j++) {
|
2009-01-14 17:49:17 +03:00
|
|
|
for (CFIndex flavorIndex=0; flavorIndex<flavorCount; flavorIndex++) {
|
2009-01-17 12:18:46 +03:00
|
|
|
CFStringRef flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex);
|
2009-01-14 17:49:17 +03:00
|
|
|
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;
|
|
|
|
}
|
2009-01-27 16:38:23 +03:00
|
|
|
if (flavorTypeArray) {CFRelease(flavorTypeArray); flavorTypeArray = NULL;}
|
2009-01-16 17:39:41 +03:00
|
|
|
if (found) break;
|
2009-01-14 17:49:17 +03:00
|
|
|
}
|
|
|
|
if(found) {
|
2009-01-17 12:18:46 +03:00
|
|
|
CFIndex len = CFDataGetLength(flavorData);
|
|
|
|
CFStringRef mycfs = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(flavorData), len, encoding, false);
|
2009-01-27 16:38:23 +03:00
|
|
|
CFRelease(flavorData);
|
2009-01-14 17:49:17 +03:00
|
|
|
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);
|
2009-01-27 16:38:23 +03:00
|
|
|
CFRelease(mycfs);
|
2009-01-14 17:49:17 +03:00
|
|
|
len = strlen(fl_selection_buffer[1]);
|
|
|
|
fl_selection_length[1] = len;
|
|
|
|
convert_crlf(fl_selection_buffer[1],len); // turn all \r characters into \n:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
ScrapRef scrap = 0;
|
|
|
|
if (GetCurrentScrap(&scrap) == noErr && scrap != myScrap &&
|
|
|
|
GetScrapFlavorSize(scrap, kScrapFlavorTypeText, &len) == noErr) {
|
2009-01-12 19:45:55 +03:00
|
|
|
if ( len >= fl_selection_buffer_length[1] ) {
|
2009-01-14 17:49:17 +03:00
|
|
|
fl_selection_buffer_length[1] = len + 32;
|
|
|
|
delete[] fl_selection_buffer[1];
|
|
|
|
fl_selection_buffer[1] = new char[len + 32];
|
2009-01-12 19:45:55 +03:00
|
|
|
}
|
|
|
|
fl_selection_length[1] = len; len++;
|
|
|
|
GetScrapFlavorData( scrap, kScrapFlavorTypeText, &len,
|
2009-01-14 17:49:17 +03:00
|
|
|
fl_selection_buffer[1] );
|
2009-01-12 19:45:55 +03:00
|
|
|
fl_selection_buffer[1][fl_selection_length[1]] = 0;
|
2009-01-14 17:49:17 +03:00
|
|
|
convert_crlf(fl_selection_buffer[1],len);
|
2009-01-12 19:45:55 +03:00
|
|
|
}
|
2008-12-21 03:44:55 +03:00
|
|
|
#endif
|
2009-01-14 17:49:17 +03:00
|
|
|
}
|
|
|
|
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);
|
2002-03-07 22:22:58 +03:00
|
|
|
}
|
|
|
|
|
2006-01-02 13:31:59 +03:00
|
|
|
void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
|
|
|
|
{
|
2006-04-20 07:02:37 +04:00
|
|
|
// 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:
|
2006-01-02 13:31:59 +03:00
|
|
|
int timer_id = -1;
|
2006-04-20 07:02:37 +04:00
|
|
|
// find an empty slot in the timer array
|
2006-01-02 13:31:59 +03:00
|
|
|
for (int i = 0; i < mac_timer_used; ++i) {
|
|
|
|
if ( !mac_timers[i].timer ) {
|
|
|
|
timer_id = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-04-20 07:02:37 +04:00
|
|
|
// if there was no empty slot, append a new timer
|
2006-01-02 13:31:59 +03:00
|
|
|
if (timer_id == -1) {
|
2006-04-20 07:02:37 +04:00
|
|
|
// make space if needed
|
2006-01-02 13:31:59 +03:00
|
|
|
if (mac_timer_used == mac_timer_alloc) {
|
|
|
|
realloc_timers();
|
|
|
|
}
|
|
|
|
timer_id = mac_timer_used++;
|
|
|
|
}
|
2006-04-20 07:02:37 +04:00
|
|
|
// now install a brand new timer
|
|
|
|
MacTimeout& t = mac_timers[timer_id];
|
|
|
|
EventTimerInterval fireDelay = (EventTimerInterval)time;
|
2006-01-02 13:31:59 +03:00
|
|
|
EventLoopTimerUPP timerUPP = NewEventLoopTimerUPP(do_timer);
|
2006-04-20 07:02:37 +04:00
|
|
|
EventLoopTimerRef timerRef = 0;
|
2006-01-02 13:31:59 +03:00
|
|
|
OSStatus err = InstallEventLoopTimer(GetMainEventLoop(), fireDelay, 0, timerUPP, data, &timerRef);
|
|
|
|
if (err == noErr) {
|
2006-04-20 07:02:37 +04:00
|
|
|
t.callback = cb;
|
|
|
|
t.data = data;
|
|
|
|
t.timer = timerRef;
|
|
|
|
t.upp = timerUPP;
|
|
|
|
t.pending = 1;
|
|
|
|
} else {
|
|
|
|
if (timerRef)
|
|
|
|
RemoveEventLoopTimer(timerRef);
|
|
|
|
if (timerUPP)
|
|
|
|
DisposeEventLoopTimerUPP(timerUPP);
|
2006-01-02 13:31:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data)
|
|
|
|
{
|
2006-04-20 07:02:37 +04:00
|
|
|
// currently, repeat_timeout does not subtract the trigger time of the previous timer event as it should.
|
2006-01-02 13:31:59 +03:00
|
|
|
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];
|
2006-04-20 07:02:37 +04:00
|
|
|
if (t.callback == cb && t.data == data && t.pending) {
|
2006-01-02 13:31:59 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-29 15:03:05 +04:00
|
|
|
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, WindowPtr p) {
|
|
|
|
MacUnmapWindow(w, p);
|
|
|
|
if (w && !w->parent() && p)
|
|
|
|
DisposeWindow(p);
|
|
|
|
}
|
2006-01-02 13:31:59 +03:00
|
|
|
|
2006-08-29 15:03:05 +04:00
|
|
|
void MacMapWindow(Fl_Window *w, WindowPtr p) {
|
|
|
|
if (w && p)
|
|
|
|
ShowWindow(p);
|
|
|
|
//+ 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, WindowPtr p) {
|
|
|
|
if (w && !w->parent() && p)
|
|
|
|
HideWindow(p);
|
|
|
|
if (w && Fl_X::i(w))
|
|
|
|
MacUnlinkWindow(Fl_X::i(w));
|
|
|
|
}
|
2008-09-18 23:09:34 +04:00
|
|
|
#endif // FL_DOXYGEN
|
2002-03-07 22:22:58 +03:00
|
|
|
|
2001-11-27 20:44:08 +03:00
|
|
|
//
|
2005-02-25 00:55:12 +03:00
|
|
|
// End of "$Id$".
|
2001-11-27 20:44:08 +03:00
|
|
|
//
|