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
82 // ---------------------------------------------------------------------------
84 // ---------------------------------------------------------------------------
86 static const EventTypeSpec eventList
[] =
88 { kEventClassCommand
, kEventProcessCommand
} ,
89 { kEventClassCommand
, kEventCommandUpdateStatus
} ,
91 { kEventClassControl
, kEventControlGetClickActivation
} ,
92 { kEventClassControl
, kEventControlHit
} ,
94 { kEventClassTextInput
, kEventTextInputUnicodeForKeyEvent
} ,
95 { kEventClassTextInput
, kEventTextInputUpdateActiveInputArea
} ,
97 { kEventClassControl
, kEventControlDraw
} ,
99 { kEventClassControl
, kEventControlVisibilityChanged
} ,
100 { kEventClassControl
, kEventControlEnabledStateChanged
} ,
101 { kEventClassControl
, kEventControlHiliteChanged
} ,
103 { kEventClassControl
, kEventControlActivate
} ,
104 { kEventClassControl
, kEventControlDeactivate
} ,
106 { kEventClassControl
, kEventControlSetFocusPart
} ,
107 { kEventClassControl
, kEventControlFocusPartChanged
} ,
109 { kEventClassService
, kEventServiceGetTypes
},
110 { kEventClassService
, kEventServiceCopy
},
111 { kEventClassService
, kEventServicePaste
},
113 // { kEventClassControl , kEventControlInvalidateForSizeChange } , // 10.3 only
114 // { kEventClassControl , kEventControlBoundsChanged } ,
117 static pascal OSStatus
wxMacWindowControlEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
119 OSStatus result
= eventNotHandledErr
;
120 static wxWindowMac
* targetFocusWindow
= NULL
;
121 static wxWindowMac
* formerFocusWindow
= NULL
;
123 wxMacCarbonEvent
cEvent( event
) ;
125 ControlRef controlRef
;
126 wxWindowMac
* thisWindow
= (wxWindowMac
*) data
;
128 cEvent
.GetParameter( kEventParamDirectObject
, &controlRef
) ;
130 switch ( GetEventKind( event
) )
132 case kEventControlDraw
:
134 RgnHandle updateRgn
= NULL
;
135 RgnHandle allocatedRgn
= NULL
;
136 wxRegion visRegion
= thisWindow
->MacGetVisibleRegion() ;
138 if ( cEvent
.GetParameter
<RgnHandle
>(kEventParamRgnHandle
, &updateRgn
) != noErr
)
140 HIShapeGetAsQDRgn( visRegion
.GetWXHRGN(), updateRgn
);
144 if ( thisWindow
->MacGetLeftBorderSize() != 0 || thisWindow
->MacGetTopBorderSize() != 0 )
146 // as this update region is in native window locals we must adapt it to wx window local
147 allocatedRgn
= NewRgn() ;
148 CopyRgn( updateRgn
, allocatedRgn
) ;
150 // hide the given region by the new region that must be shifted
151 OffsetRgn( allocatedRgn
, thisWindow
->MacGetLeftBorderSize() , thisWindow
->MacGetTopBorderSize() ) ;
152 updateRgn
= allocatedRgn
;
156 #if wxMAC_DEBUG_REDRAW
157 if ( thisWindow
->MacIsUserPane() )
159 static float color
= 0.5 ;
160 static int channel
= 0 ;
162 CGContextRef cgContext
= cEvent
.GetParameter
<CGContextRef
>(kEventParamCGContextRef
) ;
164 HIViewGetBounds( controlRef
, &bounds
);
165 CGContextSetRGBFillColor( cgContext
, channel
== 0 ? color
: 0.5 ,
166 channel
== 1 ? color
: 0.5 , channel
== 2 ? color
: 0.5 , 1 );
167 CGContextFillRect( cgContext
, bounds
);
180 bool created
= false ;
181 CGContextRef cgContext
= NULL
;
182 OSStatus err
= cEvent
.GetParameter
<CGContextRef
>(kEventParamCGContextRef
, &cgContext
) ;
185 wxFAIL_MSG("Unable to retrieve CGContextRef");
188 thisWindow
->MacSetCGContextRef( cgContext
) ;
191 wxMacCGContextStateSaver
sg( cgContext
) ;
192 CGFloat alpha
= (CGFloat
)1.0 ;
194 wxWindow
* iter
= thisWindow
;
197 alpha
*= (CGFloat
)( iter
->GetTransparent()/255.0 ) ;
198 if ( iter
->IsTopLevel() )
201 iter
= iter
->GetParent() ;
204 CGContextSetAlpha( cgContext
, alpha
) ;
206 if ( thisWindow
->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT
)
209 HIViewGetBounds( controlRef
, &bounds
);
210 CGContextClearRect( cgContext
, bounds
);
215 if ( thisWindow
->MacDoRedraw( updateRgn
, cEvent
.GetTicks() ) )
218 thisWindow
->MacSetCGContextRef( NULL
) ;
222 CGContextRelease( cgContext
) ;
226 DisposeRgn( allocatedRgn
) ;
230 case kEventControlVisibilityChanged
:
231 // we might have two native controls attributed to the same wxWindow instance
232 // eg a scrollview and an embedded textview, make sure we only fire for the 'outer'
233 // control, as otherwise native and wx visibility are different
234 if ( thisWindow
->GetPeer() != NULL
&& thisWindow
->GetPeer()->GetControlRef() == controlRef
)
236 thisWindow
->MacVisibilityChanged() ;
240 case kEventControlEnabledStateChanged
:
241 thisWindow
->MacEnabledStateChanged();
244 case kEventControlHiliteChanged
:
245 thisWindow
->MacHiliteChanged() ;
248 case kEventControlActivate
:
249 case kEventControlDeactivate
:
250 // FIXME: we should have a virtual function for this!
252 if ( thisWindow
->IsKindOf( CLASSINFO( wxTreeCtrl
) ) )
253 thisWindow
->Refresh();
256 if ( thisWindow
->IsKindOf( CLASSINFO( wxListCtrl
) ) )
257 thisWindow
->Refresh();
263 // different handling on OS X
266 case kEventControlFocusPartChanged
:
267 // the event is emulated by wxmac for systems lower than 10.5
269 if ( UMAGetSystemVersion() < 0x1050 )
271 // as it is synthesized here, we have to manually avoid propagation
274 ControlPartCode previousControlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlPreviousPart
, typeControlPartCode
);
275 ControlPartCode currentControlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlCurrentPart
, typeControlPartCode
);
277 if ( thisWindow
->MacGetTopLevelWindow() && thisWindow
->GetPeer()->NeedsFocusRect() )
279 thisWindow
->MacInvalidateBorders();
282 if ( currentControlPart
== 0 )
286 if ( thisWindow
->GetCaret() )
287 thisWindow
->GetCaret()->OnKillFocus();
290 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), wx_static_cast(void*, thisWindow
));
292 wxPrintf( "Focus lost %s\n", thisWindow
->GetClassInfo()->GetClassName() );
294 // remove this as soon as posting the synthesized event works properly
295 static bool inKillFocusEvent
= false ;
297 if ( !inKillFocusEvent
)
299 inKillFocusEvent
= true ;
300 wxFocusEvent
event( wxEVT_KILL_FOCUS
, thisWindow
->GetId());
301 event
.SetEventObject(thisWindow
);
302 event
.SetWindow(targetFocusWindow
);
303 thisWindow
->HandleWindowEvent(event
) ;
304 inKillFocusEvent
= false ;
305 targetFocusWindow
= NULL
;
308 else if ( previousControlPart
== 0 )
311 // panel wants to track the window which was the last to have focus in it
312 wxLogTrace(_T("Focus"), _T("focus set(%p)"), wx_static_cast(void*, thisWindow
));
313 wxChildFocusEvent
eventFocus((wxWindow
*)thisWindow
);
314 thisWindow
->HandleWindowEvent(eventFocus
);
317 if ( thisWindow
->GetCaret() )
318 thisWindow
->GetCaret()->OnSetFocus();
321 wxFocusEvent
event(wxEVT_SET_FOCUS
, thisWindow
->GetId());
322 event
.SetEventObject(thisWindow
);
323 event
.SetWindow(formerFocusWindow
);
324 thisWindow
->HandleWindowEvent(event
) ;
325 formerFocusWindow
= NULL
;
329 case kEventControlSetFocusPart
:
331 Boolean focusEverything
= false ;
332 if ( cEvent
.GetParameter
<Boolean
>(kEventParamControlFocusEverything
, &focusEverything
) == noErr
)
334 // put a breakpoint here to catch focus everything events
336 ControlPartCode controlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlPart
, typeControlPartCode
);
337 if ( controlPart
!= kControlFocusNoPart
)
339 targetFocusWindow
= thisWindow
;
340 wxLogTrace(_T("Focus"), _T("focus to be set(%p)"), wx_static_cast(void*, thisWindow
));
344 formerFocusWindow
= thisWindow
;
345 wxLogTrace(_T("Focus"), _T("focus to be lost(%p)"), wx_static_cast(void*, thisWindow
));
348 ControlPartCode previousControlPart
= 0;
349 verify_noerr( HIViewGetFocusPart(controlRef
, &previousControlPart
));
351 if ( thisWindow
->MacIsUserPane() )
353 if ( controlPart
!= kControlFocusNoPart
)
354 cEvent
.SetParameter
<ControlPartCode
>( kEventParamControlPart
, typeControlPartCode
, 1 ) ;
358 result
= CallNextEventHandler(handler
, event
);
360 if ( UMAGetSystemVersion() < 0x1050 )
362 // set back to 0 if problems arise
364 if ( result
== noErr
)
366 ControlPartCode currentControlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlPart
, typeControlPartCode
);
367 // synthesize the event focus changed event
368 EventRef evRef
= NULL
;
370 OSStatus err
= MacCreateEvent(
371 NULL
, kEventClassControl
, kEventControlFocusPartChanged
, TicksToEventTime( TickCount() ) ,
372 kEventAttributeUserEvent
, &evRef
);
375 wxMacCarbonEvent
iEvent( evRef
) ;
376 iEvent
.SetParameter
<ControlRef
>( kEventParamDirectObject
, controlRef
);
377 iEvent
.SetParameter
<EventTargetRef
>( kEventParamPostTarget
, typeEventTargetRef
, GetControlEventTarget( controlRef
) );
378 iEvent
.SetParameter
<ControlPartCode
>( kEventParamControlPreviousPart
, typeControlPartCode
, previousControlPart
);
379 iEvent
.SetParameter
<ControlPartCode
>( kEventParamControlCurrentPart
, typeControlPartCode
, currentControlPart
);
382 // TODO test this first, avoid double posts etc...
383 PostEventToQueue( GetMainEventQueue(), evRef
, kEventPriorityHigh
);
385 wxMacWindowControlEventHandler( NULL
, evRef
, data
) ;
387 ReleaseEvent( evRef
) ;
390 // old implementation, to be removed if the new one works
391 if ( controlPart
== kControlFocusNoPart
)
394 if ( thisWindow
->GetCaret() )
395 thisWindow
->GetCaret()->OnKillFocus();
398 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), wx_static_cast(void*, thisWindow
));
400 static bool inKillFocusEvent
= false ;
402 if ( !inKillFocusEvent
)
404 inKillFocusEvent
= true ;
405 wxFocusEvent
event( wxEVT_KILL_FOCUS
, thisWindow
->GetId());
406 event
.SetEventObject(thisWindow
);
407 thisWindow
->HandleWindowEvent(event
) ;
408 inKillFocusEvent
= false ;
413 // panel wants to track the window which was the last to have focus in it
414 wxLogTrace(_T("Focus"), _T("focus set(%p)"), wx_static_cast(void*, thisWindow
));
415 wxChildFocusEvent
eventFocus((wxWindow
*)thisWindow
);
416 thisWindow
->HandleWindowEvent(eventFocus
);
419 if ( thisWindow
->GetCaret() )
420 thisWindow
->GetCaret()->OnSetFocus();
423 wxFocusEvent
event(wxEVT_SET_FOCUS
, thisWindow
->GetId());
424 event
.SetEventObject(thisWindow
);
425 thisWindow
->HandleWindowEvent(event
) ;
432 case kEventControlHit
:
433 result
= thisWindow
->MacControlHit( handler
, event
) ;
436 case kEventControlGetClickActivation
:
438 // fix to always have a proper activation for DataBrowser controls (stay in bkgnd otherwise)
439 WindowRef owner
= cEvent
.GetParameter
<WindowRef
>(kEventParamWindowRef
);
440 if ( !IsWindowActive(owner
) )
442 cEvent
.SetParameter(kEventParamClickActivation
,typeClickActivationResult
, (UInt32
) kActivateAndIgnoreClick
) ;
455 static pascal OSStatus
456 wxMacWindowServiceEventHandler(EventHandlerCallRef
WXUNUSED(handler
),
460 OSStatus result
= eventNotHandledErr
;
462 wxMacCarbonEvent
cEvent( event
) ;
464 ControlRef controlRef
;
465 wxWindowMac
* thisWindow
= (wxWindowMac
*) data
;
466 wxTextCtrl
* textCtrl
= wxDynamicCast( thisWindow
, wxTextCtrl
) ;
467 cEvent
.GetParameter( kEventParamDirectObject
, &controlRef
) ;
469 switch ( GetEventKind( event
) )
471 case kEventServiceGetTypes
:
475 textCtrl
->GetSelection( &from
, &to
) ;
477 CFMutableArrayRef copyTypes
= 0 , pasteTypes
= 0;
479 copyTypes
= cEvent
.GetParameter
< CFMutableArrayRef
>( kEventParamServiceCopyTypes
, typeCFMutableArrayRef
) ;
480 if ( textCtrl
->IsEditable() )
481 pasteTypes
= cEvent
.GetParameter
< CFMutableArrayRef
>( kEventParamServicePasteTypes
, typeCFMutableArrayRef
) ;
483 static const OSType textDataTypes
[] = { kTXNTextData
/* , 'utxt', 'PICT', 'MooV', 'AIFF' */ };
484 for ( size_t i
= 0 ; i
< WXSIZEOF(textDataTypes
) ; ++i
)
486 CFStringRef typestring
= CreateTypeStringWithOSType(textDataTypes
[i
]);
490 CFArrayAppendValue(copyTypes
, typestring
) ;
492 CFArrayAppendValue(pasteTypes
, typestring
) ;
494 CFRelease( typestring
) ;
502 case kEventServiceCopy
:
507 textCtrl
->GetSelection( &from
, &to
) ;
508 wxString val
= textCtrl
->GetValue() ;
509 val
= val
.Mid( from
, to
- from
) ;
510 PasteboardRef pasteboard
= cEvent
.GetParameter
<PasteboardRef
>( kEventParamPasteboardRef
, typePasteboardRef
);
511 verify_noerr( PasteboardClear( pasteboard
) ) ;
512 PasteboardSynchronize( pasteboard
);
513 // TODO add proper conversion
514 CFDataRef data
= CFDataCreate( kCFAllocatorDefault
, (const UInt8
*)val
.c_str(), val
.length() );
515 PasteboardPutItemFlavor( pasteboard
, (PasteboardItemID
) 1, CFSTR("com.apple.traditional-mac-plain-text"), data
, 0);
521 case kEventServicePaste
:
524 PasteboardRef pasteboard
= cEvent
.GetParameter
<PasteboardRef
>( kEventParamPasteboardRef
, typePasteboardRef
);
525 PasteboardSynchronize( pasteboard
);
527 verify_noerr( PasteboardGetItemCount( pasteboard
, &itemCount
) );
528 for( UInt32 itemIndex
= 1; itemIndex
<= itemCount
; itemIndex
++ )
530 PasteboardItemID itemID
;
531 if ( PasteboardGetItemIdentifier( pasteboard
, itemIndex
, &itemID
) == noErr
)
533 CFDataRef flavorData
= NULL
;
534 if ( PasteboardCopyItemFlavorData( pasteboard
, itemID
, CFSTR("com.apple.traditional-mac-plain-text"), &flavorData
) == noErr
)
536 CFIndex flavorDataSize
= CFDataGetLength( flavorData
);
537 char *content
= new char[flavorDataSize
+1] ;
538 memcpy( content
, CFDataGetBytePtr( flavorData
), flavorDataSize
);
539 content
[flavorDataSize
]=0;
540 CFRelease( flavorData
);
542 textCtrl
->WriteText( wxString( content
, wxConvLocal
) );
544 textCtrl
->WriteText( wxString( content
) ) ;
562 pascal OSStatus
wxMacUnicodeTextEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
564 OSStatus result
= eventNotHandledErr
;
565 wxWindowMac
* focus
= (wxWindowMac
*) data
;
567 wchar_t* uniChars
= NULL
;
568 UInt32 when
= EventTimeToTicks( GetEventTime( event
) ) ;
570 UniChar
* charBuf
= NULL
;
571 ByteCount dataSize
= 0 ;
574 if ( GetEventParameter( event
, kEventParamTextInputSendText
, typeUnicodeText
, NULL
, 0 , &dataSize
, NULL
) == noErr
)
576 numChars
= dataSize
/ sizeof( UniChar
) + 1;
579 if ( (size_t) numChars
* 2 > sizeof(buf
) )
580 charBuf
= new UniChar
[ numChars
] ;
584 uniChars
= new wchar_t[ numChars
] ;
585 GetEventParameter( event
, kEventParamTextInputSendText
, typeUnicodeText
, NULL
, dataSize
, NULL
, charBuf
) ;
586 charBuf
[ numChars
- 1 ] = 0;
587 #if SIZEOF_WCHAR_T == 2
588 uniChars
= (wchar_t*) charBuf
;
589 /* 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...)
591 // the resulting string will never have more chars than the utf16 version, so this is safe
592 wxMBConvUTF16 converter
;
593 numChars
= converter
.MB2WC( uniChars
, (const char*)charBuf
, numChars
) ;
597 switch ( GetEventKind( event
) )
599 case kEventTextInputUpdateActiveInputArea
:
601 // An IME input event may return several characters, but we need to send one char at a time to
603 for (int pos
=0 ; pos
< numChars
; pos
++)
605 WXEVENTREF formerEvent
= wxTheApp
->MacGetCurrentEvent() ;
606 WXEVENTHANDLERCALLREF formerHandler
= wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
607 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
609 UInt32 message
= uniChars
[pos
] < 128 ?
(char)uniChars
[pos
] : '?';
611 NB: faking a charcode here is problematic. The kEventTextInputUpdateActiveInputArea event is sent
612 multiple times to update the active range during inline input, so this handler will often receive
613 uncommited text, which should usually not trigger side effects. It might be a good idea to check the
614 kEventParamTextInputSendFixLen parameter and verify if input is being confirmed (see CarbonEvents.h).
615 On the other hand, it can be useful for some applications to react to uncommitted text (for example,
616 to update a status display), as long as it does not disrupt the inline input session. Ideally, wx
617 should add new event types to support advanced text input. For now, I would keep things as they are.
619 However, the code that was being used caused additional problems:
620 UInt32 message = (0 << 8) + ((char)uniChars[pos] );
621 Since it simply truncated the unichar to the last byte, it ended up causing weird bugs with inline
622 input, such as switching to another field when one attempted to insert the character U+4E09 (the kanji
623 for "three"), because it was truncated to 09 (kTabCharCode), which was later "converted" to WXK_TAB
624 (still 09) in wxMacTranslateKey; or triggering the default button when one attempted to insert U+840D
625 (the kanji for "name"), which got truncated to 0D and interpreted as a carriage return keypress.
626 Note that even single-byte characters could have been misinterpreted, since MacRoman charcodes only
627 overlap with Unicode within the (7-bit) ASCII range.
628 But simply passing a NUL charcode would disable text updated events, because wxTextCtrl::OnChar checks
629 for codes within a specific range. Therefore I went for the solution seen above, which keeps ASCII
630 characters as they are and replaces the rest with '?', ensuring that update events are triggered.
631 It would be better to change wxTextCtrl::OnChar to look at the actual unicode character instead, but
632 I don't have time to look into that right now.
635 if ( wxTheApp
->MacSendCharEvent(
636 focus
, message
, 0 , when
, 0 , 0 , uniChars
[pos
] ) )
641 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerHandler
) ;
645 case kEventTextInputUnicodeForKeyEvent
:
647 UInt32 keyCode
, modifiers
;
650 unsigned char charCode
;
652 GetEventParameter( event
, kEventParamTextInputSendKeyboardEvent
, typeEventRef
, NULL
, sizeof(rawEvent
), NULL
, &rawEvent
) ;
653 GetEventParameter( rawEvent
, kEventParamKeyMacCharCodes
, typeChar
, NULL
, sizeof(char), NULL
, &charCode
);
654 GetEventParameter( rawEvent
, kEventParamKeyCode
, typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
655 GetEventParameter( rawEvent
, kEventParamKeyModifiers
, typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &modifiers
);
656 GetEventParameter( rawEvent
, kEventParamMouseLocation
, typeQDPoint
, NULL
, sizeof(Point
), NULL
, &point
);
658 UInt32 message
= (keyCode
<< 8) + charCode
;
660 // An IME input event may return several characters, but we need to send one char at a time to
662 for (int pos
=0 ; pos
< numChars
; pos
++)
664 WXEVENTREF formerEvent
= wxTheApp
->MacGetCurrentEvent() ;
665 WXEVENTHANDLERCALLREF formerHandler
= wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
666 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
668 if ( wxTheApp
->MacSendCharEvent(
669 focus
, message
, modifiers
, when
, point
.h
, point
.v
, uniChars
[pos
] ) )
674 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerHandler
) ;
683 if ( charBuf
!= buf
)
689 static pascal OSStatus
690 wxMacWindowCommandEventHandler(EventHandlerCallRef
WXUNUSED(handler
),
694 OSStatus result
= eventNotHandledErr
;
695 wxWindowMac
* focus
= (wxWindowMac
*) data
;
699 wxMacCarbonEvent
cEvent( event
) ;
700 cEvent
.GetParameter
<HICommand
>(kEventParamDirectObject
,typeHICommand
,&command
) ;
702 wxMenuItem
* item
= NULL
;
703 wxMenu
* itemMenu
= wxFindMenuFromMacCommand( command
, item
) ;
707 wxASSERT( itemMenu
!= NULL
) ;
709 switch ( cEvent
.GetKind() )
711 case kEventProcessCommand
:
712 if ( itemMenu
->HandleCommandProcess( item
, focus
) )
716 case kEventCommandUpdateStatus
:
717 if ( itemMenu
->HandleCommandUpdateStatus( item
, focus
) )
728 pascal OSStatus
wxMacWindowEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
730 EventRef formerEvent
= (EventRef
) wxTheApp
->MacGetCurrentEvent() ;
731 EventHandlerCallRef formerEventHandlerCallRef
= (EventHandlerCallRef
) wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
732 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
733 OSStatus result
= eventNotHandledErr
;
735 switch ( GetEventClass( event
) )
737 case kEventClassCommand
:
738 result
= wxMacWindowCommandEventHandler( handler
, event
, data
) ;
741 case kEventClassControl
:
742 result
= wxMacWindowControlEventHandler( handler
, event
, data
) ;
745 case kEventClassService
:
746 result
= wxMacWindowServiceEventHandler( handler
, event
, data
) ;
749 case kEventClassTextInput
:
750 result
= wxMacUnicodeTextEventHandler( handler
, event
, data
) ;
757 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerEventHandlerCallRef
) ;
762 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacWindowEventHandler
)
764 // ---------------------------------------------------------------------------
765 // Scrollbar Tracking for all
766 // ---------------------------------------------------------------------------
768 pascal void wxMacLiveScrollbarActionProc( ControlRef control
, ControlPartCode partCode
) ;
769 pascal void wxMacLiveScrollbarActionProc( ControlRef control
, ControlPartCode partCode
)
773 wxWindow
* wx
= wxFindWindowFromWXWidget( (WXWidget
) control
) ;
775 wx
->MacHandleControlClick( (WXWidget
) control
, partCode
, true /* stillDown */ ) ;
778 wxMAC_DEFINE_PROC_GETTER( ControlActionUPP
, wxMacLiveScrollbarActionProc
) ;
780 wxWidgetImplType
* wxWidgetImpl
::CreateUserPane( wxWindowMac
* wxpeer
, wxWindowMac
* parent
, wxWindowID id
, const wxPoint
& pos
, const wxSize
& size
,
781 long style
, long extraStyle
)
783 OSStatus err
= noErr
;
784 Rect bounds
= wxMacGetBoundsForControl( wxpeer
, pos
, size
) ;
785 wxMacControl
* c
= new wxMacControl(wxpeer
) ;
787 | kControlSupportsEmbedding
788 | kControlSupportsLiveFeedback
789 | kControlGetsFocusOnClick
790 // | kControlHasSpecialBackground
791 // | kControlSupportsCalcBestRect
792 | kControlHandlesTracking
793 | kControlSupportsFocus
794 | kControlWantsActivate
795 | kControlWantsIdle
;
797 err
=::CreateUserPaneControl( MAC_WXHWND(wxpeer
->GetParent()->MacGetTopLevelWindowRef()) , &bounds
, features
, c
->GetControlRefAddr() );
803 void wxMacControl
::InstallEventHandler( WXWidget control
)
805 wxWidgetImpl
::Associate( control ? control
: (WXWidget
) m_controlRef
, this ) ;
806 ::InstallControlEventHandler( control ?
(ControlRef
) control
: m_controlRef
, GetwxMacWindowEventHandlerUPP(),
807 GetEventTypeCount(eventList
), eventList
, GetWXPeer(), NULL
);
810 IMPLEMENT_DYNAMIC_CLASS( wxMacControl
, wxWidgetImpl
)
812 wxMacControl
::wxMacControl()
817 wxMacControl
::wxMacControl(wxWindowMac
* peer
, bool isRootControl
) :
818 wxWidgetImpl( peer
, isRootControl
)
823 wxMacControl
::~wxMacControl()
825 if ( m_controlRef
&& !IsRootControl() )
827 wxASSERT_MSG( m_controlRef
!= NULL
, wxT("Control Handle already NULL, Dispose called twice ?") );
828 wxASSERT_MSG( IsValidControlHandle(m_controlRef
) , wxT("Invalid Control Handle (maybe already released) in Dispose") );
830 wxWidgetImpl
::RemoveAssociations( this ) ;
831 // we cannot check the ref count here anymore, as autorelease objects might delete their refs later
832 // we can have situations when being embedded, where the control gets deleted behind our back, so only
833 // CFRelease if we are safe
834 if ( IsValidControlHandle(m_controlRef
) )
835 CFRelease(m_controlRef
);
840 void wxMacControl
::Init()
843 m_macControlEventHandler
= NULL
;
846 void wxMacControl
::RemoveFromParent()
848 // nothing to do here for carbon
849 HIViewRemoveFromSuperview(m_controlRef
);
852 void wxMacControl
::Embed( wxWidgetImpl
*parent
)
854 HIViewAddSubview((ControlRef
)parent
->GetWXWidget(), m_controlRef
);
857 void wxMacControl
::SetNeedsDisplay( const wxRect
* rect
)
864 HIRect updatearea
= CGRectMake( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
865 HIViewSetNeedsDisplayInRect( m_controlRef
, &updatearea
, true );
868 HIViewSetNeedsDisplay( m_controlRef
, true );
871 void wxMacControl
::Raise()
873 verify_noerr( HIViewSetZOrder( m_controlRef
, kHIViewZOrderAbove
, NULL
) );
876 void wxMacControl
::Lower()
878 verify_noerr( HIViewSetZOrder( m_controlRef
, kHIViewZOrderBelow
, NULL
) );
881 void wxMacControl
::GetContentArea(int &left
, int &top
, int &width
, int &height
) const
883 RgnHandle rgn
= NewRgn() ;
885 if ( GetControlRegion( m_controlRef
, kControlContentMetaPart
, rgn
) == noErr
)
886 GetRegionBounds( rgn
, &content
) ;
889 GetControlBounds( m_controlRef
, &content
);
890 content
.right
-= content
.left
;
892 content
.bottom
-= content
.top
;
900 width
= content
.right
- content
.left
;
901 height
= content
.bottom
- content
.top
;
904 void wxMacControl
::Move(int x
, int y
, int width
, int height
)
906 HIRect hir
= CGRectMake(x
,y
,width
,height
);
907 HIViewSetFrame ( m_controlRef
, &hir
);
910 void wxMacControl
::GetPosition( int &x
, int &y
) const
913 GetControlBounds( m_controlRef
, &r
);
918 void wxMacControl
::GetSize( int &width
, int &height
) const
921 GetControlBounds( m_controlRef
, &r
);
922 width
= r
.right
- r
.left
;
923 height
= r
.bottom
- r
.top
;
926 void wxMacControl
::SetControlSize( wxWindowVariant variant
)
931 case wxWINDOW_VARIANT_NORMAL
:
932 size
= kControlSizeNormal
;
935 case wxWINDOW_VARIANT_SMALL
:
936 size
= kControlSizeSmall
;
939 case wxWINDOW_VARIANT_MINI
:
940 // not always defined in the headers
944 case wxWINDOW_VARIANT_LARGE
:
945 size
= kControlSizeLarge
;
949 wxFAIL_MSG(_T("unexpected window variant"));
953 SetData
<ControlSize
>(kControlEntireControl
, kControlSizeTag
, &size
) ;
956 void wxMacControl
::ScrollRect( const wxRect
*rect
, int dx
, int dy
)
958 if (GetNeedsDisplay() )
960 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
961 // in case there is already a pending redraw on that area
962 // either immediate redraw or full invalidate
964 // is the better overall solution, as it does not slow down scrolling
967 // this would be the preferred version for fast drawing controls
968 HIViewRender(GetControlRef()) ;
972 // note there currently is a bug in OSX (10.3 +?) which makes inefficient refreshes in case an entire control
973 // area is scrolled, this does not occur if width and height are 2 pixels less,
974 // TODO: write optimal workaround
976 HIRect scrollarea
= CGRectMake( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
977 HIViewScrollRect ( m_controlRef
, &scrollarea
, dx
,dy
);
980 // this would be the preferred version for fast drawing controls
981 HIViewRender(GetControlRef()) ;
985 bool wxMacControl
::CanFocus() const
987 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
988 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
989 // but the value range is nowhere documented
990 Boolean keyExistsAndHasValidFormat
;
991 CFIndex fullKeyboardAccess
= CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
992 kCFPreferencesCurrentApplication
, &keyExistsAndHasValidFormat
);
994 if ( keyExistsAndHasValidFormat
&& fullKeyboardAccess
> 0 )
1000 UInt32 features
= 0 ;
1001 GetControlFeatures( m_controlRef
, &features
) ;
1003 return features
& ( kControlSupportsFocus
| kControlGetsFocusOnClick
) ;
1007 bool wxMacControl
::GetNeedsDisplay() const
1009 return HIViewGetNeedsDisplay( m_controlRef
);
1012 void wxWidgetImpl
::Convert( wxPoint
*pt
, wxWidgetImpl
*from
, wxWidgetImpl
*to
)
1018 HIViewConvertPoint( &hiPoint
, (ControlRef
) from
->GetWXWidget() , (ControlRef
) to
->GetWXWidget() );
1019 pt
->x
= (int)hiPoint
.x
;
1020 pt
->y
= (int)hiPoint
.y
;
1023 bool wxMacControl
::SetFocus()
1025 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1026 // we can only leave in case of an error
1028 OSStatus err
= SetKeyboardFocus( GetControlOwner( m_controlRef
), m_controlRef
, kControlFocusNextPart
);
1029 if ( err
== errCouldntSetFocus
)
1031 SetUserFocusWindow(GetControlOwner( m_controlRef
) );
1036 bool wxMacControl
::HasFocus() const
1039 GetKeyboardFocus( GetUserFocusWindow() , &control
);
1040 return control
== m_controlRef
;
1044 // subclass specifics
1047 OSStatus wxMacControl
::GetData(ControlPartCode inPartCode
, ResType inTag
, Size inBufferSize
, void * inOutBuffer
, Size
* outActualSize
) const
1049 return ::GetControlData( m_controlRef
, inPartCode
, inTag
, inBufferSize
, inOutBuffer
, outActualSize
);
1052 OSStatus wxMacControl
::GetDataSize(ControlPartCode inPartCode
, ResType inTag
, Size
* outActualSize
) const
1054 return ::GetControlDataSize( m_controlRef
, inPartCode
, inTag
, outActualSize
);
1057 OSStatus wxMacControl
::SetData(ControlPartCode inPartCode
, ResType inTag
, Size inSize
, const void * inData
)
1059 return ::SetControlData( m_controlRef
, inPartCode
, inTag
, inSize
, inData
);
1062 OSStatus wxMacControl
::SendEvent( EventRef event
, OptionBits inOptions
)
1064 return SendEventToEventTargetWithOptions( event
,
1065 HIObjectGetEventTarget( (HIObjectRef
) m_controlRef
), inOptions
);
1068 OSStatus wxMacControl
::SendHICommand( HICommand
&command
, OptionBits inOptions
)
1070 wxMacCarbonEvent
event( kEventClassCommand
, kEventCommandProcess
);
1072 event
.SetParameter
<HICommand
>(kEventParamDirectObject
,command
);
1074 return SendEvent( event
, inOptions
);
1077 OSStatus wxMacControl
::SendHICommand( UInt32 commandID
, OptionBits inOptions
)
1081 memset( &command
, 0 , sizeof(command
) );
1082 command
.commandID
= commandID
;
1083 return SendHICommand( command
, inOptions
);
1086 void wxMacControl
::PerformClick()
1088 HIViewSimulateClick (m_controlRef
, kControlButtonPart
, 0, NULL
);
1091 wxInt32 wxMacControl
::GetValue() const
1093 return ::GetControl32BitValue( m_controlRef
);
1096 SInt32 wxMacControl
::GetMaximum() const
1098 return ::GetControl32BitMaximum( m_controlRef
);
1102 wxInt32 wxMacControl::GetMinimum() const
1104 return ::GetControl32BitMinimum( m_controlRef );
1108 void wxMacControl
::SetValue( wxInt32 v
)
1110 ::SetControl32BitValue( m_controlRef
, v
);
1113 void wxMacControl
::SetMinimum( wxInt32 v
)
1115 ::SetControl32BitMinimum( m_controlRef
, v
);
1118 void wxMacControl
::SetMaximum( wxInt32 v
)
1120 ::SetControl32BitMaximum( m_controlRef
, v
);
1123 void wxMacControl
::SetValueAndRange( SInt32 value
, SInt32 minimum
, SInt32 maximum
)
1125 ::SetControl32BitMinimum( m_controlRef
, minimum
);
1126 ::SetControl32BitMaximum( m_controlRef
, maximum
);
1127 ::SetControl32BitValue( m_controlRef
, value
);
1130 void wxMacControl
::VisibilityChanged(bool WXUNUSED(shown
))
1134 void wxMacControl
::SuperChangedPosition()
1138 void wxMacControl
::SetFont( const wxFont
& font
, const wxColour
& foreground
, long windowStyle
, bool ignoreBlack
)
1141 #if wxOSX_USE_CORE_TEXT
1142 if ( UMAGetSystemVersion() >= 0x1050 )
1144 HIViewPartCode part
= 0;
1145 HIThemeTextHorizontalFlush flush
= kHIThemeTextHorizontalFlushDefault
;
1146 if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_CENTER_HORIZONTAL
)
1147 flush
= kHIThemeTextHorizontalFlushCenter
;
1148 else if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_RIGHT
)
1149 flush
= kHIThemeTextHorizontalFlushRight
;
1150 HIViewSetTextFont( m_controlRef
, part
, (CTFontRef
) font
.MacGetCTFont() );
1151 HIViewSetTextHorizontalFlush( m_controlRef
, part
, flush
);
1153 if ( foreground
!= *wxBLACK
|| ignoreBlack
== false )
1155 ControlFontStyleRec fontStyle
;
1156 foreground
.GetRGBColor( &fontStyle
.foreColor
);
1157 fontStyle
.flags
= kControlUseForeColorMask
;
1158 ::SetControlFontStyle( m_controlRef
, &fontStyle
);
1162 #if wxOSX_USE_ATSU_TEXT
1163 ControlFontStyleRec fontStyle
;
1164 if ( font
.MacGetThemeFontID() != kThemeCurrentPortFont
)
1166 switch ( font
.MacGetThemeFontID() )
1168 case kThemeSmallSystemFont
:
1169 fontStyle
.font
= kControlFontSmallSystemFont
;
1172 case 109 : // mini font
1173 fontStyle
.font
= -5;
1176 case kThemeSystemFont
:
1177 fontStyle
.font
= kControlFontBigSystemFont
;
1181 fontStyle
.font
= kControlFontBigSystemFont
;
1185 fontStyle
.flags
= kControlUseFontMask
;
1189 fontStyle
.font
= font
.MacGetFontNum();
1190 fontStyle
.style
= font
.MacGetFontStyle();
1191 fontStyle
.size
= font
.MacGetFontSize();
1192 fontStyle
.flags
= kControlUseFontMask
| kControlUseFaceMask
| kControlUseSizeMask
;
1195 fontStyle
.just
= teJustLeft
;
1196 fontStyle
.flags
|= kControlUseJustMask
;
1197 if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_CENTER_HORIZONTAL
)
1198 fontStyle
.just
= teJustCenter
;
1199 else if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_RIGHT
)
1200 fontStyle
.just
= teJustRight
;
1203 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1204 // won't get grayed out by the system anymore
1206 if ( foreground
!= *wxBLACK
|| ignoreBlack
== false )
1208 foreground
.GetRGBColor( &fontStyle
.foreColor
);
1209 fontStyle
.flags
|= kControlUseForeColorMask
;
1212 ::SetControlFontStyle( m_controlRef
, &fontStyle
);
1216 void wxMacControl
::SetBackgroundColour( const wxColour
&WXUNUSED(col
) )
1218 // HITextViewSetBackgroundColor( m_textView , color );
1221 void wxMacControl
::SetRange( SInt32 minimum
, SInt32 maximum
)
1223 ::SetControl32BitMinimum( m_controlRef
, minimum
);
1224 ::SetControl32BitMaximum( m_controlRef
, maximum
);
1227 short wxMacControl
::HandleKey( SInt16 keyCode
, SInt16 charCode
, EventModifiers modifiers
)
1229 return HandleControlKey( m_controlRef
, keyCode
, charCode
, modifiers
);
1232 void wxMacControl
::SetActionProc( ControlActionUPP actionProc
)
1234 SetControlAction( m_controlRef
, actionProc
);
1237 SInt32 wxMacControl
::GetViewSize() const
1239 return GetControlViewSize( m_controlRef
);
1242 bool wxMacControl
::IsVisible() const
1244 return IsControlVisible( m_controlRef
);
1247 void wxMacControl
::SetVisibility( bool visible
)
1249 SetControlVisibility( m_controlRef
, visible
, true );
1252 bool wxMacControl
::IsEnabled() const
1254 return IsControlEnabled( m_controlRef
);
1257 bool wxMacControl
::IsActive() const
1259 return IsControlActive( m_controlRef
);
1262 void wxMacControl
::Enable( bool enable
)
1265 EnableControl( m_controlRef
);
1267 DisableControl( m_controlRef
);
1270 void wxMacControl
::SetDrawingEnabled( bool enable
)
1272 HIViewSetDrawingEnabled( m_controlRef
, enable
);
1275 void wxMacControl
::GetRectInWindowCoords( Rect
*r
)
1277 GetControlBounds( m_controlRef
, r
) ;
1279 WindowRef tlwref
= GetControlOwner( m_controlRef
) ;
1281 wxNonOwnedWindow
* tlwwx
= wxNonOwnedWindow
::GetFromWXWindow( (WXWindow
) tlwref
) ;
1282 if ( tlwwx
!= NULL
)
1284 ControlRef rootControl
= tlwwx
->GetPeer()->GetControlRef() ;
1285 HIPoint hiPoint
= CGPointMake( 0 , 0 ) ;
1286 HIViewConvertPoint( &hiPoint
, HIViewGetSuperview(m_controlRef
) , rootControl
) ;
1287 OffsetRect( r
, (short) hiPoint
.x
, (short) hiPoint
.y
) ;
1291 void wxMacControl
::GetBestRect( wxRect
*rect
) const
1293 short baselineoffset
;
1296 GetBestControlRect( m_controlRef
, &r
, &baselineoffset
);
1297 *rect
= wxRect( r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
-r
.top
);
1300 void wxMacControl
::GetBestRect( Rect
*r
) const
1302 short baselineoffset
;
1303 GetBestControlRect( m_controlRef
, r
, &baselineoffset
);
1306 void wxMacControl
::SetLabel( const wxString
&title
, wxFontEncoding encoding
)
1308 SetControlTitleWithCFString( m_controlRef
, wxCFStringRef( title
, encoding
) );
1311 void wxMacControl
::GetFeatures( UInt32
* features
)
1313 GetControlFeatures( m_controlRef
, features
);
1316 OSStatus wxMacControl
::GetRegion( ControlPartCode partCode
, RgnHandle region
)
1318 OSStatus err
= GetControlRegion( m_controlRef
, partCode
, region
);
1322 void wxMacControl
::PulseGauge()
1326 // SetNeedsDisplay would not invalidate the children
1327 static void InvalidateControlAndChildren( HIViewRef control
)
1329 HIViewSetNeedsDisplay( control
, true );
1330 UInt16 childrenCount
= 0;
1331 OSStatus err
= CountSubControls( control
, &childrenCount
);
1332 if ( err
== errControlIsNotEmbedder
)
1335 wxASSERT_MSG( err
== noErr
, wxT("Unexpected error when accessing subcontrols") );
1337 for ( UInt16 i
= childrenCount
; i
>=1; --i
)
1341 err
= GetIndexedSubControl( control
, i
, & child
);
1342 if ( err
== errControlIsNotEmbedder
)
1345 InvalidateControlAndChildren( child
);
1349 void wxMacControl
::InvalidateWithChildren()
1351 InvalidateControlAndChildren( m_controlRef
);
1354 OSType wxMacCreator
= 'WXMC';
1355 OSType wxMacControlProperty
= 'MCCT';
1357 void wxMacControl
::SetReferenceInNativeControl()
1360 verify_noerr( SetControlProperty ( m_controlRef
,
1361 wxMacCreator
,wxMacControlProperty
, sizeof(data
), &data
) );
1364 wxMacControl
* wxMacControl
::GetReferenceFromNativeControl(ControlRef control
)
1366 wxMacControl
* ctl
= NULL
;
1367 ByteCount actualSize
;
1368 if ( GetControlProperty( control
,wxMacCreator
,wxMacControlProperty
, sizeof(ctl
) ,
1369 &actualSize
, &ctl
) == noErr
)
1376 void wxMacControl
::SetBitmap( const wxBitmap
& WXUNUSED(bmp
) )
1378 // implemented in the respective subclasses
1381 void wxMacControl
::SetScrollThumb( wxInt32
WXUNUSED(pos
), wxInt32
WXUNUSED(viewsize
) )
1383 // implemented in respective subclass
1390 OSStatus wxMacControl
::SetTabEnabled( SInt16 tabNo
, bool enable
)
1392 return ::SetTabEnabled( m_controlRef
, tabNo
, enable
);
1399 wxWidgetImplType
* wxWidgetImpl
::CreateContentView( wxNonOwnedWindow
* now
)
1401 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1402 // the content view, so we have to retrieve it explicitly
1404 wxMacControl
* contentview
= new wxMacControl(now
, true /*isRootControl*/);
1405 HIViewFindByID( HIViewGetRoot( (WindowRef
) now
->GetWXWindow() ) , kHIViewWindowContentID
,
1406 contentview
->GetControlRefAddr() ) ;
1407 if ( !contentview
->IsOk() )
1409 // compatibility mode fallback
1410 GetRootControl( (WindowRef
) now
->GetWXWindow() , contentview
->GetControlRefAddr() ) ;
1413 // the root control level handler
1414 contentview
->InstallEventHandler() ;