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