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