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