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