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