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)"), 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)"), 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)"), static_cast<void*>(thisWindow
));
342 formerFocusWindow
= thisWindow
;
343 wxLogTrace(_T("Focus"), _T("focus to be lost(%p)"), 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)"), 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)"), 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::RemoveFromParent()
846 // nothing to do here for carbon
847 HIViewRemoveFromSuperview(m_controlRef
);
850 void wxMacControl::Embed( wxWidgetImpl
*parent
)
852 HIViewAddSubview((ControlRef
)parent
->GetWXWidget(), m_controlRef
);
855 void wxMacControl::SetNeedsDisplay( const wxRect
* rect
)
862 HIRect updatearea
= CGRectMake( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
863 HIViewSetNeedsDisplayInRect( m_controlRef
, &updatearea
, true );
866 HIViewSetNeedsDisplay( m_controlRef
, true );
869 void wxMacControl::Raise()
871 verify_noerr( HIViewSetZOrder( m_controlRef
, kHIViewZOrderAbove
, NULL
) );
874 void wxMacControl::Lower()
876 verify_noerr( HIViewSetZOrder( m_controlRef
, kHIViewZOrderBelow
, NULL
) );
879 void wxMacControl::GetContentArea(int &left
, int &top
, int &width
, int &height
) const
881 RgnHandle rgn
= NewRgn() ;
883 if ( GetControlRegion( m_controlRef
, kControlContentMetaPart
, rgn
) == noErr
)
884 GetRegionBounds( rgn
, &content
) ;
887 GetControlBounds( m_controlRef
, &content
);
888 content
.right
-= content
.left
;
890 content
.bottom
-= content
.top
;
898 width
= content
.right
- content
.left
;
899 height
= content
.bottom
- content
.top
;
902 void wxMacControl::Move(int x
, int y
, int width
, int height
)
904 HIRect hir
= CGRectMake(x
,y
,width
,height
);
905 HIViewSetFrame ( m_controlRef
, &hir
);
908 void wxMacControl::GetPosition( int &x
, int &y
) const
911 GetControlBounds( m_controlRef
, &r
);
916 void wxMacControl::GetSize( int &width
, int &height
) const
919 GetControlBounds( m_controlRef
, &r
);
920 width
= r
.right
- r
.left
;
921 height
= r
.bottom
- r
.top
;
924 void wxMacControl::SetControlSize( wxWindowVariant variant
)
929 case wxWINDOW_VARIANT_NORMAL
:
930 size
= kControlSizeNormal
;
933 case wxWINDOW_VARIANT_SMALL
:
934 size
= kControlSizeSmall
;
937 case wxWINDOW_VARIANT_MINI
:
938 // not always defined in the headers
942 case wxWINDOW_VARIANT_LARGE
:
943 size
= kControlSizeLarge
;
947 wxFAIL_MSG(_T("unexpected window variant"));
951 SetData
<ControlSize
>(kControlEntireControl
, kControlSizeTag
, &size
) ;
954 void wxMacControl::ScrollRect( const wxRect
*rect
, int dx
, int dy
)
956 if (GetNeedsDisplay() )
958 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
959 // in case there is already a pending redraw on that area
960 // either immediate redraw or full invalidate
962 // is the better overall solution, as it does not slow down scrolling
965 // this would be the preferred version for fast drawing controls
966 HIViewRender(GetControlRef()) ;
970 // note there currently is a bug in OSX (10.3 +?) which makes inefficient refreshes in case an entire control
971 // area is scrolled, this does not occur if width and height are 2 pixels less,
972 // TODO: write optimal workaround
974 HIRect scrollarea
= CGRectMake( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
975 HIViewScrollRect ( m_controlRef
, &scrollarea
, dx
,dy
);
978 // this would be the preferred version for fast drawing controls
979 HIViewRender(GetControlRef()) ;
983 bool wxMacControl::CanFocus() const
985 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
986 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
987 // but the value range is nowhere documented
988 Boolean keyExistsAndHasValidFormat
;
989 CFIndex fullKeyboardAccess
= CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
990 kCFPreferencesCurrentApplication
, &keyExistsAndHasValidFormat
);
992 if ( keyExistsAndHasValidFormat
&& fullKeyboardAccess
> 0 )
998 UInt32 features
= 0 ;
999 GetControlFeatures( m_controlRef
, &features
) ;
1001 return features
& ( kControlSupportsFocus
| kControlGetsFocusOnClick
) ;
1005 bool wxMacControl::GetNeedsDisplay() const
1007 return HIViewGetNeedsDisplay( m_controlRef
);
1010 void wxWidgetImpl::Convert( wxPoint
*pt
, wxWidgetImpl
*from
, wxWidgetImpl
*to
)
1016 HIViewConvertPoint( &hiPoint
, (ControlRef
) from
->GetWXWidget() , (ControlRef
) to
->GetWXWidget() );
1017 pt
->x
= (int)hiPoint
.x
;
1018 pt
->y
= (int)hiPoint
.y
;
1021 bool wxMacControl::SetFocus()
1023 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1024 // we can only leave in case of an error
1026 OSStatus err
= SetKeyboardFocus( GetControlOwner( m_controlRef
), m_controlRef
, kControlFocusNextPart
);
1027 if ( err
== errCouldntSetFocus
)
1029 SetUserFocusWindow(GetControlOwner( m_controlRef
) );
1034 bool wxMacControl::HasFocus() const
1037 GetKeyboardFocus( GetUserFocusWindow() , &control
);
1038 return control
== m_controlRef
;
1042 // subclass specifics
1045 OSStatus
wxMacControl::GetData(ControlPartCode inPartCode
, ResType inTag
, Size inBufferSize
, void * inOutBuffer
, Size
* outActualSize
) const
1047 return ::GetControlData( m_controlRef
, inPartCode
, inTag
, inBufferSize
, inOutBuffer
, outActualSize
);
1050 OSStatus
wxMacControl::GetDataSize(ControlPartCode inPartCode
, ResType inTag
, Size
* outActualSize
) const
1052 return ::GetControlDataSize( m_controlRef
, inPartCode
, inTag
, outActualSize
);
1055 OSStatus
wxMacControl::SetData(ControlPartCode inPartCode
, ResType inTag
, Size inSize
, const void * inData
)
1057 return ::SetControlData( m_controlRef
, inPartCode
, inTag
, inSize
, inData
);
1060 OSStatus
wxMacControl::SendEvent( EventRef event
, OptionBits inOptions
)
1062 return SendEventToEventTargetWithOptions( event
,
1063 HIObjectGetEventTarget( (HIObjectRef
) m_controlRef
), inOptions
);
1066 OSStatus
wxMacControl::SendHICommand( HICommand
&command
, OptionBits inOptions
)
1068 wxMacCarbonEvent
event( kEventClassCommand
, kEventCommandProcess
);
1070 event
.SetParameter
<HICommand
>(kEventParamDirectObject
,command
);
1072 return SendEvent( event
, inOptions
);
1075 OSStatus
wxMacControl::SendHICommand( UInt32 commandID
, OptionBits inOptions
)
1079 memset( &command
, 0 , sizeof(command
) );
1080 command
.commandID
= commandID
;
1081 return SendHICommand( command
, inOptions
);
1084 void wxMacControl::PerformClick()
1086 HIViewSimulateClick (m_controlRef
, kControlButtonPart
, 0, NULL
);
1089 wxInt32
wxMacControl::GetValue() const
1091 return ::GetControl32BitValue( m_controlRef
);
1094 SInt32
wxMacControl::GetMaximum() const
1096 return ::GetControl32BitMaximum( m_controlRef
);
1100 wxInt32 wxMacControl::GetMinimum() const
1102 return ::GetControl32BitMinimum( m_controlRef );
1106 void wxMacControl::SetValue( wxInt32 v
)
1108 ::SetControl32BitValue( m_controlRef
, v
);
1111 void wxMacControl::SetMinimum( wxInt32 v
)
1113 ::SetControl32BitMinimum( m_controlRef
, v
);
1116 void wxMacControl::SetMaximum( wxInt32 v
)
1118 ::SetControl32BitMaximum( m_controlRef
, v
);
1121 void wxMacControl::SetValueAndRange( SInt32 value
, SInt32 minimum
, SInt32 maximum
)
1123 ::SetControl32BitMinimum( m_controlRef
, minimum
);
1124 ::SetControl32BitMaximum( m_controlRef
, maximum
);
1125 ::SetControl32BitValue( m_controlRef
, value
);
1128 void wxMacControl::VisibilityChanged(bool WXUNUSED(shown
))
1132 void wxMacControl::SuperChangedPosition()
1136 void wxMacControl::SetFont( const wxFont
& font
, const wxColour
& foreground
, long windowStyle
, bool ignoreBlack
)
1139 #if wxOSX_USE_CORE_TEXT
1140 if ( UMAGetSystemVersion() >= 0x1050 )
1142 HIViewPartCode part
= 0;
1143 HIThemeTextHorizontalFlush flush
= kHIThemeTextHorizontalFlushDefault
;
1144 if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_CENTER_HORIZONTAL
)
1145 flush
= kHIThemeTextHorizontalFlushCenter
;
1146 else if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_RIGHT
)
1147 flush
= kHIThemeTextHorizontalFlushRight
;
1148 HIViewSetTextFont( m_controlRef
, part
, (CTFontRef
) font
.MacGetCTFont() );
1149 HIViewSetTextHorizontalFlush( m_controlRef
, part
, flush
);
1151 if ( foreground
!= *wxBLACK
|| ignoreBlack
== false )
1153 ControlFontStyleRec fontStyle
;
1154 foreground
.GetRGBColor( &fontStyle
.foreColor
);
1155 fontStyle
.flags
= kControlUseForeColorMask
;
1156 ::SetControlFontStyle( m_controlRef
, &fontStyle
);
1160 #if wxOSX_USE_ATSU_TEXT
1161 ControlFontStyleRec fontStyle
;
1162 if ( font
.MacGetThemeFontID() != kThemeCurrentPortFont
)
1164 switch ( font
.MacGetThemeFontID() )
1166 case kThemeSmallSystemFont
:
1167 fontStyle
.font
= kControlFontSmallSystemFont
;
1170 case 109 : // mini font
1171 fontStyle
.font
= -5;
1174 case kThemeSystemFont
:
1175 fontStyle
.font
= kControlFontBigSystemFont
;
1179 fontStyle
.font
= kControlFontBigSystemFont
;
1183 fontStyle
.flags
= kControlUseFontMask
;
1187 fontStyle
.font
= font
.MacGetFontNum();
1188 fontStyle
.style
= font
.MacGetFontStyle();
1189 fontStyle
.size
= font
.MacGetFontSize();
1190 fontStyle
.flags
= kControlUseFontMask
| kControlUseFaceMask
| kControlUseSizeMask
;
1193 fontStyle
.just
= teJustLeft
;
1194 fontStyle
.flags
|= kControlUseJustMask
;
1195 if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_CENTER_HORIZONTAL
)
1196 fontStyle
.just
= teJustCenter
;
1197 else if ( ( windowStyle
& wxALIGN_MASK
) & wxALIGN_RIGHT
)
1198 fontStyle
.just
= teJustRight
;
1201 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1202 // won't get grayed out by the system anymore
1204 if ( foreground
!= *wxBLACK
|| ignoreBlack
== false )
1206 foreground
.GetRGBColor( &fontStyle
.foreColor
);
1207 fontStyle
.flags
|= kControlUseForeColorMask
;
1210 ::SetControlFontStyle( m_controlRef
, &fontStyle
);
1214 void wxMacControl::SetBackgroundColour( const wxColour
&WXUNUSED(col
) )
1216 // HITextViewSetBackgroundColor( m_textView , color );
1219 void wxMacControl::SetRange( SInt32 minimum
, SInt32 maximum
)
1221 ::SetControl32BitMinimum( m_controlRef
, minimum
);
1222 ::SetControl32BitMaximum( m_controlRef
, maximum
);
1225 short wxMacControl::HandleKey( SInt16 keyCode
, SInt16 charCode
, EventModifiers modifiers
)
1227 return HandleControlKey( m_controlRef
, keyCode
, charCode
, modifiers
);
1230 void wxMacControl::SetActionProc( ControlActionUPP actionProc
)
1232 SetControlAction( m_controlRef
, actionProc
);
1235 SInt32
wxMacControl::GetViewSize() const
1237 return GetControlViewSize( m_controlRef
);
1240 bool wxMacControl::IsVisible() const
1242 return IsControlVisible( m_controlRef
);
1245 void wxMacControl::SetVisibility( bool visible
)
1247 SetControlVisibility( m_controlRef
, visible
, true );
1250 bool wxMacControl::IsEnabled() const
1252 return IsControlEnabled( m_controlRef
);
1255 bool wxMacControl::IsActive() const
1257 return IsControlActive( m_controlRef
);
1260 void wxMacControl::Enable( bool enable
)
1263 EnableControl( m_controlRef
);
1265 DisableControl( m_controlRef
);
1268 void wxMacControl::SetDrawingEnabled( bool enable
)
1270 HIViewSetDrawingEnabled( m_controlRef
, enable
);
1273 void wxMacControl::GetRectInWindowCoords( Rect
*r
)
1275 GetControlBounds( m_controlRef
, r
) ;
1277 WindowRef tlwref
= GetControlOwner( m_controlRef
) ;
1279 wxNonOwnedWindow
* tlwwx
= wxNonOwnedWindow::GetFromWXWindow( (WXWindow
) tlwref
) ;
1280 if ( tlwwx
!= NULL
)
1282 ControlRef rootControl
= tlwwx
->GetPeer()->GetControlRef() ;
1283 HIPoint hiPoint
= CGPointMake( 0 , 0 ) ;
1284 HIViewConvertPoint( &hiPoint
, HIViewGetSuperview(m_controlRef
) , rootControl
) ;
1285 OffsetRect( r
, (short) hiPoint
.x
, (short) hiPoint
.y
) ;
1289 void wxMacControl::GetBestRect( wxRect
*rect
) const
1291 short baselineoffset
;
1294 GetBestControlRect( m_controlRef
, &r
, &baselineoffset
);
1295 *rect
= wxRect( r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
-r
.top
);
1298 void wxMacControl::GetBestRect( Rect
*r
) const
1300 short baselineoffset
;
1301 GetBestControlRect( m_controlRef
, r
, &baselineoffset
);
1304 void wxMacControl::SetLabel( const wxString
&title
, wxFontEncoding encoding
)
1306 SetControlTitleWithCFString( m_controlRef
, wxCFStringRef( title
, encoding
) );
1309 void wxMacControl::GetFeatures( UInt32
* features
)
1311 GetControlFeatures( m_controlRef
, features
);
1314 OSStatus
wxMacControl::GetRegion( ControlPartCode partCode
, RgnHandle region
)
1316 OSStatus err
= GetControlRegion( m_controlRef
, partCode
, region
);
1320 void wxMacControl::PulseGauge()
1324 // SetNeedsDisplay would not invalidate the children
1325 static void InvalidateControlAndChildren( HIViewRef control
)
1327 HIViewSetNeedsDisplay( control
, true );
1328 UInt16 childrenCount
= 0;
1329 OSStatus err
= CountSubControls( control
, &childrenCount
);
1330 if ( err
== errControlIsNotEmbedder
)
1333 wxASSERT_MSG( err
== noErr
, wxT("Unexpected error when accessing subcontrols") );
1335 for ( UInt16 i
= childrenCount
; i
>=1; --i
)
1339 err
= GetIndexedSubControl( control
, i
, & child
);
1340 if ( err
== errControlIsNotEmbedder
)
1343 InvalidateControlAndChildren( child
);
1347 void wxMacControl::InvalidateWithChildren()
1349 InvalidateControlAndChildren( m_controlRef
);
1352 OSType wxMacCreator
= 'WXMC';
1353 OSType wxMacControlProperty
= 'MCCT';
1355 void wxMacControl::SetReferenceInNativeControl()
1358 verify_noerr( SetControlProperty ( m_controlRef
,
1359 wxMacCreator
,wxMacControlProperty
, sizeof(data
), &data
) );
1362 wxMacControl
* wxMacControl::GetReferenceFromNativeControl(ControlRef control
)
1364 wxMacControl
* ctl
= NULL
;
1365 ByteCount actualSize
;
1366 if ( GetControlProperty( control
,wxMacCreator
,wxMacControlProperty
, sizeof(ctl
) ,
1367 &actualSize
, &ctl
) == noErr
)
1374 void wxMacControl::SetBitmap( const wxBitmap
& WXUNUSED(bmp
) )
1376 // implemented in the respective subclasses
1379 void wxMacControl::SetScrollThumb( wxInt32
WXUNUSED(pos
), wxInt32
WXUNUSED(viewsize
) )
1381 // implemented in respective subclass
1388 OSStatus
wxMacControl::SetTabEnabled( SInt16 tabNo
, bool enable
)
1390 return ::SetTabEnabled( m_controlRef
, tabNo
, enable
);
1397 wxWidgetImplType
* wxWidgetImpl::CreateContentView( wxNonOwnedWindow
* now
)
1399 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1400 // the content view, so we have to retrieve it explicitly
1402 wxMacControl
* contentview
= new wxMacControl(now
, true /*isRootControl*/);
1403 HIViewFindByID( HIViewGetRoot( (WindowRef
) now
->GetWXWindow() ) , kHIViewWindowContentID
,
1404 contentview
->GetControlRefAddr() ) ;
1405 if ( !contentview
->IsOk() )
1407 // compatibility mode fallback
1408 GetRootControl( (WindowRef
) now
->GetWXWindow() , contentview
->GetControlRefAddr() ) ;
1411 // the root control level handler
1412 contentview
->InstallEventHandler() ;