reworking event handling to redirect to c++ virtual functions
[wxWidgets.git] / src / osx / carbon / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/window.cpp
3 // Purpose: wxWindowMac
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/window.h"
15
16 #ifndef WX_PRECOMP
17 #include "wx/log.h"
18 #include "wx/app.h"
19 #include "wx/utils.h"
20 #include "wx/panel.h"
21 #include "wx/frame.h"
22 #include "wx/dc.h"
23 #include "wx/dcclient.h"
24 #include "wx/button.h"
25 #include "wx/menu.h"
26 #include "wx/dialog.h"
27 #include "wx/settings.h"
28 #include "wx/msgdlg.h"
29 #include "wx/scrolbar.h"
30 #include "wx/statbox.h"
31 #include "wx/textctrl.h"
32 #include "wx/toolbar.h"
33 #include "wx/layout.h"
34 #include "wx/statusbr.h"
35 #include "wx/menuitem.h"
36 #include "wx/treectrl.h"
37 #include "wx/listctrl.h"
38 #endif
39
40 #include "wx/tooltip.h"
41 #include "wx/spinctrl.h"
42 #include "wx/geometry.h"
43
44 #if wxUSE_LISTCTRL
45 #include "wx/listctrl.h"
46 #endif
47
48 #if wxUSE_TREECTRL
49 #include "wx/treectrl.h"
50 #endif
51
52 #if wxUSE_CARET
53 #include "wx/caret.h"
54 #endif
55
56 #if wxUSE_POPUPWIN
57 #include "wx/popupwin.h"
58 #endif
59
60 #if wxUSE_DRAG_AND_DROP
61 #include "wx/dnd.h"
62 #endif
63
64 #if wxOSX_USE_CARBON
65 #include "wx/osx/uma.h"
66 #else
67 #include "wx/osx/private.h"
68 // bring in themeing
69 #include <Carbon/Carbon.h>
70 #endif
71
72 #define MAC_SCROLLBAR_SIZE 15
73 #define MAC_SMALL_SCROLLBAR_SIZE 11
74
75 #include <string.h>
76
77 #define wxMAC_DEBUG_REDRAW 0
78 #ifndef wxMAC_DEBUG_REDRAW
79 #define wxMAC_DEBUG_REDRAW 0
80 #endif
81
82 // ---------------------------------------------------------------------------
83 // Carbon Events
84 // ---------------------------------------------------------------------------
85
86 static const EventTypeSpec eventList[] =
87 {
88 { kEventClassCommand, kEventProcessCommand } ,
89 { kEventClassCommand, kEventCommandUpdateStatus } ,
90
91 { kEventClassControl , kEventControlGetClickActivation } ,
92 { kEventClassControl , kEventControlHit } ,
93
94 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,
95 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea } ,
96
97 { kEventClassControl , kEventControlDraw } ,
98
99 { kEventClassControl , kEventControlVisibilityChanged } ,
100 { kEventClassControl , kEventControlEnabledStateChanged } ,
101 { kEventClassControl , kEventControlHiliteChanged } ,
102
103 { kEventClassControl , kEventControlActivate } ,
104 { kEventClassControl , kEventControlDeactivate } ,
105
106 { kEventClassControl , kEventControlSetFocusPart } ,
107 { kEventClassControl , kEventControlFocusPartChanged } ,
108
109 { kEventClassService , kEventServiceGetTypes },
110 { kEventClassService , kEventServiceCopy },
111 { kEventClassService , kEventServicePaste },
112
113 // { kEventClassControl , kEventControlInvalidateForSizeChange } , // 10.3 only
114 // { kEventClassControl , kEventControlBoundsChanged } ,
115 } ;
116
117 static pascal OSStatus wxMacWindowControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
118 {
119 OSStatus result = eventNotHandledErr ;
120 static wxWindowMac* targetFocusWindow = NULL;
121 static wxWindowMac* formerFocusWindow = NULL;
122
123 wxMacCarbonEvent cEvent( event ) ;
124
125 ControlRef controlRef ;
126 wxWindowMac* thisWindow = (wxWindowMac*) data ;
127
128 cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
129
130 switch ( GetEventKind( event ) )
131 {
132 case kEventControlDraw :
133 {
134 RgnHandle updateRgn = NULL ;
135 RgnHandle allocatedRgn = NULL ;
136 wxRegion visRegion = thisWindow->MacGetVisibleRegion() ;
137
138 if ( cEvent.GetParameter<RgnHandle>(kEventParamRgnHandle, &updateRgn) != noErr )
139 {
140 HIShapeGetAsQDRgn( visRegion.GetWXHRGN(), updateRgn );
141 }
142 else
143 {
144 if ( thisWindow->MacGetLeftBorderSize() != 0 || thisWindow->MacGetTopBorderSize() != 0 )
145 {
146 // as this update region is in native window locals we must adapt it to wx window local
147 allocatedRgn = NewRgn() ;
148 CopyRgn( updateRgn , allocatedRgn ) ;
149
150 // hide the given region by the new region that must be shifted
151 OffsetRgn( allocatedRgn , thisWindow->MacGetLeftBorderSize() , thisWindow->MacGetTopBorderSize() ) ;
152 updateRgn = allocatedRgn ;
153 }
154 }
155
156 #if wxMAC_DEBUG_REDRAW
157 if ( thisWindow->MacIsUserPane() )
158 {
159 static float color = 0.5 ;
160 static int channel = 0 ;
161 HIRect bounds;
162 CGContextRef cgContext = cEvent.GetParameter<CGContextRef>(kEventParamCGContextRef) ;
163
164 HIViewGetBounds( controlRef, &bounds );
165 CGContextSetRGBFillColor( cgContext, channel == 0 ? color : 0.5 ,
166 channel == 1 ? color : 0.5 , channel == 2 ? color : 0.5 , 1 );
167 CGContextFillRect( cgContext, bounds );
168 color += 0.1 ;
169 if ( color > 0.9 )
170 {
171 color = 0.5 ;
172 channel++ ;
173 if ( channel == 3 )
174 channel = 0 ;
175 }
176 }
177 #endif
178
179 {
180 bool created = false ;
181 CGContextRef cgContext = NULL ;
182 OSStatus err = cEvent.GetParameter<CGContextRef>(kEventParamCGContextRef, &cgContext) ;
183 if ( err != noErr )
184 {
185 wxFAIL_MSG("Unable to retrieve CGContextRef");
186 }
187
188 thisWindow->MacSetCGContextRef( cgContext ) ;
189
190 {
191 wxMacCGContextStateSaver sg( cgContext ) ;
192 CGFloat alpha = (CGFloat)1.0 ;
193 {
194 wxWindow* iter = thisWindow ;
195 while ( iter )
196 {
197 alpha *= (CGFloat)( iter->GetTransparent()/255.0 ) ;
198 if ( iter->IsTopLevel() )
199 iter = NULL ;
200 else
201 iter = iter->GetParent() ;
202 }
203 }
204 CGContextSetAlpha( cgContext , alpha ) ;
205
206 if ( thisWindow->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT )
207 {
208 HIRect bounds;
209 HIViewGetBounds( controlRef, &bounds );
210 CGContextClearRect( cgContext, bounds );
211 }
212
213 if ( thisWindow->MacDoRedraw( updateRgn , cEvent.GetTicks() ) )
214 result = noErr ;
215
216 thisWindow->MacSetCGContextRef( NULL ) ;
217 }
218
219 if ( created )
220 CGContextRelease( cgContext ) ;
221 }
222
223 if ( allocatedRgn )
224 DisposeRgn( allocatedRgn ) ;
225 }
226 break ;
227
228 case kEventControlVisibilityChanged :
229 // we might have two native controls attributed to the same wxWindow instance
230 // eg a scrollview and an embedded textview, make sure we only fire for the 'outer'
231 // control, as otherwise native and wx visibility are different
232 if ( thisWindow->GetPeer() != NULL && thisWindow->GetPeer()->GetControlRef() == controlRef )
233 {
234 thisWindow->MacVisibilityChanged() ;
235 }
236 break ;
237
238 case kEventControlEnabledStateChanged :
239 thisWindow->MacEnabledStateChanged();
240 break ;
241
242 case kEventControlHiliteChanged :
243 thisWindow->MacHiliteChanged() ;
244 break ;
245
246 case kEventControlActivate :
247 case kEventControlDeactivate :
248 // FIXME: we should have a virtual function for this!
249 #if wxUSE_TREECTRL
250 if ( thisWindow->IsKindOf( CLASSINFO( wxTreeCtrl ) ) )
251 thisWindow->Refresh();
252 #endif
253 #if wxUSE_LISTCTRL
254 if ( thisWindow->IsKindOf( CLASSINFO( wxListCtrl ) ) )
255 thisWindow->Refresh();
256 #endif
257 break ;
258
259 //
260 // focus handling
261 // different handling on OS X
262 //
263
264 case kEventControlFocusPartChanged :
265 // the event is emulated by wxmac for systems lower than 10.5
266 {
267 if ( UMAGetSystemVersion() < 0x1050 )
268 {
269 // as it is synthesized here, we have to manually avoid propagation
270 result = noErr;
271 }
272 ControlPartCode previousControlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPreviousPart , typeControlPartCode );
273 ControlPartCode currentControlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlCurrentPart , typeControlPartCode );
274
275 if ( thisWindow->MacGetTopLevelWindow() && thisWindow->GetPeer()->NeedsFocusRect() )
276 {
277 thisWindow->MacInvalidateBorders();
278 }
279
280 if ( currentControlPart == 0 )
281 {
282 // kill focus
283 #if wxUSE_CARET
284 if ( thisWindow->GetCaret() )
285 thisWindow->GetCaret()->OnKillFocus();
286 #endif
287
288 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), static_cast<void*>(thisWindow));
289
290 // remove this as soon as posting the synthesized event works properly
291 static bool inKillFocusEvent = false ;
292
293 if ( !inKillFocusEvent )
294 {
295 inKillFocusEvent = true ;
296 wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId());
297 event.SetEventObject(thisWindow);
298 event.SetWindow(targetFocusWindow);
299 thisWindow->HandleWindowEvent(event) ;
300 inKillFocusEvent = false ;
301 targetFocusWindow = NULL;
302 }
303 }
304 else if ( previousControlPart == 0 )
305 {
306 // set focus
307 // panel wants to track the window which was the last to have focus in it
308 wxLogTrace(_T("Focus"), _T("focus set(%p)"), static_cast<void*>(thisWindow));
309 wxChildFocusEvent eventFocus((wxWindow*)thisWindow);
310 thisWindow->HandleWindowEvent(eventFocus);
311
312 #if wxUSE_CARET
313 if ( thisWindow->GetCaret() )
314 thisWindow->GetCaret()->OnSetFocus();
315 #endif
316
317 wxFocusEvent event(wxEVT_SET_FOCUS, thisWindow->GetId());
318 event.SetEventObject(thisWindow);
319 event.SetWindow(formerFocusWindow);
320 thisWindow->HandleWindowEvent(event) ;
321 formerFocusWindow = NULL;
322 }
323 }
324 break;
325 case kEventControlSetFocusPart :
326 {
327 Boolean focusEverything = false ;
328 if ( cEvent.GetParameter<Boolean>(kEventParamControlFocusEverything , &focusEverything ) == noErr )
329 {
330 // put a breakpoint here to catch focus everything events
331 }
332 ControlPartCode controlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart , typeControlPartCode );
333 if ( controlPart != kControlFocusNoPart )
334 {
335 targetFocusWindow = thisWindow;
336 wxLogTrace(_T("Focus"), _T("focus to be set(%p)"), static_cast<void*>(thisWindow));
337 }
338 else
339 {
340 formerFocusWindow = thisWindow;
341 wxLogTrace(_T("Focus"), _T("focus to be lost(%p)"), static_cast<void*>(thisWindow));
342 }
343
344 ControlPartCode previousControlPart = 0;
345 verify_noerr( HIViewGetFocusPart(controlRef, &previousControlPart));
346
347 if ( thisWindow->MacIsUserPane() )
348 {
349 if ( controlPart != kControlFocusNoPart )
350 cEvent.SetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, 1 ) ;
351 result = noErr ;
352 }
353 else
354 result = CallNextEventHandler(handler, event);
355
356 if ( UMAGetSystemVersion() < 0x1050 )
357 {
358 // set back to 0 if problems arise
359 #if 1
360 if ( result == noErr )
361 {
362 ControlPartCode currentControlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart , typeControlPartCode );
363 // synthesize the event focus changed event
364 EventRef evRef = NULL ;
365
366 OSStatus err = MacCreateEvent(
367 NULL , kEventClassControl , kEventControlFocusPartChanged , TicksToEventTime( TickCount() ) ,
368 kEventAttributeUserEvent , &evRef );
369 verify_noerr( err );
370
371 wxMacCarbonEvent iEvent( evRef ) ;
372 iEvent.SetParameter<ControlRef>( kEventParamDirectObject , controlRef );
373 iEvent.SetParameter<EventTargetRef>( kEventParamPostTarget, typeEventTargetRef, GetControlEventTarget( controlRef ) );
374 iEvent.SetParameter<ControlPartCode>( kEventParamControlPreviousPart, typeControlPartCode, previousControlPart );
375 iEvent.SetParameter<ControlPartCode>( kEventParamControlCurrentPart, typeControlPartCode, currentControlPart );
376
377 #if 1
378 // TODO test this first, avoid double posts etc...
379 PostEventToQueue( GetMainEventQueue(), evRef , kEventPriorityHigh );
380 #else
381 wxMacWindowControlEventHandler( NULL , evRef , data ) ;
382 #endif
383 ReleaseEvent( evRef ) ;
384 }
385 #else
386 // old implementation, to be removed if the new one works
387 if ( controlPart == kControlFocusNoPart )
388 {
389 #if wxUSE_CARET
390 if ( thisWindow->GetCaret() )
391 thisWindow->GetCaret()->OnKillFocus();
392 #endif
393
394 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), static_cast<void*>(thisWindow));
395
396 static bool inKillFocusEvent = false ;
397
398 if ( !inKillFocusEvent )
399 {
400 inKillFocusEvent = true ;
401 wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId());
402 event.SetEventObject(thisWindow);
403 thisWindow->HandleWindowEvent(event) ;
404 inKillFocusEvent = false ;
405 }
406 }
407 else
408 {
409 // panel wants to track the window which was the last to have focus in it
410 wxLogTrace(_T("Focus"), _T("focus set(%p)"), static_cast<void*>(thisWindow));
411 wxChildFocusEvent eventFocus((wxWindow*)thisWindow);
412 thisWindow->HandleWindowEvent(eventFocus);
413
414 #if wxUSE_CARET
415 if ( thisWindow->GetCaret() )
416 thisWindow->GetCaret()->OnSetFocus();
417 #endif
418
419 wxFocusEvent event(wxEVT_SET_FOCUS, thisWindow->GetId());
420 event.SetEventObject(thisWindow);
421 thisWindow->HandleWindowEvent(event) ;
422 }
423 #endif
424 }
425 }
426 break ;
427
428 case kEventControlHit :
429 result = thisWindow->MacControlHit( handler , event ) ;
430 break ;
431
432 case kEventControlGetClickActivation :
433 {
434 // fix to always have a proper activation for DataBrowser controls (stay in bkgnd otherwise)
435 WindowRef owner = cEvent.GetParameter<WindowRef>(kEventParamWindowRef);
436 if ( !IsWindowActive(owner) )
437 {
438 cEvent.SetParameter(kEventParamClickActivation,typeClickActivationResult, (UInt32) kActivateAndIgnoreClick) ;
439 result = noErr ;
440 }
441 }
442 break ;
443
444 default :
445 break ;
446 }
447
448 return result ;
449 }
450
451 static pascal OSStatus
452 wxMacWindowServiceEventHandler(EventHandlerCallRef WXUNUSED(handler),
453 EventRef event,
454 void *data)
455 {
456 OSStatus result = eventNotHandledErr ;
457
458 wxMacCarbonEvent cEvent( event ) ;
459
460 ControlRef controlRef ;
461 wxWindowMac* thisWindow = (wxWindowMac*) data ;
462 wxTextCtrl* textCtrl = wxDynamicCast( thisWindow , wxTextCtrl ) ;
463 cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
464
465 switch ( GetEventKind( event ) )
466 {
467 case kEventServiceGetTypes :
468 if ( textCtrl )
469 {
470 long from, to ;
471 textCtrl->GetSelection( &from , &to ) ;
472
473 CFMutableArrayRef copyTypes = 0 , pasteTypes = 0;
474 if ( from != to )
475 copyTypes = cEvent.GetParameter< CFMutableArrayRef >( kEventParamServiceCopyTypes , typeCFMutableArrayRef ) ;
476 if ( textCtrl->IsEditable() )
477 pasteTypes = cEvent.GetParameter< CFMutableArrayRef >( kEventParamServicePasteTypes , typeCFMutableArrayRef ) ;
478
479 static const OSType textDataTypes[] = { kTXNTextData /* , 'utxt', 'PICT', 'MooV', 'AIFF' */ };
480 for ( size_t i = 0 ; i < WXSIZEOF(textDataTypes) ; ++i )
481 {
482 CFStringRef typestring = CreateTypeStringWithOSType(textDataTypes[i]);
483 if ( typestring )
484 {
485 if ( copyTypes )
486 CFArrayAppendValue(copyTypes, typestring) ;
487 if ( pasteTypes )
488 CFArrayAppendValue(pasteTypes, typestring) ;
489
490 CFRelease( typestring ) ;
491 }
492 }
493
494 result = noErr ;
495 }
496 break ;
497
498 case kEventServiceCopy :
499 if ( textCtrl )
500 {
501 long from, to ;
502
503 textCtrl->GetSelection( &from , &to ) ;
504 wxString val = textCtrl->GetValue() ;
505 val = val.Mid( from , to - from ) ;
506 PasteboardRef pasteboard = cEvent.GetParameter<PasteboardRef>( kEventParamPasteboardRef, typePasteboardRef );
507 verify_noerr( PasteboardClear( pasteboard ) ) ;
508 PasteboardSynchronize( pasteboard );
509 // TODO add proper conversion
510 CFDataRef data = CFDataCreate( kCFAllocatorDefault, (const UInt8*)val.c_str(), val.length() );
511 PasteboardPutItemFlavor( pasteboard, (PasteboardItemID) 1, CFSTR("com.apple.traditional-mac-plain-text"), data, 0);
512 CFRelease( data );
513 result = noErr ;
514 }
515 break ;
516
517 case kEventServicePaste :
518 if ( textCtrl )
519 {
520 PasteboardRef pasteboard = cEvent.GetParameter<PasteboardRef>( kEventParamPasteboardRef, typePasteboardRef );
521 PasteboardSynchronize( pasteboard );
522 ItemCount itemCount;
523 verify_noerr( PasteboardGetItemCount( pasteboard, &itemCount ) );
524 for( UInt32 itemIndex = 1; itemIndex <= itemCount; itemIndex++ )
525 {
526 PasteboardItemID itemID;
527 if ( PasteboardGetItemIdentifier( pasteboard, itemIndex, &itemID ) == noErr )
528 {
529 CFDataRef flavorData = NULL;
530 if ( PasteboardCopyItemFlavorData( pasteboard, itemID, CFSTR("com.apple.traditional-mac-plain-text"), &flavorData ) == noErr )
531 {
532 CFIndex flavorDataSize = CFDataGetLength( flavorData );
533 char *content = new char[flavorDataSize+1] ;
534 memcpy( content, CFDataGetBytePtr( flavorData ), flavorDataSize );
535 content[flavorDataSize]=0;
536 CFRelease( flavorData );
537 #if wxUSE_UNICODE
538 textCtrl->WriteText( wxString( content , wxConvLocal ) );
539 #else
540 textCtrl->WriteText( wxString( content ) ) ;
541 #endif
542
543 delete[] content ;
544 result = noErr ;
545 }
546 }
547 }
548 }
549 break ;
550
551 default:
552 break ;
553 }
554
555 return result ;
556 }
557
558 pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
559 {
560 OSStatus result = eventNotHandledErr ;
561 wxWindowMac* focus = (wxWindowMac*) data ;
562
563 wchar_t* uniChars = NULL ;
564 UInt32 when = EventTimeToTicks( GetEventTime( event ) ) ;
565
566 UniChar* charBuf = NULL;
567 ByteCount dataSize = 0 ;
568 int numChars = 0 ;
569 UniChar buf[2] ;
570 if ( GetEventParameter( event, kEventParamTextInputSendText, typeUnicodeText, NULL, 0 , &dataSize, NULL ) == noErr )
571 {
572 numChars = dataSize / sizeof( UniChar) + 1;
573 charBuf = buf ;
574
575 if ( (size_t) numChars * 2 > sizeof(buf) )
576 charBuf = new UniChar[ numChars ] ;
577 else
578 charBuf = buf ;
579
580 uniChars = new wchar_t[ numChars ] ;
581 GetEventParameter( event, kEventParamTextInputSendText, typeUnicodeText, NULL, dataSize , NULL , charBuf ) ;
582 charBuf[ numChars - 1 ] = 0;
583 #if SIZEOF_WCHAR_T == 2
584 uniChars = (wchar_t*) charBuf ;
585 /* memcpy( uniChars , charBuf , numChars * 2 ) ;*/ // is there any point in copying charBuf over itself? (in fact, memcpy isn't even guaranteed to work correctly if the source and destination ranges overlap...)
586 #else
587 // the resulting string will never have more chars than the utf16 version, so this is safe
588 wxMBConvUTF16 converter ;
589 numChars = converter.MB2WC( uniChars , (const char*)charBuf , numChars ) ;
590 #endif
591 }
592
593 switch ( GetEventKind( event ) )
594 {
595 case kEventTextInputUpdateActiveInputArea :
596 {
597 // An IME input event may return several characters, but we need to send one char at a time to
598 // EVT_CHAR
599 for (int pos=0 ; pos < numChars ; pos++)
600 {
601 WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
602 WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
603 wxTheApp->MacSetCurrentEvent( event , handler ) ;
604
605 UInt32 message = uniChars[pos] < 128 ? (char)uniChars[pos] : '?';
606 /*
607 NB: faking a charcode here is problematic. The kEventTextInputUpdateActiveInputArea event is sent
608 multiple times to update the active range during inline input, so this handler will often receive
609 uncommited text, which should usually not trigger side effects. It might be a good idea to check the
610 kEventParamTextInputSendFixLen parameter and verify if input is being confirmed (see CarbonEvents.h).
611 On the other hand, it can be useful for some applications to react to uncommitted text (for example,
612 to update a status display), as long as it does not disrupt the inline input session. Ideally, wx
613 should add new event types to support advanced text input. For now, I would keep things as they are.
614
615 However, the code that was being used caused additional problems:
616 UInt32 message = (0 << 8) + ((char)uniChars[pos] );
617 Since it simply truncated the unichar to the last byte, it ended up causing weird bugs with inline
618 input, such as switching to another field when one attempted to insert the character U+4E09 (the kanji
619 for "three"), because it was truncated to 09 (kTabCharCode), which was later "converted" to WXK_TAB
620 (still 09) in wxMacTranslateKey; or triggering the default button when one attempted to insert U+840D
621 (the kanji for "name"), which got truncated to 0D and interpreted as a carriage return keypress.
622 Note that even single-byte characters could have been misinterpreted, since MacRoman charcodes only
623 overlap with Unicode within the (7-bit) ASCII range.
624 But simply passing a NUL charcode would disable text updated events, because wxTextCtrl::OnChar checks
625 for codes within a specific range. Therefore I went for the solution seen above, which keeps ASCII
626 characters as they are and replaces the rest with '?', ensuring that update events are triggered.
627 It would be better to change wxTextCtrl::OnChar to look at the actual unicode character instead, but
628 I don't have time to look into that right now.
629 -- CL
630 */
631 if ( wxTheApp->MacSendCharEvent(
632 focus , message , 0 , when , 0 , 0 , uniChars[pos] ) )
633 {
634 result = noErr ;
635 }
636
637 wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
638 }
639 }
640 break ;
641 case kEventTextInputUnicodeForKeyEvent :
642 {
643 UInt32 keyCode, modifiers ;
644 Point point ;
645 EventRef rawEvent ;
646 unsigned char charCode ;
647
648 GetEventParameter( event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(rawEvent), NULL, &rawEvent ) ;
649 GetEventParameter( rawEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &charCode );
650 GetEventParameter( rawEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode );
651 GetEventParameter( rawEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers );
652 GetEventParameter( rawEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &point );
653
654 UInt32 message = (keyCode << 8) + charCode;
655
656 // An IME input event may return several characters, but we need to send one char at a time to
657 // EVT_CHAR
658 for (int pos=0 ; pos < numChars ; pos++)
659 {
660 WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
661 WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
662 wxTheApp->MacSetCurrentEvent( event , handler ) ;
663
664 if ( wxTheApp->MacSendCharEvent(
665 focus , message , modifiers , when , point.h , point.v , uniChars[pos] ) )
666 {
667 result = noErr ;
668 }
669
670 wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
671 }
672 }
673 break;
674 default:
675 break ;
676 }
677
678 delete [] uniChars ;
679 if ( charBuf != buf )
680 delete [] charBuf ;
681
682 return result ;
683 }
684
685 static pascal OSStatus
686 wxMacWindowCommandEventHandler(EventHandlerCallRef WXUNUSED(handler),
687 EventRef event,
688 void *data)
689 {
690 OSStatus result = eventNotHandledErr ;
691 wxWindowMac* focus = (wxWindowMac*) data ;
692
693 HICommand command ;
694
695 wxMacCarbonEvent cEvent( event ) ;
696 cEvent.GetParameter<HICommand>(kEventParamDirectObject,typeHICommand,&command) ;
697
698 wxMenuItem* item = NULL ;
699 wxMenu* itemMenu = wxFindMenuFromMacCommand( command , item ) ;
700
701 if ( item )
702 {
703 wxASSERT( itemMenu != NULL ) ;
704
705 switch ( cEvent.GetKind() )
706 {
707 case kEventProcessCommand :
708 if ( itemMenu->HandleCommandProcess( item, focus ) )
709 result = noErr;
710 break ;
711
712 case kEventCommandUpdateStatus:
713 if ( itemMenu->HandleCommandUpdateStatus( item, focus ) )
714 result = noErr;
715 break ;
716
717 default :
718 break ;
719 }
720 }
721 return result ;
722 }
723
724 pascal OSStatus wxMacWindowEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
725 {
726 EventRef formerEvent = (EventRef) wxTheApp->MacGetCurrentEvent() ;
727 EventHandlerCallRef formerEventHandlerCallRef = (EventHandlerCallRef) wxTheApp->MacGetCurrentEventHandlerCallRef() ;
728 wxTheApp->MacSetCurrentEvent( event , handler ) ;
729 OSStatus result = eventNotHandledErr ;
730
731 switch ( GetEventClass( event ) )
732 {
733 case kEventClassCommand :
734 result = wxMacWindowCommandEventHandler( handler , event , data ) ;
735 break ;
736
737 case kEventClassControl :
738 result = wxMacWindowControlEventHandler( handler, event, data ) ;
739 break ;
740
741 case kEventClassService :
742 result = wxMacWindowServiceEventHandler( handler, event , data ) ;
743 break ;
744
745 case kEventClassTextInput :
746 result = wxMacUnicodeTextEventHandler( handler , event , data ) ;
747 break ;
748
749 default :
750 break ;
751 }
752
753 wxTheApp->MacSetCurrentEvent( formerEvent, formerEventHandlerCallRef ) ;
754
755 return result ;
756 }
757
758 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacWindowEventHandler )
759
760 // ---------------------------------------------------------------------------
761 // Scrollbar Tracking for all
762 // ---------------------------------------------------------------------------
763
764 pascal void wxMacLiveScrollbarActionProc( ControlRef control , ControlPartCode partCode ) ;
765 pascal void wxMacLiveScrollbarActionProc( ControlRef control , ControlPartCode partCode )
766 {
767 if ( partCode != 0)
768 {
769 wxWindow* wx = wxFindWindowFromWXWidget( (WXWidget) control ) ;
770 if ( wx )
771 {
772 wxEventType scrollEvent = wxEVT_NULL;
773 switch ( partCode )
774 {
775 case kControlUpButtonPart:
776 scrollEvent = wxEVT_SCROLL_LINEUP;
777 break;
778
779 case kControlDownButtonPart:
780 scrollEvent = wxEVT_SCROLL_LINEDOWN;
781 break;
782
783 case kControlPageUpPart:
784 scrollEvent = wxEVT_SCROLL_PAGEUP;
785 break;
786
787 case kControlPageDownPart:
788 scrollEvent = wxEVT_SCROLL_PAGEDOWN;
789 break;
790
791 case kControlIndicatorPart:
792 scrollEvent = wxEVT_SCROLL_THUMBTRACK;
793 // when this is called as a live proc, mouse is always still down
794 // so no need for thumbrelease
795 // scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
796 break;
797 }
798 wx->TriggerScrollEvent(scrollEvent) ;
799 }
800 }
801 }
802 wxMAC_DEFINE_PROC_GETTER( ControlActionUPP , wxMacLiveScrollbarActionProc ) ;
803
804 wxWidgetImplType* wxWidgetImpl::CreateUserPane( wxWindowMac* wxpeer, wxWindowMac* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
805 long style, long extraStyle)
806 {
807 OSStatus err = noErr;
808 Rect bounds = wxMacGetBoundsForControl( wxpeer , pos , size ) ;
809 wxMacControl* c = new wxMacControl(wxpeer) ;
810 UInt32 features = 0
811 | kControlSupportsEmbedding
812 | kControlSupportsLiveFeedback
813 | kControlGetsFocusOnClick
814 // | kControlHasSpecialBackground
815 // | kControlSupportsCalcBestRect
816 | kControlHandlesTracking
817 | kControlSupportsFocus
818 | kControlWantsActivate
819 | kControlWantsIdle ;
820
821 err =::CreateUserPaneControl( MAC_WXHWND(wxpeer->GetParent()->MacGetTopLevelWindowRef()) , &bounds, features , c->GetControlRefAddr() );
822 verify_noerr( err );
823 return c;
824 }
825
826
827 void wxMacControl::InstallEventHandler( WXWidget control )
828 {
829 wxWidgetImpl::Associate( control ? control : (WXWidget) m_controlRef , this ) ;
830 ::InstallControlEventHandler( control ? (ControlRef) control : m_controlRef , GetwxMacWindowEventHandlerUPP(),
831 GetEventTypeCount(eventList), eventList, GetWXPeer(), NULL);
832 }
833
834 IMPLEMENT_DYNAMIC_CLASS( wxMacControl , wxWidgetImpl )
835
836 wxMacControl::wxMacControl()
837 {
838 Init();
839 }
840
841 wxMacControl::wxMacControl(wxWindowMac* peer , bool isRootControl ) :
842 wxWidgetImpl( peer, isRootControl )
843 {
844 Init();
845 }
846
847 wxMacControl::~wxMacControl()
848 {
849 if ( m_controlRef && !IsRootControl() )
850 {
851 wxASSERT_MSG( m_controlRef != NULL , wxT("Control Handle already NULL, Dispose called twice ?") );
852 wxASSERT_MSG( IsValidControlHandle(m_controlRef) , wxT("Invalid Control Handle (maybe already released) in Dispose") );
853
854 wxWidgetImpl::RemoveAssociations( this ) ;
855 // we cannot check the ref count here anymore, as autorelease objects might delete their refs later
856 // we can have situations when being embedded, where the control gets deleted behind our back, so only
857 // CFRelease if we are safe
858 if ( IsValidControlHandle(m_controlRef) )
859 CFRelease(m_controlRef);
860 }
861 m_controlRef = NULL;
862 }
863
864 void wxMacControl::Init()
865 {
866 m_controlRef = NULL;
867 m_macControlEventHandler = NULL;
868 }
869
870 void wxMacControl::RemoveFromParent()
871 {
872 // nothing to do here for carbon
873 HIViewRemoveFromSuperview(m_controlRef);
874 }
875
876 void wxMacControl::Embed( wxWidgetImpl *parent )
877 {
878 HIViewAddSubview((ControlRef)parent->GetWXWidget(), m_controlRef);
879 }
880
881 void wxMacControl::SetNeedsDisplay( const wxRect* rect )
882 {
883 if ( !IsVisible() )
884 return;
885
886 if ( rect != NULL )
887 {
888 HIRect updatearea = CGRectMake( rect->x , rect->y , rect->width , rect->height);
889 HIViewSetNeedsDisplayInRect( m_controlRef, &updatearea, true );
890 }
891 else
892 HIViewSetNeedsDisplay( m_controlRef , true );
893 }
894
895 void wxMacControl::Raise()
896 {
897 verify_noerr( HIViewSetZOrder( m_controlRef, kHIViewZOrderAbove, NULL ) );
898 }
899
900 void wxMacControl::Lower()
901 {
902 verify_noerr( HIViewSetZOrder( m_controlRef, kHIViewZOrderBelow, NULL ) );
903 }
904
905 void wxMacControl::GetContentArea(int &left , int &top , int &width , int &height) const
906 {
907 RgnHandle rgn = NewRgn() ;
908 Rect content ;
909 if ( GetControlRegion( m_controlRef, kControlContentMetaPart , rgn ) == noErr )
910 GetRegionBounds( rgn , &content ) ;
911 else
912 {
913 GetControlBounds( m_controlRef , &content );
914 content.right -= content.left;
915 content.left = 0;
916 content.bottom -= content.top;
917 content.top = 0;
918 }
919 DisposeRgn( rgn ) ;
920
921 left = content.left;
922 top = content.top;
923
924 width = content.right - content.left ;
925 height = content.bottom - content.top ;
926 }
927
928 void wxMacControl::Move(int x, int y, int width, int height)
929 {
930 HIRect hir = CGRectMake(x,y,width,height);
931 HIViewSetFrame ( m_controlRef , &hir );
932 }
933
934 void wxMacControl::GetPosition( int &x, int &y ) const
935 {
936 Rect r;
937 GetControlBounds( m_controlRef , &r );
938 x = r.left;
939 y = r.top;
940 }
941
942 void wxMacControl::GetSize( int &width, int &height ) const
943 {
944 Rect r;
945 GetControlBounds( m_controlRef , &r );
946 width = r.right - r.left;
947 height = r.bottom - r.top;
948 }
949
950 void wxMacControl::SetControlSize( wxWindowVariant variant )
951 {
952 ControlSize size ;
953 switch ( variant )
954 {
955 case wxWINDOW_VARIANT_NORMAL :
956 size = kControlSizeNormal;
957 break ;
958
959 case wxWINDOW_VARIANT_SMALL :
960 size = kControlSizeSmall;
961 break ;
962
963 case wxWINDOW_VARIANT_MINI :
964 // not always defined in the headers
965 size = 3 ;
966 break ;
967
968 case wxWINDOW_VARIANT_LARGE :
969 size = kControlSizeLarge;
970 break ;
971
972 default:
973 wxFAIL_MSG(_T("unexpected window variant"));
974 break ;
975 }
976
977 SetData<ControlSize>(kControlEntireControl, kControlSizeTag, &size ) ;
978 }
979
980 void wxMacControl::ScrollRect( const wxRect *rect, int dx, int dy )
981 {
982 if (GetNeedsDisplay() )
983 {
984 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
985 // in case there is already a pending redraw on that area
986 // either immediate redraw or full invalidate
987 #if 1
988 // is the better overall solution, as it does not slow down scrolling
989 SetNeedsDisplay() ;
990 #else
991 // this would be the preferred version for fast drawing controls
992 HIViewRender(GetControlRef()) ;
993 #endif
994 }
995
996 // note there currently is a bug in OSX (10.3 +?) which makes inefficient refreshes in case an entire control
997 // area is scrolled, this does not occur if width and height are 2 pixels less,
998 // TODO: write optimal workaround
999
1000 HIRect scrollarea = CGRectMake( rect->x , rect->y , rect->width , rect->height);
1001 HIViewScrollRect ( m_controlRef , &scrollarea , dx ,dy );
1002
1003 #if 0
1004 // this would be the preferred version for fast drawing controls
1005 HIViewRender(GetControlRef()) ;
1006 #endif
1007 }
1008
1009 bool wxMacControl::CanFocus() const
1010 {
1011 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
1012 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
1013 // but the value range is nowhere documented
1014 Boolean keyExistsAndHasValidFormat ;
1015 CFIndex fullKeyboardAccess = CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
1016 kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat );
1017
1018 if ( keyExistsAndHasValidFormat && fullKeyboardAccess > 0 )
1019 {
1020 return true ;
1021 }
1022 else
1023 {
1024 UInt32 features = 0 ;
1025 GetControlFeatures( m_controlRef, &features ) ;
1026
1027 return features & ( kControlSupportsFocus | kControlGetsFocusOnClick ) ;
1028 }
1029 }
1030
1031 bool wxMacControl::GetNeedsDisplay() const
1032 {
1033 return HIViewGetNeedsDisplay( m_controlRef );
1034 }
1035
1036 void wxWidgetImpl::Convert( wxPoint *pt , wxWidgetImpl *from , wxWidgetImpl *to )
1037 {
1038 HIPoint hiPoint;
1039
1040 hiPoint.x = pt->x;
1041 hiPoint.y = pt->y;
1042 HIViewConvertPoint( &hiPoint , (ControlRef) from->GetWXWidget() , (ControlRef) to->GetWXWidget() );
1043 pt->x = (int)hiPoint.x;
1044 pt->y = (int)hiPoint.y;
1045 }
1046
1047 bool wxMacControl::SetFocus()
1048 {
1049 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1050 // we can only leave in case of an error
1051
1052 OSStatus err = SetKeyboardFocus( GetControlOwner( m_controlRef ), m_controlRef, kControlFocusNextPart );
1053 if ( err == errCouldntSetFocus )
1054 return false ;
1055 SetUserFocusWindow(GetControlOwner( m_controlRef ) );
1056
1057 return true;
1058 }
1059
1060 bool wxMacControl::HasFocus() const
1061 {
1062 ControlRef control;
1063 GetKeyboardFocus( GetUserFocusWindow() , &control );
1064 return control == m_controlRef;
1065 }
1066
1067 void wxMacControl::SetCursor(const wxCursor& cursor)
1068 {
1069 wxWindowMac *mouseWin = 0 ;
1070 WindowRef window = GetControlOwner( m_controlRef ) ;
1071
1072 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) window ) ;
1073 if ( tlwwx != NULL )
1074 {
1075 ControlPartCode part ;
1076 ControlRef control ;
1077 Point pt ;
1078 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1079 HIPoint hiPoint ;
1080 HIGetMousePosition(kHICoordSpaceWindow, window, &hiPoint);
1081 pt.h = hiPoint.x;
1082 pt.v = hiPoint.y;
1083 #else
1084 GetGlobalMouse( &pt );
1085 int x = pt.h;
1086 int y = pt.v;
1087 tlwwx->ScreenToClient(&x, &y);
1088 pt.h = x;
1089 pt.v = y;
1090 #endif
1091 control = FindControlUnderMouse( pt , window , &part ) ;
1092 if ( control )
1093 mouseWin = wxFindWindowFromWXWidget( (WXWidget) control ) ;
1094 }
1095
1096 if ( mouseWin == tlwwx && !wxIsBusy() )
1097 cursor.MacInstall() ;
1098 }
1099
1100 void wxMacControl::CaptureMouse()
1101 {
1102 }
1103
1104 void wxMacControl::ReleaseMouse()
1105 {
1106 }
1107
1108 //
1109 // subclass specifics
1110 //
1111
1112 OSStatus wxMacControl::GetData(ControlPartCode inPartCode , ResType inTag , Size inBufferSize , void * inOutBuffer , Size * outActualSize ) const
1113 {
1114 return ::GetControlData( m_controlRef , inPartCode , inTag , inBufferSize , inOutBuffer , outActualSize );
1115 }
1116
1117 OSStatus wxMacControl::GetDataSize(ControlPartCode inPartCode , ResType inTag , Size * outActualSize ) const
1118 {
1119 return ::GetControlDataSize( m_controlRef , inPartCode , inTag , outActualSize );
1120 }
1121
1122 OSStatus wxMacControl::SetData(ControlPartCode inPartCode , ResType inTag , Size inSize , const void * inData)
1123 {
1124 return ::SetControlData( m_controlRef , inPartCode , inTag , inSize , inData );
1125 }
1126
1127 OSStatus wxMacControl::SendEvent( EventRef event , OptionBits inOptions )
1128 {
1129 return SendEventToEventTargetWithOptions( event,
1130 HIObjectGetEventTarget( (HIObjectRef) m_controlRef ), inOptions );
1131 }
1132
1133 OSStatus wxMacControl::SendHICommand( HICommand &command , OptionBits inOptions )
1134 {
1135 wxMacCarbonEvent event( kEventClassCommand , kEventCommandProcess );
1136
1137 event.SetParameter<HICommand>(kEventParamDirectObject,command);
1138
1139 return SendEvent( event , inOptions );
1140 }
1141
1142 OSStatus wxMacControl::SendHICommand( UInt32 commandID , OptionBits inOptions )
1143 {
1144 HICommand command;
1145
1146 memset( &command, 0 , sizeof(command) );
1147 command.commandID = commandID;
1148 return SendHICommand( command , inOptions );
1149 }
1150
1151 void wxMacControl::PerformClick()
1152 {
1153 HIViewSimulateClick (m_controlRef, kControlButtonPart, 0, NULL );
1154 }
1155
1156 wxInt32 wxMacControl::GetValue() const
1157 {
1158 return ::GetControl32BitValue( m_controlRef );
1159 }
1160
1161 wxInt32 wxMacControl::GetMaximum() const
1162 {
1163 return ::GetControl32BitMaximum( m_controlRef );
1164 }
1165
1166 wxInt32 wxMacControl::GetMinimum() const
1167 {
1168 return ::GetControl32BitMinimum( m_controlRef );
1169 }
1170
1171 void wxMacControl::SetValue( wxInt32 v )
1172 {
1173 ::SetControl32BitValue( m_controlRef , v );
1174 }
1175
1176 void wxMacControl::SetMinimum( wxInt32 v )
1177 {
1178 ::SetControl32BitMinimum( m_controlRef , v );
1179 }
1180
1181 void wxMacControl::SetMaximum( wxInt32 v )
1182 {
1183 ::SetControl32BitMaximum( m_controlRef , v );
1184 }
1185
1186 void wxMacControl::SetValueAndRange( SInt32 value , SInt32 minimum , SInt32 maximum )
1187 {
1188 ::SetControl32BitMinimum( m_controlRef , minimum );
1189 ::SetControl32BitMaximum( m_controlRef , maximum );
1190 ::SetControl32BitValue( m_controlRef , value );
1191 }
1192
1193 void wxMacControl::VisibilityChanged(bool WXUNUSED(shown))
1194 {
1195 }
1196
1197 void wxMacControl::SuperChangedPosition()
1198 {
1199 }
1200
1201 void wxMacControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack )
1202 {
1203 m_font = font;
1204 #if wxOSX_USE_CORE_TEXT
1205 if ( UMAGetSystemVersion() >= 0x1050 )
1206 {
1207 HIViewPartCode part = 0;
1208 HIThemeTextHorizontalFlush flush = kHIThemeTextHorizontalFlushDefault;
1209 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1210 flush = kHIThemeTextHorizontalFlushCenter;
1211 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1212 flush = kHIThemeTextHorizontalFlushRight;
1213 HIViewSetTextFont( m_controlRef , part , (CTFontRef) font.MacGetCTFont() );
1214 HIViewSetTextHorizontalFlush( m_controlRef, part, flush );
1215
1216 if ( foreground != *wxBLACK || ignoreBlack == false )
1217 {
1218 ControlFontStyleRec fontStyle;
1219 foreground.GetRGBColor( &fontStyle.foreColor );
1220 fontStyle.flags = kControlUseForeColorMask;
1221 ::SetControlFontStyle( m_controlRef , &fontStyle );
1222 }
1223 }
1224 #endif
1225 #if wxOSX_USE_ATSU_TEXT
1226 ControlFontStyleRec fontStyle;
1227 if ( font.MacGetThemeFontID() != kThemeCurrentPortFont )
1228 {
1229 switch ( font.MacGetThemeFontID() )
1230 {
1231 case kThemeSmallSystemFont :
1232 fontStyle.font = kControlFontSmallSystemFont;
1233 break;
1234
1235 case 109 : // mini font
1236 fontStyle.font = -5;
1237 break;
1238
1239 case kThemeSystemFont :
1240 fontStyle.font = kControlFontBigSystemFont;
1241 break;
1242
1243 default :
1244 fontStyle.font = kControlFontBigSystemFont;
1245 break;
1246 }
1247
1248 fontStyle.flags = kControlUseFontMask;
1249 }
1250 else
1251 {
1252 fontStyle.font = font.MacGetFontNum();
1253 fontStyle.style = font.MacGetFontStyle();
1254 fontStyle.size = font.MacGetFontSize();
1255 fontStyle.flags = kControlUseFontMask | kControlUseFaceMask | kControlUseSizeMask;
1256 }
1257
1258 fontStyle.just = teJustLeft;
1259 fontStyle.flags |= kControlUseJustMask;
1260 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1261 fontStyle.just = teJustCenter;
1262 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1263 fontStyle.just = teJustRight;
1264
1265
1266 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1267 // won't get grayed out by the system anymore
1268
1269 if ( foreground != *wxBLACK || ignoreBlack == false )
1270 {
1271 foreground.GetRGBColor( &fontStyle.foreColor );
1272 fontStyle.flags |= kControlUseForeColorMask;
1273 }
1274
1275 ::SetControlFontStyle( m_controlRef , &fontStyle );
1276 #endif
1277 }
1278
1279 void wxMacControl::SetBackgroundColour( const wxColour &WXUNUSED(col) )
1280 {
1281 // HITextViewSetBackgroundColor( m_textView , color );
1282 }
1283
1284 void wxMacControl::SetRange( SInt32 minimum , SInt32 maximum )
1285 {
1286 ::SetControl32BitMinimum( m_controlRef , minimum );
1287 ::SetControl32BitMaximum( m_controlRef , maximum );
1288 }
1289
1290 short wxMacControl::HandleKey( SInt16 keyCode, SInt16 charCode, EventModifiers modifiers )
1291 {
1292 return HandleControlKey( m_controlRef , keyCode , charCode , modifiers );
1293 }
1294
1295 void wxMacControl::SetActionProc( ControlActionUPP actionProc )
1296 {
1297 SetControlAction( m_controlRef , actionProc );
1298 }
1299
1300 SInt32 wxMacControl::GetViewSize() const
1301 {
1302 return GetControlViewSize( m_controlRef );
1303 }
1304
1305 bool wxMacControl::IsVisible() const
1306 {
1307 return IsControlVisible( m_controlRef );
1308 }
1309
1310 void wxMacControl::SetVisibility( bool visible )
1311 {
1312 SetControlVisibility( m_controlRef , visible, true );
1313 }
1314
1315 bool wxMacControl::IsEnabled() const
1316 {
1317 return IsControlEnabled( m_controlRef );
1318 }
1319
1320 bool wxMacControl::IsActive() const
1321 {
1322 return IsControlActive( m_controlRef );
1323 }
1324
1325 void wxMacControl::Enable( bool enable )
1326 {
1327 if ( enable )
1328 EnableControl( m_controlRef );
1329 else
1330 DisableControl( m_controlRef );
1331 }
1332
1333 void wxMacControl::SetDrawingEnabled( bool enable )
1334 {
1335 HIViewSetDrawingEnabled( m_controlRef , enable );
1336 }
1337
1338 void wxMacControl::GetRectInWindowCoords( Rect *r )
1339 {
1340 GetControlBounds( m_controlRef , r ) ;
1341
1342 WindowRef tlwref = GetControlOwner( m_controlRef ) ;
1343
1344 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) tlwref ) ;
1345 if ( tlwwx != NULL )
1346 {
1347 ControlRef rootControl = tlwwx->GetPeer()->GetControlRef() ;
1348 HIPoint hiPoint = CGPointMake( 0 , 0 ) ;
1349 HIViewConvertPoint( &hiPoint , HIViewGetSuperview(m_controlRef) , rootControl ) ;
1350 OffsetRect( r , (short) hiPoint.x , (short) hiPoint.y ) ;
1351 }
1352 }
1353
1354 void wxMacControl::GetBestRect( wxRect *rect ) const
1355 {
1356 short baselineoffset;
1357 Rect r = {0,0,0,0};
1358
1359 GetBestControlRect( m_controlRef , &r , &baselineoffset );
1360 *rect = wxRect( r.left, r.top, r.right - r.left, r.bottom-r.top );
1361 }
1362
1363 void wxMacControl::GetBestRect( Rect *r ) const
1364 {
1365 short baselineoffset;
1366 GetBestControlRect( m_controlRef , r , &baselineoffset );
1367 }
1368
1369 void wxMacControl::SetLabel( const wxString &title , wxFontEncoding encoding)
1370 {
1371 SetControlTitleWithCFString( m_controlRef , wxCFStringRef( title , encoding ) );
1372 }
1373
1374 void wxMacControl::GetFeatures( UInt32 * features )
1375 {
1376 GetControlFeatures( m_controlRef , features );
1377 }
1378
1379 OSStatus wxMacControl::GetRegion( ControlPartCode partCode , RgnHandle region )
1380 {
1381 OSStatus err = GetControlRegion( m_controlRef , partCode , region );
1382 return err;
1383 }
1384
1385 void wxMacControl::PulseGauge()
1386 {
1387 }
1388
1389 // SetNeedsDisplay would not invalidate the children
1390 static void InvalidateControlAndChildren( HIViewRef control )
1391 {
1392 HIViewSetNeedsDisplay( control , true );
1393 UInt16 childrenCount = 0;
1394 OSStatus err = CountSubControls( control , &childrenCount );
1395 if ( err == errControlIsNotEmbedder )
1396 return;
1397
1398 wxASSERT_MSG( err == noErr , wxT("Unexpected error when accessing subcontrols") );
1399
1400 for ( UInt16 i = childrenCount; i >=1; --i )
1401 {
1402 HIViewRef child;
1403
1404 err = GetIndexedSubControl( control , i , & child );
1405 if ( err == errControlIsNotEmbedder )
1406 return;
1407
1408 InvalidateControlAndChildren( child );
1409 }
1410 }
1411
1412 void wxMacControl::InvalidateWithChildren()
1413 {
1414 InvalidateControlAndChildren( m_controlRef );
1415 }
1416
1417 OSType wxMacCreator = 'WXMC';
1418 OSType wxMacControlProperty = 'MCCT';
1419
1420 void wxMacControl::SetReferenceInNativeControl()
1421 {
1422 void * data = this;
1423 verify_noerr( SetControlProperty ( m_controlRef ,
1424 wxMacCreator,wxMacControlProperty, sizeof(data), &data ) );
1425 }
1426
1427 wxMacControl* wxMacControl::GetReferenceFromNativeControl(ControlRef control)
1428 {
1429 wxMacControl* ctl = NULL;
1430 ByteCount actualSize;
1431 if ( GetControlProperty( control ,wxMacCreator,wxMacControlProperty, sizeof(ctl) ,
1432 &actualSize , &ctl ) == noErr )
1433 {
1434 return ctl;
1435 }
1436 return NULL;
1437 }
1438
1439 void wxMacControl::SetBitmap( const wxBitmap& WXUNUSED(bmp) )
1440 {
1441 // implemented in the respective subclasses
1442 }
1443
1444 void wxMacControl::SetScrollThumb( wxInt32 WXUNUSED(pos), wxInt32 WXUNUSED(viewsize) )
1445 {
1446 // implemented in respective subclass
1447 }
1448
1449 //
1450 // Tab Control
1451 //
1452
1453 OSStatus wxMacControl::SetTabEnabled( SInt16 tabNo , bool enable )
1454 {
1455 return ::SetTabEnabled( m_controlRef , tabNo , enable );
1456 }
1457
1458
1459
1460 // Control Factory
1461
1462 wxWidgetImplType* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
1463 {
1464 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1465 // the content view, so we have to retrieve it explicitly
1466
1467 wxMacControl* contentview = new wxMacControl(now , true /*isRootControl*/);
1468 HIViewFindByID( HIViewGetRoot( (WindowRef) now->GetWXWindow() ) , kHIViewWindowContentID ,
1469 contentview->GetControlRefAddr() ) ;
1470 if ( !contentview->IsOk() )
1471 {
1472 // compatibility mode fallback
1473 GetRootControl( (WindowRef) now->GetWXWindow() , contentview->GetControlRefAddr() ) ;
1474 }
1475
1476 // the root control level handler
1477 contentview->InstallEventHandler() ;
1478 return contentview;
1479 }