mouse and cursor additions for cocoa, see #10361
[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)"), 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)"), 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)"), static_cast<void*>(thisWindow));
339 }
340 else
341 {
342 formerFocusWindow = thisWindow;
343 wxLogTrace(_T("Focus"), _T("focus to be lost(%p)"), 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)"), 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)"), 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 void wxMacControl::SetCursor(const wxCursor& cursor)
1042 {
1043 wxWindowMac *mouseWin = 0 ;
1044 WindowRef window = GetControlOwner( m_controlRef ) ;
1045
1046 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) window ) ;
1047 if ( tlwwx != NULL )
1048 {
1049 ControlPartCode part ;
1050 ControlRef control ;
1051 Point pt ;
1052 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1053 HIPoint hiPoint ;
1054 HIGetMousePosition(kHICoordSpaceWindow, window, &hiPoint);
1055 pt.h = hiPoint.x;
1056 pt.v = hiPoint.y;
1057 #else
1058 GetGlobalMouse( &pt );
1059 int x = pt.h;
1060 int y = pt.v;
1061 tlwwx->ScreenToClient(&x, &y);
1062 pt.h = x;
1063 pt.v = y;
1064 #endif
1065 control = FindControlUnderMouse( pt , window , &part ) ;
1066 if ( control )
1067 mouseWin = wxFindWindowFromWXWidget( (WXWidget) control ) ;
1068 }
1069
1070 if ( mouseWin == tlwwx && !wxIsBusy() )
1071 cursor.MacInstall() ;
1072 }
1073
1074 void wxMacControl::CaptureMouse()
1075 {
1076 }
1077
1078 void wxMacControl::ReleaseMouse()
1079 {
1080 }
1081
1082 //
1083 // subclass specifics
1084 //
1085
1086 OSStatus wxMacControl::GetData(ControlPartCode inPartCode , ResType inTag , Size inBufferSize , void * inOutBuffer , Size * outActualSize ) const
1087 {
1088 return ::GetControlData( m_controlRef , inPartCode , inTag , inBufferSize , inOutBuffer , outActualSize );
1089 }
1090
1091 OSStatus wxMacControl::GetDataSize(ControlPartCode inPartCode , ResType inTag , Size * outActualSize ) const
1092 {
1093 return ::GetControlDataSize( m_controlRef , inPartCode , inTag , outActualSize );
1094 }
1095
1096 OSStatus wxMacControl::SetData(ControlPartCode inPartCode , ResType inTag , Size inSize , const void * inData)
1097 {
1098 return ::SetControlData( m_controlRef , inPartCode , inTag , inSize , inData );
1099 }
1100
1101 OSStatus wxMacControl::SendEvent( EventRef event , OptionBits inOptions )
1102 {
1103 return SendEventToEventTargetWithOptions( event,
1104 HIObjectGetEventTarget( (HIObjectRef) m_controlRef ), inOptions );
1105 }
1106
1107 OSStatus wxMacControl::SendHICommand( HICommand &command , OptionBits inOptions )
1108 {
1109 wxMacCarbonEvent event( kEventClassCommand , kEventCommandProcess );
1110
1111 event.SetParameter<HICommand>(kEventParamDirectObject,command);
1112
1113 return SendEvent( event , inOptions );
1114 }
1115
1116 OSStatus wxMacControl::SendHICommand( UInt32 commandID , OptionBits inOptions )
1117 {
1118 HICommand command;
1119
1120 memset( &command, 0 , sizeof(command) );
1121 command.commandID = commandID;
1122 return SendHICommand( command , inOptions );
1123 }
1124
1125 void wxMacControl::PerformClick()
1126 {
1127 HIViewSimulateClick (m_controlRef, kControlButtonPart, 0, NULL );
1128 }
1129
1130 wxInt32 wxMacControl::GetValue() const
1131 {
1132 return ::GetControl32BitValue( m_controlRef );
1133 }
1134
1135 SInt32 wxMacControl::GetMaximum() const
1136 {
1137 return ::GetControl32BitMaximum( m_controlRef );
1138 }
1139
1140 /*
1141 wxInt32 wxMacControl::GetMinimum() const
1142 {
1143 return ::GetControl32BitMinimum( m_controlRef );
1144 }
1145 */
1146
1147 void wxMacControl::SetValue( wxInt32 v )
1148 {
1149 ::SetControl32BitValue( m_controlRef , v );
1150 }
1151
1152 void wxMacControl::SetMinimum( wxInt32 v )
1153 {
1154 ::SetControl32BitMinimum( m_controlRef , v );
1155 }
1156
1157 void wxMacControl::SetMaximum( wxInt32 v )
1158 {
1159 ::SetControl32BitMaximum( m_controlRef , v );
1160 }
1161
1162 void wxMacControl::SetValueAndRange( SInt32 value , SInt32 minimum , SInt32 maximum )
1163 {
1164 ::SetControl32BitMinimum( m_controlRef , minimum );
1165 ::SetControl32BitMaximum( m_controlRef , maximum );
1166 ::SetControl32BitValue( m_controlRef , value );
1167 }
1168
1169 void wxMacControl::VisibilityChanged(bool WXUNUSED(shown))
1170 {
1171 }
1172
1173 void wxMacControl::SuperChangedPosition()
1174 {
1175 }
1176
1177 void wxMacControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack )
1178 {
1179 m_font = font;
1180 #if wxOSX_USE_CORE_TEXT
1181 if ( UMAGetSystemVersion() >= 0x1050 )
1182 {
1183 HIViewPartCode part = 0;
1184 HIThemeTextHorizontalFlush flush = kHIThemeTextHorizontalFlushDefault;
1185 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1186 flush = kHIThemeTextHorizontalFlushCenter;
1187 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1188 flush = kHIThemeTextHorizontalFlushRight;
1189 HIViewSetTextFont( m_controlRef , part , (CTFontRef) font.MacGetCTFont() );
1190 HIViewSetTextHorizontalFlush( m_controlRef, part, flush );
1191
1192 if ( foreground != *wxBLACK || ignoreBlack == false )
1193 {
1194 ControlFontStyleRec fontStyle;
1195 foreground.GetRGBColor( &fontStyle.foreColor );
1196 fontStyle.flags = kControlUseForeColorMask;
1197 ::SetControlFontStyle( m_controlRef , &fontStyle );
1198 }
1199 }
1200 #endif
1201 #if wxOSX_USE_ATSU_TEXT
1202 ControlFontStyleRec fontStyle;
1203 if ( font.MacGetThemeFontID() != kThemeCurrentPortFont )
1204 {
1205 switch ( font.MacGetThemeFontID() )
1206 {
1207 case kThemeSmallSystemFont :
1208 fontStyle.font = kControlFontSmallSystemFont;
1209 break;
1210
1211 case 109 : // mini font
1212 fontStyle.font = -5;
1213 break;
1214
1215 case kThemeSystemFont :
1216 fontStyle.font = kControlFontBigSystemFont;
1217 break;
1218
1219 default :
1220 fontStyle.font = kControlFontBigSystemFont;
1221 break;
1222 }
1223
1224 fontStyle.flags = kControlUseFontMask;
1225 }
1226 else
1227 {
1228 fontStyle.font = font.MacGetFontNum();
1229 fontStyle.style = font.MacGetFontStyle();
1230 fontStyle.size = font.MacGetFontSize();
1231 fontStyle.flags = kControlUseFontMask | kControlUseFaceMask | kControlUseSizeMask;
1232 }
1233
1234 fontStyle.just = teJustLeft;
1235 fontStyle.flags |= kControlUseJustMask;
1236 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1237 fontStyle.just = teJustCenter;
1238 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1239 fontStyle.just = teJustRight;
1240
1241
1242 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1243 // won't get grayed out by the system anymore
1244
1245 if ( foreground != *wxBLACK || ignoreBlack == false )
1246 {
1247 foreground.GetRGBColor( &fontStyle.foreColor );
1248 fontStyle.flags |= kControlUseForeColorMask;
1249 }
1250
1251 ::SetControlFontStyle( m_controlRef , &fontStyle );
1252 #endif
1253 }
1254
1255 void wxMacControl::SetBackgroundColour( const wxColour &WXUNUSED(col) )
1256 {
1257 // HITextViewSetBackgroundColor( m_textView , color );
1258 }
1259
1260 void wxMacControl::SetRange( SInt32 minimum , SInt32 maximum )
1261 {
1262 ::SetControl32BitMinimum( m_controlRef , minimum );
1263 ::SetControl32BitMaximum( m_controlRef , maximum );
1264 }
1265
1266 short wxMacControl::HandleKey( SInt16 keyCode, SInt16 charCode, EventModifiers modifiers )
1267 {
1268 return HandleControlKey( m_controlRef , keyCode , charCode , modifiers );
1269 }
1270
1271 void wxMacControl::SetActionProc( ControlActionUPP actionProc )
1272 {
1273 SetControlAction( m_controlRef , actionProc );
1274 }
1275
1276 SInt32 wxMacControl::GetViewSize() const
1277 {
1278 return GetControlViewSize( m_controlRef );
1279 }
1280
1281 bool wxMacControl::IsVisible() const
1282 {
1283 return IsControlVisible( m_controlRef );
1284 }
1285
1286 void wxMacControl::SetVisibility( bool visible )
1287 {
1288 SetControlVisibility( m_controlRef , visible, true );
1289 }
1290
1291 bool wxMacControl::IsEnabled() const
1292 {
1293 return IsControlEnabled( m_controlRef );
1294 }
1295
1296 bool wxMacControl::IsActive() const
1297 {
1298 return IsControlActive( m_controlRef );
1299 }
1300
1301 void wxMacControl::Enable( bool enable )
1302 {
1303 if ( enable )
1304 EnableControl( m_controlRef );
1305 else
1306 DisableControl( m_controlRef );
1307 }
1308
1309 void wxMacControl::SetDrawingEnabled( bool enable )
1310 {
1311 HIViewSetDrawingEnabled( m_controlRef , enable );
1312 }
1313
1314 void wxMacControl::GetRectInWindowCoords( Rect *r )
1315 {
1316 GetControlBounds( m_controlRef , r ) ;
1317
1318 WindowRef tlwref = GetControlOwner( m_controlRef ) ;
1319
1320 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) tlwref ) ;
1321 if ( tlwwx != NULL )
1322 {
1323 ControlRef rootControl = tlwwx->GetPeer()->GetControlRef() ;
1324 HIPoint hiPoint = CGPointMake( 0 , 0 ) ;
1325 HIViewConvertPoint( &hiPoint , HIViewGetSuperview(m_controlRef) , rootControl ) ;
1326 OffsetRect( r , (short) hiPoint.x , (short) hiPoint.y ) ;
1327 }
1328 }
1329
1330 void wxMacControl::GetBestRect( wxRect *rect ) const
1331 {
1332 short baselineoffset;
1333 Rect r = {0,0,0,0};
1334
1335 GetBestControlRect( m_controlRef , &r , &baselineoffset );
1336 *rect = wxRect( r.left, r.top, r.right - r.left, r.bottom-r.top );
1337 }
1338
1339 void wxMacControl::GetBestRect( Rect *r ) const
1340 {
1341 short baselineoffset;
1342 GetBestControlRect( m_controlRef , r , &baselineoffset );
1343 }
1344
1345 void wxMacControl::SetLabel( const wxString &title , wxFontEncoding encoding)
1346 {
1347 SetControlTitleWithCFString( m_controlRef , wxCFStringRef( title , encoding ) );
1348 }
1349
1350 void wxMacControl::GetFeatures( UInt32 * features )
1351 {
1352 GetControlFeatures( m_controlRef , features );
1353 }
1354
1355 OSStatus wxMacControl::GetRegion( ControlPartCode partCode , RgnHandle region )
1356 {
1357 OSStatus err = GetControlRegion( m_controlRef , partCode , region );
1358 return err;
1359 }
1360
1361 void wxMacControl::PulseGauge()
1362 {
1363 }
1364
1365 // SetNeedsDisplay would not invalidate the children
1366 static void InvalidateControlAndChildren( HIViewRef control )
1367 {
1368 HIViewSetNeedsDisplay( control , true );
1369 UInt16 childrenCount = 0;
1370 OSStatus err = CountSubControls( control , &childrenCount );
1371 if ( err == errControlIsNotEmbedder )
1372 return;
1373
1374 wxASSERT_MSG( err == noErr , wxT("Unexpected error when accessing subcontrols") );
1375
1376 for ( UInt16 i = childrenCount; i >=1; --i )
1377 {
1378 HIViewRef child;
1379
1380 err = GetIndexedSubControl( control , i , & child );
1381 if ( err == errControlIsNotEmbedder )
1382 return;
1383
1384 InvalidateControlAndChildren( child );
1385 }
1386 }
1387
1388 void wxMacControl::InvalidateWithChildren()
1389 {
1390 InvalidateControlAndChildren( m_controlRef );
1391 }
1392
1393 OSType wxMacCreator = 'WXMC';
1394 OSType wxMacControlProperty = 'MCCT';
1395
1396 void wxMacControl::SetReferenceInNativeControl()
1397 {
1398 void * data = this;
1399 verify_noerr( SetControlProperty ( m_controlRef ,
1400 wxMacCreator,wxMacControlProperty, sizeof(data), &data ) );
1401 }
1402
1403 wxMacControl* wxMacControl::GetReferenceFromNativeControl(ControlRef control)
1404 {
1405 wxMacControl* ctl = NULL;
1406 ByteCount actualSize;
1407 if ( GetControlProperty( control ,wxMacCreator,wxMacControlProperty, sizeof(ctl) ,
1408 &actualSize , &ctl ) == noErr )
1409 {
1410 return ctl;
1411 }
1412 return NULL;
1413 }
1414
1415 void wxMacControl::SetBitmap( const wxBitmap& WXUNUSED(bmp) )
1416 {
1417 // implemented in the respective subclasses
1418 }
1419
1420 void wxMacControl::SetScrollThumb( wxInt32 WXUNUSED(pos), wxInt32 WXUNUSED(viewsize) )
1421 {
1422 // implemented in respective subclass
1423 }
1424
1425 //
1426 // Tab Control
1427 //
1428
1429 OSStatus wxMacControl::SetTabEnabled( SInt16 tabNo , bool enable )
1430 {
1431 return ::SetTabEnabled( m_controlRef , tabNo , enable );
1432 }
1433
1434
1435
1436 // Control Factory
1437
1438 wxWidgetImplType* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
1439 {
1440 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1441 // the content view, so we have to retrieve it explicitly
1442
1443 wxMacControl* contentview = new wxMacControl(now , true /*isRootControl*/);
1444 HIViewFindByID( HIViewGetRoot( (WindowRef) now->GetWXWindow() ) , kHIViewWindowContentID ,
1445 contentview->GetControlRefAddr() ) ;
1446 if ( !contentview->IsOk() )
1447 {
1448 // compatibility mode fallback
1449 GetRootControl( (WindowRef) now->GetWXWindow() , contentview->GetControlRefAddr() ) ;
1450 }
1451
1452 // the root control level handler
1453 contentview->InstallEventHandler() ;
1454 return contentview;
1455 }