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