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