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