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