]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/window.cpp
non PCH compilation
[wxWidgets.git] / src / osx / carbon / window.cpp
CommitLineData
489468fe 1/////////////////////////////////////////////////////////////////////////////
524c47aa 2// Name: src/osx/carbon/window.cpp
489468fe
SC
3// Purpose: wxWindowMac
4// Author: Stefan Csomor
5// Modified by:
6// Created: 1998-01-01
7// RCS-ID: $Id$
8// Copyright: (c) Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#include "wx/window.h"
15
16#ifndef WX_PRECOMP
17 #include "wx/log.h"
18 #include "wx/app.h"
19 #include "wx/utils.h"
20 #include "wx/panel.h"
21 #include "wx/frame.h"
22 #include "wx/dc.h"
23 #include "wx/dcclient.h"
24 #include "wx/button.h"
25 #include "wx/menu.h"
26 #include "wx/dialog.h"
27 #include "wx/settings.h"
28 #include "wx/msgdlg.h"
29 #include "wx/scrolbar.h"
30 #include "wx/statbox.h"
31 #include "wx/textctrl.h"
32 #include "wx/toolbar.h"
33 #include "wx/layout.h"
34 #include "wx/statusbr.h"
35 #include "wx/menuitem.h"
36 #include "wx/treectrl.h"
37 #include "wx/listctrl.h"
38#endif
39
40#include "wx/tooltip.h"
41#include "wx/spinctrl.h"
42#include "wx/geometry.h"
43
44#if wxUSE_LISTCTRL
45 #include "wx/listctrl.h"
46#endif
47
48#if wxUSE_TREECTRL
49 #include "wx/treectrl.h"
50#endif
51
52#if wxUSE_CARET
53 #include "wx/caret.h"
54#endif
55
56#if wxUSE_POPUPWIN
57 #include "wx/popupwin.h"
58#endif
59
60#if wxUSE_DRAG_AND_DROP
61#include "wx/dnd.h"
62#endif
63
b2680ced 64#if wxOSX_USE_CARBON
1f0c8f31 65#include "wx/osx/uma.h"
b2680ced
SC
66#else
67#include "wx/osx/private.h"
b3b17ee7 68// bring in theming
524c47aa 69#include <Carbon/Carbon.h>
b2680ced 70#endif
489468fe
SC
71
72#define MAC_SCROLLBAR_SIZE 15
73#define MAC_SMALL_SCROLLBAR_SIZE 11
74
75#include <string.h>
76
524c47aa
SC
77#define wxMAC_DEBUG_REDRAW 0
78#ifndef wxMAC_DEBUG_REDRAW
79#define wxMAC_DEBUG_REDRAW 0
489468fe 80#endif
b2680ced 81
f06e0fea
SC
82// Get the window with the focus
83WXWidget wxWidgetImpl::FindFocus()
84{
85 ControlRef control = NULL ;
86 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
87 return control;
88}
89
b2680ced
SC
90// ---------------------------------------------------------------------------
91// Carbon Events
92// ---------------------------------------------------------------------------
489468fe 93
b2680ced
SC
94static const EventTypeSpec eventList[] =
95{
96 { kEventClassCommand, kEventProcessCommand } ,
97 { kEventClassCommand, kEventCommandUpdateStatus } ,
489468fe 98
b2680ced
SC
99 { kEventClassControl , kEventControlGetClickActivation } ,
100 { kEventClassControl , kEventControlHit } ,
489468fe 101
b2680ced
SC
102 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,
103 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea } ,
489468fe 104
b2680ced 105 { kEventClassControl , kEventControlDraw } ,
489468fe 106
b2680ced
SC
107 { kEventClassControl , kEventControlVisibilityChanged } ,
108 { kEventClassControl , kEventControlEnabledStateChanged } ,
109 { kEventClassControl , kEventControlHiliteChanged } ,
489468fe 110
b2680ced
SC
111 { kEventClassControl , kEventControlActivate } ,
112 { kEventClassControl , kEventControlDeactivate } ,
489468fe 113
b2680ced
SC
114 { kEventClassControl , kEventControlSetFocusPart } ,
115 { kEventClassControl , kEventControlFocusPartChanged } ,
489468fe 116
b2680ced
SC
117 { kEventClassService , kEventServiceGetTypes },
118 { kEventClassService , kEventServiceCopy },
119 { kEventClassService , kEventServicePaste },
489468fe 120
b2680ced
SC
121// { kEventClassControl , kEventControlInvalidateForSizeChange } , // 10.3 only
122// { kEventClassControl , kEventControlBoundsChanged } ,
123} ;
124
125static pascal OSStatus wxMacWindowControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
489468fe 126{
b2680ced
SC
127 OSStatus result = eventNotHandledErr ;
128 static wxWindowMac* targetFocusWindow = NULL;
129 static wxWindowMac* formerFocusWindow = NULL;
489468fe 130
b2680ced 131 wxMacCarbonEvent cEvent( event ) ;
489468fe 132
b2680ced
SC
133 ControlRef controlRef ;
134 wxWindowMac* thisWindow = (wxWindowMac*) data ;
135
136 cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
489468fe 137
b2680ced 138 switch ( GetEventKind( event ) )
489468fe 139 {
b2680ced
SC
140 case kEventControlDraw :
141 {
5398a2e0
SC
142 HIShapeRef updateRgn = NULL ;
143 HIMutableShapeRef allocatedRgn = NULL ;
b2680ced 144 wxRegion visRegion = thisWindow->MacGetVisibleRegion() ;
489468fe 145
5398a2e0
SC
146 // according to the docs: redraw entire control if param not present
147 if ( cEvent.GetParameter<HIShapeRef>(kEventParamShape, &updateRgn) != noErr )
b2680ced 148 {
5398a2e0 149 updateRgn = visRegion.GetWXHRGN();
b2680ced
SC
150 }
151 else
152 {
153 if ( thisWindow->MacGetLeftBorderSize() != 0 || thisWindow->MacGetTopBorderSize() != 0 )
154 {
155 // as this update region is in native window locals we must adapt it to wx window local
5398a2e0
SC
156 allocatedRgn = HIShapeCreateMutableCopy(updateRgn);
157 HIShapeOffset(allocatedRgn, thisWindow->MacGetLeftBorderSize() , thisWindow->MacGetTopBorderSize());
b2680ced 158 // hide the given region by the new region that must be shifted
b2680ced
SC
159 updateRgn = allocatedRgn ;
160 }
161 }
489468fe 162
b2680ced
SC
163#if wxMAC_DEBUG_REDRAW
164 if ( thisWindow->MacIsUserPane() )
165 {
166 static float color = 0.5 ;
167 static int channel = 0 ;
168 HIRect bounds;
169 CGContextRef cgContext = cEvent.GetParameter<CGContextRef>(kEventParamCGContextRef) ;
489468fe 170
b2680ced
SC
171 HIViewGetBounds( controlRef, &bounds );
172 CGContextSetRGBFillColor( cgContext, channel == 0 ? color : 0.5 ,
173 channel == 1 ? color : 0.5 , channel == 2 ? color : 0.5 , 1 );
174 CGContextFillRect( cgContext, bounds );
175 color += 0.1 ;
176 if ( color > 0.9 )
177 {
178 color = 0.5 ;
179 channel++ ;
180 if ( channel == 3 )
181 channel = 0 ;
182 }
183 }
489468fe 184#endif
489468fe 185
b2680ced 186 {
b2680ced
SC
187 CGContextRef cgContext = NULL ;
188 OSStatus err = cEvent.GetParameter<CGContextRef>(kEventParamCGContextRef, &cgContext) ;
189 if ( err != noErr )
190 {
191 wxFAIL_MSG("Unable to retrieve CGContextRef");
192 }
489468fe 193
b2680ced 194 thisWindow->MacSetCGContextRef( cgContext ) ;
489468fe 195
b2680ced
SC
196 {
197 wxMacCGContextStateSaver sg( cgContext ) ;
198 CGFloat alpha = (CGFloat)1.0 ;
199 {
200 wxWindow* iter = thisWindow ;
201 while ( iter )
202 {
203 alpha *= (CGFloat)( iter->GetTransparent()/255.0 ) ;
204 if ( iter->IsTopLevel() )
205 iter = NULL ;
206 else
207 iter = iter->GetParent() ;
208 }
209 }
8ceeb6c2 210 CGContextSetAlpha( cgContext, alpha ) ;
489468fe 211
b2680ced
SC
212 if ( thisWindow->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT )
213 {
214 HIRect bounds;
215 HIViewGetBounds( controlRef, &bounds );
216 CGContextClearRect( cgContext, bounds );
217 }
489468fe 218
5398a2e0
SC
219 if ( !HIShapeIsEmpty(updateRgn) )
220 {
221 // refcount increase because wxRegion constructor takes ownership of the native region
222 CFRetain(updateRgn);
223 thisWindow->GetUpdateRegion() = wxRegion(updateRgn);
224 if ( !thisWindow->MacDoRedraw( cEvent.GetTicks() ) )
225 {
226 // for native controls: call their native paint method
8f2a8de6 227 if ( !thisWindow->MacIsUserPane() ||
5398a2e0
SC
228 ( thisWindow->IsTopLevel() && thisWindow->GetBackgroundStyle() == wxBG_STYLE_SYSTEM ) )
229 {
230 if ( thisWindow->GetBackgroundStyle() != wxBG_STYLE_TRANSPARENT )
8ceeb6c2
SC
231 {
232 CallNextEventHandler( handler,event ) ;
233 result = noErr ;
234 }
5398a2e0
SC
235 }
236 }
8f2a8de6 237 else
8ceeb6c2
SC
238 {
239 result = noErr ;
240 }
5398a2e0
SC
241 thisWindow->MacPaintChildrenBorders();
242 }
b2680ced
SC
243 thisWindow->MacSetCGContextRef( NULL ) ;
244 }
b2680ced 245 }
489468fe 246
b2680ced 247 if ( allocatedRgn )
5398a2e0 248 CFRelease( allocatedRgn ) ;
b2680ced
SC
249 }
250 break ;
489468fe 251
b2680ced
SC
252 case kEventControlVisibilityChanged :
253 // we might have two native controls attributed to the same wxWindow instance
254 // eg a scrollview and an embedded textview, make sure we only fire for the 'outer'
255 // control, as otherwise native and wx visibility are different
256 if ( thisWindow->GetPeer() != NULL && thisWindow->GetPeer()->GetControlRef() == controlRef )
257 {
258 thisWindow->MacVisibilityChanged() ;
259 }
260 break ;
489468fe 261
b2680ced
SC
262 case kEventControlEnabledStateChanged :
263 thisWindow->MacEnabledStateChanged();
264 break ;
489468fe 265
b2680ced
SC
266 case kEventControlHiliteChanged :
267 thisWindow->MacHiliteChanged() ;
268 break ;
489468fe 269
b2680ced
SC
270 case kEventControlActivate :
271 case kEventControlDeactivate :
272 // FIXME: we should have a virtual function for this!
273#if wxUSE_TREECTRL
274 if ( thisWindow->IsKindOf( CLASSINFO( wxTreeCtrl ) ) )
275 thisWindow->Refresh();
276#endif
277#if wxUSE_LISTCTRL
278 if ( thisWindow->IsKindOf( CLASSINFO( wxListCtrl ) ) )
279 thisWindow->Refresh();
280#endif
281 break ;
282
283 //
284 // focus handling
285 // different handling on OS X
286 //
287
288 case kEventControlFocusPartChanged :
289 // the event is emulated by wxmac for systems lower than 10.5
290 {
291 if ( UMAGetSystemVersion() < 0x1050 )
292 {
293 // as it is synthesized here, we have to manually avoid propagation
294 result = noErr;
295 }
296 ControlPartCode previousControlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPreviousPart , typeControlPartCode );
297 ControlPartCode currentControlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlCurrentPart , typeControlPartCode );
298
299 if ( thisWindow->MacGetTopLevelWindow() && thisWindow->GetPeer()->NeedsFocusRect() )
300 {
301 thisWindow->MacInvalidateBorders();
302 }
303
304 if ( currentControlPart == 0 )
305 {
306 // kill focus
307#if wxUSE_CARET
308 if ( thisWindow->GetCaret() )
309 thisWindow->GetCaret()->OnKillFocus();
310#endif
311
9a83f860 312 wxLogTrace(wxT("Focus"), wxT("focus lost(%p)"), static_cast<void*>(thisWindow));
8f2a8de6 313
b2680ced
SC
314 // remove this as soon as posting the synthesized event works properly
315 static bool inKillFocusEvent = false ;
316
317 if ( !inKillFocusEvent )
318 {
319 inKillFocusEvent = true ;
320 wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId());
321 event.SetEventObject(thisWindow);
322 event.SetWindow(targetFocusWindow);
323 thisWindow->HandleWindowEvent(event) ;
324 inKillFocusEvent = false ;
325 targetFocusWindow = NULL;
326 }
327 }
328 else if ( previousControlPart == 0 )
329 {
330 // set focus
331 // panel wants to track the window which was the last to have focus in it
9a83f860 332 wxLogTrace(wxT("Focus"), wxT("focus set(%p)"), static_cast<void*>(thisWindow));
b2680ced
SC
333 wxChildFocusEvent eventFocus((wxWindow*)thisWindow);
334 thisWindow->HandleWindowEvent(eventFocus);
335
336#if wxUSE_CARET
337 if ( thisWindow->GetCaret() )
338 thisWindow->GetCaret()->OnSetFocus();
339#endif
340
341 wxFocusEvent event(wxEVT_SET_FOCUS, thisWindow->GetId());
342 event.SetEventObject(thisWindow);
343 event.SetWindow(formerFocusWindow);
344 thisWindow->HandleWindowEvent(event) ;
345 formerFocusWindow = NULL;
346 }
347 }
348 break;
349 case kEventControlSetFocusPart :
350 {
351 Boolean focusEverything = false ;
352 if ( cEvent.GetParameter<Boolean>(kEventParamControlFocusEverything , &focusEverything ) == noErr )
353 {
354 // put a breakpoint here to catch focus everything events
355 }
356 ControlPartCode controlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart , typeControlPartCode );
357 if ( controlPart != kControlFocusNoPart )
358 {
359 targetFocusWindow = thisWindow;
9a83f860 360 wxLogTrace(wxT("Focus"), wxT("focus to be set(%p)"), static_cast<void*>(thisWindow));
b2680ced
SC
361 }
362 else
363 {
364 formerFocusWindow = thisWindow;
9a83f860 365 wxLogTrace(wxT("Focus"), wxT("focus to be lost(%p)"), static_cast<void*>(thisWindow));
b2680ced 366 }
8f2a8de6 367
b2680ced
SC
368 ControlPartCode previousControlPart = 0;
369 verify_noerr( HIViewGetFocusPart(controlRef, &previousControlPart));
370
371 if ( thisWindow->MacIsUserPane() )
372 {
373 if ( controlPart != kControlFocusNoPart )
374 cEvent.SetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, 1 ) ;
375 result = noErr ;
376 }
377 else
378 result = CallNextEventHandler(handler, event);
379
380 if ( UMAGetSystemVersion() < 0x1050 )
381 {
382// set back to 0 if problems arise
383#if 1
384 if ( result == noErr )
385 {
386 ControlPartCode currentControlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart , typeControlPartCode );
387 // synthesize the event focus changed event
388 EventRef evRef = NULL ;
389
390 OSStatus err = MacCreateEvent(
391 NULL , kEventClassControl , kEventControlFocusPartChanged , TicksToEventTime( TickCount() ) ,
392 kEventAttributeUserEvent , &evRef );
393 verify_noerr( err );
394
395 wxMacCarbonEvent iEvent( evRef ) ;
396 iEvent.SetParameter<ControlRef>( kEventParamDirectObject , controlRef );
397 iEvent.SetParameter<EventTargetRef>( kEventParamPostTarget, typeEventTargetRef, GetControlEventTarget( controlRef ) );
398 iEvent.SetParameter<ControlPartCode>( kEventParamControlPreviousPart, typeControlPartCode, previousControlPart );
399 iEvent.SetParameter<ControlPartCode>( kEventParamControlCurrentPart, typeControlPartCode, currentControlPart );
8f2a8de6 400
489468fe 401#if 1
b2680ced
SC
402 // TODO test this first, avoid double posts etc...
403 PostEventToQueue( GetMainEventQueue(), evRef , kEventPriorityHigh );
489468fe 404#else
b2680ced
SC
405 wxMacWindowControlEventHandler( NULL , evRef , data ) ;
406#endif
407 ReleaseEvent( evRef ) ;
408 }
409#else
410 // old implementation, to be removed if the new one works
411 if ( controlPart == kControlFocusNoPart )
412 {
413#if wxUSE_CARET
414 if ( thisWindow->GetCaret() )
415 thisWindow->GetCaret()->OnKillFocus();
489468fe 416#endif
489468fe 417
9a83f860 418 wxLogTrace(wxT("Focus"), wxT("focus lost(%p)"), static_cast<void*>(thisWindow));
489468fe 419
b2680ced
SC
420 static bool inKillFocusEvent = false ;
421
422 if ( !inKillFocusEvent )
423 {
424 inKillFocusEvent = true ;
425 wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId());
426 event.SetEventObject(thisWindow);
427 thisWindow->HandleWindowEvent(event) ;
428 inKillFocusEvent = false ;
429 }
430 }
431 else
432 {
433 // panel wants to track the window which was the last to have focus in it
9a83f860 434 wxLogTrace(wxT("Focus"), wxT("focus set(%p)"), static_cast<void*>(thisWindow));
b2680ced
SC
435 wxChildFocusEvent eventFocus((wxWindow*)thisWindow);
436 thisWindow->HandleWindowEvent(eventFocus);
437
438 #if wxUSE_CARET
439 if ( thisWindow->GetCaret() )
440 thisWindow->GetCaret()->OnSetFocus();
441 #endif
442
443 wxFocusEvent event(wxEVT_SET_FOCUS, thisWindow->GetId());
444 event.SetEventObject(thisWindow);
445 thisWindow->HandleWindowEvent(event) ;
446 }
489468fe 447#endif
b2680ced
SC
448 }
449 }
450 break ;
451
452 case kEventControlHit :
453 result = thisWindow->MacControlHit( handler , event ) ;
454 break ;
455
456 case kEventControlGetClickActivation :
457 {
458 // fix to always have a proper activation for DataBrowser controls (stay in bkgnd otherwise)
459 WindowRef owner = cEvent.GetParameter<WindowRef>(kEventParamWindowRef);
460 if ( !IsWindowActive(owner) )
461 {
cf1c280f 462 cEvent.SetParameter(kEventParamClickActivation,typeClickActivationResult, (UInt32) kActivateAndIgnoreClick) ;
b2680ced
SC
463 result = noErr ;
464 }
465 }
466 break ;
467
468 default :
469 break ;
489468fe
SC
470 }
471
b2680ced
SC
472 return result ;
473}
474
475static pascal OSStatus
476wxMacWindowServiceEventHandler(EventHandlerCallRef WXUNUSED(handler),
477 EventRef event,
478 void *data)
479{
480 OSStatus result = eventNotHandledErr ;
481
482 wxMacCarbonEvent cEvent( event ) ;
483
484 ControlRef controlRef ;
485 wxWindowMac* thisWindow = (wxWindowMac*) data ;
486 wxTextCtrl* textCtrl = wxDynamicCast( thisWindow , wxTextCtrl ) ;
487 cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
488
489 switch ( GetEventKind( event ) )
489468fe 490 {
b2680ced
SC
491 case kEventServiceGetTypes :
492 if ( textCtrl )
493 {
494 long from, to ;
495 textCtrl->GetSelection( &from , &to ) ;
489468fe 496
b2680ced
SC
497 CFMutableArrayRef copyTypes = 0 , pasteTypes = 0;
498 if ( from != to )
499 copyTypes = cEvent.GetParameter< CFMutableArrayRef >( kEventParamServiceCopyTypes , typeCFMutableArrayRef ) ;
500 if ( textCtrl->IsEditable() )
501 pasteTypes = cEvent.GetParameter< CFMutableArrayRef >( kEventParamServicePasteTypes , typeCFMutableArrayRef ) ;
502
503 static const OSType textDataTypes[] = { kTXNTextData /* , 'utxt', 'PICT', 'MooV', 'AIFF' */ };
504 for ( size_t i = 0 ; i < WXSIZEOF(textDataTypes) ; ++i )
505 {
506 CFStringRef typestring = CreateTypeStringWithOSType(textDataTypes[i]);
507 if ( typestring )
508 {
509 if ( copyTypes )
510 CFArrayAppendValue(copyTypes, typestring) ;
511 if ( pasteTypes )
512 CFArrayAppendValue(pasteTypes, typestring) ;
513
514 CFRelease( typestring ) ;
515 }
516 }
517
518 result = noErr ;
519 }
520 break ;
521
522 case kEventServiceCopy :
523 if ( textCtrl )
524 {
525 long from, to ;
526
527 textCtrl->GetSelection( &from , &to ) ;
528 wxString val = textCtrl->GetValue() ;
529 val = val.Mid( from , to - from ) ;
530 PasteboardRef pasteboard = cEvent.GetParameter<PasteboardRef>( kEventParamPasteboardRef, typePasteboardRef );
531 verify_noerr( PasteboardClear( pasteboard ) ) ;
532 PasteboardSynchronize( pasteboard );
533 // TODO add proper conversion
534 CFDataRef data = CFDataCreate( kCFAllocatorDefault, (const UInt8*)val.c_str(), val.length() );
535 PasteboardPutItemFlavor( pasteboard, (PasteboardItemID) 1, CFSTR("com.apple.traditional-mac-plain-text"), data, 0);
536 CFRelease( data );
537 result = noErr ;
538 }
539 break ;
540
541 case kEventServicePaste :
542 if ( textCtrl )
543 {
544 PasteboardRef pasteboard = cEvent.GetParameter<PasteboardRef>( kEventParamPasteboardRef, typePasteboardRef );
545 PasteboardSynchronize( pasteboard );
546 ItemCount itemCount;
547 verify_noerr( PasteboardGetItemCount( pasteboard, &itemCount ) );
548 for( UInt32 itemIndex = 1; itemIndex <= itemCount; itemIndex++ )
549 {
550 PasteboardItemID itemID;
551 if ( PasteboardGetItemIdentifier( pasteboard, itemIndex, &itemID ) == noErr )
552 {
553 CFDataRef flavorData = NULL;
554 if ( PasteboardCopyItemFlavorData( pasteboard, itemID, CFSTR("com.apple.traditional-mac-plain-text"), &flavorData ) == noErr )
555 {
556 CFIndex flavorDataSize = CFDataGetLength( flavorData );
557 char *content = new char[flavorDataSize+1] ;
558 memcpy( content, CFDataGetBytePtr( flavorData ), flavorDataSize );
559 content[flavorDataSize]=0;
560 CFRelease( flavorData );
561#if wxUSE_UNICODE
562 textCtrl->WriteText( wxString( content , wxConvLocal ) );
563#else
564 textCtrl->WriteText( wxString( content ) ) ;
565#endif
566
567 delete[] content ;
568 result = noErr ;
569 }
570 }
571 }
572 }
573 break ;
574
575 default:
576 break ;
489468fe 577 }
b2680ced
SC
578
579 return result ;
489468fe
SC
580}
581
b2680ced 582pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
489468fe 583{
b2680ced
SC
584 OSStatus result = eventNotHandledErr ;
585 wxWindowMac* focus = (wxWindowMac*) data ;
586
587 wchar_t* uniChars = NULL ;
588 UInt32 when = EventTimeToTicks( GetEventTime( event ) ) ;
589
590 UniChar* charBuf = NULL;
591 ByteCount dataSize = 0 ;
592 int numChars = 0 ;
593 UniChar buf[2] ;
594 if ( GetEventParameter( event, kEventParamTextInputSendText, typeUnicodeText, NULL, 0 , &dataSize, NULL ) == noErr )
489468fe 595 {
b2680ced
SC
596 numChars = dataSize / sizeof( UniChar) + 1;
597 charBuf = buf ;
489468fe 598
b2680ced
SC
599 if ( (size_t) numChars * 2 > sizeof(buf) )
600 charBuf = new UniChar[ numChars ] ;
601 else
602 charBuf = buf ;
603
604 uniChars = new wchar_t[ numChars ] ;
605 GetEventParameter( event, kEventParamTextInputSendText, typeUnicodeText, NULL, dataSize , NULL , charBuf ) ;
606 charBuf[ numChars - 1 ] = 0;
607#if SIZEOF_WCHAR_T == 2
608 uniChars = (wchar_t*) charBuf ;
609/* 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...)
610#else
611 // the resulting string will never have more chars than the utf16 version, so this is safe
612 wxMBConvUTF16 converter ;
613 numChars = converter.MB2WC( uniChars , (const char*)charBuf , numChars ) ;
614#endif
615 }
616
617 switch ( GetEventKind( event ) )
618 {
619 case kEventTextInputUpdateActiveInputArea :
620 {
621 // An IME input event may return several characters, but we need to send one char at a time to
622 // EVT_CHAR
623 for (int pos=0 ; pos < numChars ; pos++)
624 {
625 WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
626 WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
627 wxTheApp->MacSetCurrentEvent( event , handler ) ;
628
629 UInt32 message = uniChars[pos] < 128 ? (char)uniChars[pos] : '?';
630/*
631 NB: faking a charcode here is problematic. The kEventTextInputUpdateActiveInputArea event is sent
632 multiple times to update the active range during inline input, so this handler will often receive
633 uncommited text, which should usually not trigger side effects. It might be a good idea to check the
634 kEventParamTextInputSendFixLen parameter and verify if input is being confirmed (see CarbonEvents.h).
635 On the other hand, it can be useful for some applications to react to uncommitted text (for example,
636 to update a status display), as long as it does not disrupt the inline input session. Ideally, wx
637 should add new event types to support advanced text input. For now, I would keep things as they are.
638
639 However, the code that was being used caused additional problems:
640 UInt32 message = (0 << 8) + ((char)uniChars[pos] );
641 Since it simply truncated the unichar to the last byte, it ended up causing weird bugs with inline
642 input, such as switching to another field when one attempted to insert the character U+4E09 (the kanji
643 for "three"), because it was truncated to 09 (kTabCharCode), which was later "converted" to WXK_TAB
644 (still 09) in wxMacTranslateKey; or triggering the default button when one attempted to insert U+840D
645 (the kanji for "name"), which got truncated to 0D and interpreted as a carriage return keypress.
646 Note that even single-byte characters could have been misinterpreted, since MacRoman charcodes only
647 overlap with Unicode within the (7-bit) ASCII range.
648 But simply passing a NUL charcode would disable text updated events, because wxTextCtrl::OnChar checks
649 for codes within a specific range. Therefore I went for the solution seen above, which keeps ASCII
650 characters as they are and replaces the rest with '?', ensuring that update events are triggered.
651 It would be better to change wxTextCtrl::OnChar to look at the actual unicode character instead, but
652 I don't have time to look into that right now.
653 -- CL
654*/
655 if ( wxTheApp->MacSendCharEvent(
656 focus , message , 0 , when , 0 , 0 , uniChars[pos] ) )
657 {
658 result = noErr ;
659 }
660
661 wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
662 }
663 }
664 break ;
665 case kEventTextInputUnicodeForKeyEvent :
666 {
667 UInt32 keyCode, modifiers ;
668 Point point ;
669 EventRef rawEvent ;
670 unsigned char charCode ;
671
672 GetEventParameter( event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(rawEvent), NULL, &rawEvent ) ;
673 GetEventParameter( rawEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &charCode );
674 GetEventParameter( rawEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode );
675 GetEventParameter( rawEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers );
676 GetEventParameter( rawEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &point );
677
678 UInt32 message = (keyCode << 8) + charCode;
489468fe 679
b2680ced
SC
680 // An IME input event may return several characters, but we need to send one char at a time to
681 // EVT_CHAR
682 for (int pos=0 ; pos < numChars ; pos++)
683 {
684 WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
685 WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
686 wxTheApp->MacSetCurrentEvent( event , handler ) ;
687
688 if ( wxTheApp->MacSendCharEvent(
689 focus , message , modifiers , when , point.h , point.v , uniChars[pos] ) )
690 {
691 result = noErr ;
692 }
693
694 wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
695 }
696 }
697 break;
698 default:
699 break ;
489468fe 700 }
489468fe 701
b2680ced
SC
702 delete [] uniChars ;
703 if ( charBuf != buf )
704 delete [] charBuf ;
489468fe 705
b2680ced 706 return result ;
489468fe
SC
707}
708
b2680ced
SC
709static pascal OSStatus
710wxMacWindowCommandEventHandler(EventHandlerCallRef WXUNUSED(handler),
711 EventRef event,
712 void *data)
489468fe 713{
b2680ced
SC
714 OSStatus result = eventNotHandledErr ;
715 wxWindowMac* focus = (wxWindowMac*) data ;
489468fe 716
b2680ced 717 HICommand command ;
489468fe 718
b2680ced
SC
719 wxMacCarbonEvent cEvent( event ) ;
720 cEvent.GetParameter<HICommand>(kEventParamDirectObject,typeHICommand,&command) ;
489468fe 721
b2680ced
SC
722 wxMenuItem* item = NULL ;
723 wxMenu* itemMenu = wxFindMenuFromMacCommand( command , item ) ;
489468fe 724
b2680ced 725 if ( item )
489468fe 726 {
b2680ced 727 wxASSERT( itemMenu != NULL ) ;
489468fe 728
b2680ced 729 switch ( cEvent.GetKind() )
489468fe 730 {
b2680ced 731 case kEventProcessCommand :
524c47aa
SC
732 if ( itemMenu->HandleCommandProcess( item, focus ) )
733 result = noErr;
b2680ced 734 break ;
489468fe 735
b2680ced 736 case kEventCommandUpdateStatus:
524c47aa
SC
737 if ( itemMenu->HandleCommandUpdateStatus( item, focus ) )
738 result = noErr;
b2680ced 739 break ;
489468fe 740
b2680ced
SC
741 default :
742 break ;
743 }
489468fe 744 }
b2680ced 745 return result ;
489468fe
SC
746}
747
b2680ced 748pascal OSStatus wxMacWindowEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
489468fe 749{
b2680ced
SC
750 EventRef formerEvent = (EventRef) wxTheApp->MacGetCurrentEvent() ;
751 EventHandlerCallRef formerEventHandlerCallRef = (EventHandlerCallRef) wxTheApp->MacGetCurrentEventHandlerCallRef() ;
752 wxTheApp->MacSetCurrentEvent( event , handler ) ;
753 OSStatus result = eventNotHandledErr ;
489468fe 754
b2680ced
SC
755 switch ( GetEventClass( event ) )
756 {
757 case kEventClassCommand :
758 result = wxMacWindowCommandEventHandler( handler , event , data ) ;
759 break ;
489468fe 760
b2680ced
SC
761 case kEventClassControl :
762 result = wxMacWindowControlEventHandler( handler, event, data ) ;
763 break ;
489468fe 764
b2680ced
SC
765 case kEventClassService :
766 result = wxMacWindowServiceEventHandler( handler, event , data ) ;
767 break ;
489468fe 768
b2680ced
SC
769 case kEventClassTextInput :
770 result = wxMacUnicodeTextEventHandler( handler , event , data ) ;
771 break ;
489468fe 772
b2680ced
SC
773 default :
774 break ;
775 }
489468fe 776
b2680ced 777 wxTheApp->MacSetCurrentEvent( formerEvent, formerEventHandlerCallRef ) ;
489468fe 778
b2680ced 779 return result ;
489468fe
SC
780}
781
b2680ced 782DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacWindowEventHandler )
489468fe 783
b2680ced
SC
784// ---------------------------------------------------------------------------
785// Scrollbar Tracking for all
786// ---------------------------------------------------------------------------
489468fe 787
b2680ced
SC
788pascal void wxMacLiveScrollbarActionProc( ControlRef control , ControlPartCode partCode ) ;
789pascal void wxMacLiveScrollbarActionProc( ControlRef control , ControlPartCode partCode )
489468fe 790{
b2680ced 791 if ( partCode != 0)
489468fe 792 {
b2680ced
SC
793 wxWindow* wx = wxFindWindowFromWXWidget( (WXWidget) control ) ;
794 if ( wx )
8f2a8de6 795 {
19c7ac3d
SC
796 wxEventType scrollEvent = wxEVT_NULL;
797 switch ( partCode )
798 {
799 case kControlUpButtonPart:
800 scrollEvent = wxEVT_SCROLL_LINEUP;
801 break;
802
803 case kControlDownButtonPart:
804 scrollEvent = wxEVT_SCROLL_LINEDOWN;
805 break;
806
807 case kControlPageUpPart:
808 scrollEvent = wxEVT_SCROLL_PAGEUP;
809 break;
810
811 case kControlPageDownPart:
812 scrollEvent = wxEVT_SCROLL_PAGEDOWN;
813 break;
814
815 case kControlIndicatorPart:
816 scrollEvent = wxEVT_SCROLL_THUMBTRACK;
817 // when this is called as a live proc, mouse is always still down
818 // so no need for thumbrelease
819 // scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
820 break;
821 }
822 wx->TriggerScrollEvent(scrollEvent) ;
823 }
489468fe
SC
824 }
825}
b2680ced 826wxMAC_DEFINE_PROC_GETTER( ControlActionUPP , wxMacLiveScrollbarActionProc ) ;
489468fe 827
8f2a8de6
VZ
828wxWidgetImplType* wxWidgetImpl::CreateUserPane( wxWindowMac* wxpeer,
829 wxWindowMac* WXUNUSED(parent),
830 wxWindowID WXUNUSED(id),
831 const wxPoint& pos,
a4fec5b4 832 const wxSize& size,
8f2a8de6 833 long WXUNUSED(style),
a4fec5b4 834 long WXUNUSED(extraStyle))
489468fe 835{
b2680ced
SC
836 OSStatus err = noErr;
837 Rect bounds = wxMacGetBoundsForControl( wxpeer , pos , size ) ;
838 wxMacControl* c = new wxMacControl(wxpeer) ;
839 UInt32 features = 0
840 | kControlSupportsEmbedding
841 | kControlSupportsLiveFeedback
842 | kControlGetsFocusOnClick
843// | kControlHasSpecialBackground
844// | kControlSupportsCalcBestRect
845 | kControlHandlesTracking
846 | kControlSupportsFocus
847 | kControlWantsActivate
848 | kControlWantsIdle ;
489468fe 849
b2680ced
SC
850 err =::CreateUserPaneControl( MAC_WXHWND(wxpeer->GetParent()->MacGetTopLevelWindowRef()) , &bounds, features , c->GetControlRefAddr() );
851 verify_noerr( err );
852 return c;
853}
489468fe 854
489468fe 855
f55d9f74 856void wxMacControl::InstallEventHandler( WXWidget control )
b2680ced 857{
f55d9f74
SC
858 wxWidgetImpl::Associate( control ? control : (WXWidget) m_controlRef , this ) ;
859 ::InstallControlEventHandler( control ? (ControlRef) control : m_controlRef , GetwxMacWindowEventHandlerUPP(),
860 GetEventTypeCount(eventList), eventList, GetWXPeer(), NULL);
489468fe
SC
861}
862
b2680ced
SC
863IMPLEMENT_DYNAMIC_CLASS( wxMacControl , wxWidgetImpl )
864
865wxMacControl::wxMacControl()
489468fe 866{
b2680ced
SC
867 Init();
868}
489468fe 869
b2680ced
SC
870wxMacControl::wxMacControl(wxWindowMac* peer , bool isRootControl ) :
871 wxWidgetImpl( peer, isRootControl )
872{
873 Init();
874}
489468fe 875
b2680ced
SC
876wxMacControl::~wxMacControl()
877{
524c47aa
SC
878 if ( m_controlRef && !IsRootControl() )
879 {
880 wxASSERT_MSG( m_controlRef != NULL , wxT("Control Handle already NULL, Dispose called twice ?") );
881 wxASSERT_MSG( IsValidControlHandle(m_controlRef) , wxT("Invalid Control Handle (maybe already released) in Dispose") );
489468fe 882
f55d9f74 883 wxWidgetImpl::RemoveAssociations( this ) ;
524c47aa
SC
884 // we cannot check the ref count here anymore, as autorelease objects might delete their refs later
885 // we can have situations when being embedded, where the control gets deleted behind our back, so only
886 // CFRelease if we are safe
887 if ( IsValidControlHandle(m_controlRef) )
888 CFRelease(m_controlRef);
889 }
b2680ced 890 m_controlRef = NULL;
b2680ced 891}
489468fe 892
524c47aa 893void wxMacControl::Init()
b2680ced 894{
b2680ced 895 m_controlRef = NULL;
524c47aa 896 m_macControlEventHandler = NULL;
b2680ced 897}
489468fe 898
b2680ced
SC
899void wxMacControl::RemoveFromParent()
900{
901 // nothing to do here for carbon
c4825ef7 902 HIViewRemoveFromSuperview(m_controlRef);
b2680ced 903}
489468fe 904
b2680ced
SC
905void wxMacControl::Embed( wxWidgetImpl *parent )
906{
bd412bc6 907 HIViewAddSubview((ControlRef)parent->GetWXWidget(), m_controlRef);
b2680ced 908}
489468fe 909
b2680ced
SC
910void wxMacControl::SetNeedsDisplay( const wxRect* rect )
911{
912 if ( !IsVisible() )
913 return;
489468fe 914
b2680ced
SC
915 if ( rect != NULL )
916 {
917 HIRect updatearea = CGRectMake( rect->x , rect->y , rect->width , rect->height);
918 HIViewSetNeedsDisplayInRect( m_controlRef, &updatearea, true );
919 }
920 else
921 HIViewSetNeedsDisplay( m_controlRef , true );
922}
489468fe 923
b2680ced
SC
924void wxMacControl::Raise()
925{
926 verify_noerr( HIViewSetZOrder( m_controlRef, kHIViewZOrderAbove, NULL ) );
927}
8f2a8de6 928
b2680ced
SC
929void wxMacControl::Lower()
930{
931 verify_noerr( HIViewSetZOrder( m_controlRef, kHIViewZOrderBelow, NULL ) );
932}
489468fe 933
b2680ced
SC
934void wxMacControl::GetContentArea(int &left , int &top , int &width , int &height) const
935{
f215225d 936 HIShapeRef rgn = NULL;
8f2a8de6 937 Rect content ;
f215225d
SC
938
939 if ( HIViewCopyShape(m_controlRef, kHIViewContentMetaPart, &rgn) == noErr)
940 {
941 CGRect cgrect;
942 HIShapeGetBounds(rgn, &cgrect);
8f2a8de6
VZ
943 content = (Rect){ (short)cgrect.origin.y,
944 (short)cgrect.origin.x,
945 (short)(cgrect.origin.y+cgrect.size.height),
946 (short)(cgrect.origin.x+cgrect.size.width) };
f215225d
SC
947 CFRelease(rgn);
948 }
b2680ced 949 else
524c47aa 950 {
f215225d 951 GetControlBounds(m_controlRef, &content);
524c47aa
SC
952 content.right -= content.left;
953 content.left = 0;
954 content.bottom -= content.top;
955 content.top = 0;
956 }
489468fe 957
b2680ced
SC
958 left = content.left;
959 top = content.top;
489468fe 960
b2680ced
SC
961 width = content.right - content.left ;
962 height = content.bottom - content.top ;
963}
964
965void wxMacControl::Move(int x, int y, int width, int height)
966{
967 HIRect hir = CGRectMake(x,y,width,height);
968 HIViewSetFrame ( m_controlRef , &hir );
489468fe
SC
969}
970
b2680ced
SC
971void wxMacControl::GetPosition( int &x, int &y ) const
972{
973 Rect r;
974 GetControlBounds( m_controlRef , &r );
975 x = r.left;
976 y = r.top;
977}
489468fe 978
b2680ced 979void wxMacControl::GetSize( int &width, int &height ) const
489468fe 980{
b2680ced
SC
981 Rect r;
982 GetControlBounds( m_controlRef , &r );
983 width = r.right - r.left;
984 height = r.bottom - r.top;
985}
489468fe 986
8f2a8de6 987void wxMacControl::SetControlSize( wxWindowVariant variant )
524c47aa
SC
988{
989 ControlSize size ;
990 switch ( variant )
991 {
992 case wxWINDOW_VARIANT_NORMAL :
993 size = kControlSizeNormal;
994 break ;
995
996 case wxWINDOW_VARIANT_SMALL :
997 size = kControlSizeSmall;
998 break ;
999
1000 case wxWINDOW_VARIANT_MINI :
1001 // not always defined in the headers
1002 size = 3 ;
1003 break ;
1004
1005 case wxWINDOW_VARIANT_LARGE :
1006 size = kControlSizeLarge;
1007 break ;
1008
1009 default:
9a83f860 1010 wxFAIL_MSG(wxT("unexpected window variant"));
524c47aa
SC
1011 break ;
1012 }
1013
1014 SetData<ControlSize>(kControlEntireControl, kControlSizeTag, &size ) ;
1015}
1016
b2680ced
SC
1017void wxMacControl::ScrollRect( const wxRect *rect, int dx, int dy )
1018{
1019 if (GetNeedsDisplay() )
489468fe 1020 {
b2680ced
SC
1021 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
1022 // in case there is already a pending redraw on that area
1023 // either immediate redraw or full invalidate
1024#if 1
1025 // is the better overall solution, as it does not slow down scrolling
1026 SetNeedsDisplay() ;
1027#else
1028 // this would be the preferred version for fast drawing controls
1029 HIViewRender(GetControlRef()) ;
489468fe 1030#endif
489468fe
SC
1031 }
1032
b2680ced
SC
1033 // note there currently is a bug in OSX (10.3 +?) which makes inefficient refreshes in case an entire control
1034 // area is scrolled, this does not occur if width and height are 2 pixels less,
1035 // TODO: write optimal workaround
1036
1037 HIRect scrollarea = CGRectMake( rect->x , rect->y , rect->width , rect->height);
1038 HIViewScrollRect ( m_controlRef , &scrollarea , dx ,dy );
1039
1040#if 0
1041 // this would be the preferred version for fast drawing controls
1042 HIViewRender(GetControlRef()) ;
1043#endif
489468fe
SC
1044}
1045
b2680ced 1046bool wxMacControl::CanFocus() const
489468fe 1047{
b2680ced
SC
1048 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
1049 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
1050 // but the value range is nowhere documented
1051 Boolean keyExistsAndHasValidFormat ;
1052 CFIndex fullKeyboardAccess = CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
1053 kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat );
489468fe 1054
b2680ced 1055 if ( keyExistsAndHasValidFormat && fullKeyboardAccess > 0 )
489468fe 1056 {
b2680ced 1057 return true ;
489468fe
SC
1058 }
1059 else
1060 {
b2680ced
SC
1061 UInt32 features = 0 ;
1062 GetControlFeatures( m_controlRef, &features ) ;
489468fe 1063
b2680ced 1064 return features & ( kControlSupportsFocus | kControlGetsFocusOnClick ) ;
489468fe
SC
1065 }
1066}
1067
b2680ced 1068bool wxMacControl::GetNeedsDisplay() const
489468fe 1069{
b2680ced
SC
1070 return HIViewGetNeedsDisplay( m_controlRef );
1071}
489468fe 1072
b2680ced
SC
1073void wxWidgetImpl::Convert( wxPoint *pt , wxWidgetImpl *from , wxWidgetImpl *to )
1074{
1075 HIPoint hiPoint;
489468fe 1076
b2680ced
SC
1077 hiPoint.x = pt->x;
1078 hiPoint.y = pt->y;
1079 HIViewConvertPoint( &hiPoint , (ControlRef) from->GetWXWidget() , (ControlRef) to->GetWXWidget() );
1080 pt->x = (int)hiPoint.x;
1081 pt->y = (int)hiPoint.y;
1082}
489468fe 1083
b2680ced
SC
1084bool wxMacControl::SetFocus()
1085{
1086 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1087 // we can only leave in case of an error
489468fe 1088
b2680ced
SC
1089 OSStatus err = SetKeyboardFocus( GetControlOwner( m_controlRef ), m_controlRef, kControlFocusNextPart );
1090 if ( err == errCouldntSetFocus )
1091 return false ;
1092 SetUserFocusWindow(GetControlOwner( m_controlRef ) );
8f2a8de6 1093
b2680ced 1094 return true;
489468fe
SC
1095}
1096
b2680ced 1097bool wxMacControl::HasFocus() const
489468fe 1098{
b2680ced
SC
1099 ControlRef control;
1100 GetKeyboardFocus( GetUserFocusWindow() , &control );
1101 return control == m_controlRef;
1102}
489468fe 1103
54f11060
SC
1104void wxMacControl::SetCursor(const wxCursor& cursor)
1105{
1106 wxWindowMac *mouseWin = 0 ;
1107 WindowRef window = GetControlOwner( m_controlRef ) ;
1108
1109 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) window ) ;
1110 if ( tlwwx != NULL )
1111 {
1112 ControlPartCode part ;
1113 ControlRef control ;
1114 Point pt ;
1115#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1116 HIPoint hiPoint ;
1117 HIGetMousePosition(kHICoordSpaceWindow, window, &hiPoint);
1118 pt.h = hiPoint.x;
1119 pt.v = hiPoint.y;
1120#else
1121 GetGlobalMouse( &pt );
1122 int x = pt.h;
1123 int y = pt.v;
1124 tlwwx->ScreenToClient(&x, &y);
1125 pt.h = x;
1126 pt.v = y;
1127#endif
1128 control = FindControlUnderMouse( pt , window , &part ) ;
1129 if ( control )
1130 mouseWin = wxFindWindowFromWXWidget( (WXWidget) control ) ;
1131 }
1132
1133 if ( mouseWin == tlwwx && !wxIsBusy() )
1134 cursor.MacInstall() ;
1135}
1136
1137void wxMacControl::CaptureMouse()
1138{
1139}
1140
1141void wxMacControl::ReleaseMouse()
1142{
1143}
1144
b2680ced
SC
1145//
1146// subclass specifics
1147//
1148
1149OSStatus wxMacControl::GetData(ControlPartCode inPartCode , ResType inTag , Size inBufferSize , void * inOutBuffer , Size * outActualSize ) const
1150{
1151 return ::GetControlData( m_controlRef , inPartCode , inTag , inBufferSize , inOutBuffer , outActualSize );
489468fe
SC
1152}
1153
b2680ced 1154OSStatus wxMacControl::GetDataSize(ControlPartCode inPartCode , ResType inTag , Size * outActualSize ) const
489468fe 1155{
b2680ced
SC
1156 return ::GetControlDataSize( m_controlRef , inPartCode , inTag , outActualSize );
1157}
489468fe 1158
b2680ced
SC
1159OSStatus wxMacControl::SetData(ControlPartCode inPartCode , ResType inTag , Size inSize , const void * inData)
1160{
1161 return ::SetControlData( m_controlRef , inPartCode , inTag , inSize , inData );
1162}
489468fe 1163
b2680ced
SC
1164OSStatus wxMacControl::SendEvent( EventRef event , OptionBits inOptions )
1165{
1166 return SendEventToEventTargetWithOptions( event,
1167 HIObjectGetEventTarget( (HIObjectRef) m_controlRef ), inOptions );
1168}
489468fe 1169
b2680ced
SC
1170OSStatus wxMacControl::SendHICommand( HICommand &command , OptionBits inOptions )
1171{
1172 wxMacCarbonEvent event( kEventClassCommand , kEventCommandProcess );
489468fe 1173
b2680ced 1174 event.SetParameter<HICommand>(kEventParamDirectObject,command);
489468fe 1175
b2680ced
SC
1176 return SendEvent( event , inOptions );
1177}
489468fe 1178
b2680ced
SC
1179OSStatus wxMacControl::SendHICommand( UInt32 commandID , OptionBits inOptions )
1180{
1181 HICommand command;
489468fe 1182
b2680ced
SC
1183 memset( &command, 0 , sizeof(command) );
1184 command.commandID = commandID;
1185 return SendHICommand( command , inOptions );
1186}
489468fe 1187
524c47aa 1188void wxMacControl::PerformClick()
b2680ced 1189{
524c47aa 1190 HIViewSimulateClick (m_controlRef, kControlButtonPart, 0, NULL );
b2680ced 1191}
489468fe 1192
524c47aa 1193wxInt32 wxMacControl::GetValue() const
b2680ced
SC
1194{
1195 return ::GetControl32BitValue( m_controlRef );
1196}
489468fe 1197
19c7ac3d 1198wxInt32 wxMacControl::GetMaximum() const
b2680ced
SC
1199{
1200 return ::GetControl32BitMaximum( m_controlRef );
1201}
489468fe 1202
524c47aa 1203wxInt32 wxMacControl::GetMinimum() const
b2680ced
SC
1204{
1205 return ::GetControl32BitMinimum( m_controlRef );
489468fe
SC
1206}
1207
524c47aa 1208void wxMacControl::SetValue( wxInt32 v )
489468fe 1209{
b2680ced 1210 ::SetControl32BitValue( m_controlRef , v );
489468fe
SC
1211}
1212
524c47aa 1213void wxMacControl::SetMinimum( wxInt32 v )
489468fe 1214{
b2680ced
SC
1215 ::SetControl32BitMinimum( m_controlRef , v );
1216}
489468fe 1217
524c47aa 1218void wxMacControl::SetMaximum( wxInt32 v )
b2680ced
SC
1219{
1220 ::SetControl32BitMaximum( m_controlRef , v );
1221}
489468fe 1222
b2680ced
SC
1223void wxMacControl::SetValueAndRange( SInt32 value , SInt32 minimum , SInt32 maximum )
1224{
1225 ::SetControl32BitMinimum( m_controlRef , minimum );
1226 ::SetControl32BitMaximum( m_controlRef , maximum );
1227 ::SetControl32BitValue( m_controlRef , value );
1228}
489468fe 1229
b2680ced
SC
1230void wxMacControl::VisibilityChanged(bool WXUNUSED(shown))
1231{
489468fe
SC
1232}
1233
b2680ced 1234void wxMacControl::SuperChangedPosition()
489468fe 1235{
b2680ced 1236}
489468fe 1237
1e181c7a 1238void wxMacControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack )
b2680ced
SC
1239{
1240 m_font = font;
292e5e1f 1241#if wxOSX_USE_CORE_TEXT
b2680ced 1242 if ( UMAGetSystemVersion() >= 0x1050 )
489468fe 1243 {
b2680ced
SC
1244 HIViewPartCode part = 0;
1245 HIThemeTextHorizontalFlush flush = kHIThemeTextHorizontalFlushDefault;
1246 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1247 flush = kHIThemeTextHorizontalFlushCenter;
1248 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1249 flush = kHIThemeTextHorizontalFlushRight;
aa6208d9 1250 HIViewSetTextFont( m_controlRef , part , (CTFontRef) font.OSXGetCTFont() );
b2680ced 1251 HIViewSetTextHorizontalFlush( m_controlRef, part, flush );
489468fe 1252
1e181c7a 1253 if ( foreground != *wxBLACK || ignoreBlack == false )
b2680ced
SC
1254 {
1255 ControlFontStyleRec fontStyle;
1256 foreground.GetRGBColor( &fontStyle.foreColor );
1257 fontStyle.flags = kControlUseForeColorMask;
1258 ::SetControlFontStyle( m_controlRef , &fontStyle );
1259 }
489468fe 1260 }
b2680ced 1261#endif
292e5e1f 1262#if wxOSX_USE_ATSU_TEXT
b2680ced
SC
1263 ControlFontStyleRec fontStyle;
1264 if ( font.MacGetThemeFontID() != kThemeCurrentPortFont )
1265 {
1266 switch ( font.MacGetThemeFontID() )
1267 {
1268 case kThemeSmallSystemFont :
1269 fontStyle.font = kControlFontSmallSystemFont;
1270 break;
489468fe 1271
b2680ced
SC
1272 case 109 : // mini font
1273 fontStyle.font = -5;
1274 break;
489468fe 1275
b2680ced
SC
1276 case kThemeSystemFont :
1277 fontStyle.font = kControlFontBigSystemFont;
1278 break;
489468fe 1279
b2680ced
SC
1280 default :
1281 fontStyle.font = kControlFontBigSystemFont;
1282 break;
1283 }
1284
1285 fontStyle.flags = kControlUseFontMask;
1286 }
1287 else
489468fe 1288 {
b2680ced
SC
1289 fontStyle.font = font.MacGetFontNum();
1290 fontStyle.style = font.MacGetFontStyle();
f1c40652 1291 fontStyle.size = font.GetPointSize();
b2680ced 1292 fontStyle.flags = kControlUseFontMask | kControlUseFaceMask | kControlUseSizeMask;
489468fe 1293 }
b2680ced
SC
1294
1295 fontStyle.just = teJustLeft;
1296 fontStyle.flags |= kControlUseJustMask;
1297 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1298 fontStyle.just = teJustCenter;
1299 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1300 fontStyle.just = teJustRight;
1301
1302
1303 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1304 // won't get grayed out by the system anymore
1305
1e181c7a 1306 if ( foreground != *wxBLACK || ignoreBlack == false )
489468fe 1307 {
b2680ced
SC
1308 foreground.GetRGBColor( &fontStyle.foreColor );
1309 fontStyle.flags |= kControlUseForeColorMask;
489468fe
SC
1310 }
1311
b2680ced
SC
1312 ::SetControlFontStyle( m_controlRef , &fontStyle );
1313#endif
489468fe
SC
1314}
1315
b2680ced 1316void wxMacControl::SetBackgroundColour( const wxColour &WXUNUSED(col) )
489468fe 1317{
b2680ced 1318// HITextViewSetBackgroundColor( m_textView , color );
489468fe
SC
1319}
1320
b2680ced 1321void wxMacControl::SetRange( SInt32 minimum , SInt32 maximum )
489468fe 1322{
b2680ced
SC
1323 ::SetControl32BitMinimum( m_controlRef , minimum );
1324 ::SetControl32BitMaximum( m_controlRef , maximum );
489468fe
SC
1325}
1326
b2680ced 1327short wxMacControl::HandleKey( SInt16 keyCode, SInt16 charCode, EventModifiers modifiers )
489468fe 1328{
b2680ced 1329 return HandleControlKey( m_controlRef , keyCode , charCode , modifiers );
489468fe
SC
1330}
1331
b2680ced 1332void wxMacControl::SetActionProc( ControlActionUPP actionProc )
489468fe 1333{
b2680ced 1334 SetControlAction( m_controlRef , actionProc );
489468fe
SC
1335}
1336
b2680ced
SC
1337SInt32 wxMacControl::GetViewSize() const
1338{
1339 return GetControlViewSize( m_controlRef );
489468fe
SC
1340}
1341
b2680ced 1342bool wxMacControl::IsVisible() const
489468fe 1343{
b2680ced
SC
1344 return IsControlVisible( m_controlRef );
1345}
489468fe 1346
b2680ced
SC
1347void wxMacControl::SetVisibility( bool visible )
1348{
1349 SetControlVisibility( m_controlRef , visible, true );
1350}
489468fe 1351
b2680ced
SC
1352bool wxMacControl::IsEnabled() const
1353{
1354 return IsControlEnabled( m_controlRef );
489468fe
SC
1355}
1356
b2680ced 1357bool wxMacControl::IsActive() const
489468fe 1358{
b2680ced
SC
1359 return IsControlActive( m_controlRef );
1360}
489468fe 1361
b2680ced
SC
1362void wxMacControl::Enable( bool enable )
1363{
1364 if ( enable )
1365 EnableControl( m_controlRef );
489468fe 1366 else
b2680ced 1367 DisableControl( m_controlRef );
489468fe
SC
1368}
1369
b2680ced 1370void wxMacControl::SetDrawingEnabled( bool enable )
489468fe 1371{
b2680ced
SC
1372 HIViewSetDrawingEnabled( m_controlRef , enable );
1373}
1374
1375void wxMacControl::GetRectInWindowCoords( Rect *r )
1376{
1377 GetControlBounds( m_controlRef , r ) ;
1378
1379 WindowRef tlwref = GetControlOwner( m_controlRef ) ;
1380
1381 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) tlwref ) ;
1382 if ( tlwwx != NULL )
489468fe 1383 {
b2680ced
SC
1384 ControlRef rootControl = tlwwx->GetPeer()->GetControlRef() ;
1385 HIPoint hiPoint = CGPointMake( 0 , 0 ) ;
1386 HIViewConvertPoint( &hiPoint , HIViewGetSuperview(m_controlRef) , rootControl ) ;
1387 OffsetRect( r , (short) hiPoint.x , (short) hiPoint.y ) ;
489468fe
SC
1388 }
1389}
1390
524c47aa 1391void wxMacControl::GetBestRect( wxRect *rect ) const
489468fe 1392{
b2680ced 1393 short baselineoffset;
524c47aa 1394 Rect r = {0,0,0,0};
b2680ced 1395
524c47aa
SC
1396 GetBestControlRect( m_controlRef , &r , &baselineoffset );
1397 *rect = wxRect( r.left, r.top, r.right - r.left, r.bottom-r.top );
489468fe
SC
1398}
1399
524c47aa 1400void wxMacControl::GetBestRect( Rect *r ) const
489468fe 1401{
524c47aa
SC
1402 short baselineoffset;
1403 GetBestControlRect( m_controlRef , r , &baselineoffset );
1404}
489468fe 1405
524c47aa
SC
1406void wxMacControl::SetLabel( const wxString &title , wxFontEncoding encoding)
1407{
b2680ced 1408 SetControlTitleWithCFString( m_controlRef , wxCFStringRef( title , encoding ) );
489468fe
SC
1409}
1410
b2680ced 1411void wxMacControl::GetFeatures( UInt32 * features )
489468fe 1412{
b2680ced 1413 GetControlFeatures( m_controlRef , features );
489468fe
SC
1414}
1415
524c47aa
SC
1416void wxMacControl::PulseGauge()
1417{
1418}
1419
b2680ced
SC
1420// SetNeedsDisplay would not invalidate the children
1421static void InvalidateControlAndChildren( HIViewRef control )
1422{
1423 HIViewSetNeedsDisplay( control , true );
1424 UInt16 childrenCount = 0;
1425 OSStatus err = CountSubControls( control , &childrenCount );
1426 if ( err == errControlIsNotEmbedder )
1427 return;
489468fe 1428
b2680ced 1429 wxASSERT_MSG( err == noErr , wxT("Unexpected error when accessing subcontrols") );
489468fe 1430
b2680ced
SC
1431 for ( UInt16 i = childrenCount; i >=1; --i )
1432 {
1433 HIViewRef child;
489468fe 1434
b2680ced
SC
1435 err = GetIndexedSubControl( control , i , & child );
1436 if ( err == errControlIsNotEmbedder )
1437 return;
1438
1439 InvalidateControlAndChildren( child );
1440 }
489468fe
SC
1441}
1442
b2680ced 1443void wxMacControl::InvalidateWithChildren()
489468fe 1444{
b2680ced
SC
1445 InvalidateControlAndChildren( m_controlRef );
1446}
489468fe 1447
b2680ced
SC
1448OSType wxMacCreator = 'WXMC';
1449OSType wxMacControlProperty = 'MCCT';
1450
1451void wxMacControl::SetReferenceInNativeControl()
1452{
1453 void * data = this;
1454 verify_noerr( SetControlProperty ( m_controlRef ,
1455 wxMacCreator,wxMacControlProperty, sizeof(data), &data ) );
1456}
1457
1458wxMacControl* wxMacControl::GetReferenceFromNativeControl(ControlRef control)
1459{
1460 wxMacControl* ctl = NULL;
1461 ByteCount actualSize;
1462 if ( GetControlProperty( control ,wxMacCreator,wxMacControlProperty, sizeof(ctl) ,
1463 &actualSize , &ctl ) == noErr )
489468fe 1464 {
b2680ced 1465 return ctl;
489468fe 1466 }
b2680ced 1467 return NULL;
489468fe
SC
1468}
1469
e5d05b90
VZ
1470wxBitmap wxMacControl::GetBitmap() const
1471{
1472 return wxNullBitmap;
1473}
1474
524c47aa
SC
1475void wxMacControl::SetBitmap( const wxBitmap& WXUNUSED(bmp) )
1476{
1477 // implemented in the respective subclasses
1478}
1479
e5d05b90
VZ
1480void wxMacControl::SetBitmapPosition( wxDirection WXUNUSED(dir) )
1481{
1482 // implemented in the same subclasses that implement SetBitmap()
1483}
1484
524c47aa
SC
1485void wxMacControl::SetScrollThumb( wxInt32 WXUNUSED(pos), wxInt32 WXUNUSED(viewsize) )
1486{
1487 // implemented in respective subclass
1488}
489468fe 1489
b2680ced
SC
1490//
1491// Tab Control
1492//
489468fe 1493
b2680ced 1494OSStatus wxMacControl::SetTabEnabled( SInt16 tabNo , bool enable )
489468fe 1495{
b2680ced 1496 return ::SetTabEnabled( m_controlRef , tabNo , enable );
489468fe
SC
1497}
1498
b2680ced
SC
1499
1500
1501// Control Factory
1502
8f2a8de6 1503wxWidgetImplType* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
489468fe 1504{
b2680ced
SC
1505 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1506 // the content view, so we have to retrieve it explicitly
8f2a8de6 1507
b2680ced
SC
1508 wxMacControl* contentview = new wxMacControl(now , true /*isRootControl*/);
1509 HIViewFindByID( HIViewGetRoot( (WindowRef) now->GetWXWindow() ) , kHIViewWindowContentID ,
1510 contentview->GetControlRefAddr() ) ;
1511 if ( !contentview->IsOk() )
489468fe 1512 {
b2680ced
SC
1513 // compatibility mode fallback
1514 GetRootControl( (WindowRef) now->GetWXWindow() , contentview->GetControlRefAddr() ) ;
489468fe 1515 }
489468fe 1516
b2680ced
SC
1517 // the root control level handler
1518 contentview->InstallEventHandler() ;
1519 return contentview;
489468fe 1520}