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