Use +(void)initialize method of the NSObject class.

Create classes FLWindowDelegateBefore10_6 and FLViewBefore10_6 to support text input before Mac OS 10.6

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10435 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2014-11-06 15:35:32 +00:00
parent 4c811151c0
commit f5e023f9c8

View File

@ -106,7 +106,6 @@ bool fl_show_iconic; // true if called from iconize() - shows
Window fl_window; Window fl_window;
Fl_Window *Fl_Window::current_; Fl_Window *Fl_Window::current_;
int fl_mac_os_version = calc_mac_os_version(); // the version number of the running Mac OS X (e.g., 100604 for 10.6.4) int fl_mac_os_version = calc_mac_os_version(); // the version number of the running Mac OS X (e.g., 100604 for 10.6.4)
static SEL inputContextSEL = (fl_mac_os_version >= 100600 ? @selector(inputContext) : @selector(FLinputContext));
Fl_Fontdesc* fl_fonts = Fl_X::calc_fl_fonts(); Fl_Fontdesc* fl_fonts = Fl_X::calc_fl_fonts();
static NSString *utf8_format = calc_utf8_format(); static NSString *utf8_format = calc_utf8_format();
@ -389,15 +388,14 @@ void* DataReady::DataReadyThread(void *o)
if (FD_ISSET(cancelpipe, &r) || FD_ISSET(cancelpipe, &x)) // cancel? if (FD_ISSET(cancelpipe, &r) || FD_ISSET(cancelpipe, &x)) // cancel?
{ return(NULL); } // just exit { return(NULL); } // just exit
DEBUGMSG("CHILD THREAD: DATA IS READY\n"); DEBUGMSG("CHILD THREAD: DATA IS READY\n");
NSPoint pt={0,0}; NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];
NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:pt location:NSMakePoint(0,0)
modifierFlags:0 modifierFlags:0
timestamp:0 timestamp:0
windowNumber:0 context:NULL windowNumber:0 context:NULL subtype:FLTKDataReadyEvent data1:0 data2:0];
subtype:FLTKDataReadyEvent data1:0 data2:0];
[NSApp postEvent:event atStart:NO]; [NSApp postEvent:event atStart:NO];
[localPool release]; [localPool release];
return(NULL); // done with thread return(NULL); // done with thread
} }
} }
@ -495,12 +493,9 @@ static void processFLTKEvent(void) {
*/ */
static void breakMacEventLoop() static void breakMacEventLoop()
{ {
NSPoint pt={0,0}; NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0,0)
NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:pt modifierFlags:0 timestamp:0
modifierFlags:0 windowNumber:0 context:NULL subtype:FLTKTimerEvent data1:0 data2:0];
timestamp:0
windowNumber:0 context:NULL
subtype:FLTKTimerEvent data1:0 data2:0];
[NSApp postEvent:event atStart:NO]; [NSApp postEvent:event atStart:NO];
} }
@ -1070,11 +1065,21 @@ static void cocoaMouseHandler(NSEvent *theEvent)
{ {
BOOL isActive; BOOL isActive;
} }
+ (void)initialize;
+ (FLTextView*)singleInstance;
- (void)insertText:(id)aString; - (void)insertText:(id)aString;
- (void)doCommandBySelector:(SEL)aSelector; - (void)doCommandBySelector:(SEL)aSelector;
- (void)setActive:(BOOL)a; - (void)setActive:(BOOL)a;
@end @end
static FLTextView *fltextview_instance = nil;
@implementation FLTextView @implementation FLTextView
+ (void)initialize {
NSRect rect={{0,0},{20,20}};
fltextview_instance = [[FLTextView alloc] initWithFrame:rect];
}
+ (FLTextView*)singleInstance {
return fltextview_instance;
}
- (void)insertText:(id)aString - (void)insertText:(id)aString
{ {
if (isActive) [[[NSApp keyWindow] contentView] insertText:aString]; if (isActive) [[[NSApp keyWindow] contentView] insertText:aString];
@ -1094,7 +1099,8 @@ static void cocoaMouseHandler(NSEvent *theEvent)
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
<NSWindowDelegate> <NSWindowDelegate>
#endif #endif
+ (FLWindowDelegate*)createOnce; + (void)initialize;
+ (FLWindowDelegate*)singleInstance;
- (void)windowDidMove:(NSNotification *)notif; - (void)windowDidMove:(NSNotification *)notif;
- (void)windowDidResize:(NSNotification *)notif; - (void)windowDidResize:(NSNotification *)notif;
- (void)windowDidResignKey:(NSNotification *)notif; - (void)windowDidResignKey:(NSNotification *)notif;
@ -1103,17 +1109,31 @@ static void cocoaMouseHandler(NSEvent *theEvent)
- (void)windowDidDeminiaturize:(NSNotification *)notif; - (void)windowDidDeminiaturize:(NSNotification *)notif;
- (void)windowDidMiniaturize:(NSNotification *)notif; - (void)windowDidMiniaturize:(NSNotification *)notif;
- (BOOL)windowShouldClose:(id)fl; - (BOOL)windowShouldClose:(id)fl;
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client;
- (void)anyWindowWillClose:(NSNotification *)notif; - (void)anyWindowWillClose:(NSNotification *)notif;
@end @end
@implementation FLWindowDelegate
+ (FLWindowDelegate*)createOnce @interface FLWindowDelegateBefore10_6 : FLWindowDelegate
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client;
@end
@implementation FLWindowDelegateBefore10_6
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client
{ {
static FLWindowDelegate* delegate = nil; return [FLTextView singleInstance];
if (!delegate) { }
delegate = [[FLWindowDelegate alloc] init]; @end
}
return delegate; static FLWindowDelegate *flwindowdelegate_instance = nil;
@implementation FLWindowDelegate
+ (void)initialize
{
if (self == [FLWindowDelegate self]) {
if (fl_mac_os_version < 100600) flwindowdelegate_instance = [FLWindowDelegateBefore10_6 alloc];
else flwindowdelegate_instance = [FLWindowDelegate alloc];
flwindowdelegate_instance = [flwindowdelegate_instance init];
}
}
+ (FLWindowDelegate*)singleInstance {
return flwindowdelegate_instance;
} }
- (void)windowDidMove:(NSNotification *)notif - (void)windowDidMove:(NSNotification *)notif
{ {
@ -1211,18 +1231,6 @@ static void cocoaMouseHandler(NSEvent *theEvent)
// the system doesn't need to send [fl close] because FLTK does it when needed // the system doesn't need to send [fl close] because FLTK does it when needed
return NO; return NO;
} }
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client
{
if (fl_mac_os_version < 100600) {
static FLTextView *view = nil;
if (!view) {
NSRect rect={{0,0},{20,20}};
view = [[FLTextView alloc] initWithFrame:rect];
}
return view;
}
return nil;
}
- (void)anyWindowWillClose:(NSNotification *)notif - (void)anyWindowWillClose:(NSNotification *)notif
{ {
fl_lock_function(); fl_lock_function();
@ -1381,11 +1389,10 @@ static void cocoaMouseHandler(NSEvent *theEvent)
- (void)applicationWillUnhide:(NSNotification *)notify - (void)applicationWillUnhide:(NSNotification *)notify
{ {
fl_lock_function(); fl_lock_function();
Fl_X *x; for (Fl_X *x = Fl_X::first;x;x = x->next) {
for (x = Fl_X::first;x;x = x->next) {
Fl_Window *w = x->w; Fl_Window *w = x->w;
if ( !w->parent() && ![x->xid isMiniaturized]) { if ( !w->parent() && ![x->xid isMiniaturized]) {
Fl::handle( FL_SHOW, w); Fl::handle(FL_SHOW, w);
} }
} }
fl_unlock_function(); fl_unlock_function();
@ -1528,7 +1535,7 @@ void fl_open_display() {
} }
if (![NSApp servicesMenu]) createAppleMenu(); if (![NSApp servicesMenu]) createAppleMenu();
main_screen_height = [[[NSScreen screens] objectAtIndex:0] frame].size.height; main_screen_height = [[[NSScreen screens] objectAtIndex:0] frame].size.height;
[[NSNotificationCenter defaultCenter] addObserver:[FLWindowDelegate createOnce] [[NSNotificationCenter defaultCenter] addObserver:[FLWindowDelegate singleInstance]
selector:@selector(anyWindowWillClose:) selector:@selector(anyWindowWillClose:)
name:NSWindowWillCloseNotification name:NSWindowWillCloseNotification
object:nil]; object:nil];
@ -1847,12 +1854,14 @@ static void q_set_window_title(NSWindow *nsw, const char * name, const char *mi
that implements the NSTextInputClient protocol to properly handle text input. It also implements the old NSTextInput that implements the NSTextInputClient protocol to properly handle text input. It also implements the old NSTextInput
protocol to run with OS <= 10.4. The few NSTextInput protocol methods that differ in signature from the NSTextInputClient protocol to run with OS <= 10.4. The few NSTextInput protocol methods that differ in signature from the NSTextInputClient
protocol transmit the received message to the corresponding NSTextInputClient method. protocol transmit the received message to the corresponding NSTextInputClient method.
If OS < 10.6, the FLView class is replaced by the FLViewBefore10_6 class that re-implements its fl_handle_keydown_event method.
Keyboard input sends keyDown: and performKeyEquivalent: messages to myview. The latter occurs for keys such as Keyboard input sends keyDown: and performKeyEquivalent: messages to myview. The latter occurs for keys such as
ForwardDelete, arrows and F1, and when the Ctrl or Cmd modifiers are used. Other key presses send keyDown: messages. ForwardDelete, arrows and F1, and when the Ctrl or Cmd modifiers are used. Other key presses send keyDown: messages.
The keyDown: method calls [[myview inputContext] handleEvent:theEvent] that triggers system The keyDown: method calls [myview fl_handle_keydown_event:theEvent] (equivalent to [[myview inputContext] handleEvent:theEvent])
processing of keyboard events. The performKeyEquivalent: method directly calls Fl::handle(FL_KEYBOARD, focus-window) that triggers system processing of keyboard events.
when the Ctrl or Cmd modifiers are used. If not, it also calls [[myview inputContext] handleEvent:theEvent]. The performKeyEquivalent: method directly calls Fl::handle(FL_KEYBOARD, focus-window)
when the Ctrl or Cmd modifiers are used. If not, it also calls [myview fl_handle_keydown_event:theEvent].
The performKeyEquivalent: method returns YES when the keystroke has been handled and NO otherwise, which allows The performKeyEquivalent: method returns YES when the keystroke has been handled and NO otherwise, which allows
shortcuts of the system menu to be processed. Three sorts of messages are then sent back by the system to myview: shortcuts of the system menu to be processed. Three sorts of messages are then sent back by the system to myview:
doCommandBySelector:, setMarkedText: and insertText:. All 3 messages eventually produce Fl::handle(FL_KEYBOARD, win) calls. doCommandBySelector:, setMarkedText: and insertText:. All 3 messages eventually produce Fl::handle(FL_KEYBOARD, win) calls.
@ -1884,16 +1893,12 @@ static void q_set_window_title(NSWindow *nsw, const char * name, const char *mi
selectedRange = NSMakeRange(100, 0); to indicate no text is selected. The setMarkedText: method does selectedRange = NSMakeRange(100, 0); to indicate no text is selected. The setMarkedText: method does
selectedRange = NSMakeRange(100, newSelection.length); to indicate that this length of text is selected. selectedRange = NSMakeRange(100, newSelection.length); to indicate that this length of text is selected.
With OS <= 10.5, the crucial call [[myview inputContext] handleEvent:theEvent] is not possible because neither the With OS <= 10.5, the fl_handle_keydown_event: method is implemented differently because neither the
inputContext nor the handleEvent: methods are implemented. This call is re-written: inputContext nor the handleEvent: methods are available. It is re-implemented
static SEL inputContextSEL = (fl_mac_os_version >= 100600 ? @selector(inputContext) : @selector(FLinputContext)); by the FLViewBefore10_6 class as [[FLTextInputContext singleInstance] handleEvent:event].
[[myview performSelector:inputContextSEL] handleEvent:theEvent]; Method +[FLTextInputContext singleInstance] returns an instance of class FLTextInputContext that possesses
that replaces the 10.6 inputContext message by the FLinputContext message. This message and two FLTK-defined classes, a handleEvent: method. The class FLTextView implements the so-called view's "field editor". This editor is an instance
FLTextInputContext and FLTextView, are used to emulate with OS <= 10.5 what's possible with OS >= 10.6. of the FLTextView class allocated by the -(id)[FLWindowDelegate windowWillReturnFieldEditor: toObject:] method.
Method -(FLTextInputContext*)[FLView FLinputContext] returns an instance of class FLTextInputContext that possesses
a handleEvent: method. FLView's FLinputContext method also calls [[self window] fieldEditor:YES forObject:nil] which
returns the so-called view's "field editor". This editor is an instance of the FLTextView class allocated by the
-(id)[FLWindowDelegate windowWillReturnFieldEditor: toObject:] method.
The -(BOOL)[FLTextInputContext handleEvent:] method emulates the missing 10.6 -(BOOL)[NSTextInputContext handleEvent:] The -(BOOL)[FLTextInputContext handleEvent:] method emulates the missing 10.6 -(BOOL)[NSTextInputContext handleEvent:]
by sending the interpretKeyEvents: message to the FLTextView object. The system sends back doCommandBySelector: and by sending the interpretKeyEvents: message to the FLTextView object. The system sends back doCommandBySelector: and
insertText: messages to the FLTextView object that are transmitted unchanged to myview to be processed as with OS >= 10.6. insertText: messages to the FLTextView object that are transmitted unchanged to myview to be processed as with OS >= 10.6.
@ -1946,17 +1951,24 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
Fl::e_text = (char*)""; Fl::e_text = (char*)"";
} }
@interface FLTextInputContext : NSObject { // "emulates" NSTextInputContext before OS 10.6 @interface FLTextInputContext : NSObject // "emulates" NSTextInputContext before OS 10.6
@public + (void)initialize;
FLTextView *edit; + (FLTextInputContext*)singleInstance;
}
-(BOOL)handleEvent:(NSEvent*)theEvent; -(BOOL)handleEvent:(NSEvent*)theEvent;
@end @end
static FLTextInputContext* fltextinputcontext_instance = nil;
@implementation FLTextInputContext @implementation FLTextInputContext
+ (void)initialize {
fltextinputcontext_instance = [[FLTextInputContext alloc] init];
}
+ (FLTextInputContext*)singleInstance {
return fltextinputcontext_instance;
}
-(BOOL)handleEvent:(NSEvent*)theEvent { -(BOOL)handleEvent:(NSEvent*)theEvent {
[self->edit setActive:YES]; FLTextView *edit = [FLTextView singleInstance];
[self->edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; [edit setActive:YES];
[self->edit setActive:YES]; [edit interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
[edit setActive:YES];
return YES; return YES;
} }
@end @end
@ -1998,7 +2010,7 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender; - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
- (void)draggingExited:(id < NSDraggingInfo >)sender; - (void)draggingExited:(id < NSDraggingInfo >)sender;
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal; - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;
- (FLTextInputContext*)FLinputContext; - (BOOL)fl_handle_keydown_event:(NSEvent*)event;
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange; - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange;
- (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection replacementRange:(NSRange)replacementRange; - (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection replacementRange:(NSRange)replacementRange;
@ -2054,7 +2066,7 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
else { else {
in_key_event = YES; in_key_event = YES;
need_handle = NO; need_handle = NO;
handled = [[self performSelector:inputContextSEL] handleEvent:theEvent]; handled = [self fl_handle_keydown_event:theEvent];
if (need_handle) handled = Fl::handle(FL_KEYBOARD, [(FLWindow*)[theEvent window] getFl_Window]); if (need_handle) handled = Fl::handle(FL_KEYBOARD, [(FLWindow*)[theEvent window] getFl_Window]);
in_key_event = NO; in_key_event = NO;
} }
@ -2119,7 +2131,7 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
cocoaKeyboardHandler(theEvent); cocoaKeyboardHandler(theEvent);
in_key_event = YES; in_key_event = YES;
need_handle = NO; need_handle = NO;
[[self performSelector:inputContextSEL] handleEvent:theEvent]; [self fl_handle_keydown_event:theEvent];
if (need_handle) Fl::handle(FL_KEYBOARD, window); if (need_handle) Fl::handle(FL_KEYBOARD, window);
in_key_event = NO; in_key_event = NO;
fl_unlock_function(); fl_unlock_function();
@ -2248,13 +2260,8 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
return NSDragOperationGeneric; return NSDragOperationGeneric;
} }
- (FLTextInputContext*)FLinputContext { // used only if OS < 10.6 to replace [NSView inputContext] - (BOOL)fl_handle_keydown_event:(NSEvent*)event { // used if OS ≥ 10.6
static FLTextInputContext *context = NULL; return [[self performSelector:@selector(inputContext)] handleEvent:event];
if (!context) {
context = [[FLTextInputContext alloc] init];
}
context->edit = (FLTextView*)[[self window] fieldEditor:YES forObject:nil];
return context;
} }
+ (void)prepareEtext:(NSString*)aString { + (void)prepareEtext:(NSString*)aString {
@ -2339,7 +2346,6 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
// for some reason, with the palette, the window does not redraw until the next mouse move or button push // for some reason, with the palette, the window does not redraw until the next mouse move or button push
// sending a 'redraw()' or 'awake()' does not solve the issue! // sending a 'redraw()' or 'awake()' does not solve the issue!
if (palette) Fl::flush(); if (palette) Fl::flush();
if (fl_mac_os_version < 100600) [(FLTextView*)[[self window] fieldEditor:YES forObject:nil] setActive:NO];
fl_unlock_function(); fl_unlock_function();
} }
@ -2472,6 +2478,24 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
@end @end
@interface FLViewBefore10_6 : FLView
- (BOOL)fl_handle_keydown_event:(NSEvent*)event;
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange;
@end
@implementation FLViewBefore10_6
- (BOOL)fl_handle_keydown_event:(NSEvent*)event
{
return [[FLTextInputContext singleInstance] handleEvent:event];
}
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
[super insertText:aString replacementRange:replacementRange];
[[FLTextView singleInstance] setActive:NO];
}
@end
static Class FLViewThisOS = (fl_mac_os_version >= 100600 ? [FLView class] : [FLViewBefore10_6 class]);
void Fl_Window::fullscreen_x() { void Fl_Window::fullscreen_x() {
_set_fullscreen(); _set_fullscreen();
/* On OS X < 10.6, it is necessary to recreate the window. This is done /* On OS X < 10.6, it is necessary to recreate the window. This is done
@ -2676,7 +2700,7 @@ void Fl_X::make(Fl_Window* w)
x->wait_for_expose = 1; x->wait_for_expose = 1;
x->next = Fl_X::first; x->next = Fl_X::first;
Fl_X::first = x; Fl_X::first = x;
FLView *myview = [[FLView alloc] init]; FLView *myview = [[FLViewThisOS alloc] init];
[cw setContentView:myview]; [cw setContentView:myview];
[myview release]; [myview release];
[cw setLevel:winlevel]; [cw setLevel:winlevel];
@ -2713,7 +2737,7 @@ void Fl_X::make(Fl_Window* w)
w->set_visible(); w->set_visible();
if ( w->border() || (!w->modal() && !w->tooltip_window()) ) Fl::handle(FL_FOCUS, w); if ( w->border() || (!w->modal() && !w->tooltip_window()) ) Fl::handle(FL_FOCUS, w);
Fl::first_window(w); Fl::first_window(w);
[cw setDelegate:[FLWindowDelegate createOnce]]; [cw setDelegate:[FLWindowDelegate singleInstance]];
if (fl_show_iconic) { if (fl_show_iconic) {
fl_show_iconic = 0; fl_show_iconic = 0;
[cw miniaturize:nil]; [cw miniaturize:nil];
@ -2803,11 +2827,11 @@ void Fl_Window::show() {
} else { } else {
if ( !parent() ) { if ( !parent() ) {
if ([i->xid isMiniaturized]) { if ([i->xid isMiniaturized]) {
i->w->redraw(); i->w->redraw();
[i->xid deminiaturize:nil]; [i->xid deminiaturize:nil];
} }
if (!fl_capture) { if (!fl_capture) {
[i->xid makeKeyAndOrderFront:nil]; [i->xid makeKeyAndOrderFront:nil];
} }
} }
} }
@ -3970,7 +3994,7 @@ void Fl_Paged_Device::print_window(Fl_Window *win, int x_offset, int y_offset)
} }
fl_gc = NULL; fl_gc = NULL;
Fl::check(); Fl::check();
BOOL to_quartz = dynamic_cast<Fl_Printer*>(this) != NULL; BOOL to_quartz = dynamic_cast<Fl_Quartz_Graphics_Driver*>(this->driver()) != NULL;
// capture the window title bar with no title // capture the window title bar with no title
CGImageRef img = NULL; CGImageRef img = NULL;
unsigned char *bitmap = NULL; unsigned char *bitmap = NULL;