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 // remove this as soon as posting the synthesized event works properly
293 static bool inKillFocusEvent
= false ;
295 if ( !inKillFocusEvent
)
297 inKillFocusEvent
= true ;
298 wxFocusEvent
event( wxEVT_KILL_FOCUS
, thisWindow
->GetId());
299 event
.SetEventObject(thisWindow
);
300 event
.SetWindow(targetFocusWindow
);
301 thisWindow
->HandleWindowEvent(event
) ;
302 inKillFocusEvent
= false ;
303 targetFocusWindow
= NULL
;
306 else if ( previousControlPart
== 0 )
309 // panel wants to track the window which was the last to have focus in it
310 wxLogTrace(_T("Focus"), _T("focus set(%p)"), wx_static_cast(void*, thisWindow
));
311 wxChildFocusEvent
eventFocus((wxWindow
*)thisWindow
);
312 thisWindow
->HandleWindowEvent(eventFocus
);
315 if ( thisWindow
->GetCaret() )
316 thisWindow
->GetCaret()->OnSetFocus();
319 wxFocusEvent
event(wxEVT_SET_FOCUS
, thisWindow
->GetId());
320 event
.SetEventObject(thisWindow
);
321 event
.SetWindow(formerFocusWindow
);
322 thisWindow
->HandleWindowEvent(event
) ;
323 formerFocusWindow
= NULL
;
327 case kEventControlSetFocusPart
:
329 Boolean focusEverything
= false ;
330 if ( cEvent
.GetParameter
<Boolean
>(kEventParamControlFocusEverything
, &focusEverything
) == noErr
)
332 // put a breakpoint here to catch focus everything events
334 ControlPartCode controlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlPart
, typeControlPartCode
);
335 if ( controlPart
!= kControlFocusNoPart
)
337 targetFocusWindow
= thisWindow
;
338 wxLogTrace(_T("Focus"), _T("focus to be set(%p)"), wx_static_cast(void*, thisWindow
));
342 formerFocusWindow
= thisWindow
;
343 wxLogTrace(_T("Focus"), _T("focus to be lost(%p)"), wx_static_cast(void*, thisWindow
));
346 ControlPartCode previousControlPart
= 0;
347 verify_noerr( HIViewGetFocusPart(controlRef
, &previousControlPart
));
349 if ( thisWindow
->MacIsUserPane() )
351 if ( controlPart
!= kControlFocusNoPart
)
352 cEvent
.SetParameter
<ControlPartCode
>( kEventParamControlPart
, typeControlPartCode
, 1 ) ;
356 result
= CallNextEventHandler(handler
, event
);
358 if ( UMAGetSystemVersion() < 0x1050 )
360 // set back to 0 if problems arise
362 if ( result
== noErr
)
364 ControlPartCode currentControlPart
= cEvent
.GetParameter
<ControlPartCode
>(kEventParamControlPart
, typeControlPartCode
);
365 // synthesize the event focus changed event
366 EventRef evRef
= NULL
;
368 OSStatus err
= MacCreateEvent(
369 NULL
, kEventClassControl
, kEventControlFocusPartChanged
, TicksToEventTime( TickCount() ) ,
370 kEventAttributeUserEvent
, &evRef
);
373 wxMacCarbonEvent
iEvent( evRef
) ;
374 iEvent
.SetParameter
<ControlRef
>( kEventParamDirectObject
, controlRef
);
375 iEvent
.SetParameter
<EventTargetRef
>( kEventParamPostTarget
, typeEventTargetRef
, GetControlEventTarget( controlRef
) );
376 iEvent
.SetParameter
<ControlPartCode
>( kEventParamControlPreviousPart
, typeControlPartCode
, previousControlPart
);
377 iEvent
.SetParameter
<ControlPartCode
>( kEventParamControlCurrentPart
, typeControlPartCode
, currentControlPart
);
380 // TODO test this first, avoid double posts etc...
381 PostEventToQueue( GetMainEventQueue(), evRef
, kEventPriorityHigh
);
383 wxMacWindowControlEventHandler( NULL
, evRef
, data
) ;
385 ReleaseEvent( evRef
) ;
388 // old implementation, to be removed if the new one works
389 if ( controlPart
== kControlFocusNoPart
)
392 if ( thisWindow
->GetCaret() )
393 thisWindow
->GetCaret()->OnKillFocus();
396 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), wx_static_cast(void*, thisWindow
));
398 static bool inKillFocusEvent
= false ;
400 if ( !inKillFocusEvent
)
402 inKillFocusEvent
= true ;
403 wxFocusEvent
event( wxEVT_KILL_FOCUS
, thisWindow
->GetId());
404 event
.SetEventObject(thisWindow
);
405 thisWindow
->HandleWindowEvent(event
) ;
406 inKillFocusEvent
= false ;
411 // panel wants to track the window which was the last to have focus in it
412 wxLogTrace(_T("Focus"), _T("focus set(%p)"), wx_static_cast(void*, thisWindow
));
413 wxChildFocusEvent
eventFocus((wxWindow
*)thisWindow
);
414 thisWindow
->HandleWindowEvent(eventFocus
);
417 if ( thisWindow
->GetCaret() )
418 thisWindow
->GetCaret()->OnSetFocus();
421 wxFocusEvent
event(wxEVT_SET_FOCUS
, thisWindow
->GetId());
422 event
.SetEventObject(thisWindow
);
423 thisWindow
->HandleWindowEvent(event
) ;
430 case kEventControlHit
:
431 result
= thisWindow
->MacControlHit( handler
, event
) ;
434 case kEventControlGetClickActivation
:
436 // fix to always have a proper activation for DataBrowser controls (stay in bkgnd otherwise)
437 WindowRef owner
= cEvent
.GetParameter
<WindowRef
>(kEventParamWindowRef
);
438 if ( !IsWindowActive(owner
) )
440 cEvent
.SetParameter(kEventParamClickActivation
,typeClickActivationResult
, (UInt32
) kActivateAndIgnoreClick
) ;
453 static pascal OSStatus
454 wxMacWindowServiceEventHandler(EventHandlerCallRef
WXUNUSED(handler
),
458 OSStatus result
= eventNotHandledErr
;
460 wxMacCarbonEvent
cEvent( event
) ;
462 ControlRef controlRef
;
463 wxWindowMac
* thisWindow
= (wxWindowMac
*) data
;
464 wxTextCtrl
* textCtrl
= wxDynamicCast( thisWindow
, wxTextCtrl
) ;
465 cEvent
.GetParameter( kEventParamDirectObject
, &controlRef
) ;
467 switch ( GetEventKind( event
) )
469 case kEventServiceGetTypes
:
473 textCtrl
->GetSelection( &from
, &to
) ;
475 CFMutableArrayRef copyTypes
= 0 , pasteTypes
= 0;
477 copyTypes
= cEvent
.GetParameter
< CFMutableArrayRef
>( kEventParamServiceCopyTypes
, typeCFMutableArrayRef
) ;
478 if ( textCtrl
->IsEditable() )
479 pasteTypes
= cEvent
.GetParameter
< CFMutableArrayRef
>( kEventParamServicePasteTypes
, typeCFMutableArrayRef
) ;
481 static const OSType textDataTypes
[] = { kTXNTextData
/* , 'utxt', 'PICT', 'MooV', 'AIFF' */ };
482 for ( size_t i
= 0 ; i
< WXSIZEOF(textDataTypes
) ; ++i
)
484 CFStringRef typestring
= CreateTypeStringWithOSType(textDataTypes
[i
]);
488 CFArrayAppendValue(copyTypes
, typestring
) ;
490 CFArrayAppendValue(pasteTypes
, typestring
) ;
492 CFRelease( typestring
) ;
500 case kEventServiceCopy
:
505 textCtrl
->GetSelection( &from
, &to
) ;
506 wxString val
= textCtrl
->GetValue() ;
507 val
= val
.Mid( from
, to
- from
) ;
508 PasteboardRef pasteboard
= cEvent
.GetParameter
<PasteboardRef
>( kEventParamPasteboardRef
, typePasteboardRef
);
509 verify_noerr( PasteboardClear( pasteboard
) ) ;
510 PasteboardSynchronize( pasteboard
);
511 // TODO add proper conversion
512 CFDataRef data
= CFDataCreate( kCFAllocatorDefault
, (const UInt8
*)val
.c_str(), val
.length() );
513 PasteboardPutItemFlavor( pasteboard
, (PasteboardItemID
) 1, CFSTR("com.apple.traditional-mac-plain-text"), data
, 0);
519 case kEventServicePaste
:
522 PasteboardRef pasteboard
= cEvent
.GetParameter
<PasteboardRef
>( kEventParamPasteboardRef
, typePasteboardRef
);
523 PasteboardSynchronize( pasteboard
);
525 verify_noerr( PasteboardGetItemCount( pasteboard
, &itemCount
) );
526 for( UInt32 itemIndex
= 1; itemIndex
<= itemCount
; itemIndex
++ )
528 PasteboardItemID itemID
;
529 if ( PasteboardGetItemIdentifier( pasteboard
, itemIndex
, &itemID
) == noErr
)
531 CFDataRef flavorData
= NULL
;
532 if ( PasteboardCopyItemFlavorData( pasteboard
, itemID
, CFSTR("com.apple.traditional-mac-plain-text"), &flavorData
) == noErr
)
534 CFIndex flavorDataSize
= CFDataGetLength( flavorData
);
535 char *content
= new char[flavorDataSize
+1] ;
536 memcpy( content
, CFDataGetBytePtr( flavorData
), flavorDataSize
);
537 content
[flavorDataSize
]=0;
538 CFRelease( flavorData
);
540 textCtrl
->WriteText( wxString( content
, wxConvLocal
) );
542 textCtrl
->WriteText( wxString( content
) ) ;
560 pascal OSStatus
wxMacUnicodeTextEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
562 OSStatus result
= eventNotHandledErr
;
563 wxWindowMac
* focus
= (wxWindowMac
*) data
;
565 wchar_t* uniChars
= NULL
;
566 UInt32 when
= EventTimeToTicks( GetEventTime( event
) ) ;
568 UniChar
* charBuf
= NULL
;
569 ByteCount dataSize
= 0 ;
572 if ( GetEventParameter( event
, kEventParamTextInputSendText
, typeUnicodeText
, NULL
, 0 , &dataSize
, NULL
) == noErr
)
574 numChars
= dataSize
/ sizeof( UniChar
) + 1;
577 if ( (size_t) numChars
* 2 > sizeof(buf
) )
578 charBuf
= new UniChar
[ numChars
] ;
582 uniChars
= new wchar_t[ numChars
] ;
583 GetEventParameter( event
, kEventParamTextInputSendText
, typeUnicodeText
, NULL
, dataSize
, NULL
, charBuf
) ;
584 charBuf
[ numChars
- 1 ] = 0;
585 #if SIZEOF_WCHAR_T == 2
586 uniChars
= (wchar_t*) charBuf
;
587 /* 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...)
589 // the resulting string will never have more chars than the utf16 version, so this is safe
590 wxMBConvUTF16 converter
;
591 numChars
= converter
.MB2WC( uniChars
, (const char*)charBuf
, numChars
) ;
595 switch ( GetEventKind( event
) )
597 case kEventTextInputUpdateActiveInputArea
:
599 // An IME input event may return several characters, but we need to send one char at a time to
601 for (int pos
=0 ; pos
< numChars
; pos
++)
603 WXEVENTREF formerEvent
= wxTheApp
->MacGetCurrentEvent() ;
604 WXEVENTHANDLERCALLREF formerHandler
= wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
605 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
607 UInt32 message
= uniChars
[pos
] < 128 ? (char)uniChars
[pos
] : '?';
609 NB: faking a charcode here is problematic. The kEventTextInputUpdateActiveInputArea event is sent
610 multiple times to update the active range during inline input, so this handler will often receive
611 uncommited text, which should usually not trigger side effects. It might be a good idea to check the
612 kEventParamTextInputSendFixLen parameter and verify if input is being confirmed (see CarbonEvents.h).
613 On the other hand, it can be useful for some applications to react to uncommitted text (for example,
614 to update a status display), as long as it does not disrupt the inline input session. Ideally, wx
615 should add new event types to support advanced text input. For now, I would keep things as they are.
617 However, the code that was being used caused additional problems:
618 UInt32 message = (0 << 8) + ((char)uniChars[pos] );
619 Since it simply truncated the unichar to the last byte, it ended up causing weird bugs with inline
620 input, such as switching to another field when one attempted to insert the character U+4E09 (the kanji
621 for "three"), because it was truncated to 09 (kTabCharCode), which was later "converted" to WXK_TAB
622 (still 09) in wxMacTranslateKey; or triggering the default button when one attempted to insert U+840D
623 (the kanji for "name"), which got truncated to 0D and interpreted as a carriage return keypress.
624 Note that even single-byte characters could have been misinterpreted, since MacRoman charcodes only
625 overlap with Unicode within the (7-bit) ASCII range.
626 But simply passing a NUL charcode would disable text updated events, because wxTextCtrl::OnChar checks
627 for codes within a specific range. Therefore I went for the solution seen above, which keeps ASCII
628 characters as they are and replaces the rest with '?', ensuring that update events are triggered.
629 It would be better to change wxTextCtrl::OnChar to look at the actual unicode character instead, but
630 I don't have time to look into that right now.
633 if ( wxTheApp
->MacSendCharEvent(
634 focus
, message
, 0 , when
, 0 , 0 , uniChars
[pos
] ) )
639 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerHandler
) ;
643 case kEventTextInputUnicodeForKeyEvent
:
645 UInt32 keyCode
, modifiers
;
648 unsigned char charCode
;
650 GetEventParameter( event
, kEventParamTextInputSendKeyboardEvent
, typeEventRef
, NULL
, sizeof(rawEvent
), NULL
, &rawEvent
) ;
651 GetEventParameter( rawEvent
, kEventParamKeyMacCharCodes
, typeChar
, NULL
, sizeof(char), NULL
, &charCode
);
652 GetEventParameter( rawEvent
, kEventParamKeyCode
, typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &keyCode
);
653 GetEventParameter( rawEvent
, kEventParamKeyModifiers
, typeUInt32
, NULL
, sizeof(UInt32
), NULL
, &modifiers
);
654 GetEventParameter( rawEvent
, kEventParamMouseLocation
, typeQDPoint
, NULL
, sizeof(Point
), NULL
, &point
);
656 UInt32 message
= (keyCode
<< 8) + charCode
;
658 // An IME input event may return several characters, but we need to send one char at a time to
660 for (int pos
=0 ; pos
< numChars
; pos
++)
662 WXEVENTREF formerEvent
= wxTheApp
->MacGetCurrentEvent() ;
663 WXEVENTHANDLERCALLREF formerHandler
= wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
664 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
666 if ( wxTheApp
->MacSendCharEvent(
667 focus
, message
, modifiers
, when
, point
.h
, point
.v
, uniChars
[pos
] ) )
672 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerHandler
) ;
681 if ( charBuf
!= buf
)
687 static pascal OSStatus
688 wxMacWindowCommandEventHandler(EventHandlerCallRef
WXUNUSED(handler
),
692 OSStatus result
= eventNotHandledErr
;
693 wxWindowMac
* focus
= (wxWindowMac
*) data
;
697 wxMacCarbonEvent
cEvent( event
) ;
698 cEvent
.GetParameter
<HICommand
>(kEventParamDirectObject
,typeHICommand
,&command
) ;
700 wxMenuItem
* item
= NULL
;
701 wxMenu
* itemMenu
= wxFindMenuFromMacCommand( command
, item
) ;
705 wxASSERT( itemMenu
!= NULL
) ;
707 switch ( cEvent
.GetKind() )
709 case kEventProcessCommand
:
710 if ( itemMenu
->HandleCommandProcess( item
, focus
) )
714 case kEventCommandUpdateStatus
:
715 if ( itemMenu
->HandleCommandUpdateStatus( item
, focus
) )
726 pascal OSStatus
wxMacWindowEventHandler( EventHandlerCallRef handler
, EventRef event
, void *data
)
728 EventRef formerEvent
= (EventRef
) wxTheApp
->MacGetCurrentEvent() ;
729 EventHandlerCallRef formerEventHandlerCallRef
= (EventHandlerCallRef
) wxTheApp
->MacGetCurrentEventHandlerCallRef() ;
730 wxTheApp
->MacSetCurrentEvent( event
, handler
) ;
731 OSStatus result
= eventNotHandledErr
;
733 switch ( GetEventClass( event
) )
735 case kEventClassCommand
:
736 result
= wxMacWindowCommandEventHandler( handler
, event
, data
) ;
739 case kEventClassControl
:
740 result
= wxMacWindowControlEventHandler( handler
, event
, data
) ;
743 case kEventClassService
:
744 result
= wxMacWindowServiceEventHandler( handler
, event
, data
) ;
747 case kEventClassTextInput
:
748 result
= wxMacUnicodeTextEventHandler( handler
, event
, data
) ;
755 wxTheApp
->MacSetCurrentEvent( formerEvent
, formerEventHandlerCallRef
) ;
760 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacWindowEventHandler
)
762 // ---------------------------------------------------------------------------
763 // Scrollbar Tracking for all
764 // ---------------------------------------------------------------------------
766 pascal void wxMacLiveScrollbarActionProc( ControlRef control
, ControlPartCode partCode
) ;
767 pascal void wxMacLiveScrollbarActionProc( ControlRef control
, ControlPartCode partCode
)
771 wxWindow
* wx
= wxFindWindowFromWXWidget( (WXWidget
) control
) ;
773 wx
->MacHandleControlClick( (WXWidget
) control
, partCode
, true /* stillDown */ ) ;
776 wxMAC_DEFINE_PROC_GETTER( ControlActionUPP
, wxMacLiveScrollbarActionProc
) ;
778 wxWidgetImplType
* wxWidgetImpl::CreateUserPane( wxWindowMac
* wxpeer
, wxWindowMac
* parent
, wxWindowID id
, const wxPoint
& pos
, const wxSize
& size
,
779 long style
, long extraStyle
)
781 OSStatus err
= noErr
;
782 Rect bounds
= wxMacGetBoundsForControl( wxpeer
, pos
, size
) ;
783 wxMacControl
* c
= new wxMacControl(wxpeer
) ;
785 | kControlSupportsEmbedding
786 | kControlSupportsLiveFeedback
787 | kControlGetsFocusOnClick
788 // | kControlHasSpecialBackground
789 // | kControlSupportsCalcBestRect
790 | kControlHandlesTracking
791 | kControlSupportsFocus
792 | kControlWantsActivate
793 | kControlWantsIdle
;
795 err
=::CreateUserPaneControl( MAC_WXHWND(wxpeer
->GetParent()->MacGetTopLevelWindowRef()) , &bounds
, features
, c
->GetControlRefAddr() );
801 void wxMacControl::InstallEventHandler( WXWidget control
)
803 wxWidgetImpl::Associate( control
? control
: (WXWidget
) m_controlRef
, this ) ;
804 ::InstallControlEventHandler( control
? (ControlRef
) control
: m_controlRef
, GetwxMacWindowEventHandlerUPP(),
805 GetEventTypeCount(eventList
), eventList
, GetWXPeer(), NULL
);
808 IMPLEMENT_DYNAMIC_CLASS( wxMacControl
, wxWidgetImpl
)
810 wxMacControl::wxMacControl()
815 wxMacControl::wxMacControl(wxWindowMac
* peer
, bool isRootControl
) :
816 wxWidgetImpl( peer
, isRootControl
)
821 wxMacControl::~wxMacControl()
823 if ( m_controlRef
&& !IsRootControl() )
825 wxASSERT_MSG( m_controlRef
!= NULL
, wxT("Control Handle already NULL, Dispose called twice ?") );
826 wxASSERT_MSG( IsValidControlHandle(m_controlRef
) , wxT("Invalid Control Handle (maybe already released) in Dispose") );
828 wxWidgetImpl::RemoveAssociations( this ) ;
829 // we cannot check the ref count here anymore, as autorelease objects might delete their refs later
830 // we can have situations when being embedded, where the control gets deleted behind our back, so only
831 // CFRelease if we are safe
832 if ( IsValidControlHandle(m_controlRef
) )
833 CFRelease(m_controlRef
);
838 void wxMacControl::Init()
841 m_macControlEventHandler
= NULL
;
844 void wxMacControl::SetReference( URefCon data
)
846 SetControlReference( m_controlRef
, data
);
849 void wxMacControl::RemoveFromParent()
851 // nothing to do here for carbon
854 void wxMacControl::Embed( wxWidgetImpl
*parent
)
856 // copied from MacPostControlCreate
857 ControlRef container
= (ControlRef
) parent
->GetWXWidget() ;
858 wxASSERT_MSG( container
!= NULL
, wxT("No valid mac container control") ) ;
859 ::EmbedControl( m_controlRef
, container
) ;
862 void wxMacControl::SetNeedsDisplay( const wxRect
* rect
)
869 HIRect updatearea
= CGRectMake( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
870 HIViewSetNeedsDisplayInRect( m_controlRef
, &updatearea
, true );
873 HIViewSetNeedsDisplay( m_controlRef
, true );
876 void wxMacControl::Raise()
878 verify_noerr( HIViewSetZOrder( m_controlRef
, kHIViewZOrderAbove
, NULL
) );
881 void wxMacControl::Lower()
883 verify_noerr( HIViewSetZOrder( m_controlRef
, kHIViewZOrderBelow
, NULL
) );
886 void wxMacControl::GetContentArea(int &left
, int &top
, int &width
, int &height
) const
888 RgnHandle rgn
= NewRgn() ;
890 if ( GetControlRegion( m_controlRef
, kControlContentMetaPart
, rgn
) == noErr
)
891 GetRegionBounds( rgn
, &content
) ;
894 GetControlBounds( m_controlRef
, &content
);
895 content
.right
-= content
.left
;
897 content
.bottom
-= content
.top
;
905 width
= content
.right
- content
.left
;
906 height
= content
.bottom
- content
.top
;
909 void wxMacControl::Move(int x
, int y
, int width
, int height
)
911 HIRect hir
= CGRectMake(x
,y
,width
,height
);
912 HIViewSetFrame ( m_controlRef
, &hir
);
915 void wxMacControl::GetPosition( int &x
, int &y
) const
918 GetControlBounds( m_controlRef
, &r
);
923 void wxMacControl::GetSize( int &width
, int &height
) const
926 GetControlBounds( m_controlRef
, &r
);
927 width
= r
.right
- r
.left
;
928 height
= r
.bottom
- r
.top
;
931 void wxMacControl::SetControlSize( wxWindowVariant variant
)
936 case wxWINDOW_VARIANT_NORMAL
:
937 size
= kControlSizeNormal
;
940 case wxWINDOW_VARIANT_SMALL
:
941 size
= kControlSizeSmall
;
944 case wxWINDOW_VARIANT_MINI
:
945 // not always defined in the headers
949 case wxWINDOW_VARIANT_LARGE
:
950 size
= kControlSizeLarge
;
954 wxFAIL_MSG(_T("unexpected window variant"));
958 SetData
<ControlSize
>(kControlEntireControl
, kControlSizeTag
, &size
) ;
961 void wxMacControl::ScrollRect( const wxRect
*rect
, int dx
, int dy
)
963 if (GetNeedsDisplay() )
965 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
966 // in case there is already a pending redraw on that area
967 // either immediate redraw or full invalidate
969 // is the better overall solution, as it does not slow down scrolling
972 // this would be the preferred version for fast drawing controls
973 HIViewRender(GetControlRef()) ;
977 // note there currently is a bug in OSX (10.3 +?) which makes inefficient refreshes in case an entire control
978 // area is scrolled, this does not occur if width and height are 2 pixels less,
979 // TODO: write optimal workaround
981 HIRect scrollarea
= CGRectMake( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
982 HIViewScrollRect ( m_controlRef
, &scrollarea
, dx
,dy
);
985 // this would be the preferred version for fast drawing controls
986 HIViewRender(GetControlRef()) ;
990 bool wxMacControl::CanFocus() const
992 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
993 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
994 // but the value range is nowhere documented
995 Boolean keyExistsAndHasValidFormat
;
996 CFIndex fullKeyboardAccess
= CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
997 kCFPreferencesCurrentApplication
, &keyExistsAndHasValidFormat
);
999 if ( keyExistsAndHasValidFormat
&& fullKeyboardAccess
> 0 )
1005 UInt32 features
= 0 ;
1006 GetControlFeatures( m_controlRef
, &features
) ;
1008 return features
& ( kControlSupportsFocus
| kControlGetsFocusOnClick
) ;
1012 bool wxMacControl::GetNeedsDisplay() const
1014 return HIViewGetNeedsDisplay( m_controlRef
);
1017 void wxWidgetImpl::Convert( wxPoint
*pt
, wxWidgetImpl
*from
, wxWidgetImpl
*to
)
1023 HIViewConvertPoint( &hiPoint
, (ControlRef
) from
->GetWXWidget() , (ControlRef
) to
->GetWXWidget() );
1024 pt
->x
= (int)hiPoint
.x
;
1025 pt
->y
= (int)hiPoint
.y
;
1028 bool wxMacControl::SetFocus()
1030 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1031 // we can only leave in case of an error
1033 OSStatus err
= SetKeyboardFocus( GetControlOwner( m_controlRef
), m_controlRef
, kControlFocusNextPart
);
1034 if ( err
== errCouldntSetFocus
)
1036 SetUserFocusWindow(GetControlOwner( m_controlRef
) );
1041 bool wxMacControl::HasFocus() const
1044 GetKeyboardFocus( GetUserFocusWindow() , &control
);
1045 return control
== m_controlRef
;
1049 // subclass specifics
1052 OSStatus
wxMacControl::GetData(ControlPartCode inPartCode
, ResType inTag
, Size inBufferSize
, void * inOutBuffer
, Size
* outActualSize
) const
1054 return ::GetControlData( m_controlRef
, inPartCode
, inTag
, inBufferSize
, inOutBuffer
, outActualSize
);
1057 OSStatus
wxMacControl::GetDataSize(ControlPartCode inPartCode
, ResType inTag
, Size
* outActualSize
) const
1059 return ::GetControlDataSize( m_controlRef
, inPartCode
, inTag
, outActualSize
);
1062 OSStatus
wxMacControl::SetData(ControlPartCode inPartCode
, ResType inTag
, Size inSize
, const void * inData
)
1064 return ::SetControlData( m_controlRef
, inPartCode
, inTag
, inSize
, inData
);
1067 OSStatus
wxMacControl::SendEvent( EventRef event
, OptionBits inOptions
)
1069 return SendEventToEventTargetWithOptions( event
,
1070 HIObjectGetEventTarget( (HIObjectRef
) m_controlRef
), inOptions
);
1073 OSStatus
wxMacControl::SendHICommand( HICommand
&command
, OptionBits inOptions
)
1075 wxMacCarbonEvent
event( kEventClassCommand
, kEventCommandProcess
);
1077 event
.SetParameter
<HICommand
>(kEventParamDirectObject
,command
);
1079 return SendEvent( event
, inOptions
);
1082 OSStatus
wxMacControl::SendHICommand( UInt32 commandID
, OptionBits inOptions
)
1086 memset( &command
, 0 , sizeof(command
) );
1087 command
.commandID
= commandID
;
1088 return SendHICommand( command
, inOptions
);
1091 void wxMacControl::PerformClick()
1093 HIViewSimulateClick (m_controlRef
, kControlButtonPart
, 0, NULL
);
1096 wxInt32
wxMacControl::GetValue() const
1098 return ::GetControl32BitValue( m_controlRef
);
1101 SInt32
wxMacControl::GetMaximum() const
1103 return ::GetControl32BitMaximum( m_controlRef
);
1107 wxInt32 wxMacControl::GetMinimum() const
1109 return ::GetControl32BitMinimum( m_controlRef );
1113 void wxMacControl::SetValue( wxInt32 v
)
1115 ::SetControl32BitValue( m_controlRef
, v
);
1118 void wxMacControl::SetMinimum( wxInt32 v
)
1120 ::SetControl32BitMinimum( m_controlRef
, v
);
1123 void wxMacControl::SetMaximum( wxInt32 v
)
1125 ::SetControl32BitMaximum( m_controlRef
, v
);
1128 void wxMacControl::SetValueAndRange( SInt32 value
, SInt32 minimum
, SInt32 maximum
)
1130 ::SetControl32BitMinimum( m_controlRef
, minimum
);
1131 ::SetControl32BitMaximum( m_controlRef
, maximum
);
1132 ::SetControl32BitValue( m_controlRef
, value
);
1135 void wxMacControl::VisibilityChanged(bool WXUNUSED(shown
))
1139 void wxMacControl::SuperChangedPosition()
1143 void wxMacControl::SetFont( const wxFont
& font
, const wxColour
& foreground
, long windowStyle
, bool ignoreBlack
)
1146 #if wxOSX_USE_CORE_TEXT
1147 if ( UMAGetSystemVersion() >= 0x1050 )
1149 HIViewPartCode part
= 0;
1150 HIThemeTextHorizontalFlush flush
= kHIThemeTextHorizontalFlushDefault
;
1151 if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_CENTER_HORIZONTAL
)
1152 flush
= kHIThemeTextHorizontalFlushCenter
;
1153 else if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_RIGHT
)
1154 flush
= kHIThemeTextHorizontalFlushRight
;
1155 HIViewSetTextFont( m_controlRef
, part
, (CTFontRef
) font
.MacGetCTFont() );
1156 HIViewSetTextHorizontalFlush( m_controlRef
, part
, flush
);
1158 if ( foreground
!= *wxBLACK
|| ignoreBlack
== false )
1160 ControlFontStyleRec fontStyle
;
1161 foreground
.GetRGBColor( &fontStyle
.foreColor
);
1162 fontStyle
.flags
= kControlUseForeColorMask
;
1163 ::SetControlFontStyle( m_controlRef
, &fontStyle
);
1167 #if wxOSX_USE_ATSU_TEXT
1168 ControlFontStyleRec fontStyle
;
1169 if ( font
.MacGetThemeFontID() != kThemeCurrentPortFont
)
1171 switch ( font
.MacGetThemeFontID() )
1173 case kThemeSmallSystemFont
:
1174 fontStyle
.font
= kControlFontSmallSystemFont
;
1177 case 109 : // mini font
1178 fontStyle
.font
= -5;
1181 case kThemeSystemFont
:
1182 fontStyle
.font
= kControlFontBigSystemFont
;
1186 fontStyle
.font
= kControlFontBigSystemFont
;
1190 fontStyle
.flags
= kControlUseFontMask
;
1194 fontStyle
.font
= font
.MacGetFontNum();
1195 fontStyle
.style
= font
.MacGetFontStyle();
1196 fontStyle
.size
= font
.MacGetFontSize();
1197 fontStyle
.flags
= kControlUseFontMask
| kControlUseFaceMask
| kControlUseSizeMask
;
1200 fontStyle
.just
= teJustLeft
;
1201 fontStyle
.flags
|= kControlUseJustMask
;
1202 if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_CENTER_HORIZONTAL
)
1203 fontStyle
.just
= teJustCenter
;
1204 else if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_RIGHT
)
1205 fontStyle
.just
= teJustRight
;
1208 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1209 // won't get grayed out by the system anymore
1211 if ( foreground
!= *wxBLACK
|| ignoreBlack
== false )
1213 foreground
.GetRGBColor( &fontStyle
.foreColor
);
1214 fontStyle
.flags
|= kControlUseForeColorMask
;
1217 ::SetControlFontStyle( m_controlRef
, &fontStyle
);
1221 void wxMacControl::SetBackgroundColour( const wxColour
&WXUNUSED(col
) )
1223 // HITextViewSetBackgroundColor( m_textView , color );
1226 void wxMacControl::SetRange( SInt32 minimum
, SInt32 maximum
)
1228 ::SetControl32BitMinimum( m_controlRef
, minimum
);
1229 ::SetControl32BitMaximum( m_controlRef
, maximum
);
1232 short wxMacControl::HandleKey( SInt16 keyCode
, SInt16 charCode
, EventModifiers modifiers
)
1234 return HandleControlKey( m_controlRef
, keyCode
, charCode
, modifiers
);
1237 void wxMacControl::SetActionProc( ControlActionUPP actionProc
)
1239 SetControlAction( m_controlRef
, actionProc
);
1242 SInt32
wxMacControl::GetViewSize() const
1244 return GetControlViewSize( m_controlRef
);
1247 bool wxMacControl::IsVisible() const
1249 return IsControlVisible( m_controlRef
);
1252 void wxMacControl::SetVisibility( bool visible
)
1254 SetControlVisibility( m_controlRef
, visible
, true );
1257 bool wxMacControl::IsEnabled() const
1259 return IsControlEnabled( m_controlRef
);
1262 bool wxMacControl::IsActive() const
1264 return IsControlActive( m_controlRef
);
1267 void wxMacControl::Enable( bool enable
)
1270 EnableControl( m_controlRef
);
1272 DisableControl( m_controlRef
);
1275 void wxMacControl::SetDrawingEnabled( bool enable
)
1277 HIViewSetDrawingEnabled( m_controlRef
, enable
);
1280 void wxMacControl::GetRectInWindowCoords( Rect
*r
)
1282 GetControlBounds( m_controlRef
, r
) ;
1284 WindowRef tlwref
= GetControlOwner( m_controlRef
) ;
1286 wxNonOwnedWindow
* tlwwx
= wxNonOwnedWindow::GetFromWXWindow( (WXWindow
) tlwref
) ;
1287 if ( tlwwx
!= NULL
)
1289 ControlRef rootControl
= tlwwx
->GetPeer()->GetControlRef() ;
1290 HIPoint hiPoint
= CGPointMake( 0 , 0 ) ;
1291 HIViewConvertPoint( &hiPoint
, HIViewGetSuperview(m_controlRef
) , rootControl
) ;
1292 OffsetRect( r
, (short) hiPoint
.x
, (short) hiPoint
.y
) ;
1296 void wxMacControl::GetBestRect( wxRect
*rect
) const
1298 short baselineoffset
;
1301 GetBestControlRect( m_controlRef
, &r
, &baselineoffset
);
1302 *rect
= wxRect( r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
-r
.top
);
1305 void wxMacControl::GetBestRect( Rect
*r
) const
1307 short baselineoffset
;
1308 GetBestControlRect( m_controlRef
, r
, &baselineoffset
);
1311 void wxMacControl::SetLabel( const wxString
&title
, wxFontEncoding encoding
)
1313 SetControlTitleWithCFString( m_controlRef
, wxCFStringRef( title
, encoding
) );
1316 void wxMacControl::GetFeatures( UInt32
* features
)
1318 GetControlFeatures( m_controlRef
, features
);
1321 OSStatus
wxMacControl::GetRegion( ControlPartCode partCode
, RgnHandle region
)
1323 OSStatus err
= GetControlRegion( m_controlRef
, partCode
, region
);
1327 void wxMacControl::PulseGauge()
1331 // SetNeedsDisplay would not invalidate the children
1332 static void InvalidateControlAndChildren( HIViewRef control
)
1334 HIViewSetNeedsDisplay( control
, true );
1335 UInt16 childrenCount
= 0;
1336 OSStatus err
= CountSubControls( control
, &childrenCount
);
1337 if ( err
== errControlIsNotEmbedder
)
1340 wxASSERT_MSG( err
== noErr
, wxT("Unexpected error when accessing subcontrols") );
1342 for ( UInt16 i
= childrenCount
; i
>=1; --i
)
1346 err
= GetIndexedSubControl( control
, i
, & child
);
1347 if ( err
== errControlIsNotEmbedder
)
1350 InvalidateControlAndChildren( child
);
1354 void wxMacControl::InvalidateWithChildren()
1356 InvalidateControlAndChildren( m_controlRef
);
1359 OSType wxMacCreator
= 'WXMC';
1360 OSType wxMacControlProperty
= 'MCCT';
1362 void wxMacControl::SetReferenceInNativeControl()
1365 verify_noerr( SetControlProperty ( m_controlRef
,
1366 wxMacCreator
,wxMacControlProperty
, sizeof(data
), &data
) );
1369 wxMacControl
* wxMacControl::GetReferenceFromNativeControl(ControlRef control
)
1371 wxMacControl
* ctl
= NULL
;
1372 ByteCount actualSize
;
1373 if ( GetControlProperty( control
,wxMacCreator
,wxMacControlProperty
, sizeof(ctl
) ,
1374 &actualSize
, &ctl
) == noErr
)
1381 void wxMacControl::SetBitmap( const wxBitmap
& WXUNUSED(bmp
) )
1383 // implemented in the respective subclasses
1386 void wxMacControl::SetScrollThumb( wxInt32
WXUNUSED(pos
), wxInt32
WXUNUSED(viewsize
) )
1388 // implemented in respective subclass
1395 OSStatus
wxMacControl::SetTabEnabled( SInt16 tabNo
, bool enable
)
1397 return ::SetTabEnabled( m_controlRef
, tabNo
, enable
);
1404 wxWidgetImplType
* wxWidgetImpl::CreateContentView( wxNonOwnedWindow
* now
)
1406 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1407 // the content view, so we have to retrieve it explicitly
1409 wxMacControl
* contentview
= new wxMacControl(now
, true /*isRootControl*/);
1410 HIViewFindByID( HIViewGetRoot( (WindowRef
) now
->GetWXWindow() ) , kHIViewWindowContentID
,
1411 contentview
->GetControlRefAddr() ) ;
1412 if ( !contentview
->IsOk() )
1414 // compatibility mode fallback
1415 GetRootControl( (WindowRef
) now
->GetWXWindow() , contentview
->GetControlRefAddr() ) ;
1418 // the root control level handler
1419 contentview
->InstallEventHandler() ;