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