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