1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/window.cpp
3 // Purpose: wxWindowMac
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
14 #include "wx/window.h"
23 #include "wx/dcclient.h"
24 #include "wx/button.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"
40 #include "wx/tooltip.h"
41 #include "wx/spinctrl.h"
42 #include "wx/geometry.h"
45 #include "wx/listctrl.h"
49 #include "wx/treectrl.h"
57 #include "wx/popupwin.h"
60 #if wxUSE_DRAG_AND_DROP
65 #include "wx/osx/uma.h"
67 #include "wx/osx/private.h"
69 #include <Carbon/Carbon.h>
72 #define MAC_SCROLLBAR_SIZE 15
73 #define MAC_SMALL_SCROLLBAR_SIZE 11
77 #define wxMAC_DEBUG_REDRAW 0
78 #ifndef wxMAC_DEBUG_REDRAW
79 #define wxMAC_DEBUG_REDRAW 0
83 WX_DECLARE_HASH_MAP(WXWidget
, wxWindow
*, wxPointerHash
, wxPointerEqual
, MacControlMap
);
85 static MacControlMap wxWinMacControlList
;
87 wxWindowMac
*wxFindWindowFromWXWidget(WXWidget inControl
)
89 MacControlMap::iterator node
= wxWinMacControlList
.find(inControl
);
91 return (node
== wxWinMacControlList
.end()) ? NULL
: node
->second
;
94 void wxAssociateWindowWithWXWidget(WXWidget inControl
, wxWindow
*control
)
96 // adding NULL ControlRef is (first) surely a result of an error and
97 // (secondly) breaks native event processing
98 wxCHECK_RET( inControl
!= (WXWidget
) NULL
, wxT("attempt to add a NULL WindowRef to window list") );
100 wxWinMacControlList
[inControl
] = control
;
103 void wxRemoveWXWidgetAssociation(wxWindow
*control
)
105 // iterate over all the elements in the class
106 // is the iterator stable ? as we might have two associations pointing to the same wxWindow
107 // we should go on...
113 MacControlMap::iterator it
;
114 for ( it
= wxWinMacControlList
.begin(); it
!= wxWinMacControlList
.end(); ++it
)
116 if ( it
->second
== control
)
118 wxWinMacControlList
.erase(it
);
126 // ---------------------------------------------------------------------------
128 // ---------------------------------------------------------------------------
130 static const EventTypeSpec eventList
[] =
132 { kEventClassCommand
, kEventProcessCommand
} ,
133 { kEventClassCommand
, kEventCommandUpdateStatus
} ,
135 { kEventClassControl
, kEventControlGetClickActivation
} ,
136 { kEventClassControl
, kEventControlHit
} ,
138 { kEventClassTextInput
, kEventTextInputUnicodeForKeyEvent
} ,
139 { kEventClassTextInput
, kEventTextInputUpdateActiveInputArea
} ,
141 { kEventClassControl
, kEventControlDraw
} ,
143 { kEventClassControl
, kEventControlVisibilityChanged
} ,
144 { kEventClassControl
, kEventControlEnabledStateChanged
} ,
145 { kEventClassControl
, kEventControlHiliteChanged
} ,
147 { kEventClassControl
, kEventControlActivate
} ,
148 { kEventClassControl
, kEventControlDeactivate
} ,
150 { kEventClassControl
, kEventControlSetFocusPart
} ,
151 { kEventClassControl
, kEventControlFocusPartChanged
} ,
153 { kEventClassService
, kEventServiceGetTypes
},
154 { kEventClassService
, kEventServiceCopy
},
155 { kEventClassService
, kEventServicePaste
},
157 // { kEventClassControl , kEventControlInvalidateForSizeChange } , // 10.3 only
158 // { kEventClassControl , kEventControlBoundsChanged } ,
161 static pascal OSStatus
wxMacWindowControlEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
163 OSStatus result
= eventNotHandledErr
;
164 static wxWindowMac
* targetFocusWindow
= NULL
;
165 static wxWindowMac
* formerFocusWindow
= NULL
;
167 wxMacCarbonEvent
cEvent( event
) ;
169 ControlRef controlRef
;
170 wxWindowMac
* thisWindow
= (wxWindowMac
*) data
;
172 cEvent
.GetParameter( kEventParamDirectObject
, &controlRef
) ;
174 switch ( GetEventKind( event
) )
176 case kEventControlDraw
:
178 RgnHandle updateRgn
= NULL
;
179 RgnHandle allocatedRgn
= NULL
;
180 wxRegion visRegion
= thisWindow
->MacGetVisibleRegion() ;
182 if ( cEvent
.GetParameter
<RgnHandle
>(kEventParamRgnHandle
, &updateRgn
) != noErr
)
184 HIShapeGetAsQDRgn( visRegion
.GetWXHRGN(), updateRgn
);
188 if ( thisWindow
->MacGetLeftBorderSize() != 0 || thisWindow
->MacGetTopBorderSize() != 0 )
190 // as this update region is in native window locals we must adapt it to wx window local
191 allocatedRgn
= NewRgn() ;
192 CopyRgn( updateRgn
, allocatedRgn
) ;
194 // hide the given region by the new region that must be shifted
195 OffsetRgn( allocatedRgn
, thisWindow
->MacGetLeftBorderSize() , thisWindow
->MacGetTopBorderSize() ) ;
196 updateRgn
= allocatedRgn
;
200 #if wxMAC_DEBUG_REDRAW
201 if ( thisWindow
->MacIsUserPane() )
203 static float color
= 0.5 ;
204 static int channel
= 0 ;
206 CGContextRef cgContext
= cEvent
.GetParameter
<CGContextRef
>(kEventParamCGContextRef
) ;
208 HIViewGetBounds( controlRef
, &bounds
);
209 CGContextSetRGBFillColor( cgContext
, channel
== 0 ? color
: 0.5 ,
210 channel
== 1 ? color
: 0.5 , channel
== 2 ? color
: 0.5 , 1 );
211 CGContextFillRect( cgContext
, bounds
);
224 bool created
= false ;
225 CGContextRef cgContext
= NULL
;
226 OSStatus err
= cEvent
.GetParameter
<CGContextRef
>(kEventParamCGContextRef
, &cgContext
) ;
229 wxFAIL_MSG("Unable to retrieve CGContextRef");
232 thisWindow
->MacSetCGContextRef( cgContext
) ;
235 wxMacCGContextStateSaver
sg( cgContext
) ;
236 CGFloat alpha
= (CGFloat
)1.0 ;
238 wxWindow
* iter
= thisWindow
;
241 alpha
*= (CGFloat
)( iter
->GetTransparent()/255.0 ) ;
242 if ( iter
->IsTopLevel() )
245 iter
= iter
->GetParent() ;
248 CGContextSetAlpha( cgContext
, alpha
) ;
250 if ( thisWindow
->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT
)
253 HIViewGetBounds( controlRef
, &bounds
);
254 CGContextClearRect( cgContext
, bounds
);
259 if ( thisWindow
->MacDoRedraw( updateRgn
, cEvent
.GetTicks() ) )
262 thisWindow
->MacSetCGContextRef( NULL
) ;
266 CGContextRelease( cgContext
) ;
270 DisposeRgn( allocatedRgn
) ;
274 case kEventControlVisibilityChanged
:
275 // we might have two native controls attributed to the same wxWindow instance
276 // eg a scrollview and an embedded textview, make sure we only fire for the 'outer'
277 // control, as otherwise native and wx visibility are different
278 if ( thisWindow
->GetPeer() != NULL
&& thisWindow
->GetPeer()->GetControlRef() == controlRef
)
280 thisWindow
->MacVisibilityChanged() ;
284 case kEventControlEnabledStateChanged
:
285 thisWindow
->MacEnabledStateChanged();
288 case kEventControlHiliteChanged
:
289 thisWindow
->MacHiliteChanged() ;
292 case kEventControlActivate
:
293 case kEventControlDeactivate
:
294 // FIXME: we should have a virtual function for this!
296 if ( thisWindow
->IsKindOf( CLASSINFO( wxTreeCtrl
) ) )
297 thisWindow
->Refresh();
300 if ( thisWindow
->IsKindOf( CLASSINFO( wxListCtrl
) ) )
301 thisWindow
->Refresh();
307 // different handling on OS X
310 case kEventControlFocusPartChanged
:
311 // the event is emulated by wxmac for systems lower than 10.5
313 if ( UMAGetSystemVersion() < 0x1050 )
315 // as it is synthesized here, we have to manually avoid propagation
318 ControlPartCode previousControlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlPreviousPart
, typeControlPartCode
);
319 ControlPartCode currentControlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlCurrentPart
, typeControlPartCode
);
321 if ( thisWindow
->MacGetTopLevelWindow() && thisWindow
->GetPeer()->NeedsFocusRect() )
323 thisWindow
->MacInvalidateBorders();
326 if ( currentControlPart
== 0 )
330 if ( thisWindow
->GetCaret() )
331 thisWindow
->GetCaret()->OnKillFocus();
334 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), wx_static_cast(void*, thisWindow
));
336 // remove this as soon as posting the synthesized event works properly
337 static bool inKillFocusEvent
= false ;
339 if ( !inKillFocusEvent
)
341 inKillFocusEvent
= true ;
342 wxFocusEvent
event( wxEVT_KILL_FOCUS
, thisWindow
->GetId());
343 event
.SetEventObject(thisWindow
);
344 event
.SetWindow(targetFocusWindow
);
345 thisWindow
->HandleWindowEvent(event
) ;
346 inKillFocusEvent
= false ;
347 targetFocusWindow
= NULL
;
350 else if ( previousControlPart
== 0 )
353 // panel wants to track the window which was the last to have focus in it
354 wxLogTrace(_T("Focus"), _T("focus set(%p)"), wx_static_cast(void*, thisWindow
));
355 wxChildFocusEvent
eventFocus((wxWindow
*)thisWindow
);
356 thisWindow
->HandleWindowEvent(eventFocus
);
359 if ( thisWindow
->GetCaret() )
360 thisWindow
->GetCaret()->OnSetFocus();
363 wxFocusEvent
event(wxEVT_SET_FOCUS
, thisWindow
->GetId());
364 event
.SetEventObject(thisWindow
);
365 event
.SetWindow(formerFocusWindow
);
366 thisWindow
->HandleWindowEvent(event
) ;
367 formerFocusWindow
= NULL
;
371 case kEventControlSetFocusPart
:
373 Boolean focusEverything
= false ;
374 if ( cEvent
.GetParameter
<Boolean
>(kEventParamControlFocusEverything
, &focusEverything
) == noErr
)
376 // put a breakpoint here to catch focus everything events
378 ControlPartCode controlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlPart
, typeControlPartCode
);
379 if ( controlPart
!= kControlFocusNoPart
)
381 targetFocusWindow
= thisWindow
;
382 wxLogTrace(_T("Focus"), _T("focus to be set(%p)"), wx_static_cast(void*, thisWindow
));
386 formerFocusWindow
= thisWindow
;
387 wxLogTrace(_T("Focus"), _T("focus to be lost(%p)"), wx_static_cast(void*, thisWindow
));
390 ControlPartCode previousControlPart
= 0;
391 verify_noerr( HIViewGetFocusPart(controlRef
, &previousControlPart
));
393 if ( thisWindow
->MacIsUserPane() )
395 if ( controlPart
!= kControlFocusNoPart
)
396 cEvent
.SetParameter
<ControlPartCode
>( kEventParamControlPart
, typeControlPartCode
, 1 ) ;
400 result
= CallNextEventHandler(handler
, event
);
402 if ( UMAGetSystemVersion() < 0x1050 )
404 // set back to 0 if problems arise
406 if ( result
== noErr
)
408 ControlPartCode currentControlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlPart
, typeControlPartCode
);
409 // synthesize the event focus changed event
410 EventRef evRef
= NULL
;
412 OSStatus err
= MacCreateEvent(
413 NULL
, kEventClassControl
, kEventControlFocusPartChanged
, TicksToEventTime( TickCount() ) ,
414 kEventAttributeUserEvent
, &evRef
);
417 wxMacCarbonEvent
iEvent( evRef
) ;
418 iEvent
.SetParameter
<ControlRef
>( kEventParamDirectObject
, controlRef
);
419 iEvent
.SetParameter
<EventTargetRef
>( kEventParamPostTarget
, typeEventTargetRef
, GetControlEventTarget( controlRef
) );
420 iEvent
.SetParameter
<ControlPartCode
>( kEventParamControlPreviousPart
, typeControlPartCode
, previousControlPart
);
421 iEvent
.SetParameter
<ControlPartCode
>( kEventParamControlCurrentPart
, typeControlPartCode
, currentControlPart
);
424 // TODO test this first, avoid double posts etc...
425 PostEventToQueue( GetMainEventQueue(), evRef
, kEventPriorityHigh
);
427 wxMacWindowControlEventHandler( NULL
, evRef
, data
) ;
429 ReleaseEvent( evRef
) ;
432 // old implementation, to be removed if the new one works
433 if ( controlPart
== kControlFocusNoPart
)
436 if ( thisWindow
->GetCaret() )
437 thisWindow
->GetCaret()->OnKillFocus();
440 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), wx_static_cast(void*, thisWindow
));
442 static bool inKillFocusEvent
= false ;
444 if ( !inKillFocusEvent
)
446 inKillFocusEvent
= true ;
447 wxFocusEvent
event( wxEVT_KILL_FOCUS
, thisWindow
->GetId());
448 event
.SetEventObject(thisWindow
);
449 thisWindow
->HandleWindowEvent(event
) ;
450 inKillFocusEvent
= false ;
455 // panel wants to track the window which was the last to have focus in it
456 wxLogTrace(_T("Focus"), _T("focus set(%p)"), wx_static_cast(void*, thisWindow
));
457 wxChildFocusEvent
eventFocus((wxWindow
*)thisWindow
);
458 thisWindow
->HandleWindowEvent(eventFocus
);
461 if ( thisWindow
->GetCaret() )
462 thisWindow
->GetCaret()->OnSetFocus();
465 wxFocusEvent
event(wxEVT_SET_FOCUS
, thisWindow
->GetId());
466 event
.SetEventObject(thisWindow
);
467 thisWindow
->HandleWindowEvent(event
) ;
474 case kEventControlHit
:
475 result
= thisWindow
->MacControlHit( handler
, event
) ;
478 case kEventControlGetClickActivation
:
480 // fix to always have a proper activation for DataBrowser controls (stay in bkgnd otherwise)
481 WindowRef owner
= cEvent
.GetParameter
<WindowRef
>(kEventParamWindowRef
);
482 if ( !IsWindowActive(owner
) )
484 cEvent
.SetParameter(kEventParamClickActivation
,typeClickActivationResult
, (UInt32
) kActivateAndIgnoreClick
) ;
497 static pascal OSStatus
498 wxMacWindowServiceEventHandler(EventHandlerCallRef
WXUNUSED(handler
),
502 OSStatus result
= eventNotHandledErr
;
504 wxMacCarbonEvent
cEvent( event
) ;
506 ControlRef controlRef
;
507 wxWindowMac
* thisWindow
= (wxWindowMac
*) data
;
508 wxTextCtrl
* textCtrl
= wxDynamicCast( thisWindow
, wxTextCtrl
) ;
509 cEvent
.GetParameter( kEventParamDirectObject
, &controlRef
) ;
511 switch ( GetEventKind( event
) )
513 case kEventServiceGetTypes
:
517 textCtrl
->GetSelection( &from
, &to
) ;
519 CFMutableArrayRef copyTypes
= 0 , pasteTypes
= 0;
521 copyTypes
= cEvent
.GetParameter
< CFMutableArrayRef
>( kEventParamServiceCopyTypes
, typeCFMutableArrayRef
) ;
522 if ( textCtrl
->IsEditable() )
523 pasteTypes
= cEvent
.GetParameter
< CFMutableArrayRef
>( kEventParamServicePasteTypes
, typeCFMutableArrayRef
) ;
525 static const OSType textDataTypes
[] = { kTXNTextData
/* , 'utxt', 'PICT', 'MooV', 'AIFF' */ };
526 for ( size_t i
= 0 ; i
< WXSIZEOF(textDataTypes
) ; ++i
)
528 CFStringRef typestring
= CreateTypeStringWithOSType(textDataTypes
[i
]);
532 CFArrayAppendValue(copyTypes
, typestring
) ;
534 CFArrayAppendValue(pasteTypes
, typestring
) ;
536 CFRelease( typestring
) ;
544 case kEventServiceCopy
:
549 textCtrl
->GetSelection( &from
, &to
) ;
550 wxString val
= textCtrl
->GetValue() ;
551 val
= val
.Mid( from
, to
- from
) ;
552 PasteboardRef pasteboard
= cEvent
.GetParameter
<PasteboardRef
>( kEventParamPasteboardRef
, typePasteboardRef
);
553 verify_noerr( PasteboardClear( pasteboard
) ) ;
554 PasteboardSynchronize( pasteboard
);
555 // TODO add proper conversion
556 CFDataRef data
= CFDataCreate( kCFAllocatorDefault
, (const UInt8
*)val
.c_str(), val
.length() );
557 PasteboardPutItemFlavor( pasteboard
, (PasteboardItemID
) 1, CFSTR("com.apple.traditional-mac-plain-text"), data
, 0);
563 case kEventServicePaste
:
566 PasteboardRef pasteboard
= cEvent
.GetParameter
<PasteboardRef
>( kEventParamPasteboardRef
, typePasteboardRef
);
567 PasteboardSynchronize( pasteboard
);
569 verify_noerr( PasteboardGetItemCount( pasteboard
, &itemCount
) );
570 for( UInt32 itemIndex
= 1; itemIndex
<= itemCount
; itemIndex
++ )
572 PasteboardItemID itemID
;
573 if ( PasteboardGetItemIdentifier( pasteboard
, itemIndex
, &itemID
) == noErr
)
575 CFDataRef flavorData
= NULL
;
576 if ( PasteboardCopyItemFlavorData( pasteboard
, itemID
, CFSTR("com.apple.traditional-mac-plain-text"), &flavorData
) == noErr
)
578 CFIndex flavorDataSize
= CFDataGetLength( flavorData
);
579 char *content
= new char[flavorDataSize
+1] ;
580 memcpy( content
, CFDataGetBytePtr( flavorData
), flavorDataSize
);
581 content
[flavorDataSize
]=0;
582 CFRelease( flavorData
);
584 textCtrl
->WriteText( wxString( content
, wxConvLocal
) );
586 textCtrl
->WriteText( wxString( content
) ) ;
604 pascal OSStatus
wxMacUnicodeTextEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
606 OSStatus result
= eventNotHandledErr
;
607 wxWindowMac
* focus
= (wxWindowMac
*) data
;
609 wchar_t* uniChars
= NULL
;
610 UInt32 when
= EventTimeToTicks( GetEventTime( event
) ) ;
612 UniChar
* charBuf
= NULL
;
613 ByteCount dataSize
= 0 ;
616 if ( GetEventParameter( event
, kEventParamTextInputSendText
, typeUnicodeText
, NULL
, 0 , &dataSize
, NULL
) == noErr
)
618 numChars
= dataSize
/ sizeof( UniChar
) + 1;
621 if ( (size_t) numChars
* 2 > sizeof(buf
) )
622 charBuf
= new UniChar
[ numChars
] ;
626 uniChars
= new wchar_t[ numChars
] ;
627 GetEventParameter( event
, kEventParamTextInputSendText
, typeUnicodeText
, NULL
, dataSize
, NULL
, charBuf
) ;
628 charBuf
[ numChars
- 1 ] = 0;
629 #if SIZEOF_WCHAR_T == 2
630 uniChars
= (wchar_t*) charBuf
;
631 /* 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...)
633 // the resulting string will never have more chars than the utf16 version, so this is safe
634 wxMBConvUTF16 converter
;
635 numChars
= converter
.MB2WC( uniChars
, (const char*)charBuf
, numChars
) ;
639 switch ( GetEventKind( event
) )
641 case kEventTextInputUpdateActiveInputArea
:
643 // An IME input event may return several characters, but we need to send one char at a time to
645 for (int pos
=0 ; pos
< numChars
; pos
++)
647 WXEVENTREF formerEvent
= wxTheApp
->MacGetCurrentEvent() ;
648 WXEVENTHANDLERCALLREF formerHandler
= wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
649 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
651 UInt32 message
= uniChars
[pos
] < 128 ? (char)uniChars
[pos
] : '?';
653 NB: faking a charcode here is problematic. The kEventTextInputUpdateActiveInputArea event is sent
654 multiple times to update the active range during inline input, so this handler will often receive
655 uncommited text, which should usually not trigger side effects. It might be a good idea to check the
656 kEventParamTextInputSendFixLen parameter and verify if input is being confirmed (see CarbonEvents.h).
657 On the other hand, it can be useful for some applications to react to uncommitted text (for example,
658 to update a status display), as long as it does not disrupt the inline input session. Ideally, wx
659 should add new event types to support advanced text input. For now, I would keep things as they are.
661 However, the code that was being used caused additional problems:
662 UInt32 message = (0 << 8) + ((char)uniChars[pos] );
663 Since it simply truncated the unichar to the last byte, it ended up causing weird bugs with inline
664 input, such as switching to another field when one attempted to insert the character U+4E09 (the kanji
665 for "three"), because it was truncated to 09 (kTabCharCode), which was later "converted" to WXK_TAB
666 (still 09) in wxMacTranslateKey; or triggering the default button when one attempted to insert U+840D
667 (the kanji for "name"), which got truncated to 0D and interpreted as a carriage return keypress.
668 Note that even single-byte characters could have been misinterpreted, since MacRoman charcodes only
669 overlap with Unicode within the (7-bit) ASCII range.
670 But simply passing a NUL charcode would disable text updated events, because wxTextCtrl::OnChar checks
671 for codes within a specific range. Therefore I went for the solution seen above, which keeps ASCII
672 characters as they are and replaces the rest with '?', ensuring that update events are triggered.
673 It would be better to change wxTextCtrl::OnChar to look at the actual unicode character instead, but
674 I don't have time to look into that right now.
677 if ( wxTheApp
->MacSendCharEvent(
678 focus
, message
, 0 , when
, 0 , 0 , uniChars
[pos
] ) )
683 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerHandler
) ;
687 case kEventTextInputUnicodeForKeyEvent
:
689 UInt32 keyCode
, modifiers
;
692 unsigned char charCode
;
694 GetEventParameter( event
, kEventParamTextInputSendKeyboardEvent
, typeEventRef
, NULL
, sizeof(rawEvent
), NULL
, &rawEvent
) ;
695 GetEventParameter( rawEvent
, kEventParamKeyMacCharCodes
, typeChar
, NULL
, sizeof(char), NULL
, &charCode
);
696 GetEventParameter( rawEvent
, kEventParamKeyCode
, typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
697 GetEventParameter( rawEvent
, kEventParamKeyModifiers
, typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &modifiers
);
698 GetEventParameter( rawEvent
, kEventParamMouseLocation
, typeQDPoint
, NULL
, sizeof(Point
), NULL
, &point
);
700 UInt32 message
= (keyCode
<< 8) + charCode
;
702 // An IME input event may return several characters, but we need to send one char at a time to
704 for (int pos
=0 ; pos
< numChars
; pos
++)
706 WXEVENTREF formerEvent
= wxTheApp
->MacGetCurrentEvent() ;
707 WXEVENTHANDLERCALLREF formerHandler
= wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
708 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
710 if ( wxTheApp
->MacSendCharEvent(
711 focus
, message
, modifiers
, when
, point
.h
, point
.v
, uniChars
[pos
] ) )
716 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerHandler
) ;
725 if ( charBuf
!= buf
)
731 static pascal OSStatus
732 wxMacWindowCommandEventHandler(EventHandlerCallRef
WXUNUSED(handler
),
736 OSStatus result
= eventNotHandledErr
;
737 wxWindowMac
* focus
= (wxWindowMac
*) data
;
741 wxMacCarbonEvent
cEvent( event
) ;
742 cEvent
.GetParameter
<HICommand
>(kEventParamDirectObject
,typeHICommand
,&command
) ;
744 wxMenuItem
* item
= NULL
;
745 wxMenu
* itemMenu
= wxFindMenuFromMacCommand( command
, item
) ;
749 wxASSERT( itemMenu
!= NULL
) ;
751 switch ( cEvent
.GetKind() )
753 case kEventProcessCommand
:
754 if ( itemMenu
->HandleCommandProcess( item
, focus
) )
758 case kEventCommandUpdateStatus
:
759 if ( itemMenu
->HandleCommandUpdateStatus( item
, focus
) )
770 pascal OSStatus
wxMacWindowEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
772 EventRef formerEvent
= (EventRef
) wxTheApp
->MacGetCurrentEvent() ;
773 EventHandlerCallRef formerEventHandlerCallRef
= (EventHandlerCallRef
) wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
774 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
775 OSStatus result
= eventNotHandledErr
;
777 switch ( GetEventClass( event
) )
779 case kEventClassCommand
:
780 result
= wxMacWindowCommandEventHandler( handler
, event
, data
) ;
783 case kEventClassControl
:
784 result
= wxMacWindowControlEventHandler( handler
, event
, data
) ;
787 case kEventClassService
:
788 result
= wxMacWindowServiceEventHandler( handler
, event
, data
) ;
791 case kEventClassTextInput
:
792 result
= wxMacUnicodeTextEventHandler( handler
, event
, data
) ;
799 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerEventHandlerCallRef
) ;
804 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacWindowEventHandler
)
806 // ---------------------------------------------------------------------------
807 // Scrollbar Tracking for all
808 // ---------------------------------------------------------------------------
810 pascal void wxMacLiveScrollbarActionProc( ControlRef control
, ControlPartCode partCode
) ;
811 pascal void wxMacLiveScrollbarActionProc( ControlRef control
, ControlPartCode partCode
)
815 wxWindow
* wx
= wxFindWindowFromWXWidget( (WXWidget
) control
) ;
817 wx
->MacHandleControlClick( (WXWidget
) control
, partCode
, true /* stillDown */ ) ;
820 wxMAC_DEFINE_PROC_GETTER( ControlActionUPP
, wxMacLiveScrollbarActionProc
) ;
822 wxWidgetImplType
* wxWidgetImpl::CreateUserPane( wxWindowMac
* wxpeer
, wxWindowMac
* parent
, wxWindowID id
, const wxPoint
& pos
, const wxSize
& size
,
823 long style
, long extraStyle
)
825 OSStatus err
= noErr
;
826 Rect bounds
= wxMacGetBoundsForControl( wxpeer
, pos
, size
) ;
827 wxMacControl
* c
= new wxMacControl(wxpeer
) ;
829 | kControlSupportsEmbedding
830 | kControlSupportsLiveFeedback
831 | kControlGetsFocusOnClick
832 // | kControlHasSpecialBackground
833 // | kControlSupportsCalcBestRect
834 | kControlHandlesTracking
835 | kControlSupportsFocus
836 | kControlWantsActivate
837 | kControlWantsIdle
;
839 err
=::CreateUserPaneControl( MAC_WXHWND(wxpeer
->GetParent()->MacGetTopLevelWindowRef()) , &bounds
, features
, c
->GetControlRefAddr() );
845 void wxMacControl::MacInstallEventHandler( ControlRef control
, wxWindowMac
* wxPeer
)
847 wxAssociateWindowWithWXWidget( (WXWidget
) control
, wxPeer
) ;
848 ::InstallControlEventHandler( control
, GetwxMacWindowEventHandlerUPP(),
849 GetEventTypeCount(eventList
), eventList
, wxPeer
, NULL
);
852 IMPLEMENT_DYNAMIC_CLASS( wxMacControl
, wxWidgetImpl
)
854 wxMacControl::wxMacControl()
859 wxMacControl::wxMacControl(wxWindowMac
* peer
, bool isRootControl
) :
860 wxWidgetImpl( peer
, isRootControl
)
865 wxMacControl::~wxMacControl()
867 if ( m_controlRef
&& !IsRootControl() )
869 wxASSERT_MSG( m_controlRef
!= NULL
, wxT("Control Handle already NULL, Dispose called twice ?") );
870 wxASSERT_MSG( IsValidControlHandle(m_controlRef
) , wxT("Invalid Control Handle (maybe already released) in Dispose") );
872 wxRemoveWXWidgetAssociation( m_wxPeer
) ;
873 // we cannot check the ref count here anymore, as autorelease objects might delete their refs later
874 // we can have situations when being embedded, where the control gets deleted behind our back, so only
875 // CFRelease if we are safe
876 if ( IsValidControlHandle(m_controlRef
) )
877 CFRelease(m_controlRef
);
882 void wxMacControl::Init()
885 m_macControlEventHandler
= NULL
;
888 void wxMacControl::SetReference( URefCon data
)
890 SetControlReference( m_controlRef
, data
);
893 void wxMacControl::RemoveFromParent()
895 // nothing to do here for carbon
898 void wxMacControl::Embed( wxWidgetImpl
*parent
)
900 // copied from MacPostControlCreate
901 ControlRef container
= (ControlRef
) parent
->GetWXWidget() ;
902 wxASSERT_MSG( container
!= NULL
, wxT("No valid mac container control") ) ;
903 ::EmbedControl( m_controlRef
, container
) ;
906 void wxMacControl::SetNeedsDisplay( const wxRect
* rect
)
913 HIRect updatearea
= CGRectMake( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
914 HIViewSetNeedsDisplayInRect( m_controlRef
, &updatearea
, true );
917 HIViewSetNeedsDisplay( m_controlRef
, true );
920 void wxMacControl::Raise()
922 verify_noerr( HIViewSetZOrder( m_controlRef
, kHIViewZOrderAbove
, NULL
) );
925 void wxMacControl::Lower()
927 verify_noerr( HIViewSetZOrder( m_controlRef
, kHIViewZOrderBelow
, NULL
) );
930 void wxMacControl::GetContentArea(int &left
, int &top
, int &width
, int &height
) const
932 RgnHandle rgn
= NewRgn() ;
934 if ( GetControlRegion( m_controlRef
, kControlContentMetaPart
, rgn
) == noErr
)
935 GetRegionBounds( rgn
, &content
) ;
938 GetControlBounds( m_controlRef
, &content
);
939 content
.right
-= content
.left
;
941 content
.bottom
-= content
.top
;
949 width
= content
.right
- content
.left
;
950 height
= content
.bottom
- content
.top
;
953 void wxMacControl::Move(int x
, int y
, int width
, int height
)
955 HIRect hir
= CGRectMake(x
,y
,width
,height
);
956 HIViewSetFrame ( m_controlRef
, &hir
);
959 void wxMacControl::GetPosition( int &x
, int &y
) const
962 GetControlBounds( m_controlRef
, &r
);
967 void wxMacControl::GetSize( int &width
, int &height
) const
970 GetControlBounds( m_controlRef
, &r
);
971 width
= r
.right
- r
.left
;
972 height
= r
.bottom
- r
.top
;
975 void wxMacControl::SetControlSize( wxWindowVariant variant
)
980 case wxWINDOW_VARIANT_NORMAL
:
981 size
= kControlSizeNormal
;
984 case wxWINDOW_VARIANT_SMALL
:
985 size
= kControlSizeSmall
;
988 case wxWINDOW_VARIANT_MINI
:
989 // not always defined in the headers
993 case wxWINDOW_VARIANT_LARGE
:
994 size
= kControlSizeLarge
;
998 wxFAIL_MSG(_T("unexpected window variant"));
1002 SetData
<ControlSize
>(kControlEntireControl
, kControlSizeTag
, &size
) ;
1005 void wxMacControl::ScrollRect( const wxRect
*rect
, int dx
, int dy
)
1007 if (GetNeedsDisplay() )
1009 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
1010 // in case there is already a pending redraw on that area
1011 // either immediate redraw or full invalidate
1013 // is the better overall solution, as it does not slow down scrolling
1016 // this would be the preferred version for fast drawing controls
1017 HIViewRender(GetControlRef()) ;
1021 // note there currently is a bug in OSX (10.3 +?) which makes inefficient refreshes in case an entire control
1022 // area is scrolled, this does not occur if width and height are 2 pixels less,
1023 // TODO: write optimal workaround
1025 HIRect scrollarea
= CGRectMake( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
1026 HIViewScrollRect ( m_controlRef
, &scrollarea
, dx
,dy
);
1029 // this would be the preferred version for fast drawing controls
1030 HIViewRender(GetControlRef()) ;
1034 bool wxMacControl::CanFocus() const
1036 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
1037 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
1038 // but the value range is nowhere documented
1039 Boolean keyExistsAndHasValidFormat
;
1040 CFIndex fullKeyboardAccess
= CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
1041 kCFPreferencesCurrentApplication
, &keyExistsAndHasValidFormat
);
1043 if ( keyExistsAndHasValidFormat
&& fullKeyboardAccess
> 0 )
1049 UInt32 features
= 0 ;
1050 GetControlFeatures( m_controlRef
, &features
) ;
1052 return features
& ( kControlSupportsFocus
| kControlGetsFocusOnClick
) ;
1056 bool wxMacControl::GetNeedsDisplay() const
1058 return HIViewGetNeedsDisplay( m_controlRef
);
1061 void wxWidgetImpl::Convert( wxPoint
*pt
, wxWidgetImpl
*from
, wxWidgetImpl
*to
)
1067 HIViewConvertPoint( &hiPoint
, (ControlRef
) from
->GetWXWidget() , (ControlRef
) to
->GetWXWidget() );
1068 pt
->x
= (int)hiPoint
.x
;
1069 pt
->y
= (int)hiPoint
.y
;
1072 bool wxMacControl::SetFocus()
1074 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1075 // we can only leave in case of an error
1077 OSStatus err
= SetKeyboardFocus( GetControlOwner( m_controlRef
), m_controlRef
, kControlFocusNextPart
);
1078 if ( err
== errCouldntSetFocus
)
1080 SetUserFocusWindow(GetControlOwner( m_controlRef
) );
1085 bool wxMacControl::HasFocus() const
1088 GetKeyboardFocus( GetUserFocusWindow() , &control
);
1089 return control
== m_controlRef
;
1093 // subclass specifics
1096 OSStatus
wxMacControl::GetData(ControlPartCode inPartCode
, ResType inTag
, Size inBufferSize
, void * inOutBuffer
, Size
* outActualSize
) const
1098 return ::GetControlData( m_controlRef
, inPartCode
, inTag
, inBufferSize
, inOutBuffer
, outActualSize
);
1101 OSStatus
wxMacControl::GetDataSize(ControlPartCode inPartCode
, ResType inTag
, Size
* outActualSize
) const
1103 return ::GetControlDataSize( m_controlRef
, inPartCode
, inTag
, outActualSize
);
1106 OSStatus
wxMacControl::SetData(ControlPartCode inPartCode
, ResType inTag
, Size inSize
, const void * inData
)
1108 return ::SetControlData( m_controlRef
, inPartCode
, inTag
, inSize
, inData
);
1111 OSStatus
wxMacControl::SendEvent( EventRef event
, OptionBits inOptions
)
1113 return SendEventToEventTargetWithOptions( event
,
1114 HIObjectGetEventTarget( (HIObjectRef
) m_controlRef
), inOptions
);
1117 OSStatus
wxMacControl::SendHICommand( HICommand
&command
, OptionBits inOptions
)
1119 wxMacCarbonEvent
event( kEventClassCommand
, kEventCommandProcess
);
1121 event
.SetParameter
<HICommand
>(kEventParamDirectObject
,command
);
1123 return SendEvent( event
, inOptions
);
1126 OSStatus
wxMacControl::SendHICommand( UInt32 commandID
, OptionBits inOptions
)
1130 memset( &command
, 0 , sizeof(command
) );
1131 command
.commandID
= commandID
;
1132 return SendHICommand( command
, inOptions
);
1135 void wxMacControl::PerformClick()
1137 HIViewSimulateClick (m_controlRef
, kControlButtonPart
, 0, NULL
);
1140 wxInt32
wxMacControl::GetValue() const
1142 return ::GetControl32BitValue( m_controlRef
);
1145 SInt32
wxMacControl::GetMaximum() const
1147 return ::GetControl32BitMaximum( m_controlRef
);
1151 wxInt32 wxMacControl::GetMinimum() const
1153 return ::GetControl32BitMinimum( m_controlRef );
1157 void wxMacControl::SetValue( wxInt32 v
)
1159 ::SetControl32BitValue( m_controlRef
, v
);
1162 void wxMacControl::SetMinimum( wxInt32 v
)
1164 ::SetControl32BitMinimum( m_controlRef
, v
);
1167 void wxMacControl::SetMaximum( wxInt32 v
)
1169 ::SetControl32BitMaximum( m_controlRef
, v
);
1172 void wxMacControl::SetValueAndRange( SInt32 value
, SInt32 minimum
, SInt32 maximum
)
1174 ::SetControl32BitMinimum( m_controlRef
, minimum
);
1175 ::SetControl32BitMaximum( m_controlRef
, maximum
);
1176 ::SetControl32BitValue( m_controlRef
, value
);
1179 void wxMacControl::VisibilityChanged(bool WXUNUSED(shown
))
1183 void wxMacControl::SuperChangedPosition()
1187 void wxMacControl::SetFont( const wxFont
& font
, const wxColour
& foreground
, long windowStyle
, bool ignoreBlack
)
1190 #if wxOSX_USE_CORE_TEXT
1191 if ( UMAGetSystemVersion() >= 0x1050 )
1193 HIViewPartCode part
= 0;
1194 HIThemeTextHorizontalFlush flush
= kHIThemeTextHorizontalFlushDefault
;
1195 if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_CENTER_HORIZONTAL
)
1196 flush
= kHIThemeTextHorizontalFlushCenter
;
1197 else if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_RIGHT
)
1198 flush
= kHIThemeTextHorizontalFlushRight
;
1199 HIViewSetTextFont( m_controlRef
, part
, (CTFontRef
) font
.MacGetCTFont() );
1200 HIViewSetTextHorizontalFlush( m_controlRef
, part
, flush
);
1202 if ( foreground
!= *wxBLACK
|| ignoreBlack
== false )
1204 ControlFontStyleRec fontStyle
;
1205 foreground
.GetRGBColor( &fontStyle
.foreColor
);
1206 fontStyle
.flags
= kControlUseForeColorMask
;
1207 ::SetControlFontStyle( m_controlRef
, &fontStyle
);
1211 #if wxOSX_USE_ATSU_TEXT
1212 ControlFontStyleRec fontStyle
;
1213 if ( font
.MacGetThemeFontID() != kThemeCurrentPortFont
)
1215 switch ( font
.MacGetThemeFontID() )
1217 case kThemeSmallSystemFont
:
1218 fontStyle
.font
= kControlFontSmallSystemFont
;
1221 case 109 : // mini font
1222 fontStyle
.font
= -5;
1225 case kThemeSystemFont
:
1226 fontStyle
.font
= kControlFontBigSystemFont
;
1230 fontStyle
.font
= kControlFontBigSystemFont
;
1234 fontStyle
.flags
= kControlUseFontMask
;
1238 fontStyle
.font
= font
.MacGetFontNum();
1239 fontStyle
.style
= font
.MacGetFontStyle();
1240 fontStyle
.size
= font
.MacGetFontSize();
1241 fontStyle
.flags
= kControlUseFontMask
| kControlUseFaceMask
| kControlUseSizeMask
;
1244 fontStyle
.just
= teJustLeft
;
1245 fontStyle
.flags
|= kControlUseJustMask
;
1246 if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_CENTER_HORIZONTAL
)
1247 fontStyle
.just
= teJustCenter
;
1248 else if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_RIGHT
)
1249 fontStyle
.just
= teJustRight
;
1252 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1253 // won't get grayed out by the system anymore
1255 if ( foreground
!= *wxBLACK
|| ignoreBlack
== false )
1257 foreground
.GetRGBColor( &fontStyle
.foreColor
);
1258 fontStyle
.flags
|= kControlUseForeColorMask
;
1261 ::SetControlFontStyle( m_controlRef
, &fontStyle
);
1265 void wxMacControl::SetBackgroundColour( const wxColour
&WXUNUSED(col
) )
1267 // HITextViewSetBackgroundColor( m_textView , color );
1270 void wxMacControl::SetRange( SInt32 minimum
, SInt32 maximum
)
1272 ::SetControl32BitMinimum( m_controlRef
, minimum
);
1273 ::SetControl32BitMaximum( m_controlRef
, maximum
);
1276 short wxMacControl::HandleKey( SInt16 keyCode
, SInt16 charCode
, EventModifiers modifiers
)
1278 return HandleControlKey( m_controlRef
, keyCode
, charCode
, modifiers
);
1281 void wxMacControl::SetActionProc( ControlActionUPP actionProc
)
1283 SetControlAction( m_controlRef
, actionProc
);
1286 SInt32
wxMacControl::GetViewSize() const
1288 return GetControlViewSize( m_controlRef
);
1291 bool wxMacControl::IsVisible() const
1293 return IsControlVisible( m_controlRef
);
1296 void wxMacControl::SetVisibility( bool visible
)
1298 SetControlVisibility( m_controlRef
, visible
, true );
1301 bool wxMacControl::IsEnabled() const
1303 return IsControlEnabled( m_controlRef
);
1306 bool wxMacControl::IsActive() const
1308 return IsControlActive( m_controlRef
);
1311 void wxMacControl::Enable( bool enable
)
1314 EnableControl( m_controlRef
);
1316 DisableControl( m_controlRef
);
1319 void wxMacControl::SetDrawingEnabled( bool enable
)
1321 HIViewSetDrawingEnabled( m_controlRef
, enable
);
1324 void wxMacControl::GetRectInWindowCoords( Rect
*r
)
1326 GetControlBounds( m_controlRef
, r
) ;
1328 WindowRef tlwref
= GetControlOwner( m_controlRef
) ;
1330 wxNonOwnedWindow
* tlwwx
= wxNonOwnedWindow::GetFromWXWindow( (WXWindow
) tlwref
) ;
1331 if ( tlwwx
!= NULL
)
1333 ControlRef rootControl
= tlwwx
->GetPeer()->GetControlRef() ;
1334 HIPoint hiPoint
= CGPointMake( 0 , 0 ) ;
1335 HIViewConvertPoint( &hiPoint
, HIViewGetSuperview(m_controlRef
) , rootControl
) ;
1336 OffsetRect( r
, (short) hiPoint
.x
, (short) hiPoint
.y
) ;
1340 void wxMacControl::GetBestRect( wxRect
*rect
) const
1342 short baselineoffset
;
1345 GetBestControlRect( m_controlRef
, &r
, &baselineoffset
);
1346 *rect
= wxRect( r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
-r
.top
);
1349 void wxMacControl::GetBestRect( Rect
*r
) const
1351 short baselineoffset
;
1352 GetBestControlRect( m_controlRef
, r
, &baselineoffset
);
1355 void wxMacControl::SetLabel( const wxString
&title
, wxFontEncoding encoding
)
1357 SetControlTitleWithCFString( m_controlRef
, wxCFStringRef( title
, encoding
) );
1360 void wxMacControl::GetFeatures( UInt32
* features
)
1362 GetControlFeatures( m_controlRef
, features
);
1365 OSStatus
wxMacControl::GetRegion( ControlPartCode partCode
, RgnHandle region
)
1367 OSStatus err
= GetControlRegion( m_controlRef
, partCode
, region
);
1371 void wxMacControl::PulseGauge()
1375 // SetNeedsDisplay would not invalidate the children
1376 static void InvalidateControlAndChildren( HIViewRef control
)
1378 HIViewSetNeedsDisplay( control
, true );
1379 UInt16 childrenCount
= 0;
1380 OSStatus err
= CountSubControls( control
, &childrenCount
);
1381 if ( err
== errControlIsNotEmbedder
)
1384 wxASSERT_MSG( err
== noErr
, wxT("Unexpected error when accessing subcontrols") );
1386 for ( UInt16 i
= childrenCount
; i
>=1; --i
)
1390 err
= GetIndexedSubControl( control
, i
, & child
);
1391 if ( err
== errControlIsNotEmbedder
)
1394 InvalidateControlAndChildren( child
);
1398 void wxMacControl::InvalidateWithChildren()
1400 InvalidateControlAndChildren( m_controlRef
);
1403 OSType wxMacCreator
= 'WXMC';
1404 OSType wxMacControlProperty
= 'MCCT';
1406 void wxMacControl::SetReferenceInNativeControl()
1409 verify_noerr( SetControlProperty ( m_controlRef
,
1410 wxMacCreator
,wxMacControlProperty
, sizeof(data
), &data
) );
1413 wxMacControl
* wxMacControl::GetReferenceFromNativeControl(ControlRef control
)
1415 wxMacControl
* ctl
= NULL
;
1416 ByteCount actualSize
;
1417 if ( GetControlProperty( control
,wxMacCreator
,wxMacControlProperty
, sizeof(ctl
) ,
1418 &actualSize
, &ctl
) == noErr
)
1425 void wxMacControl::SetBitmap( const wxBitmap
& WXUNUSED(bmp
) )
1427 // implemented in the respective subclasses
1430 void wxMacControl::SetScrollThumb( wxInt32
WXUNUSED(pos
), wxInt32
WXUNUSED(viewsize
) )
1432 // implemented in respective subclass
1439 OSStatus
wxMacControl::SetTabEnabled( SInt16 tabNo
, bool enable
)
1441 return ::SetTabEnabled( m_controlRef
, tabNo
, enable
);
1448 wxWidgetImplType
* wxWidgetImpl::CreateContentView( wxNonOwnedWindow
* now
)
1450 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1451 // the content view, so we have to retrieve it explicitly
1453 wxMacControl
* contentview
= new wxMacControl(now
, true /*isRootControl*/);
1454 HIViewFindByID( HIViewGetRoot( (WindowRef
) now
->GetWXWindow() ) , kHIViewWindowContentID
,
1455 contentview
->GetControlRefAddr() ) ;
1456 if ( !contentview
->IsOk() )
1458 // compatibility mode fallback
1459 GetRootControl( (WindowRef
) now
->GetWXWindow() , contentview
->GetControlRefAddr() ) ;
1462 // the root control level handler
1463 contentview
->InstallEventHandler() ;