conforming to new naming convention of starting all port specific methods with the...
[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 HIShapeRef rgn = NULL;
921 Rect content ;
922
923 if ( HIViewCopyShape(m_controlRef, kHIViewContentMetaPart, &rgn) == noErr)
924 {
925 CGRect cgrect;
926 HIShapeGetBounds(rgn, &cgrect);
927 content = (Rect){ cgrect.origin.y, cgrect.origin.x, cgrect.origin.y+cgrect.size.height, cgrect.origin.x+cgrect.size.width };
928 CFRelease(rgn);
929 }
930 else
931 {
932 GetControlBounds(m_controlRef, &content);
933 content.right -= content.left;
934 content.left = 0;
935 content.bottom -= content.top;
936 content.top = 0;
937 }
938
939 left = content.left;
940 top = content.top;
941
942 width = content.right - content.left ;
943 height = content.bottom - content.top ;
944 }
945
946 void wxMacControl::Move(int x, int y, int width, int height)
947 {
948 HIRect hir = CGRectMake(x,y,width,height);
949 HIViewSetFrame ( m_controlRef , &hir );
950 }
951
952 void wxMacControl::GetPosition( int &x, int &y ) const
953 {
954 Rect r;
955 GetControlBounds( m_controlRef , &r );
956 x = r.left;
957 y = r.top;
958 }
959
960 void wxMacControl::GetSize( int &width, int &height ) const
961 {
962 Rect r;
963 GetControlBounds( m_controlRef , &r );
964 width = r.right - r.left;
965 height = r.bottom - r.top;
966 }
967
968 void wxMacControl::SetControlSize( wxWindowVariant variant )
969 {
970 ControlSize size ;
971 switch ( variant )
972 {
973 case wxWINDOW_VARIANT_NORMAL :
974 size = kControlSizeNormal;
975 break ;
976
977 case wxWINDOW_VARIANT_SMALL :
978 size = kControlSizeSmall;
979 break ;
980
981 case wxWINDOW_VARIANT_MINI :
982 // not always defined in the headers
983 size = 3 ;
984 break ;
985
986 case wxWINDOW_VARIANT_LARGE :
987 size = kControlSizeLarge;
988 break ;
989
990 default:
991 wxFAIL_MSG(_T("unexpected window variant"));
992 break ;
993 }
994
995 SetData<ControlSize>(kControlEntireControl, kControlSizeTag, &size ) ;
996 }
997
998 void wxMacControl::ScrollRect( const wxRect *rect, int dx, int dy )
999 {
1000 if (GetNeedsDisplay() )
1001 {
1002 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
1003 // in case there is already a pending redraw on that area
1004 // either immediate redraw or full invalidate
1005 #if 1
1006 // is the better overall solution, as it does not slow down scrolling
1007 SetNeedsDisplay() ;
1008 #else
1009 // this would be the preferred version for fast drawing controls
1010 HIViewRender(GetControlRef()) ;
1011 #endif
1012 }
1013
1014 // note there currently is a bug in OSX (10.3 +?) which makes inefficient refreshes in case an entire control
1015 // area is scrolled, this does not occur if width and height are 2 pixels less,
1016 // TODO: write optimal workaround
1017
1018 HIRect scrollarea = CGRectMake( rect->x , rect->y , rect->width , rect->height);
1019 HIViewScrollRect ( m_controlRef , &scrollarea , dx ,dy );
1020
1021 #if 0
1022 // this would be the preferred version for fast drawing controls
1023 HIViewRender(GetControlRef()) ;
1024 #endif
1025 }
1026
1027 bool wxMacControl::CanFocus() const
1028 {
1029 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
1030 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
1031 // but the value range is nowhere documented
1032 Boolean keyExistsAndHasValidFormat ;
1033 CFIndex fullKeyboardAccess = CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
1034 kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat );
1035
1036 if ( keyExistsAndHasValidFormat && fullKeyboardAccess > 0 )
1037 {
1038 return true ;
1039 }
1040 else
1041 {
1042 UInt32 features = 0 ;
1043 GetControlFeatures( m_controlRef, &features ) ;
1044
1045 return features & ( kControlSupportsFocus | kControlGetsFocusOnClick ) ;
1046 }
1047 }
1048
1049 bool wxMacControl::GetNeedsDisplay() const
1050 {
1051 return HIViewGetNeedsDisplay( m_controlRef );
1052 }
1053
1054 void wxWidgetImpl::Convert( wxPoint *pt , wxWidgetImpl *from , wxWidgetImpl *to )
1055 {
1056 HIPoint hiPoint;
1057
1058 hiPoint.x = pt->x;
1059 hiPoint.y = pt->y;
1060 HIViewConvertPoint( &hiPoint , (ControlRef) from->GetWXWidget() , (ControlRef) to->GetWXWidget() );
1061 pt->x = (int)hiPoint.x;
1062 pt->y = (int)hiPoint.y;
1063 }
1064
1065 bool wxMacControl::SetFocus()
1066 {
1067 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1068 // we can only leave in case of an error
1069
1070 OSStatus err = SetKeyboardFocus( GetControlOwner( m_controlRef ), m_controlRef, kControlFocusNextPart );
1071 if ( err == errCouldntSetFocus )
1072 return false ;
1073 SetUserFocusWindow(GetControlOwner( m_controlRef ) );
1074
1075 return true;
1076 }
1077
1078 bool wxMacControl::HasFocus() const
1079 {
1080 ControlRef control;
1081 GetKeyboardFocus( GetUserFocusWindow() , &control );
1082 return control == m_controlRef;
1083 }
1084
1085 void wxMacControl::SetCursor(const wxCursor& cursor)
1086 {
1087 wxWindowMac *mouseWin = 0 ;
1088 WindowRef window = GetControlOwner( m_controlRef ) ;
1089
1090 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) window ) ;
1091 if ( tlwwx != NULL )
1092 {
1093 ControlPartCode part ;
1094 ControlRef control ;
1095 Point pt ;
1096 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1097 HIPoint hiPoint ;
1098 HIGetMousePosition(kHICoordSpaceWindow, window, &hiPoint);
1099 pt.h = hiPoint.x;
1100 pt.v = hiPoint.y;
1101 #else
1102 GetGlobalMouse( &pt );
1103 int x = pt.h;
1104 int y = pt.v;
1105 tlwwx->ScreenToClient(&x, &y);
1106 pt.h = x;
1107 pt.v = y;
1108 #endif
1109 control = FindControlUnderMouse( pt , window , &part ) ;
1110 if ( control )
1111 mouseWin = wxFindWindowFromWXWidget( (WXWidget) control ) ;
1112 }
1113
1114 if ( mouseWin == tlwwx && !wxIsBusy() )
1115 cursor.MacInstall() ;
1116 }
1117
1118 void wxMacControl::CaptureMouse()
1119 {
1120 }
1121
1122 void wxMacControl::ReleaseMouse()
1123 {
1124 }
1125
1126 //
1127 // subclass specifics
1128 //
1129
1130 OSStatus wxMacControl::GetData(ControlPartCode inPartCode , ResType inTag , Size inBufferSize , void * inOutBuffer , Size * outActualSize ) const
1131 {
1132 return ::GetControlData( m_controlRef , inPartCode , inTag , inBufferSize , inOutBuffer , outActualSize );
1133 }
1134
1135 OSStatus wxMacControl::GetDataSize(ControlPartCode inPartCode , ResType inTag , Size * outActualSize ) const
1136 {
1137 return ::GetControlDataSize( m_controlRef , inPartCode , inTag , outActualSize );
1138 }
1139
1140 OSStatus wxMacControl::SetData(ControlPartCode inPartCode , ResType inTag , Size inSize , const void * inData)
1141 {
1142 return ::SetControlData( m_controlRef , inPartCode , inTag , inSize , inData );
1143 }
1144
1145 OSStatus wxMacControl::SendEvent( EventRef event , OptionBits inOptions )
1146 {
1147 return SendEventToEventTargetWithOptions( event,
1148 HIObjectGetEventTarget( (HIObjectRef) m_controlRef ), inOptions );
1149 }
1150
1151 OSStatus wxMacControl::SendHICommand( HICommand &command , OptionBits inOptions )
1152 {
1153 wxMacCarbonEvent event( kEventClassCommand , kEventCommandProcess );
1154
1155 event.SetParameter<HICommand>(kEventParamDirectObject,command);
1156
1157 return SendEvent( event , inOptions );
1158 }
1159
1160 OSStatus wxMacControl::SendHICommand( UInt32 commandID , OptionBits inOptions )
1161 {
1162 HICommand command;
1163
1164 memset( &command, 0 , sizeof(command) );
1165 command.commandID = commandID;
1166 return SendHICommand( command , inOptions );
1167 }
1168
1169 void wxMacControl::PerformClick()
1170 {
1171 HIViewSimulateClick (m_controlRef, kControlButtonPart, 0, NULL );
1172 }
1173
1174 wxInt32 wxMacControl::GetValue() const
1175 {
1176 return ::GetControl32BitValue( m_controlRef );
1177 }
1178
1179 wxInt32 wxMacControl::GetMaximum() const
1180 {
1181 return ::GetControl32BitMaximum( m_controlRef );
1182 }
1183
1184 wxInt32 wxMacControl::GetMinimum() const
1185 {
1186 return ::GetControl32BitMinimum( m_controlRef );
1187 }
1188
1189 void wxMacControl::SetValue( wxInt32 v )
1190 {
1191 ::SetControl32BitValue( m_controlRef , v );
1192 }
1193
1194 void wxMacControl::SetMinimum( wxInt32 v )
1195 {
1196 ::SetControl32BitMinimum( m_controlRef , v );
1197 }
1198
1199 void wxMacControl::SetMaximum( wxInt32 v )
1200 {
1201 ::SetControl32BitMaximum( m_controlRef , v );
1202 }
1203
1204 void wxMacControl::SetValueAndRange( SInt32 value , SInt32 minimum , SInt32 maximum )
1205 {
1206 ::SetControl32BitMinimum( m_controlRef , minimum );
1207 ::SetControl32BitMaximum( m_controlRef , maximum );
1208 ::SetControl32BitValue( m_controlRef , value );
1209 }
1210
1211 void wxMacControl::VisibilityChanged(bool WXUNUSED(shown))
1212 {
1213 }
1214
1215 void wxMacControl::SuperChangedPosition()
1216 {
1217 }
1218
1219 void wxMacControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack )
1220 {
1221 m_font = font;
1222 #if wxOSX_USE_CORE_TEXT
1223 if ( UMAGetSystemVersion() >= 0x1050 )
1224 {
1225 HIViewPartCode part = 0;
1226 HIThemeTextHorizontalFlush flush = kHIThemeTextHorizontalFlushDefault;
1227 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1228 flush = kHIThemeTextHorizontalFlushCenter;
1229 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1230 flush = kHIThemeTextHorizontalFlushRight;
1231 HIViewSetTextFont( m_controlRef , part , (CTFontRef) font.OSXGetCTFont() );
1232 HIViewSetTextHorizontalFlush( m_controlRef, part, flush );
1233
1234 if ( foreground != *wxBLACK || ignoreBlack == false )
1235 {
1236 ControlFontStyleRec fontStyle;
1237 foreground.GetRGBColor( &fontStyle.foreColor );
1238 fontStyle.flags = kControlUseForeColorMask;
1239 ::SetControlFontStyle( m_controlRef , &fontStyle );
1240 }
1241 }
1242 #endif
1243 #if wxOSX_USE_ATSU_TEXT
1244 ControlFontStyleRec fontStyle;
1245 if ( font.MacGetThemeFontID() != kThemeCurrentPortFont )
1246 {
1247 switch ( font.MacGetThemeFontID() )
1248 {
1249 case kThemeSmallSystemFont :
1250 fontStyle.font = kControlFontSmallSystemFont;
1251 break;
1252
1253 case 109 : // mini font
1254 fontStyle.font = -5;
1255 break;
1256
1257 case kThemeSystemFont :
1258 fontStyle.font = kControlFontBigSystemFont;
1259 break;
1260
1261 default :
1262 fontStyle.font = kControlFontBigSystemFont;
1263 break;
1264 }
1265
1266 fontStyle.flags = kControlUseFontMask;
1267 }
1268 else
1269 {
1270 fontStyle.font = font.MacGetFontNum();
1271 fontStyle.style = font.MacGetFontStyle();
1272 fontStyle.size = font.GetPointSize();
1273 fontStyle.flags = kControlUseFontMask | kControlUseFaceMask | kControlUseSizeMask;
1274 }
1275
1276 fontStyle.just = teJustLeft;
1277 fontStyle.flags |= kControlUseJustMask;
1278 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1279 fontStyle.just = teJustCenter;
1280 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1281 fontStyle.just = teJustRight;
1282
1283
1284 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1285 // won't get grayed out by the system anymore
1286
1287 if ( foreground != *wxBLACK || ignoreBlack == false )
1288 {
1289 foreground.GetRGBColor( &fontStyle.foreColor );
1290 fontStyle.flags |= kControlUseForeColorMask;
1291 }
1292
1293 ::SetControlFontStyle( m_controlRef , &fontStyle );
1294 #endif
1295 }
1296
1297 void wxMacControl::SetBackgroundColour( const wxColour &WXUNUSED(col) )
1298 {
1299 // HITextViewSetBackgroundColor( m_textView , color );
1300 }
1301
1302 void wxMacControl::SetRange( SInt32 minimum , SInt32 maximum )
1303 {
1304 ::SetControl32BitMinimum( m_controlRef , minimum );
1305 ::SetControl32BitMaximum( m_controlRef , maximum );
1306 }
1307
1308 short wxMacControl::HandleKey( SInt16 keyCode, SInt16 charCode, EventModifiers modifiers )
1309 {
1310 return HandleControlKey( m_controlRef , keyCode , charCode , modifiers );
1311 }
1312
1313 void wxMacControl::SetActionProc( ControlActionUPP actionProc )
1314 {
1315 SetControlAction( m_controlRef , actionProc );
1316 }
1317
1318 SInt32 wxMacControl::GetViewSize() const
1319 {
1320 return GetControlViewSize( m_controlRef );
1321 }
1322
1323 bool wxMacControl::IsVisible() const
1324 {
1325 return IsControlVisible( m_controlRef );
1326 }
1327
1328 void wxMacControl::SetVisibility( bool visible )
1329 {
1330 SetControlVisibility( m_controlRef , visible, true );
1331 }
1332
1333 bool wxMacControl::IsEnabled() const
1334 {
1335 return IsControlEnabled( m_controlRef );
1336 }
1337
1338 bool wxMacControl::IsActive() const
1339 {
1340 return IsControlActive( m_controlRef );
1341 }
1342
1343 void wxMacControl::Enable( bool enable )
1344 {
1345 if ( enable )
1346 EnableControl( m_controlRef );
1347 else
1348 DisableControl( m_controlRef );
1349 }
1350
1351 void wxMacControl::SetDrawingEnabled( bool enable )
1352 {
1353 HIViewSetDrawingEnabled( m_controlRef , enable );
1354 }
1355
1356 void wxMacControl::GetRectInWindowCoords( Rect *r )
1357 {
1358 GetControlBounds( m_controlRef , r ) ;
1359
1360 WindowRef tlwref = GetControlOwner( m_controlRef ) ;
1361
1362 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) tlwref ) ;
1363 if ( tlwwx != NULL )
1364 {
1365 ControlRef rootControl = tlwwx->GetPeer()->GetControlRef() ;
1366 HIPoint hiPoint = CGPointMake( 0 , 0 ) ;
1367 HIViewConvertPoint( &hiPoint , HIViewGetSuperview(m_controlRef) , rootControl ) ;
1368 OffsetRect( r , (short) hiPoint.x , (short) hiPoint.y ) ;
1369 }
1370 }
1371
1372 void wxMacControl::GetBestRect( wxRect *rect ) const
1373 {
1374 short baselineoffset;
1375 Rect r = {0,0,0,0};
1376
1377 GetBestControlRect( m_controlRef , &r , &baselineoffset );
1378 *rect = wxRect( r.left, r.top, r.right - r.left, r.bottom-r.top );
1379 }
1380
1381 void wxMacControl::GetBestRect( Rect *r ) const
1382 {
1383 short baselineoffset;
1384 GetBestControlRect( m_controlRef , r , &baselineoffset );
1385 }
1386
1387 void wxMacControl::SetLabel( const wxString &title , wxFontEncoding encoding)
1388 {
1389 SetControlTitleWithCFString( m_controlRef , wxCFStringRef( title , encoding ) );
1390 }
1391
1392 void wxMacControl::GetFeatures( UInt32 * features )
1393 {
1394 GetControlFeatures( m_controlRef , features );
1395 }
1396
1397 void wxMacControl::PulseGauge()
1398 {
1399 }
1400
1401 // SetNeedsDisplay would not invalidate the children
1402 static void InvalidateControlAndChildren( HIViewRef control )
1403 {
1404 HIViewSetNeedsDisplay( control , true );
1405 UInt16 childrenCount = 0;
1406 OSStatus err = CountSubControls( control , &childrenCount );
1407 if ( err == errControlIsNotEmbedder )
1408 return;
1409
1410 wxASSERT_MSG( err == noErr , wxT("Unexpected error when accessing subcontrols") );
1411
1412 for ( UInt16 i = childrenCount; i >=1; --i )
1413 {
1414 HIViewRef child;
1415
1416 err = GetIndexedSubControl( control , i , & child );
1417 if ( err == errControlIsNotEmbedder )
1418 return;
1419
1420 InvalidateControlAndChildren( child );
1421 }
1422 }
1423
1424 void wxMacControl::InvalidateWithChildren()
1425 {
1426 InvalidateControlAndChildren( m_controlRef );
1427 }
1428
1429 OSType wxMacCreator = 'WXMC';
1430 OSType wxMacControlProperty = 'MCCT';
1431
1432 void wxMacControl::SetReferenceInNativeControl()
1433 {
1434 void * data = this;
1435 verify_noerr( SetControlProperty ( m_controlRef ,
1436 wxMacCreator,wxMacControlProperty, sizeof(data), &data ) );
1437 }
1438
1439 wxMacControl* wxMacControl::GetReferenceFromNativeControl(ControlRef control)
1440 {
1441 wxMacControl* ctl = NULL;
1442 ByteCount actualSize;
1443 if ( GetControlProperty( control ,wxMacCreator,wxMacControlProperty, sizeof(ctl) ,
1444 &actualSize , &ctl ) == noErr )
1445 {
1446 return ctl;
1447 }
1448 return NULL;
1449 }
1450
1451 void wxMacControl::SetBitmap( const wxBitmap& WXUNUSED(bmp) )
1452 {
1453 // implemented in the respective subclasses
1454 }
1455
1456 void wxMacControl::SetScrollThumb( wxInt32 WXUNUSED(pos), wxInt32 WXUNUSED(viewsize) )
1457 {
1458 // implemented in respective subclass
1459 }
1460
1461 //
1462 // Tab Control
1463 //
1464
1465 OSStatus wxMacControl::SetTabEnabled( SInt16 tabNo , bool enable )
1466 {
1467 return ::SetTabEnabled( m_controlRef , tabNo , enable );
1468 }
1469
1470
1471
1472 // Control Factory
1473
1474 wxWidgetImplType* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
1475 {
1476 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1477 // the content view, so we have to retrieve it explicitly
1478
1479 wxMacControl* contentview = new wxMacControl(now , true /*isRootControl*/);
1480 HIViewFindByID( HIViewGetRoot( (WindowRef) now->GetWXWindow() ) , kHIViewWindowContentID ,
1481 contentview->GetControlRefAddr() ) ;
1482 if ( !contentview->IsOk() )
1483 {
1484 // compatibility mode fallback
1485 GetRootControl( (WindowRef) now->GetWXWindow() , contentview->GetControlRefAddr() ) ;
1486 }
1487
1488 // the root control level handler
1489 contentview->InstallEventHandler() ;
1490 return contentview;
1491 }