]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/window.cpp
Remove old workarounds to get cut, copy, and paste working in embedded wxTextCtrl
[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::RemoveFromParent()
845 {
846 // nothing to do here for carbon
847 HIViewRemoveFromSuperview(m_controlRef);
848 }
849
850 void wxMacControl::Embed( wxWidgetImpl *parent )
851 {
852 HIViewAddSubview((ControlRef)parent->GetWXWidget(), m_controlRef);
853 }
854
855 void wxMacControl::SetNeedsDisplay( const wxRect* rect )
856 {
857 if ( !IsVisible() )
858 return;
859
860 if ( rect != NULL )
861 {
862 HIRect updatearea = CGRectMake( rect->x , rect->y , rect->width , rect->height);
863 HIViewSetNeedsDisplayInRect( m_controlRef, &updatearea, true );
864 }
865 else
866 HIViewSetNeedsDisplay( m_controlRef , true );
867 }
868
869 void wxMacControl::Raise()
870 {
871 verify_noerr( HIViewSetZOrder( m_controlRef, kHIViewZOrderAbove, NULL ) );
872 }
873
874 void wxMacControl::Lower()
875 {
876 verify_noerr( HIViewSetZOrder( m_controlRef, kHIViewZOrderBelow, NULL ) );
877 }
878
879 void wxMacControl::GetContentArea(int &left , int &top , int &width , int &height) const
880 {
881 RgnHandle rgn = NewRgn() ;
882 Rect content ;
883 if ( GetControlRegion( m_controlRef, kControlContentMetaPart , rgn ) == noErr )
884 GetRegionBounds( rgn , &content ) ;
885 else
886 {
887 GetControlBounds( m_controlRef , &content );
888 content.right -= content.left;
889 content.left = 0;
890 content.bottom -= content.top;
891 content.top = 0;
892 }
893 DisposeRgn( rgn ) ;
894
895 left = content.left;
896 top = content.top;
897
898 width = content.right - content.left ;
899 height = content.bottom - content.top ;
900 }
901
902 void wxMacControl::Move(int x, int y, int width, int height)
903 {
904 HIRect hir = CGRectMake(x,y,width,height);
905 HIViewSetFrame ( m_controlRef , &hir );
906 }
907
908 void wxMacControl::GetPosition( int &x, int &y ) const
909 {
910 Rect r;
911 GetControlBounds( m_controlRef , &r );
912 x = r.left;
913 y = r.top;
914 }
915
916 void wxMacControl::GetSize( int &width, int &height ) const
917 {
918 Rect r;
919 GetControlBounds( m_controlRef , &r );
920 width = r.right - r.left;
921 height = r.bottom - r.top;
922 }
923
924 void wxMacControl::SetControlSize( wxWindowVariant variant )
925 {
926 ControlSize size ;
927 switch ( variant )
928 {
929 case wxWINDOW_VARIANT_NORMAL :
930 size = kControlSizeNormal;
931 break ;
932
933 case wxWINDOW_VARIANT_SMALL :
934 size = kControlSizeSmall;
935 break ;
936
937 case wxWINDOW_VARIANT_MINI :
938 // not always defined in the headers
939 size = 3 ;
940 break ;
941
942 case wxWINDOW_VARIANT_LARGE :
943 size = kControlSizeLarge;
944 break ;
945
946 default:
947 wxFAIL_MSG(_T("unexpected window variant"));
948 break ;
949 }
950
951 SetData<ControlSize>(kControlEntireControl, kControlSizeTag, &size ) ;
952 }
953
954 void wxMacControl::ScrollRect( const wxRect *rect, int dx, int dy )
955 {
956 if (GetNeedsDisplay() )
957 {
958 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
959 // in case there is already a pending redraw on that area
960 // either immediate redraw or full invalidate
961 #if 1
962 // is the better overall solution, as it does not slow down scrolling
963 SetNeedsDisplay() ;
964 #else
965 // this would be the preferred version for fast drawing controls
966 HIViewRender(GetControlRef()) ;
967 #endif
968 }
969
970 // note there currently is a bug in OSX (10.3 +?) which makes inefficient refreshes in case an entire control
971 // area is scrolled, this does not occur if width and height are 2 pixels less,
972 // TODO: write optimal workaround
973
974 HIRect scrollarea = CGRectMake( rect->x , rect->y , rect->width , rect->height);
975 HIViewScrollRect ( m_controlRef , &scrollarea , dx ,dy );
976
977 #if 0
978 // this would be the preferred version for fast drawing controls
979 HIViewRender(GetControlRef()) ;
980 #endif
981 }
982
983 bool wxMacControl::CanFocus() const
984 {
985 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
986 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
987 // but the value range is nowhere documented
988 Boolean keyExistsAndHasValidFormat ;
989 CFIndex fullKeyboardAccess = CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
990 kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat );
991
992 if ( keyExistsAndHasValidFormat && fullKeyboardAccess > 0 )
993 {
994 return true ;
995 }
996 else
997 {
998 UInt32 features = 0 ;
999 GetControlFeatures( m_controlRef, &features ) ;
1000
1001 return features & ( kControlSupportsFocus | kControlGetsFocusOnClick ) ;
1002 }
1003 }
1004
1005 bool wxMacControl::GetNeedsDisplay() const
1006 {
1007 return HIViewGetNeedsDisplay( m_controlRef );
1008 }
1009
1010 void wxWidgetImpl::Convert( wxPoint *pt , wxWidgetImpl *from , wxWidgetImpl *to )
1011 {
1012 HIPoint hiPoint;
1013
1014 hiPoint.x = pt->x;
1015 hiPoint.y = pt->y;
1016 HIViewConvertPoint( &hiPoint , (ControlRef) from->GetWXWidget() , (ControlRef) to->GetWXWidget() );
1017 pt->x = (int)hiPoint.x;
1018 pt->y = (int)hiPoint.y;
1019 }
1020
1021 bool wxMacControl::SetFocus()
1022 {
1023 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1024 // we can only leave in case of an error
1025
1026 OSStatus err = SetKeyboardFocus( GetControlOwner( m_controlRef ), m_controlRef, kControlFocusNextPart );
1027 if ( err == errCouldntSetFocus )
1028 return false ;
1029 SetUserFocusWindow(GetControlOwner( m_controlRef ) );
1030
1031 return true;
1032 }
1033
1034 bool wxMacControl::HasFocus() const
1035 {
1036 ControlRef control;
1037 GetKeyboardFocus( GetUserFocusWindow() , &control );
1038 return control == m_controlRef;
1039 }
1040
1041 //
1042 // subclass specifics
1043 //
1044
1045 OSStatus wxMacControl::GetData(ControlPartCode inPartCode , ResType inTag , Size inBufferSize , void * inOutBuffer , Size * outActualSize ) const
1046 {
1047 return ::GetControlData( m_controlRef , inPartCode , inTag , inBufferSize , inOutBuffer , outActualSize );
1048 }
1049
1050 OSStatus wxMacControl::GetDataSize(ControlPartCode inPartCode , ResType inTag , Size * outActualSize ) const
1051 {
1052 return ::GetControlDataSize( m_controlRef , inPartCode , inTag , outActualSize );
1053 }
1054
1055 OSStatus wxMacControl::SetData(ControlPartCode inPartCode , ResType inTag , Size inSize , const void * inData)
1056 {
1057 return ::SetControlData( m_controlRef , inPartCode , inTag , inSize , inData );
1058 }
1059
1060 OSStatus wxMacControl::SendEvent( EventRef event , OptionBits inOptions )
1061 {
1062 return SendEventToEventTargetWithOptions( event,
1063 HIObjectGetEventTarget( (HIObjectRef) m_controlRef ), inOptions );
1064 }
1065
1066 OSStatus wxMacControl::SendHICommand( HICommand &command , OptionBits inOptions )
1067 {
1068 wxMacCarbonEvent event( kEventClassCommand , kEventCommandProcess );
1069
1070 event.SetParameter<HICommand>(kEventParamDirectObject,command);
1071
1072 return SendEvent( event , inOptions );
1073 }
1074
1075 OSStatus wxMacControl::SendHICommand( UInt32 commandID , OptionBits inOptions )
1076 {
1077 HICommand command;
1078
1079 memset( &command, 0 , sizeof(command) );
1080 command.commandID = commandID;
1081 return SendHICommand( command , inOptions );
1082 }
1083
1084 void wxMacControl::PerformClick()
1085 {
1086 HIViewSimulateClick (m_controlRef, kControlButtonPart, 0, NULL );
1087 }
1088
1089 wxInt32 wxMacControl::GetValue() const
1090 {
1091 return ::GetControl32BitValue( m_controlRef );
1092 }
1093
1094 SInt32 wxMacControl::GetMaximum() const
1095 {
1096 return ::GetControl32BitMaximum( m_controlRef );
1097 }
1098
1099 /*
1100 wxInt32 wxMacControl::GetMinimum() const
1101 {
1102 return ::GetControl32BitMinimum( m_controlRef );
1103 }
1104 */
1105
1106 void wxMacControl::SetValue( wxInt32 v )
1107 {
1108 ::SetControl32BitValue( m_controlRef , v );
1109 }
1110
1111 void wxMacControl::SetMinimum( wxInt32 v )
1112 {
1113 ::SetControl32BitMinimum( m_controlRef , v );
1114 }
1115
1116 void wxMacControl::SetMaximum( wxInt32 v )
1117 {
1118 ::SetControl32BitMaximum( m_controlRef , v );
1119 }
1120
1121 void wxMacControl::SetValueAndRange( SInt32 value , SInt32 minimum , SInt32 maximum )
1122 {
1123 ::SetControl32BitMinimum( m_controlRef , minimum );
1124 ::SetControl32BitMaximum( m_controlRef , maximum );
1125 ::SetControl32BitValue( m_controlRef , value );
1126 }
1127
1128 void wxMacControl::VisibilityChanged(bool WXUNUSED(shown))
1129 {
1130 }
1131
1132 void wxMacControl::SuperChangedPosition()
1133 {
1134 }
1135
1136 void wxMacControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack )
1137 {
1138 m_font = font;
1139 #if wxOSX_USE_CORE_TEXT
1140 if ( UMAGetSystemVersion() >= 0x1050 )
1141 {
1142 HIViewPartCode part = 0;
1143 HIThemeTextHorizontalFlush flush = kHIThemeTextHorizontalFlushDefault;
1144 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1145 flush = kHIThemeTextHorizontalFlushCenter;
1146 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1147 flush = kHIThemeTextHorizontalFlushRight;
1148 HIViewSetTextFont( m_controlRef , part , (CTFontRef) font.MacGetCTFont() );
1149 HIViewSetTextHorizontalFlush( m_controlRef, part, flush );
1150
1151 if ( foreground != *wxBLACK || ignoreBlack == false )
1152 {
1153 ControlFontStyleRec fontStyle;
1154 foreground.GetRGBColor( &fontStyle.foreColor );
1155 fontStyle.flags = kControlUseForeColorMask;
1156 ::SetControlFontStyle( m_controlRef , &fontStyle );
1157 }
1158 }
1159 #endif
1160 #if wxOSX_USE_ATSU_TEXT
1161 ControlFontStyleRec fontStyle;
1162 if ( font.MacGetThemeFontID() != kThemeCurrentPortFont )
1163 {
1164 switch ( font.MacGetThemeFontID() )
1165 {
1166 case kThemeSmallSystemFont :
1167 fontStyle.font = kControlFontSmallSystemFont;
1168 break;
1169
1170 case 109 : // mini font
1171 fontStyle.font = -5;
1172 break;
1173
1174 case kThemeSystemFont :
1175 fontStyle.font = kControlFontBigSystemFont;
1176 break;
1177
1178 default :
1179 fontStyle.font = kControlFontBigSystemFont;
1180 break;
1181 }
1182
1183 fontStyle.flags = kControlUseFontMask;
1184 }
1185 else
1186 {
1187 fontStyle.font = font.MacGetFontNum();
1188 fontStyle.style = font.MacGetFontStyle();
1189 fontStyle.size = font.MacGetFontSize();
1190 fontStyle.flags = kControlUseFontMask | kControlUseFaceMask | kControlUseSizeMask;
1191 }
1192
1193 fontStyle.just = teJustLeft;
1194 fontStyle.flags |= kControlUseJustMask;
1195 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1196 fontStyle.just = teJustCenter;
1197 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1198 fontStyle.just = teJustRight;
1199
1200
1201 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1202 // won't get grayed out by the system anymore
1203
1204 if ( foreground != *wxBLACK || ignoreBlack == false )
1205 {
1206 foreground.GetRGBColor( &fontStyle.foreColor );
1207 fontStyle.flags |= kControlUseForeColorMask;
1208 }
1209
1210 ::SetControlFontStyle( m_controlRef , &fontStyle );
1211 #endif
1212 }
1213
1214 void wxMacControl::SetBackgroundColour( const wxColour &WXUNUSED(col) )
1215 {
1216 // HITextViewSetBackgroundColor( m_textView , color );
1217 }
1218
1219 void wxMacControl::SetRange( SInt32 minimum , SInt32 maximum )
1220 {
1221 ::SetControl32BitMinimum( m_controlRef , minimum );
1222 ::SetControl32BitMaximum( m_controlRef , maximum );
1223 }
1224
1225 short wxMacControl::HandleKey( SInt16 keyCode, SInt16 charCode, EventModifiers modifiers )
1226 {
1227 return HandleControlKey( m_controlRef , keyCode , charCode , modifiers );
1228 }
1229
1230 void wxMacControl::SetActionProc( ControlActionUPP actionProc )
1231 {
1232 SetControlAction( m_controlRef , actionProc );
1233 }
1234
1235 SInt32 wxMacControl::GetViewSize() const
1236 {
1237 return GetControlViewSize( m_controlRef );
1238 }
1239
1240 bool wxMacControl::IsVisible() const
1241 {
1242 return IsControlVisible( m_controlRef );
1243 }
1244
1245 void wxMacControl::SetVisibility( bool visible )
1246 {
1247 SetControlVisibility( m_controlRef , visible, true );
1248 }
1249
1250 bool wxMacControl::IsEnabled() const
1251 {
1252 return IsControlEnabled( m_controlRef );
1253 }
1254
1255 bool wxMacControl::IsActive() const
1256 {
1257 return IsControlActive( m_controlRef );
1258 }
1259
1260 void wxMacControl::Enable( bool enable )
1261 {
1262 if ( enable )
1263 EnableControl( m_controlRef );
1264 else
1265 DisableControl( m_controlRef );
1266 }
1267
1268 void wxMacControl::SetDrawingEnabled( bool enable )
1269 {
1270 HIViewSetDrawingEnabled( m_controlRef , enable );
1271 }
1272
1273 void wxMacControl::GetRectInWindowCoords( Rect *r )
1274 {
1275 GetControlBounds( m_controlRef , r ) ;
1276
1277 WindowRef tlwref = GetControlOwner( m_controlRef ) ;
1278
1279 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) tlwref ) ;
1280 if ( tlwwx != NULL )
1281 {
1282 ControlRef rootControl = tlwwx->GetPeer()->GetControlRef() ;
1283 HIPoint hiPoint = CGPointMake( 0 , 0 ) ;
1284 HIViewConvertPoint( &hiPoint , HIViewGetSuperview(m_controlRef) , rootControl ) ;
1285 OffsetRect( r , (short) hiPoint.x , (short) hiPoint.y ) ;
1286 }
1287 }
1288
1289 void wxMacControl::GetBestRect( wxRect *rect ) const
1290 {
1291 short baselineoffset;
1292 Rect r = {0,0,0,0};
1293
1294 GetBestControlRect( m_controlRef , &r , &baselineoffset );
1295 *rect = wxRect( r.left, r.top, r.right - r.left, r.bottom-r.top );
1296 }
1297
1298 void wxMacControl::GetBestRect( Rect *r ) const
1299 {
1300 short baselineoffset;
1301 GetBestControlRect( m_controlRef , r , &baselineoffset );
1302 }
1303
1304 void wxMacControl::SetLabel( const wxString &title , wxFontEncoding encoding)
1305 {
1306 SetControlTitleWithCFString( m_controlRef , wxCFStringRef( title , encoding ) );
1307 }
1308
1309 void wxMacControl::GetFeatures( UInt32 * features )
1310 {
1311 GetControlFeatures( m_controlRef , features );
1312 }
1313
1314 OSStatus wxMacControl::GetRegion( ControlPartCode partCode , RgnHandle region )
1315 {
1316 OSStatus err = GetControlRegion( m_controlRef , partCode , region );
1317 return err;
1318 }
1319
1320 void wxMacControl::PulseGauge()
1321 {
1322 }
1323
1324 // SetNeedsDisplay would not invalidate the children
1325 static void InvalidateControlAndChildren( HIViewRef control )
1326 {
1327 HIViewSetNeedsDisplay( control , true );
1328 UInt16 childrenCount = 0;
1329 OSStatus err = CountSubControls( control , &childrenCount );
1330 if ( err == errControlIsNotEmbedder )
1331 return;
1332
1333 wxASSERT_MSG( err == noErr , wxT("Unexpected error when accessing subcontrols") );
1334
1335 for ( UInt16 i = childrenCount; i >=1; --i )
1336 {
1337 HIViewRef child;
1338
1339 err = GetIndexedSubControl( control , i , & child );
1340 if ( err == errControlIsNotEmbedder )
1341 return;
1342
1343 InvalidateControlAndChildren( child );
1344 }
1345 }
1346
1347 void wxMacControl::InvalidateWithChildren()
1348 {
1349 InvalidateControlAndChildren( m_controlRef );
1350 }
1351
1352 OSType wxMacCreator = 'WXMC';
1353 OSType wxMacControlProperty = 'MCCT';
1354
1355 void wxMacControl::SetReferenceInNativeControl()
1356 {
1357 void * data = this;
1358 verify_noerr( SetControlProperty ( m_controlRef ,
1359 wxMacCreator,wxMacControlProperty, sizeof(data), &data ) );
1360 }
1361
1362 wxMacControl* wxMacControl::GetReferenceFromNativeControl(ControlRef control)
1363 {
1364 wxMacControl* ctl = NULL;
1365 ByteCount actualSize;
1366 if ( GetControlProperty( control ,wxMacCreator,wxMacControlProperty, sizeof(ctl) ,
1367 &actualSize , &ctl ) == noErr )
1368 {
1369 return ctl;
1370 }
1371 return NULL;
1372 }
1373
1374 void wxMacControl::SetBitmap( const wxBitmap& WXUNUSED(bmp) )
1375 {
1376 // implemented in the respective subclasses
1377 }
1378
1379 void wxMacControl::SetScrollThumb( wxInt32 WXUNUSED(pos), wxInt32 WXUNUSED(viewsize) )
1380 {
1381 // implemented in respective subclass
1382 }
1383
1384 //
1385 // Tab Control
1386 //
1387
1388 OSStatus wxMacControl::SetTabEnabled( SInt16 tabNo , bool enable )
1389 {
1390 return ::SetTabEnabled( m_controlRef , tabNo , enable );
1391 }
1392
1393
1394
1395 // Control Factory
1396
1397 wxWidgetImplType* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
1398 {
1399 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1400 // the content view, so we have to retrieve it explicitly
1401
1402 wxMacControl* contentview = new wxMacControl(now , true /*isRootControl*/);
1403 HIViewFindByID( HIViewGetRoot( (WindowRef) now->GetWXWindow() ) , kHIViewWindowContentID ,
1404 contentview->GetControlRefAddr() ) ;
1405 if ( !contentview->IsOk() )
1406 {
1407 // compatibility mode fallback
1408 GetRootControl( (WindowRef) now->GetWXWindow() , contentview->GetControlRefAddr() ) ;
1409 }
1410
1411 // the root control level handler
1412 contentview->InstallEventHandler() ;
1413 return contentview;
1414 }