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