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