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