]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/window.cpp
fix memory leak in SetColFormat() if the column already had an attribute (closes...
[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"
524c47aa
SC
68// bring in themeing
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
227 if ( !thisWindow->MacIsUserPane() ||
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 }
8ceeb6c2
SC
237 else
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
5c33522f 312 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), static_cast<void*>(thisWindow));
c016394b 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
5c33522f 332 wxLogTrace(_T("Focus"), _T("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;
5c33522f 360 wxLogTrace(_T("Focus"), _T("focus to be set(%p)"), static_cast<void*>(thisWindow));
b2680ced
SC
361 }
362 else
363 {
364 formerFocusWindow = thisWindow;
5c33522f 365 wxLogTrace(_T("Focus"), _T("focus to be lost(%p)"), static_cast<void*>(thisWindow));
b2680ced
SC
366 }
367
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 );
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
5c33522f 418 wxLogTrace(_T("Focus"), _T("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
5c33522f 434 wxLogTrace(_T("Focus"), _T("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 )
19c7ac3d
SC
795 {
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
a4fec5b4
SC
828wxWidgetImplType* wxWidgetImpl::CreateUserPane( wxWindowMac* wxpeer,
829 wxWindowMac* WXUNUSED(parent),
830 wxWindowID WXUNUSED(id),
831 const wxPoint& pos,
832 const wxSize& size,
833 long WXUNUSED(style),
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}
928
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
SC
936 HIShapeRef rgn = NULL;
937 Rect content ;
938
939 if ( HIViewCopyShape(m_controlRef, kHIViewContentMetaPart, &rgn) == noErr)
940 {
941 CGRect cgrect;
942 HIShapeGetBounds(rgn, &cgrect);
943 content = (Rect){ cgrect.origin.y, cgrect.origin.x, cgrect.origin.y+cgrect.size.height, cgrect.origin.x+cgrect.size.width };
944 CFRelease(rgn);
945 }
b2680ced 946 else
524c47aa 947 {
f215225d 948 GetControlBounds(m_controlRef, &content);
524c47aa
SC
949 content.right -= content.left;
950 content.left = 0;
951 content.bottom -= content.top;
952 content.top = 0;
953 }
489468fe 954
b2680ced
SC
955 left = content.left;
956 top = content.top;
489468fe 957
b2680ced
SC
958 width = content.right - content.left ;
959 height = content.bottom - content.top ;
960}
961
962void wxMacControl::Move(int x, int y, int width, int height)
963{
964 HIRect hir = CGRectMake(x,y,width,height);
965 HIViewSetFrame ( m_controlRef , &hir );
489468fe
SC
966}
967
b2680ced
SC
968void wxMacControl::GetPosition( int &x, int &y ) const
969{
970 Rect r;
971 GetControlBounds( m_controlRef , &r );
972 x = r.left;
973 y = r.top;
974}
489468fe 975
b2680ced 976void wxMacControl::GetSize( int &width, int &height ) const
489468fe 977{
b2680ced
SC
978 Rect r;
979 GetControlBounds( m_controlRef , &r );
980 width = r.right - r.left;
981 height = r.bottom - r.top;
982}
489468fe 983
524c47aa
SC
984void wxMacControl::SetControlSize( wxWindowVariant variant )
985{
986 ControlSize size ;
987 switch ( variant )
988 {
989 case wxWINDOW_VARIANT_NORMAL :
990 size = kControlSizeNormal;
991 break ;
992
993 case wxWINDOW_VARIANT_SMALL :
994 size = kControlSizeSmall;
995 break ;
996
997 case wxWINDOW_VARIANT_MINI :
998 // not always defined in the headers
999 size = 3 ;
1000 break ;
1001
1002 case wxWINDOW_VARIANT_LARGE :
1003 size = kControlSizeLarge;
1004 break ;
1005
1006 default:
1007 wxFAIL_MSG(_T("unexpected window variant"));
1008 break ;
1009 }
1010
1011 SetData<ControlSize>(kControlEntireControl, kControlSizeTag, &size ) ;
1012}
1013
b2680ced
SC
1014void wxMacControl::ScrollRect( const wxRect *rect, int dx, int dy )
1015{
1016 if (GetNeedsDisplay() )
489468fe 1017 {
b2680ced
SC
1018 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
1019 // in case there is already a pending redraw on that area
1020 // either immediate redraw or full invalidate
1021#if 1
1022 // is the better overall solution, as it does not slow down scrolling
1023 SetNeedsDisplay() ;
1024#else
1025 // this would be the preferred version for fast drawing controls
1026 HIViewRender(GetControlRef()) ;
489468fe 1027#endif
489468fe
SC
1028 }
1029
b2680ced
SC
1030 // note there currently is a bug in OSX (10.3 +?) which makes inefficient refreshes in case an entire control
1031 // area is scrolled, this does not occur if width and height are 2 pixels less,
1032 // TODO: write optimal workaround
1033
1034 HIRect scrollarea = CGRectMake( rect->x , rect->y , rect->width , rect->height);
1035 HIViewScrollRect ( m_controlRef , &scrollarea , dx ,dy );
1036
1037#if 0
1038 // this would be the preferred version for fast drawing controls
1039 HIViewRender(GetControlRef()) ;
1040#endif
489468fe
SC
1041}
1042
b2680ced 1043bool wxMacControl::CanFocus() const
489468fe 1044{
b2680ced
SC
1045 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
1046 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
1047 // but the value range is nowhere documented
1048 Boolean keyExistsAndHasValidFormat ;
1049 CFIndex fullKeyboardAccess = CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
1050 kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat );
489468fe 1051
b2680ced 1052 if ( keyExistsAndHasValidFormat && fullKeyboardAccess > 0 )
489468fe 1053 {
b2680ced 1054 return true ;
489468fe
SC
1055 }
1056 else
1057 {
b2680ced
SC
1058 UInt32 features = 0 ;
1059 GetControlFeatures( m_controlRef, &features ) ;
489468fe 1060
b2680ced 1061 return features & ( kControlSupportsFocus | kControlGetsFocusOnClick ) ;
489468fe
SC
1062 }
1063}
1064
b2680ced 1065bool wxMacControl::GetNeedsDisplay() const
489468fe 1066{
b2680ced
SC
1067 return HIViewGetNeedsDisplay( m_controlRef );
1068}
489468fe 1069
b2680ced
SC
1070void wxWidgetImpl::Convert( wxPoint *pt , wxWidgetImpl *from , wxWidgetImpl *to )
1071{
1072 HIPoint hiPoint;
489468fe 1073
b2680ced
SC
1074 hiPoint.x = pt->x;
1075 hiPoint.y = pt->y;
1076 HIViewConvertPoint( &hiPoint , (ControlRef) from->GetWXWidget() , (ControlRef) to->GetWXWidget() );
1077 pt->x = (int)hiPoint.x;
1078 pt->y = (int)hiPoint.y;
1079}
489468fe 1080
b2680ced
SC
1081bool wxMacControl::SetFocus()
1082{
1083 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1084 // we can only leave in case of an error
489468fe 1085
b2680ced
SC
1086 OSStatus err = SetKeyboardFocus( GetControlOwner( m_controlRef ), m_controlRef, kControlFocusNextPart );
1087 if ( err == errCouldntSetFocus )
1088 return false ;
1089 SetUserFocusWindow(GetControlOwner( m_controlRef ) );
1090
1091 return true;
489468fe
SC
1092}
1093
b2680ced 1094bool wxMacControl::HasFocus() const
489468fe 1095{
b2680ced
SC
1096 ControlRef control;
1097 GetKeyboardFocus( GetUserFocusWindow() , &control );
1098 return control == m_controlRef;
1099}
489468fe 1100
54f11060
SC
1101void wxMacControl::SetCursor(const wxCursor& cursor)
1102{
1103 wxWindowMac *mouseWin = 0 ;
1104 WindowRef window = GetControlOwner( m_controlRef ) ;
1105
1106 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) window ) ;
1107 if ( tlwwx != NULL )
1108 {
1109 ControlPartCode part ;
1110 ControlRef control ;
1111 Point pt ;
1112#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1113 HIPoint hiPoint ;
1114 HIGetMousePosition(kHICoordSpaceWindow, window, &hiPoint);
1115 pt.h = hiPoint.x;
1116 pt.v = hiPoint.y;
1117#else
1118 GetGlobalMouse( &pt );
1119 int x = pt.h;
1120 int y = pt.v;
1121 tlwwx->ScreenToClient(&x, &y);
1122 pt.h = x;
1123 pt.v = y;
1124#endif
1125 control = FindControlUnderMouse( pt , window , &part ) ;
1126 if ( control )
1127 mouseWin = wxFindWindowFromWXWidget( (WXWidget) control ) ;
1128 }
1129
1130 if ( mouseWin == tlwwx && !wxIsBusy() )
1131 cursor.MacInstall() ;
1132}
1133
1134void wxMacControl::CaptureMouse()
1135{
1136}
1137
1138void wxMacControl::ReleaseMouse()
1139{
1140}
1141
b2680ced
SC
1142//
1143// subclass specifics
1144//
1145
1146OSStatus wxMacControl::GetData(ControlPartCode inPartCode , ResType inTag , Size inBufferSize , void * inOutBuffer , Size * outActualSize ) const
1147{
1148 return ::GetControlData( m_controlRef , inPartCode , inTag , inBufferSize , inOutBuffer , outActualSize );
489468fe
SC
1149}
1150
b2680ced 1151OSStatus wxMacControl::GetDataSize(ControlPartCode inPartCode , ResType inTag , Size * outActualSize ) const
489468fe 1152{
b2680ced
SC
1153 return ::GetControlDataSize( m_controlRef , inPartCode , inTag , outActualSize );
1154}
489468fe 1155
b2680ced
SC
1156OSStatus wxMacControl::SetData(ControlPartCode inPartCode , ResType inTag , Size inSize , const void * inData)
1157{
1158 return ::SetControlData( m_controlRef , inPartCode , inTag , inSize , inData );
1159}
489468fe 1160
b2680ced
SC
1161OSStatus wxMacControl::SendEvent( EventRef event , OptionBits inOptions )
1162{
1163 return SendEventToEventTargetWithOptions( event,
1164 HIObjectGetEventTarget( (HIObjectRef) m_controlRef ), inOptions );
1165}
489468fe 1166
b2680ced
SC
1167OSStatus wxMacControl::SendHICommand( HICommand &command , OptionBits inOptions )
1168{
1169 wxMacCarbonEvent event( kEventClassCommand , kEventCommandProcess );
489468fe 1170
b2680ced 1171 event.SetParameter<HICommand>(kEventParamDirectObject,command);
489468fe 1172
b2680ced
SC
1173 return SendEvent( event , inOptions );
1174}
489468fe 1175
b2680ced
SC
1176OSStatus wxMacControl::SendHICommand( UInt32 commandID , OptionBits inOptions )
1177{
1178 HICommand command;
489468fe 1179
b2680ced
SC
1180 memset( &command, 0 , sizeof(command) );
1181 command.commandID = commandID;
1182 return SendHICommand( command , inOptions );
1183}
489468fe 1184
524c47aa 1185void wxMacControl::PerformClick()
b2680ced 1186{
524c47aa 1187 HIViewSimulateClick (m_controlRef, kControlButtonPart, 0, NULL );
b2680ced 1188}
489468fe 1189
524c47aa 1190wxInt32 wxMacControl::GetValue() const
b2680ced
SC
1191{
1192 return ::GetControl32BitValue( m_controlRef );
1193}
489468fe 1194
19c7ac3d 1195wxInt32 wxMacControl::GetMaximum() const
b2680ced
SC
1196{
1197 return ::GetControl32BitMaximum( m_controlRef );
1198}
489468fe 1199
524c47aa 1200wxInt32 wxMacControl::GetMinimum() const
b2680ced
SC
1201{
1202 return ::GetControl32BitMinimum( m_controlRef );
489468fe
SC
1203}
1204
524c47aa 1205void wxMacControl::SetValue( wxInt32 v )
489468fe 1206{
b2680ced 1207 ::SetControl32BitValue( m_controlRef , v );
489468fe
SC
1208}
1209
524c47aa 1210void wxMacControl::SetMinimum( wxInt32 v )
489468fe 1211{
b2680ced
SC
1212 ::SetControl32BitMinimum( m_controlRef , v );
1213}
489468fe 1214
524c47aa 1215void wxMacControl::SetMaximum( wxInt32 v )
b2680ced
SC
1216{
1217 ::SetControl32BitMaximum( m_controlRef , v );
1218}
489468fe 1219
b2680ced
SC
1220void wxMacControl::SetValueAndRange( SInt32 value , SInt32 minimum , SInt32 maximum )
1221{
1222 ::SetControl32BitMinimum( m_controlRef , minimum );
1223 ::SetControl32BitMaximum( m_controlRef , maximum );
1224 ::SetControl32BitValue( m_controlRef , value );
1225}
489468fe 1226
b2680ced
SC
1227void wxMacControl::VisibilityChanged(bool WXUNUSED(shown))
1228{
489468fe
SC
1229}
1230
b2680ced 1231void wxMacControl::SuperChangedPosition()
489468fe 1232{
b2680ced 1233}
489468fe 1234
1e181c7a 1235void wxMacControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle, bool ignoreBlack )
b2680ced
SC
1236{
1237 m_font = font;
292e5e1f 1238#if wxOSX_USE_CORE_TEXT
b2680ced 1239 if ( UMAGetSystemVersion() >= 0x1050 )
489468fe 1240 {
b2680ced
SC
1241 HIViewPartCode part = 0;
1242 HIThemeTextHorizontalFlush flush = kHIThemeTextHorizontalFlushDefault;
1243 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1244 flush = kHIThemeTextHorizontalFlushCenter;
1245 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1246 flush = kHIThemeTextHorizontalFlushRight;
aa6208d9 1247 HIViewSetTextFont( m_controlRef , part , (CTFontRef) font.OSXGetCTFont() );
b2680ced 1248 HIViewSetTextHorizontalFlush( m_controlRef, part, flush );
489468fe 1249
1e181c7a 1250 if ( foreground != *wxBLACK || ignoreBlack == false )
b2680ced
SC
1251 {
1252 ControlFontStyleRec fontStyle;
1253 foreground.GetRGBColor( &fontStyle.foreColor );
1254 fontStyle.flags = kControlUseForeColorMask;
1255 ::SetControlFontStyle( m_controlRef , &fontStyle );
1256 }
489468fe 1257 }
b2680ced 1258#endif
292e5e1f 1259#if wxOSX_USE_ATSU_TEXT
b2680ced
SC
1260 ControlFontStyleRec fontStyle;
1261 if ( font.MacGetThemeFontID() != kThemeCurrentPortFont )
1262 {
1263 switch ( font.MacGetThemeFontID() )
1264 {
1265 case kThemeSmallSystemFont :
1266 fontStyle.font = kControlFontSmallSystemFont;
1267 break;
489468fe 1268
b2680ced
SC
1269 case 109 : // mini font
1270 fontStyle.font = -5;
1271 break;
489468fe 1272
b2680ced
SC
1273 case kThemeSystemFont :
1274 fontStyle.font = kControlFontBigSystemFont;
1275 break;
489468fe 1276
b2680ced
SC
1277 default :
1278 fontStyle.font = kControlFontBigSystemFont;
1279 break;
1280 }
1281
1282 fontStyle.flags = kControlUseFontMask;
1283 }
1284 else
489468fe 1285 {
b2680ced
SC
1286 fontStyle.font = font.MacGetFontNum();
1287 fontStyle.style = font.MacGetFontStyle();
f1c40652 1288 fontStyle.size = font.GetPointSize();
b2680ced 1289 fontStyle.flags = kControlUseFontMask | kControlUseFaceMask | kControlUseSizeMask;
489468fe 1290 }
b2680ced
SC
1291
1292 fontStyle.just = teJustLeft;
1293 fontStyle.flags |= kControlUseJustMask;
1294 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1295 fontStyle.just = teJustCenter;
1296 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1297 fontStyle.just = teJustRight;
1298
1299
1300 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1301 // won't get grayed out by the system anymore
1302
1e181c7a 1303 if ( foreground != *wxBLACK || ignoreBlack == false )
489468fe 1304 {
b2680ced
SC
1305 foreground.GetRGBColor( &fontStyle.foreColor );
1306 fontStyle.flags |= kControlUseForeColorMask;
489468fe
SC
1307 }
1308
b2680ced
SC
1309 ::SetControlFontStyle( m_controlRef , &fontStyle );
1310#endif
489468fe
SC
1311}
1312
b2680ced 1313void wxMacControl::SetBackgroundColour( const wxColour &WXUNUSED(col) )
489468fe 1314{
b2680ced 1315// HITextViewSetBackgroundColor( m_textView , color );
489468fe
SC
1316}
1317
b2680ced 1318void wxMacControl::SetRange( SInt32 minimum , SInt32 maximum )
489468fe 1319{
b2680ced
SC
1320 ::SetControl32BitMinimum( m_controlRef , minimum );
1321 ::SetControl32BitMaximum( m_controlRef , maximum );
489468fe
SC
1322}
1323
b2680ced 1324short wxMacControl::HandleKey( SInt16 keyCode, SInt16 charCode, EventModifiers modifiers )
489468fe 1325{
b2680ced 1326 return HandleControlKey( m_controlRef , keyCode , charCode , modifiers );
489468fe
SC
1327}
1328
b2680ced 1329void wxMacControl::SetActionProc( ControlActionUPP actionProc )
489468fe 1330{
b2680ced 1331 SetControlAction( m_controlRef , actionProc );
489468fe
SC
1332}
1333
b2680ced
SC
1334SInt32 wxMacControl::GetViewSize() const
1335{
1336 return GetControlViewSize( m_controlRef );
489468fe
SC
1337}
1338
b2680ced 1339bool wxMacControl::IsVisible() const
489468fe 1340{
b2680ced
SC
1341 return IsControlVisible( m_controlRef );
1342}
489468fe 1343
b2680ced
SC
1344void wxMacControl::SetVisibility( bool visible )
1345{
1346 SetControlVisibility( m_controlRef , visible, true );
1347}
489468fe 1348
b2680ced
SC
1349bool wxMacControl::IsEnabled() const
1350{
1351 return IsControlEnabled( m_controlRef );
489468fe
SC
1352}
1353
b2680ced 1354bool wxMacControl::IsActive() const
489468fe 1355{
b2680ced
SC
1356 return IsControlActive( m_controlRef );
1357}
489468fe 1358
b2680ced
SC
1359void wxMacControl::Enable( bool enable )
1360{
1361 if ( enable )
1362 EnableControl( m_controlRef );
489468fe 1363 else
b2680ced 1364 DisableControl( m_controlRef );
489468fe
SC
1365}
1366
b2680ced 1367void wxMacControl::SetDrawingEnabled( bool enable )
489468fe 1368{
b2680ced
SC
1369 HIViewSetDrawingEnabled( m_controlRef , enable );
1370}
1371
1372void wxMacControl::GetRectInWindowCoords( Rect *r )
1373{
1374 GetControlBounds( m_controlRef , r ) ;
1375
1376 WindowRef tlwref = GetControlOwner( m_controlRef ) ;
1377
1378 wxNonOwnedWindow* tlwwx = wxNonOwnedWindow::GetFromWXWindow( (WXWindow) tlwref ) ;
1379 if ( tlwwx != NULL )
489468fe 1380 {
b2680ced
SC
1381 ControlRef rootControl = tlwwx->GetPeer()->GetControlRef() ;
1382 HIPoint hiPoint = CGPointMake( 0 , 0 ) ;
1383 HIViewConvertPoint( &hiPoint , HIViewGetSuperview(m_controlRef) , rootControl ) ;
1384 OffsetRect( r , (short) hiPoint.x , (short) hiPoint.y ) ;
489468fe
SC
1385 }
1386}
1387
524c47aa 1388void wxMacControl::GetBestRect( wxRect *rect ) const
489468fe 1389{
b2680ced 1390 short baselineoffset;
524c47aa 1391 Rect r = {0,0,0,0};
b2680ced 1392
524c47aa
SC
1393 GetBestControlRect( m_controlRef , &r , &baselineoffset );
1394 *rect = wxRect( r.left, r.top, r.right - r.left, r.bottom-r.top );
489468fe
SC
1395}
1396
524c47aa 1397void wxMacControl::GetBestRect( Rect *r ) const
489468fe 1398{
524c47aa
SC
1399 short baselineoffset;
1400 GetBestControlRect( m_controlRef , r , &baselineoffset );
1401}
489468fe 1402
524c47aa
SC
1403void wxMacControl::SetLabel( const wxString &title , wxFontEncoding encoding)
1404{
b2680ced 1405 SetControlTitleWithCFString( m_controlRef , wxCFStringRef( title , encoding ) );
489468fe
SC
1406}
1407
b2680ced 1408void wxMacControl::GetFeatures( UInt32 * features )
489468fe 1409{
b2680ced 1410 GetControlFeatures( m_controlRef , features );
489468fe
SC
1411}
1412
524c47aa
SC
1413void wxMacControl::PulseGauge()
1414{
1415}
1416
b2680ced
SC
1417// SetNeedsDisplay would not invalidate the children
1418static void InvalidateControlAndChildren( HIViewRef control )
1419{
1420 HIViewSetNeedsDisplay( control , true );
1421 UInt16 childrenCount = 0;
1422 OSStatus err = CountSubControls( control , &childrenCount );
1423 if ( err == errControlIsNotEmbedder )
1424 return;
489468fe 1425
b2680ced 1426 wxASSERT_MSG( err == noErr , wxT("Unexpected error when accessing subcontrols") );
489468fe 1427
b2680ced
SC
1428 for ( UInt16 i = childrenCount; i >=1; --i )
1429 {
1430 HIViewRef child;
489468fe 1431
b2680ced
SC
1432 err = GetIndexedSubControl( control , i , & child );
1433 if ( err == errControlIsNotEmbedder )
1434 return;
1435
1436 InvalidateControlAndChildren( child );
1437 }
489468fe
SC
1438}
1439
b2680ced 1440void wxMacControl::InvalidateWithChildren()
489468fe 1441{
b2680ced
SC
1442 InvalidateControlAndChildren( m_controlRef );
1443}
489468fe 1444
b2680ced
SC
1445OSType wxMacCreator = 'WXMC';
1446OSType wxMacControlProperty = 'MCCT';
1447
1448void wxMacControl::SetReferenceInNativeControl()
1449{
1450 void * data = this;
1451 verify_noerr( SetControlProperty ( m_controlRef ,
1452 wxMacCreator,wxMacControlProperty, sizeof(data), &data ) );
1453}
1454
1455wxMacControl* wxMacControl::GetReferenceFromNativeControl(ControlRef control)
1456{
1457 wxMacControl* ctl = NULL;
1458 ByteCount actualSize;
1459 if ( GetControlProperty( control ,wxMacCreator,wxMacControlProperty, sizeof(ctl) ,
1460 &actualSize , &ctl ) == noErr )
489468fe 1461 {
b2680ced 1462 return ctl;
489468fe 1463 }
b2680ced 1464 return NULL;
489468fe
SC
1465}
1466
524c47aa
SC
1467void wxMacControl::SetBitmap( const wxBitmap& WXUNUSED(bmp) )
1468{
1469 // implemented in the respective subclasses
1470}
1471
1472void wxMacControl::SetScrollThumb( wxInt32 WXUNUSED(pos), wxInt32 WXUNUSED(viewsize) )
1473{
1474 // implemented in respective subclass
1475}
489468fe 1476
b2680ced
SC
1477//
1478// Tab Control
1479//
489468fe 1480
b2680ced 1481OSStatus wxMacControl::SetTabEnabled( SInt16 tabNo , bool enable )
489468fe 1482{
b2680ced 1483 return ::SetTabEnabled( m_controlRef , tabNo , enable );
489468fe
SC
1484}
1485
b2680ced
SC
1486
1487
1488// Control Factory
1489
524c47aa 1490wxWidgetImplType* wxWidgetImpl::CreateContentView( wxNonOwnedWindow* now )
489468fe 1491{
b2680ced
SC
1492 // There is a bug in 10.2.X for ::GetRootControl returning the window view instead of
1493 // the content view, so we have to retrieve it explicitly
1494
1495 wxMacControl* contentview = new wxMacControl(now , true /*isRootControl*/);
1496 HIViewFindByID( HIViewGetRoot( (WindowRef) now->GetWXWindow() ) , kHIViewWindowContentID ,
1497 contentview->GetControlRefAddr() ) ;
1498 if ( !contentview->IsOk() )
489468fe 1499 {
b2680ced
SC
1500 // compatibility mode fallback
1501 GetRootControl( (WindowRef) now->GetWXWindow() , contentview->GetControlRefAddr() ) ;
489468fe 1502 }
489468fe 1503
b2680ced
SC
1504 // the root control level handler
1505 contentview->InstallEventHandler() ;
1506 return contentview;
489468fe 1507}