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