]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/window.cpp
5bafb0db3f7dc65cc8ee862bcca9f7b392ff3677
[wxWidgets.git] / src / mac / carbon / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/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 #include "wx/mac/uma.h"
65
66 #define MAC_SCROLLBAR_SIZE 15
67 #define MAC_SMALL_SCROLLBAR_SIZE 11
68
69 #include <string.h>
70
71 #ifdef __WXUNIVERSAL__
72 IMPLEMENT_ABSTRACT_CLASS(wxWindowMac, wxWindowBase)
73 #else
74 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
75 #endif
76
77 BEGIN_EVENT_TABLE(wxWindowMac, wxWindowBase)
78 EVT_NC_PAINT(wxWindowMac::OnNcPaint)
79 EVT_ERASE_BACKGROUND(wxWindowMac::OnEraseBackground)
80 EVT_PAINT(wxWindowMac::OnPaint)
81 EVT_SET_FOCUS(wxWindowMac::OnSetFocus)
82 EVT_KILL_FOCUS(wxWindowMac::OnSetFocus)
83 EVT_MOUSE_EVENTS(wxWindowMac::OnMouseEvent)
84 END_EVENT_TABLE()
85
86 #define wxMAC_DEBUG_REDRAW 0
87 #ifndef wxMAC_DEBUG_REDRAW
88 #define wxMAC_DEBUG_REDRAW 0
89 #endif
90
91 // ---------------------------------------------------------------------------
92 // Utility Routines to move between different coordinate systems
93 // ---------------------------------------------------------------------------
94
95 /*
96 * Right now we have the following setup :
97 * a border that is not part of the native control is always outside the
98 * control's border (otherwise we loose all native intelligence, future ways
99 * may be to have a second embedding control responsible for drawing borders
100 * and backgrounds eventually)
101 * so all this border calculations have to be taken into account when calling
102 * native methods or getting native oriented data
103 * so we have three coordinate systems here
104 * wx client coordinates
105 * wx window coordinates (including window frames)
106 * native coordinates
107 */
108
109 //
110 // originating from native control
111 //
112
113
114 void wxMacNativeToWindow( const wxWindow* window , RgnHandle handle )
115 {
116 OffsetRgn( handle , window->MacGetLeftBorderSize() , window->MacGetTopBorderSize() ) ;
117 }
118
119 void wxMacNativeToWindow( const wxWindow* window , Rect *rect )
120 {
121 OffsetRect( rect , window->MacGetLeftBorderSize() , window->MacGetTopBorderSize() ) ;
122 }
123
124 //
125 // directed towards native control
126 //
127
128 void wxMacWindowToNative( const wxWindow* window , RgnHandle handle )
129 {
130 OffsetRgn( handle , -window->MacGetLeftBorderSize() , -window->MacGetTopBorderSize() );
131 }
132
133 void wxMacWindowToNative( const wxWindow* window , Rect *rect )
134 {
135 OffsetRect( rect , -window->MacGetLeftBorderSize() , -window->MacGetTopBorderSize() ) ;
136 }
137
138 // ---------------------------------------------------------------------------
139 // Carbon Events
140 // ---------------------------------------------------------------------------
141
142 static const EventTypeSpec eventList[] =
143 {
144 { kEventClassCommand, kEventProcessCommand } ,
145 { kEventClassCommand, kEventCommandUpdateStatus } ,
146
147 { kEventClassControl , kEventControlGetClickActivation } ,
148 { kEventClassControl , kEventControlHit } ,
149
150 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } ,
151 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea } ,
152
153 { kEventClassControl , kEventControlDraw } ,
154
155 { kEventClassControl , kEventControlVisibilityChanged } ,
156 { kEventClassControl , kEventControlEnabledStateChanged } ,
157 { kEventClassControl , kEventControlHiliteChanged } ,
158
159 { kEventClassControl , kEventControlActivate } ,
160 { kEventClassControl , kEventControlDeactivate } ,
161
162 { kEventClassControl , kEventControlSetFocusPart } ,
163 { kEventClassControl , kEventControlFocusPartChanged } ,
164
165 { kEventClassService , kEventServiceGetTypes },
166 { kEventClassService , kEventServiceCopy },
167 { kEventClassService , kEventServicePaste },
168
169 // { kEventClassControl , kEventControlInvalidateForSizeChange } , // 10.3 only
170 // { kEventClassControl , kEventControlBoundsChanged } ,
171 } ;
172
173 static pascal OSStatus wxMacWindowControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
174 {
175 OSStatus result = eventNotHandledErr ;
176
177 wxMacCarbonEvent cEvent( event ) ;
178
179 ControlRef controlRef ;
180 wxWindowMac* thisWindow = (wxWindowMac*) data ;
181
182 cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
183
184 switch ( GetEventKind( event ) )
185 {
186 case kEventControlDraw :
187 {
188 RgnHandle updateRgn = NULL ;
189 RgnHandle allocatedRgn = NULL ;
190 wxRegion visRegion = thisWindow->MacGetVisibleRegion() ;
191
192 if ( cEvent.GetParameter<RgnHandle>(kEventParamRgnHandle, &updateRgn) != noErr )
193 {
194 HIShapeGetAsQDRgn( visRegion.GetWXHRGN(), updateRgn );
195 }
196 else
197 {
198 if ( thisWindow->MacGetLeftBorderSize() != 0 || thisWindow->MacGetTopBorderSize() != 0 )
199 {
200 // as this update region is in native window locals we must adapt it to wx window local
201 allocatedRgn = NewRgn() ;
202 CopyRgn( updateRgn , allocatedRgn ) ;
203
204 // hide the given region by the new region that must be shifted
205 wxMacNativeToWindow( thisWindow , allocatedRgn ) ;
206 updateRgn = allocatedRgn ;
207 }
208 }
209
210 #if wxMAC_DEBUG_REDRAW
211 if ( thisWindow->MacIsUserPane() )
212 {
213 static float color = 0.5 ;
214 static channel = 0 ;
215 HIRect bounds;
216 CGContextRef cgContext = cEvent.GetParameter<CGContextRef>(kEventParamCGContextRef) ;
217
218 HIViewGetBounds( controlRef, &bounds );
219 CGContextSetRGBFillColor( cgContext, channel == 0 ? color : 0.5 ,
220 channel == 1 ? color : 0.5 , channel == 2 ? color : 0.5 , 1 );
221 CGContextFillRect( cgContext, bounds );
222 color += 0.1 ;
223 if ( color > 0.9 )
224 {
225 color = 0.5 ;
226 channel++ ;
227 if ( channel == 3 )
228 channel = 0 ;
229 }
230 }
231 #endif
232
233 {
234 bool created = false ;
235 CGContextRef cgContext = NULL ;
236 OSStatus err = cEvent.GetParameter<CGContextRef>(kEventParamCGContextRef, &cgContext) ;
237 wxASSERT_MSG( err == noErr , wxT("Unable to retrieve CGContextRef") ) ;
238 thisWindow->MacSetCGContextRef( cgContext ) ;
239
240 {
241 wxMacCGContextStateSaver sg( cgContext ) ;
242 float alpha = 1.0 ;
243 {
244 wxWindow* iter = thisWindow ;
245 while ( iter )
246 {
247 alpha *= (float) iter->GetTransparent()/255.0 ;
248 if ( iter->IsTopLevel() )
249 iter = NULL ;
250 else
251 iter = iter->GetParent() ;
252 }
253 }
254 CGContextSetAlpha( cgContext , alpha ) ;
255
256 if ( thisWindow->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT )
257 {
258 HIRect bounds;
259 HIViewGetBounds( controlRef, &bounds );
260 CGContextClearRect( cgContext, bounds );
261 }
262
263
264
265 if ( thisWindow->MacDoRedraw( updateRgn , cEvent.GetTicks() ) )
266 result = noErr ;
267
268 thisWindow->MacSetCGContextRef( NULL ) ;
269 }
270
271 if ( created )
272 CGContextRelease( cgContext ) ;
273 }
274
275 if ( allocatedRgn )
276 DisposeRgn( allocatedRgn ) ;
277 }
278 break ;
279
280 case kEventControlVisibilityChanged :
281 thisWindow->MacVisibilityChanged() ;
282 break ;
283
284 case kEventControlEnabledStateChanged :
285 thisWindow->MacEnabledStateChanged();
286 break ;
287
288 case kEventControlHiliteChanged :
289 thisWindow->MacHiliteChanged() ;
290 break ;
291
292 case kEventControlActivate :
293 case kEventControlDeactivate :
294 // FIXME: we should have a virtual function for this!
295 #if wxUSE_TREECTRL
296 if ( thisWindow->IsKindOf( CLASSINFO( wxTreeCtrl ) ) )
297 thisWindow->Refresh();
298 #endif
299 #if wxUSE_LISTCTRL
300 if ( thisWindow->IsKindOf( CLASSINFO( wxListCtrl ) ) )
301 thisWindow->Refresh();
302 #endif
303 break ;
304
305 //
306 // focus handling
307 // different handling on OS X
308 //
309
310 case kEventControlFocusPartChanged :
311 // the event is emulated by wxmac for systems lower than 10.5
312 {
313 ControlPartCode previousControlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPreviousPart , typeControlPartCode );
314 ControlPartCode currentControlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlCurrentPart , typeControlPartCode );
315 if ( currentControlPart == 0 )
316 {
317 // kill focus
318 #if wxUSE_CARET
319 if ( thisWindow->GetCaret() )
320 thisWindow->GetCaret()->OnKillFocus();
321 #endif
322
323 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), wx_static_cast(void*, thisWindow));
324
325 // remove this as soon as posting the synthesized event works properly
326 static bool inKillFocusEvent = false ;
327
328 if ( !inKillFocusEvent )
329 {
330 inKillFocusEvent = true ;
331 wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId());
332 event.SetEventObject(thisWindow);
333 thisWindow->GetEventHandler()->ProcessEvent(event) ;
334 inKillFocusEvent = false ;
335 }
336 }
337 else if ( previousControlPart == 0 )
338 {
339 // set focus
340 // panel wants to track the window which was the last to have focus in it
341 wxLogTrace(_T("Focus"), _T("focus set(%p)"), wx_static_cast(void*, thisWindow));
342 wxChildFocusEvent eventFocus((wxWindow*)thisWindow);
343 thisWindow->GetEventHandler()->ProcessEvent(eventFocus);
344
345 #if wxUSE_CARET
346 if ( thisWindow->GetCaret() )
347 thisWindow->GetCaret()->OnSetFocus();
348 #endif
349
350 wxFocusEvent event(wxEVT_SET_FOCUS, thisWindow->GetId());
351 event.SetEventObject(thisWindow);
352 thisWindow->GetEventHandler()->ProcessEvent(event) ;
353 }
354 }
355 break;
356 case kEventControlSetFocusPart :
357 {
358 #ifdef __WXMAC_OSX__
359 Boolean focusEverything = false ;
360 if ( cEvent.GetParameter<Boolean>(kEventParamControlFocusEverything , &focusEverything ) == noErr )
361 {
362 // put a breakpoint here to catch focus everything events
363 }
364 #endif
365 ControlPartCode controlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart , typeControlPartCode );
366
367 ControlPartCode previousControlPart = 0;
368 verify_noerr( HIViewGetFocusPart(controlRef, &previousControlPart));
369
370 if ( thisWindow->MacIsUserPane() )
371 {
372 if ( controlPart != kControlFocusNoPart )
373 cEvent.SetParameter<ControlPartCode>( kEventParamControlPart, typeControlPartCode, 1 ) ;
374 result = noErr ;
375 }
376 else
377 result = CallNextEventHandler(handler, event);
378
379 if ( UMAGetSystemVersion() < 0x1050 )
380 {
381 // set back to 0 if problems arise
382 #if 1
383 ControlPartCode currentControlPart = cEvent.GetParameter<ControlPartCode>(kEventParamControlPart , typeControlPartCode );
384 // synthesize the event focus changed event
385 EventRef evRef = NULL ;
386
387 OSStatus err = MacCreateEvent(
388 NULL , kEventClassControl , kEventControlFocusPartChanged , TicksToEventTime( TickCount() ) ,
389 kEventAttributeUserEvent , &evRef );
390 verify_noerr( err );
391
392 wxMacCarbonEvent iEvent( evRef ) ;
393 iEvent.SetParameter<ControlRef>( kEventParamDirectObject , controlRef ) ;
394 iEvent.SetParameter<ControlPartCode>( kEventParamControlPreviousPart, typeControlPartCode, previousControlPart ) ;
395 iEvent.SetParameter<ControlPartCode>( kEventParamControlCurrentPart, typeControlPartCode, currentControlPart ) ;
396
397 #if 0
398 // TODO test this first, avoid double posts etc...
399 PostEventToQueue( GetMainEventQueue(), evRef , kEventPriorityHigh );
400 #else
401 wxMacWindowControlEventHandler( NULL , evRef , data ) ;
402 #endif
403 ReleaseEvent( evRef ) ;
404 #else
405 // old implementation, to be removed if the new one works
406 if ( controlPart == kControlFocusNoPart )
407 {
408 #if wxUSE_CARET
409 if ( thisWindow->GetCaret() )
410 thisWindow->GetCaret()->OnKillFocus();
411 #endif
412
413 wxLogTrace(_T("Focus"), _T("focus lost(%p)"), wx_static_cast(void*, thisWindow));
414
415 static bool inKillFocusEvent = false ;
416
417 if ( !inKillFocusEvent )
418 {
419 inKillFocusEvent = true ;
420 wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId());
421 event.SetEventObject(thisWindow);
422 thisWindow->GetEventHandler()->ProcessEvent(event) ;
423 inKillFocusEvent = false ;
424 }
425 }
426 else
427 {
428 // panel wants to track the window which was the last to have focus in it
429 wxLogTrace(_T("Focus"), _T("focus set(%p)"), wx_static_cast(void*, thisWindow));
430 wxChildFocusEvent eventFocus((wxWindow*)thisWindow);
431 thisWindow->GetEventHandler()->ProcessEvent(eventFocus);
432
433 #if wxUSE_CARET
434 if ( thisWindow->GetCaret() )
435 thisWindow->GetCaret()->OnSetFocus();
436 #endif
437
438 wxFocusEvent event(wxEVT_SET_FOCUS, thisWindow->GetId());
439 event.SetEventObject(thisWindow);
440 thisWindow->GetEventHandler()->ProcessEvent(event) ;
441 }
442 #endif
443 }
444 }
445 break ;
446
447 case kEventControlHit :
448 result = thisWindow->MacControlHit( handler , event ) ;
449 break ;
450
451 case kEventControlGetClickActivation :
452 {
453 // fix to always have a proper activation for DataBrowser controls (stay in bkgnd otherwise)
454 WindowRef owner = cEvent.GetParameter<WindowRef>(kEventParamWindowRef);
455 if ( !IsWindowActive(owner) )
456 {
457 cEvent.SetParameter(kEventParamClickActivation,(UInt32) kActivateAndIgnoreClick) ;
458 result = noErr ;
459 }
460 }
461 break ;
462
463 default :
464 break ;
465 }
466
467 return result ;
468 }
469
470 static pascal OSStatus
471 wxMacWindowServiceEventHandler(EventHandlerCallRef WXUNUSED(handler),
472 EventRef event,
473 void *data)
474 {
475 OSStatus result = eventNotHandledErr ;
476
477 wxMacCarbonEvent cEvent( event ) ;
478
479 ControlRef controlRef ;
480 wxWindowMac* thisWindow = (wxWindowMac*) data ;
481 wxTextCtrl* textCtrl = wxDynamicCast( thisWindow , wxTextCtrl ) ;
482 cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
483
484 switch ( GetEventKind( event ) )
485 {
486 case kEventServiceGetTypes :
487 if ( textCtrl )
488 {
489 long from, to ;
490 textCtrl->GetSelection( &from , &to ) ;
491
492 CFMutableArrayRef copyTypes = 0 , pasteTypes = 0;
493 if ( from != to )
494 copyTypes = cEvent.GetParameter< CFMutableArrayRef >( kEventParamServiceCopyTypes , typeCFMutableArrayRef ) ;
495 if ( textCtrl->IsEditable() )
496 pasteTypes = cEvent.GetParameter< CFMutableArrayRef >( kEventParamServicePasteTypes , typeCFMutableArrayRef ) ;
497
498 static const OSType textDataTypes[] = { kTXNTextData /* , 'utxt', 'PICT', 'MooV', 'AIFF' */ };
499 for ( size_t i = 0 ; i < WXSIZEOF(textDataTypes) ; ++i )
500 {
501 CFStringRef typestring = CreateTypeStringWithOSType(textDataTypes[i]);
502 if ( typestring )
503 {
504 if ( copyTypes )
505 CFArrayAppendValue(copyTypes, typestring) ;
506 if ( pasteTypes )
507 CFArrayAppendValue(pasteTypes, typestring) ;
508
509 CFRelease( typestring ) ;
510 }
511 }
512
513 result = noErr ;
514 }
515 break ;
516
517 case kEventServiceCopy :
518 if ( textCtrl )
519 {
520 long from, to ;
521
522 textCtrl->GetSelection( &from , &to ) ;
523 wxString val = textCtrl->GetValue() ;
524 val = val.Mid( from , to - from ) ;
525 PasteboardRef pasteboard = cEvent.GetParameter<PasteboardRef>( kEventParamPasteboardRef, typePasteboardRef );
526 verify_noerr( PasteboardClear( pasteboard ) ) ;
527 PasteboardSynchronize( pasteboard );
528 // TODO add proper conversion
529 CFDataRef data = CFDataCreate( kCFAllocatorDefault, (const UInt8*)val.c_str(), val.length() );
530 PasteboardPutItemFlavor( pasteboard, (PasteboardItemID) 1, CFSTR("com.apple.traditional-mac-plain-text"), data, 0);
531 CFRelease( data );
532 result = noErr ;
533 }
534 break ;
535
536 case kEventServicePaste :
537 if ( textCtrl )
538 {
539 PasteboardRef pasteboard = cEvent.GetParameter<PasteboardRef>( kEventParamPasteboardRef, typePasteboardRef );
540 PasteboardSynchronize( pasteboard );
541 ItemCount itemCount;
542 verify_noerr( PasteboardGetItemCount( pasteboard, &itemCount ) );
543 for( UInt32 itemIndex = 1; itemIndex <= itemCount; itemIndex++ )
544 {
545 PasteboardItemID itemID;
546 if ( PasteboardGetItemIdentifier( pasteboard, itemIndex, &itemID ) == noErr )
547 {
548 CFDataRef flavorData = NULL;
549 if ( PasteboardCopyItemFlavorData( pasteboard, itemID, CFSTR("com.apple.traditional-mac-plain-text"), &flavorData ) == noErr )
550 {
551 CFIndex flavorDataSize = CFDataGetLength( flavorData );
552 char *content = new char[flavorDataSize+1] ;
553 memcpy( content, CFDataGetBytePtr( flavorData ), flavorDataSize );
554 content[flavorDataSize]=0;
555 CFRelease( flavorData );
556 #if wxUSE_UNICODE
557 textCtrl->WriteText( wxString( content , wxConvLocal ) );
558 #else
559 textCtrl->WriteText( wxString( content ) ) ;
560 #endif
561
562 delete[] content ;
563 result = noErr ;
564 }
565 }
566 }
567 }
568 break ;
569
570 default:
571 break ;
572 }
573
574 return result ;
575 }
576
577 pascal OSStatus wxMacUnicodeTextEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
578 {
579 OSStatus result = eventNotHandledErr ;
580 wxWindowMac* focus = (wxWindowMac*) data ;
581
582 wchar_t* uniChars = NULL ;
583 UInt32 when = EventTimeToTicks( GetEventTime( event ) ) ;
584
585 UniChar* charBuf = NULL;
586 ByteCount dataSize = 0 ;
587 int numChars = 0 ;
588 UniChar buf[2] ;
589 if ( GetEventParameter( event, kEventParamTextInputSendText, typeUnicodeText, NULL, 0 , &dataSize, NULL ) == noErr )
590 {
591 numChars = dataSize / sizeof( UniChar) + 1;
592 charBuf = buf ;
593
594 if ( (size_t) numChars * 2 > sizeof(buf) )
595 charBuf = new UniChar[ numChars ] ;
596 else
597 charBuf = buf ;
598
599 uniChars = new wchar_t[ numChars ] ;
600 GetEventParameter( event, kEventParamTextInputSendText, typeUnicodeText, NULL, dataSize , NULL , charBuf ) ;
601 charBuf[ numChars - 1 ] = 0;
602 #if SIZEOF_WCHAR_T == 2
603 uniChars = (wchar_t*) charBuf ;
604 /* 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...)
605 #else
606 // the resulting string will never have more chars than the utf16 version, so this is safe
607 wxMBConvUTF16 converter ;
608 numChars = converter.MB2WC( uniChars , (const char*)charBuf , numChars ) ;
609 #endif
610 }
611
612 switch ( GetEventKind( event ) )
613 {
614 case kEventTextInputUpdateActiveInputArea :
615 {
616 // An IME input event may return several characters, but we need to send one char at a time to
617 // EVT_CHAR
618 for (int pos=0 ; pos < numChars ; pos++)
619 {
620 WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
621 WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
622 wxTheApp->MacSetCurrentEvent( event , handler ) ;
623
624 UInt32 message = uniChars[pos] < 128 ? (char)uniChars[pos] : '?';
625 /*
626 NB: faking a charcode here is problematic. The kEventTextInputUpdateActiveInputArea event is sent
627 multiple times to update the active range during inline input, so this handler will often receive
628 uncommited text, which should usually not trigger side effects. It might be a good idea to check the
629 kEventParamTextInputSendFixLen parameter and verify if input is being confirmed (see CarbonEvents.h).
630 On the other hand, it can be useful for some applications to react to uncommitted text (for example,
631 to update a status display), as long as it does not disrupt the inline input session. Ideally, wx
632 should add new event types to support advanced text input. For now, I would keep things as they are.
633
634 However, the code that was being used caused additional problems:
635 UInt32 message = (0 << 8) + ((char)uniChars[pos] );
636 Since it simply truncated the unichar to the last byte, it ended up causing weird bugs with inline
637 input, such as switching to another field when one attempted to insert the character U+4E09 (the kanji
638 for "three"), because it was truncated to 09 (kTabCharCode), which was later "converted" to WXK_TAB
639 (still 09) in wxMacTranslateKey; or triggering the default button when one attempted to insert U+840D
640 (the kanji for "name"), which got truncated to 0D and interpreted as a carriage return keypress.
641 Note that even single-byte characters could have been misinterpreted, since MacRoman charcodes only
642 overlap with Unicode within the (7-bit) ASCII range.
643 But simply passing a NUL charcode would disable text updated events, because wxTextCtrl::OnChar checks
644 for codes within a specific range. Therefore I went for the solution seen above, which keeps ASCII
645 characters as they are and replaces the rest with '?', ensuring that update events are triggered.
646 It would be better to change wxTextCtrl::OnChar to look at the actual unicode character instead, but
647 I don't have time to look into that right now.
648 -- CL
649 */
650 if ( wxTheApp->MacSendCharEvent(
651 focus , message , 0 , when , 0 , 0 , uniChars[pos] ) )
652 {
653 result = noErr ;
654 }
655
656 wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
657 }
658 }
659 break ;
660 case kEventTextInputUnicodeForKeyEvent :
661 {
662 UInt32 keyCode, modifiers ;
663 Point point ;
664 EventRef rawEvent ;
665 unsigned char charCode ;
666
667 GetEventParameter( event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(rawEvent), NULL, &rawEvent ) ;
668 GetEventParameter( rawEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &charCode );
669 GetEventParameter( rawEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode );
670 GetEventParameter( rawEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers );
671 GetEventParameter( rawEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &point );
672
673 UInt32 message = (keyCode << 8) + charCode;
674
675 // An IME input event may return several characters, but we need to send one char at a time to
676 // EVT_CHAR
677 for (int pos=0 ; pos < numChars ; pos++)
678 {
679 WXEVENTREF formerEvent = wxTheApp->MacGetCurrentEvent() ;
680 WXEVENTHANDLERCALLREF formerHandler = wxTheApp->MacGetCurrentEventHandlerCallRef() ;
681 wxTheApp->MacSetCurrentEvent( event , handler ) ;
682
683 if ( wxTheApp->MacSendCharEvent(
684 focus , message , modifiers , when , point.h , point.v , uniChars[pos] ) )
685 {
686 result = noErr ;
687 }
688
689 wxTheApp->MacSetCurrentEvent( formerEvent , formerHandler ) ;
690 }
691 }
692 break;
693 default:
694 break ;
695 }
696
697 delete [] uniChars ;
698 if ( charBuf != buf )
699 delete [] charBuf ;
700
701 return result ;
702 }
703
704 static pascal OSStatus
705 wxMacWindowCommandEventHandler(EventHandlerCallRef WXUNUSED(handler),
706 EventRef event,
707 void *data)
708 {
709 OSStatus result = eventNotHandledErr ;
710 wxWindowMac* focus = (wxWindowMac*) data ;
711
712 HICommand command ;
713
714 wxMacCarbonEvent cEvent( event ) ;
715 cEvent.GetParameter<HICommand>(kEventParamDirectObject,typeHICommand,&command) ;
716
717 wxMenuItem* item = NULL ;
718 wxMenu* itemMenu = wxFindMenuFromMacCommand( command , item ) ;
719 int id = wxMacCommandToId( command.commandID ) ;
720
721 if ( item )
722 {
723 wxASSERT( itemMenu != NULL ) ;
724
725 switch ( cEvent.GetKind() )
726 {
727 case kEventProcessCommand :
728 result = itemMenu->MacHandleCommandProcess( item, id, focus );
729 break ;
730
731 case kEventCommandUpdateStatus:
732 result = itemMenu->MacHandleCommandUpdateStatus( item, id, focus );
733 break ;
734
735 default :
736 break ;
737 }
738 }
739 return result ;
740 }
741
742 pascal OSStatus wxMacWindowEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
743 {
744 EventRef formerEvent = (EventRef) wxTheApp->MacGetCurrentEvent() ;
745 EventHandlerCallRef formerEventHandlerCallRef = (EventHandlerCallRef) wxTheApp->MacGetCurrentEventHandlerCallRef() ;
746 wxTheApp->MacSetCurrentEvent( event , handler ) ;
747 OSStatus result = eventNotHandledErr ;
748
749 switch ( GetEventClass( event ) )
750 {
751 case kEventClassCommand :
752 result = wxMacWindowCommandEventHandler( handler , event , data ) ;
753 break ;
754
755 case kEventClassControl :
756 result = wxMacWindowControlEventHandler( handler, event, data ) ;
757 break ;
758
759 case kEventClassService :
760 result = wxMacWindowServiceEventHandler( handler, event , data ) ;
761 break ;
762
763 case kEventClassTextInput :
764 result = wxMacUnicodeTextEventHandler( handler , event , data ) ;
765 break ;
766
767 default :
768 break ;
769 }
770
771 wxTheApp->MacSetCurrentEvent( formerEvent, formerEventHandlerCallRef ) ;
772
773 return result ;
774 }
775
776 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacWindowEventHandler )
777
778 // ---------------------------------------------------------------------------
779 // Scrollbar Tracking for all
780 // ---------------------------------------------------------------------------
781
782 pascal void wxMacLiveScrollbarActionProc( ControlRef control , ControlPartCode partCode ) ;
783 pascal void wxMacLiveScrollbarActionProc( ControlRef control , ControlPartCode partCode )
784 {
785 if ( partCode != 0)
786 {
787 wxWindow* wx = wxFindControlFromMacControl( control ) ;
788 if ( wx )
789 wx->MacHandleControlClick( (WXWidget) control , partCode , true /* stillDown */ ) ;
790 }
791 }
792 wxMAC_DEFINE_PROC_GETTER( ControlActionUPP , wxMacLiveScrollbarActionProc ) ;
793
794 // ===========================================================================
795 // implementation
796 // ===========================================================================
797
798 WX_DECLARE_HASH_MAP(ControlRef, wxWindow*, wxPointerHash, wxPointerEqual, MacControlMap);
799
800 static MacControlMap wxWinMacControlList;
801
802 wxWindow *wxFindControlFromMacControl(ControlRef inControl )
803 {
804 MacControlMap::iterator node = wxWinMacControlList.find(inControl);
805
806 return (node == wxWinMacControlList.end()) ? NULL : node->second;
807 }
808
809 void wxAssociateControlWithMacControl(ControlRef inControl, wxWindow *control)
810 {
811 // adding NULL ControlRef is (first) surely a result of an error and
812 // (secondly) breaks native event processing
813 wxCHECK_RET( inControl != (ControlRef) NULL, wxT("attempt to add a NULL WindowRef to window list") );
814
815 wxWinMacControlList[inControl] = control;
816 }
817
818 void wxRemoveMacControlAssociation(wxWindow *control)
819 {
820 // iterate over all the elements in the class
821 // is the iterator stable ? as we might have two associations pointing to the same wxWindow
822 // we should go on...
823
824 bool found = true ;
825 while ( found )
826 {
827 found = false ;
828 MacControlMap::iterator it;
829 for ( it = wxWinMacControlList.begin(); it != wxWinMacControlList.end(); ++it )
830 {
831 if ( it->second == control )
832 {
833 wxWinMacControlList.erase(it);
834 found = true ;
835 break;
836 }
837 }
838 }
839 }
840
841 // ----------------------------------------------------------------------------
842 // constructors and such
843 // ----------------------------------------------------------------------------
844
845 wxWindowMac::wxWindowMac()
846 {
847 Init();
848 }
849
850 wxWindowMac::wxWindowMac(wxWindowMac *parent,
851 wxWindowID id,
852 const wxPoint& pos ,
853 const wxSize& size ,
854 long style ,
855 const wxString& name )
856 {
857 Init();
858 Create(parent, id, pos, size, style, name);
859 }
860
861 void wxWindowMac::Init()
862 {
863 m_peer = NULL ;
864 m_frozenness = 0 ;
865 m_macAlpha = 255 ;
866 m_cgContextRef = NULL ;
867
868 // as all windows are created with WS_VISIBLE style...
869 m_isShown = true;
870
871 m_hScrollBar = NULL ;
872 m_vScrollBar = NULL ;
873 m_hScrollBarAlwaysShown = false;
874 m_vScrollBarAlwaysShown = false;
875
876 m_macIsUserPane = true;
877 m_clipChildren = false ;
878 m_cachedClippedRectValid = false ;
879
880 // we need a valid font for the encodings
881 wxWindowBase::SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
882 }
883
884 wxWindowMac::~wxWindowMac()
885 {
886 SendDestroyEvent();
887
888 m_isBeingDeleted = true;
889
890 MacInvalidateBorders() ;
891
892 #ifndef __WXUNIVERSAL__
893 // VS: make sure there's no wxFrame with last focus set to us:
894 for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
895 {
896 wxFrame *frame = wxDynamicCast(win, wxFrame);
897 if ( frame )
898 {
899 if ( frame->GetLastFocus() == this )
900 frame->SetLastFocus((wxWindow*)NULL);
901 break;
902 }
903 }
904 #endif
905
906 // destroy children before destroying this window itself
907 DestroyChildren();
908
909 // wxRemoveMacControlAssociation( this ) ;
910 // If we delete an item, we should initialize the parent panel,
911 // because it could now be invalid.
912 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
913 if ( tlw )
914 {
915 if ( tlw->GetDefaultItem() == (wxButton*) this)
916 tlw->SetDefaultItem(NULL);
917 }
918
919 if ( m_peer && m_peer->Ok() )
920 {
921 // in case the callback might be called during destruction
922 wxRemoveMacControlAssociation( this) ;
923 ::RemoveEventHandler( (EventHandlerRef ) m_macControlEventHandler ) ;
924 // we currently are not using this hook
925 // ::SetControlColorProc( *m_peer , NULL ) ;
926 m_peer->Dispose() ;
927 }
928
929 if ( g_MacLastWindow == this )
930 g_MacLastWindow = NULL ;
931
932 #ifndef __WXUNIVERSAL__
933 wxFrame* frame = wxDynamicCast( wxGetTopLevelParent( (wxWindow*)this ) , wxFrame ) ;
934 if ( frame )
935 {
936 if ( frame->GetLastFocus() == this )
937 frame->SetLastFocus( NULL ) ;
938 }
939 #endif
940
941 // delete our drop target if we've got one
942 #if wxUSE_DRAG_AND_DROP
943 if ( m_dropTarget != NULL )
944 {
945 delete m_dropTarget;
946 m_dropTarget = NULL;
947 }
948 #endif
949
950 delete m_peer ;
951 }
952
953 WXWidget wxWindowMac::GetHandle() const
954 {
955 return (WXWidget) m_peer->GetControlRef() ;
956 }
957
958 void wxWindowMac::MacInstallEventHandler( WXWidget control )
959 {
960 wxAssociateControlWithMacControl( (ControlRef) control , this ) ;
961 InstallControlEventHandler( (ControlRef)control , GetwxMacWindowEventHandlerUPP(),
962 GetEventTypeCount(eventList), eventList, this,
963 (EventHandlerRef *)&m_macControlEventHandler);
964 }
965
966 // Constructor
967 bool wxWindowMac::Create(wxWindowMac *parent,
968 wxWindowID id,
969 const wxPoint& pos,
970 const wxSize& size,
971 long style,
972 const wxString& name)
973 {
974 wxCHECK_MSG( parent, false, wxT("can't create wxWindowMac without parent") );
975
976 if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
977 return false;
978
979 m_windowVariant = parent->GetWindowVariant() ;
980
981 if ( m_macIsUserPane )
982 {
983 Rect bounds = wxMacGetBoundsForControl( this , pos , size ) ;
984
985 UInt32 features = 0
986 | kControlSupportsEmbedding
987 | kControlSupportsLiveFeedback
988 | kControlGetsFocusOnClick
989 // | kControlHasSpecialBackground
990 // | kControlSupportsCalcBestRect
991 | kControlHandlesTracking
992 | kControlSupportsFocus
993 | kControlWantsActivate
994 | kControlWantsIdle ;
995
996 m_peer = new wxMacControl(this) ;
997 OSStatus err =::CreateUserPaneControl( MAC_WXHWND(GetParent()->MacGetTopLevelWindowRef()) , &bounds, features , m_peer->GetControlRefAddr() );
998 verify_noerr( err );
999
1000 MacPostControlCreate(pos, size) ;
1001 }
1002
1003 #ifndef __WXUNIVERSAL__
1004 // Don't give scrollbars to wxControls unless they ask for them
1005 if ( (! IsKindOf(CLASSINFO(wxControl)) && ! IsKindOf(CLASSINFO(wxStatusBar)))
1006 || (IsKindOf(CLASSINFO(wxControl)) && ((style & wxHSCROLL) || (style & wxVSCROLL))))
1007 {
1008 MacCreateScrollBars( style ) ;
1009 }
1010 #endif
1011
1012 wxWindowCreateEvent event(this);
1013 GetEventHandler()->AddPendingEvent(event);
1014
1015 return true;
1016 }
1017
1018 void wxWindowMac::MacChildAdded()
1019 {
1020 if ( m_vScrollBar )
1021 m_vScrollBar->Raise() ;
1022 if ( m_hScrollBar )
1023 m_hScrollBar->Raise() ;
1024 }
1025
1026 void wxWindowMac::MacPostControlCreate(const wxPoint& WXUNUSED(pos), const wxSize& size)
1027 {
1028 wxASSERT_MSG( m_peer != NULL && m_peer->Ok() , wxT("No valid mac control") ) ;
1029
1030 m_peer->SetReference( (URefCon) this ) ;
1031 GetParent()->AddChild( this );
1032
1033 MacInstallEventHandler( (WXWidget) m_peer->GetControlRef() );
1034
1035 ControlRef container = (ControlRef) GetParent()->GetHandle() ;
1036 wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
1037 ::EmbedControl( m_peer->GetControlRef() , container ) ;
1038 GetParent()->MacChildAdded() ;
1039
1040 // adjust font, controlsize etc
1041 DoSetWindowVariant( m_windowVariant ) ;
1042
1043 m_peer->SetLabel( wxStripMenuCodes(m_label, wxStrip_Mnemonics) ) ;
1044
1045 if (!m_macIsUserPane)
1046 SetInitialSize(size);
1047
1048 SetCursor( *wxSTANDARD_CURSOR ) ;
1049 }
1050
1051 void wxWindowMac::DoSetWindowVariant( wxWindowVariant variant )
1052 {
1053 // Don't assert, in case we set the window variant before
1054 // the window is created
1055 // wxASSERT( m_peer->Ok() ) ;
1056
1057 m_windowVariant = variant ;
1058
1059 if (m_peer == NULL || !m_peer->Ok())
1060 return;
1061
1062 ControlSize size ;
1063 ThemeFontID themeFont = kThemeSystemFont ;
1064
1065 // we will get that from the settings later
1066 // and make this NORMAL later, but first
1067 // we have a few calculations that we must fix
1068
1069 switch ( variant )
1070 {
1071 case wxWINDOW_VARIANT_NORMAL :
1072 size = kControlSizeNormal;
1073 themeFont = kThemeSystemFont ;
1074 break ;
1075
1076 case wxWINDOW_VARIANT_SMALL :
1077 size = kControlSizeSmall;
1078 themeFont = kThemeSmallSystemFont ;
1079 break ;
1080
1081 case wxWINDOW_VARIANT_MINI :
1082 // not always defined in the headers
1083 size = 3 ;
1084 themeFont = 109 ;
1085 break ;
1086
1087 case wxWINDOW_VARIANT_LARGE :
1088 size = kControlSizeLarge;
1089 themeFont = kThemeSystemFont ;
1090 break ;
1091
1092 default:
1093 wxFAIL_MSG(_T("unexpected window variant"));
1094 break ;
1095 }
1096
1097 m_peer->SetData<ControlSize>(kControlEntireControl, kControlSizeTag, &size ) ;
1098
1099 wxFont font ;
1100 font.MacCreateThemeFont( themeFont ) ;
1101 SetFont( font ) ;
1102 }
1103
1104 void wxWindowMac::MacUpdateControlFont()
1105 {
1106 m_peer->SetFont( GetFont() , GetForegroundColour() , GetWindowStyle() ) ;
1107 // do not trigger refreshes upon invisible and possible partly created objects
1108 if ( MacIsReallyShown() )
1109 Refresh() ;
1110 }
1111
1112 bool wxWindowMac::SetFont(const wxFont& font)
1113 {
1114 bool retval = wxWindowBase::SetFont( font );
1115
1116 MacUpdateControlFont() ;
1117
1118 return retval;
1119 }
1120
1121 bool wxWindowMac::SetForegroundColour(const wxColour& col )
1122 {
1123 bool retval = wxWindowBase::SetForegroundColour( col );
1124
1125 if (retval)
1126 MacUpdateControlFont();
1127
1128 return retval;
1129 }
1130
1131 bool wxWindowMac::SetBackgroundColour(const wxColour& col )
1132 {
1133 if ( !wxWindowBase::SetBackgroundColour(col) && m_hasBgCol )
1134 return false ;
1135
1136 m_peer->SetBackgroundColour( col ) ;
1137
1138 return true ;
1139 }
1140
1141 bool wxWindowMac::MacCanFocus() const
1142 {
1143 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
1144 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
1145 // but the value range is nowhere documented
1146 Boolean keyExistsAndHasValidFormat ;
1147 CFIndex fullKeyboardAccess = CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
1148 kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat );
1149
1150 if ( keyExistsAndHasValidFormat && fullKeyboardAccess > 0 )
1151 {
1152 return true ;
1153 }
1154 else
1155 {
1156 UInt32 features = 0 ;
1157 m_peer->GetFeatures( &features ) ;
1158
1159 return features & ( kControlSupportsFocus | kControlGetsFocusOnClick ) ;
1160 }
1161 }
1162
1163 void wxWindowMac::SetFocus()
1164 {
1165 if ( !AcceptsFocus() )
1166 return ;
1167
1168 wxWindow* former = FindFocus() ;
1169 if ( former == this )
1170 return ;
1171
1172 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1173 // we can only leave in case of an error
1174 OSStatus err = m_peer->SetFocus( kControlFocusNextPart ) ;
1175 if ( err == errCouldntSetFocus )
1176 return ;
1177
1178 SetUserFocusWindow( (WindowRef)MacGetTopLevelWindowRef() );
1179 }
1180
1181 void wxWindowMac::DoCaptureMouse()
1182 {
1183 wxApp::s_captureWindow = this ;
1184 }
1185
1186 wxWindow * wxWindowBase::GetCapture()
1187 {
1188 return wxApp::s_captureWindow ;
1189 }
1190
1191 void wxWindowMac::DoReleaseMouse()
1192 {
1193 wxApp::s_captureWindow = NULL ;
1194 }
1195
1196 #if wxUSE_DRAG_AND_DROP
1197
1198 void wxWindowMac::SetDropTarget(wxDropTarget *pDropTarget)
1199 {
1200 if ( m_dropTarget != NULL )
1201 delete m_dropTarget;
1202
1203 m_dropTarget = pDropTarget;
1204 if ( m_dropTarget != NULL )
1205 {
1206 // TODO:
1207 }
1208 }
1209
1210 #endif
1211
1212 // Old-style File Manager Drag & Drop
1213 void wxWindowMac::DragAcceptFiles(bool WXUNUSED(accept))
1214 {
1215 // TODO:
1216 }
1217
1218 // Returns the size of the native control. In the case of the toplevel window
1219 // this is the content area root control
1220
1221 void wxWindowMac::MacGetPositionAndSizeFromControl(int& WXUNUSED(x),
1222 int& WXUNUSED(y),
1223 int& WXUNUSED(w),
1224 int& WXUNUSED(h)) const
1225 {
1226 wxFAIL_MSG( wxT("Not currently supported") ) ;
1227 }
1228
1229 // From a wx position / size calculate the appropriate size of the native control
1230
1231 bool wxWindowMac::MacGetBoundsForControl(
1232 const wxPoint& pos,
1233 const wxSize& size,
1234 int& x, int& y,
1235 int& w, int& h , bool adjustOrigin ) const
1236 {
1237 // the desired size, minus the border pixels gives the correct size of the control
1238 x = (int)pos.x;
1239 y = (int)pos.y;
1240
1241 // TODO: the default calls may be used as soon as PostCreateControl Is moved here
1242 w = wxMax(size.x, 0) ; // WidthDefault( size.x );
1243 h = wxMax(size.y, 0) ; // HeightDefault( size.y ) ;
1244
1245 x += MacGetLeftBorderSize() ;
1246 y += MacGetTopBorderSize() ;
1247 w -= MacGetLeftBorderSize() + MacGetRightBorderSize() ;
1248 h -= MacGetTopBorderSize() + MacGetBottomBorderSize() ;
1249
1250 if ( adjustOrigin )
1251 AdjustForParentClientOrigin( x , y ) ;
1252
1253 // this is in window relative coordinate, as this parent may have a border, its physical position is offset by this border
1254 if ( !GetParent()->IsTopLevel() )
1255 {
1256 x -= GetParent()->MacGetLeftBorderSize() ;
1257 y -= GetParent()->MacGetTopBorderSize() ;
1258 }
1259
1260 return true ;
1261 }
1262
1263 // Get window size (not client size)
1264 void wxWindowMac::DoGetSize(int *x, int *y) const
1265 {
1266 Rect bounds ;
1267 m_peer->GetRect( &bounds ) ;
1268
1269 if (x)
1270 *x = bounds.right - bounds.left + MacGetLeftBorderSize() + MacGetRightBorderSize() ;
1271 if (y)
1272 *y = bounds.bottom - bounds.top + MacGetTopBorderSize() + MacGetBottomBorderSize() ;
1273 }
1274
1275 // get the position of the bounds of this window in client coordinates of its parent
1276 void wxWindowMac::DoGetPosition(int *x, int *y) const
1277 {
1278 Rect bounds ;
1279 m_peer->GetRect( &bounds ) ;
1280
1281 int x1 = bounds.left ;
1282 int y1 = bounds.top ;
1283
1284 // get the wx window position from the native one
1285 x1 -= MacGetLeftBorderSize() ;
1286 y1 -= MacGetTopBorderSize() ;
1287
1288 if ( !IsTopLevel() )
1289 {
1290 wxWindow *parent = GetParent();
1291 if ( parent )
1292 {
1293 // we must first adjust it to be in window coordinates of the parent,
1294 // as otherwise it gets lost by the ClientAreaOrigin fix
1295 x1 += parent->MacGetLeftBorderSize() ;
1296 y1 += parent->MacGetTopBorderSize() ;
1297
1298 // and now to client coordinates
1299 wxPoint pt(parent->GetClientAreaOrigin());
1300 x1 -= pt.x ;
1301 y1 -= pt.y ;
1302 }
1303 }
1304
1305 if (x)
1306 *x = x1 ;
1307 if (y)
1308 *y = y1 ;
1309 }
1310
1311 void wxWindowMac::DoScreenToClient(int *x, int *y) const
1312 {
1313 WindowRef window = (WindowRef) MacGetTopLevelWindowRef() ;
1314 wxCHECK_RET( window , wxT("TopLevel Window missing") ) ;
1315
1316 Point localwhere = { 0, 0 } ;
1317
1318 if (x)
1319 localwhere.h = *x ;
1320 if (y)
1321 localwhere.v = *y ;
1322
1323 wxMacGlobalToLocal( window , &localwhere ) ;
1324
1325 if (x)
1326 *x = localwhere.h ;
1327 if (y)
1328 *y = localwhere.v ;
1329
1330 MacRootWindowToWindow( x , y ) ;
1331
1332 wxPoint origin = GetClientAreaOrigin() ;
1333 if (x)
1334 *x -= origin.x ;
1335 if (y)
1336 *y -= origin.y ;
1337 }
1338
1339 void wxWindowMac::DoClientToScreen(int *x, int *y) const
1340 {
1341 WindowRef window = (WindowRef) MacGetTopLevelWindowRef() ;
1342 wxCHECK_RET( window , wxT("TopLevel window missing") ) ;
1343
1344 wxPoint origin = GetClientAreaOrigin() ;
1345 if (x)
1346 *x += origin.x ;
1347 if (y)
1348 *y += origin.y ;
1349
1350 MacWindowToRootWindow( x , y ) ;
1351
1352 Point localwhere = { 0, 0 };
1353 if (x)
1354 localwhere.h = *x ;
1355 if (y)
1356 localwhere.v = *y ;
1357
1358 wxMacLocalToGlobal( window, &localwhere ) ;
1359
1360 if (x)
1361 *x = localwhere.h ;
1362 if (y)
1363 *y = localwhere.v ;
1364 }
1365
1366 void wxWindowMac::MacClientToRootWindow( int *x , int *y ) const
1367 {
1368 wxPoint origin = GetClientAreaOrigin() ;
1369 if (x)
1370 *x += origin.x ;
1371 if (y)
1372 *y += origin.y ;
1373
1374 MacWindowToRootWindow( x , y ) ;
1375 }
1376
1377 void wxWindowMac::MacRootWindowToClient( int *x , int *y ) const
1378 {
1379 MacRootWindowToWindow( x , y ) ;
1380
1381 wxPoint origin = GetClientAreaOrigin() ;
1382 if (x)
1383 *x -= origin.x ;
1384 if (y)
1385 *y -= origin.y ;
1386 }
1387
1388 void wxWindowMac::MacWindowToRootWindow( int *x , int *y ) const
1389 {
1390 wxPoint pt ;
1391
1392 if (x)
1393 pt.x = *x ;
1394 if (y)
1395 pt.y = *y ;
1396
1397 if ( !IsTopLevel() )
1398 {
1399 wxTopLevelWindowMac* top = MacGetTopLevelWindow();
1400 if (top)
1401 {
1402 pt.x -= MacGetLeftBorderSize() ;
1403 pt.y -= MacGetTopBorderSize() ;
1404 wxMacControl::Convert( &pt , m_peer , top->m_peer ) ;
1405 }
1406 }
1407
1408 if (x)
1409 *x = (int) pt.x ;
1410 if (y)
1411 *y = (int) pt.y ;
1412 }
1413
1414 void wxWindowMac::MacWindowToRootWindow( short *x , short *y ) const
1415 {
1416 int x1 , y1 ;
1417
1418 if (x)
1419 x1 = *x ;
1420 if (y)
1421 y1 = *y ;
1422
1423 MacWindowToRootWindow( &x1 , &y1 ) ;
1424
1425 if (x)
1426 *x = x1 ;
1427 if (y)
1428 *y = y1 ;
1429 }
1430
1431 void wxWindowMac::MacRootWindowToWindow( int *x , int *y ) const
1432 {
1433 wxPoint pt ;
1434
1435 if (x)
1436 pt.x = *x ;
1437 if (y)
1438 pt.y = *y ;
1439
1440 if ( !IsTopLevel() )
1441 {
1442 wxTopLevelWindowMac* top = MacGetTopLevelWindow();
1443 if (top)
1444 {
1445 wxMacControl::Convert( &pt , top->m_peer , m_peer ) ;
1446 pt.x += MacGetLeftBorderSize() ;
1447 pt.y += MacGetTopBorderSize() ;
1448 }
1449 }
1450
1451 if (x)
1452 *x = (int) pt.x ;
1453 if (y)
1454 *y = (int) pt.y ;
1455 }
1456
1457 void wxWindowMac::MacRootWindowToWindow( short *x , short *y ) const
1458 {
1459 int x1 , y1 ;
1460
1461 if (x)
1462 x1 = *x ;
1463 if (y)
1464 y1 = *y ;
1465
1466 MacRootWindowToWindow( &x1 , &y1 ) ;
1467
1468 if (x)
1469 *x = x1 ;
1470 if (y)
1471 *y = y1 ;
1472 }
1473
1474 void wxWindowMac::MacGetContentAreaInset( int &left , int &top , int &right , int &bottom )
1475 {
1476 RgnHandle rgn = NewRgn() ;
1477
1478 if ( m_peer->GetRegion( kControlContentMetaPart , rgn ) == noErr )
1479 {
1480 Rect structure, content ;
1481
1482 GetRegionBounds( rgn , &content ) ;
1483 m_peer->GetRect( &structure ) ;
1484 OffsetRect( &structure, -structure.left , -structure.top ) ;
1485
1486 left = content.left - structure.left ;
1487 top = content.top - structure.top ;
1488 right = structure.right - content.right ;
1489 bottom = structure.bottom - content.bottom ;
1490 }
1491 else
1492 {
1493 left = top = right = bottom = 0 ;
1494 }
1495
1496 DisposeRgn( rgn ) ;
1497 }
1498
1499 wxSize wxWindowMac::DoGetSizeFromClientSize( const wxSize & size ) const
1500 {
1501 wxSize sizeTotal = size;
1502
1503 RgnHandle rgn = NewRgn() ;
1504 if ( m_peer->GetRegion( kControlContentMetaPart , rgn ) == noErr )
1505 {
1506 Rect content, structure ;
1507 GetRegionBounds( rgn , &content ) ;
1508 m_peer->GetRect( &structure ) ;
1509
1510 // structure is in parent coordinates, but we only need width and height, so it's ok
1511
1512 sizeTotal.x += (structure.right - structure.left) - (content.right - content.left) ;
1513 sizeTotal.y += (structure.bottom - structure.top) - (content.bottom - content.top) ;
1514 }
1515
1516 DisposeRgn( rgn ) ;
1517
1518 sizeTotal.x += MacGetLeftBorderSize() + MacGetRightBorderSize() ;
1519 sizeTotal.y += MacGetTopBorderSize() + MacGetBottomBorderSize() ;
1520
1521 return sizeTotal;
1522 }
1523
1524 // Get size *available for subwindows* i.e. excluding menu bar etc.
1525 void wxWindowMac::DoGetClientSize( int *x, int *y ) const
1526 {
1527 int ww, hh;
1528
1529 RgnHandle rgn = NewRgn() ;
1530 Rect content ;
1531 if ( m_peer->GetRegion( kControlContentMetaPart , rgn ) == noErr )
1532 GetRegionBounds( rgn , &content ) ;
1533 else
1534 m_peer->GetRect( &content ) ;
1535 DisposeRgn( rgn ) ;
1536
1537 ww = content.right - content.left ;
1538 hh = content.bottom - content.top ;
1539
1540 if (m_hScrollBar && m_hScrollBar->IsShown() )
1541 hh -= m_hScrollBar->GetSize().y ;
1542
1543 if (m_vScrollBar && m_vScrollBar->IsShown() )
1544 ww -= m_vScrollBar->GetSize().x ;
1545
1546 if (x)
1547 *x = ww;
1548 if (y)
1549 *y = hh;
1550 }
1551
1552 bool wxWindowMac::SetCursor(const wxCursor& cursor)
1553 {
1554 if (m_cursor.IsSameAs(cursor))
1555 return false;
1556
1557 if (!cursor.IsOk())
1558 {
1559 if ( ! wxWindowBase::SetCursor( *wxSTANDARD_CURSOR ) )
1560 return false ;
1561 }
1562 else
1563 {
1564 if ( ! wxWindowBase::SetCursor( cursor ) )
1565 return false ;
1566 }
1567
1568 wxASSERT_MSG( m_cursor.Ok(),
1569 wxT("cursor must be valid after call to the base version"));
1570
1571 wxWindowMac *mouseWin = 0 ;
1572 {
1573 wxTopLevelWindowMac *tlw = MacGetTopLevelWindow() ;
1574 WindowRef window = (WindowRef) ( tlw ? tlw->MacGetWindowRef() : 0 ) ;
1575
1576 ControlPartCode part ;
1577 ControlRef control ;
1578 Point pt ;
1579 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1580 HIPoint hiPoint ;
1581 HIGetMousePosition(kHICoordSpaceWindow, window, &hiPoint);
1582 pt.h = hiPoint.x;
1583 pt.v = hiPoint.y;
1584 #else
1585 GetGlobalMouse( &pt );
1586 int x = pt.h;
1587 int y = pt.v;
1588 ScreenToClient(&x, &y);
1589 pt.h = x;
1590 pt.v = y;
1591 #endif
1592 control = FindControlUnderMouse( pt , window , &part ) ;
1593 if ( control )
1594 mouseWin = wxFindControlFromMacControl( control ) ;
1595
1596 }
1597
1598 if ( mouseWin == this && !wxIsBusy() )
1599 m_cursor.MacInstall() ;
1600
1601 return true ;
1602 }
1603
1604 #if wxUSE_MENUS
1605 bool wxWindowMac::DoPopupMenu(wxMenu *menu, int x, int y)
1606 {
1607 #ifndef __WXUNIVERSAL__
1608 menu->SetInvokingWindow((wxWindow*)this);
1609 menu->UpdateUI();
1610
1611 if ( x == wxDefaultCoord && y == wxDefaultCoord )
1612 {
1613 wxPoint mouse = wxGetMousePosition();
1614 x = mouse.x;
1615 y = mouse.y;
1616 }
1617 else
1618 {
1619 ClientToScreen( &x , &y ) ;
1620 }
1621
1622 menu->MacBeforeDisplay( true ) ;
1623 long menuResult = ::PopUpMenuSelect((MenuHandle) menu->GetHMenu() , y, x, 0) ;
1624 if ( HiWord(menuResult) != 0 )
1625 {
1626 MenuCommand macid;
1627 GetMenuItemCommandID( GetMenuHandle(HiWord(menuResult)) , LoWord(menuResult) , &macid );
1628 int id = wxMacCommandToId( macid );
1629 wxMenuItem* item = NULL ;
1630 wxMenu* realmenu ;
1631 item = menu->FindItem( id, &realmenu ) ;
1632 if ( item )
1633 {
1634 if (item->IsCheckable())
1635 item->Check( !item->IsChecked() ) ;
1636
1637 menu->SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) ;
1638 }
1639 }
1640
1641 menu->MacAfterDisplay( true ) ;
1642 menu->SetInvokingWindow( NULL );
1643
1644 return true;
1645 #else
1646 // actually this shouldn't be called, because universal is having its own implementation
1647 return false;
1648 #endif
1649 }
1650 #endif
1651
1652 // ----------------------------------------------------------------------------
1653 // tooltips
1654 // ----------------------------------------------------------------------------
1655
1656 #if wxUSE_TOOLTIPS
1657
1658 void wxWindowMac::DoSetToolTip(wxToolTip *tooltip)
1659 {
1660 wxWindowBase::DoSetToolTip(tooltip);
1661
1662 if ( m_tooltip )
1663 m_tooltip->SetWindow(this);
1664 }
1665
1666 #endif
1667
1668 void wxWindowMac::MacInvalidateBorders()
1669 {
1670 if ( m_peer == NULL )
1671 return ;
1672
1673 bool vis = MacIsReallyShown() ;
1674 if ( !vis )
1675 return ;
1676
1677 int outerBorder = MacGetLeftBorderSize() ;
1678 if ( m_peer->NeedsFocusRect() && m_peer->HasFocus() )
1679 outerBorder += 4 ;
1680
1681 if ( outerBorder == 0 )
1682 return ;
1683
1684 // now we know that we have something to do at all
1685
1686 // as the borders are drawn on the parent we have to properly invalidate all these areas
1687 RgnHandle updateInner , updateOuter;
1688 Rect rect ;
1689
1690 // this rectangle is in HIViewCoordinates under OSX and in Window Coordinates under Carbon
1691 updateInner = NewRgn() ;
1692 updateOuter = NewRgn() ;
1693
1694 m_peer->GetRect( &rect ) ;
1695 RectRgn( updateInner, &rect ) ;
1696 InsetRect( &rect , -outerBorder , -outerBorder ) ;
1697 RectRgn( updateOuter, &rect ) ;
1698 DiffRgn( updateOuter, updateInner , updateOuter ) ;
1699
1700 GetParent()->m_peer->SetNeedsDisplay( updateOuter ) ;
1701
1702 DisposeRgn( updateOuter ) ;
1703 DisposeRgn( updateInner ) ;
1704 }
1705
1706 void wxWindowMac::DoMoveWindow(int x, int y, int width, int height)
1707 {
1708 // this is never called for a toplevel window, so we know we have a parent
1709 int former_x , former_y , former_w, former_h ;
1710
1711 // Get true coordinates of former position
1712 DoGetPosition( &former_x , &former_y ) ;
1713 DoGetSize( &former_w , &former_h ) ;
1714
1715 wxWindow *parent = GetParent();
1716 if ( parent )
1717 {
1718 wxPoint pt(parent->GetClientAreaOrigin());
1719 former_x += pt.x ;
1720 former_y += pt.y ;
1721 }
1722
1723 int actualWidth = width ;
1724 int actualHeight = height ;
1725 int actualX = x;
1726 int actualY = y;
1727
1728 if ((m_minWidth != -1) && (actualWidth < m_minWidth))
1729 actualWidth = m_minWidth;
1730 if ((m_minHeight != -1) && (actualHeight < m_minHeight))
1731 actualHeight = m_minHeight;
1732 if ((m_maxWidth != -1) && (actualWidth > m_maxWidth))
1733 actualWidth = m_maxWidth;
1734 if ((m_maxHeight != -1) && (actualHeight > m_maxHeight))
1735 actualHeight = m_maxHeight;
1736
1737 bool doMove = false, doResize = false ;
1738
1739 if ( actualX != former_x || actualY != former_y )
1740 doMove = true ;
1741
1742 if ( actualWidth != former_w || actualHeight != former_h )
1743 doResize = true ;
1744
1745 if ( doMove || doResize )
1746 {
1747 // as the borders are drawn outside the native control, we adjust now
1748
1749 wxRect bounds( wxPoint( actualX + MacGetLeftBorderSize() ,actualY + MacGetTopBorderSize() ),
1750 wxSize( actualWidth - (MacGetLeftBorderSize() + MacGetRightBorderSize()) ,
1751 actualHeight - (MacGetTopBorderSize() + MacGetBottomBorderSize()) ) ) ;
1752
1753 Rect r ;
1754 wxMacRectToNative( &bounds , &r ) ;
1755
1756 if ( !GetParent()->IsTopLevel() )
1757 wxMacWindowToNative( GetParent() , &r ) ;
1758
1759 MacInvalidateBorders() ;
1760
1761 m_cachedClippedRectValid = false ;
1762 m_peer->SetRect( &r ) ;
1763
1764 wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified
1765
1766 MacInvalidateBorders() ;
1767
1768 MacRepositionScrollBars() ;
1769 if ( doMove )
1770 {
1771 wxPoint point(actualX, actualY);
1772 wxMoveEvent event(point, m_windowId);
1773 event.SetEventObject(this);
1774 GetEventHandler()->ProcessEvent(event) ;
1775 }
1776
1777 if ( doResize )
1778 {
1779 MacRepositionScrollBars() ;
1780 wxSize size(actualWidth, actualHeight);
1781 wxSizeEvent event(size, m_windowId);
1782 event.SetEventObject(this);
1783 GetEventHandler()->ProcessEvent(event);
1784 }
1785 }
1786 }
1787
1788 wxSize wxWindowMac::DoGetBestSize() const
1789 {
1790 if ( m_macIsUserPane || IsTopLevel() )
1791 return wxWindowBase::DoGetBestSize() ;
1792
1793 Rect bestsize = { 0 , 0 , 0 , 0 } ;
1794 int bestWidth, bestHeight ;
1795
1796 m_peer->GetBestRect( &bestsize ) ;
1797 if ( EmptyRect( &bestsize ) )
1798 {
1799 bestsize.left =
1800 bestsize.top = 0 ;
1801 bestsize.right =
1802 bestsize.bottom = 16 ;
1803
1804 if ( IsKindOf( CLASSINFO( wxScrollBar ) ) )
1805 {
1806 bestsize.bottom = 16 ;
1807 }
1808 #if wxUSE_SPINBTN
1809 else if ( IsKindOf( CLASSINFO( wxSpinButton ) ) )
1810 {
1811 bestsize.bottom = 24 ;
1812 }
1813 #endif
1814 else
1815 {
1816 // return wxWindowBase::DoGetBestSize() ;
1817 }
1818 }
1819
1820 bestWidth = bestsize.right - bestsize.left ;
1821 bestHeight = bestsize.bottom - bestsize.top ;
1822 if ( bestHeight < 10 )
1823 bestHeight = 13 ;
1824
1825 return wxSize(bestWidth, bestHeight);
1826 }
1827
1828 // set the size of the window: if the dimensions are positive, just use them,
1829 // but if any of them is equal to -1, it means that we must find the value for
1830 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
1831 // which case -1 is a valid value for x and y)
1832 //
1833 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
1834 // the width/height to best suit our contents, otherwise we reuse the current
1835 // width/height
1836 void wxWindowMac::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1837 {
1838 // get the current size and position...
1839 int currentX, currentY;
1840 int currentW, currentH;
1841
1842 GetPosition(&currentX, &currentY);
1843 GetSize(&currentW, &currentH);
1844
1845 // ... and don't do anything (avoiding flicker) if it's already ok
1846 if ( x == currentX && y == currentY &&
1847 width == currentW && height == currentH && ( height != -1 && width != -1 ) )
1848 {
1849 // TODO: REMOVE
1850 MacRepositionScrollBars() ; // we might have a real position shift
1851
1852 return;
1853 }
1854
1855 if ( !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
1856 {
1857 if ( x == wxDefaultCoord )
1858 x = currentX;
1859 if ( y == wxDefaultCoord )
1860 y = currentY;
1861 }
1862
1863 AdjustForParentClientOrigin( x, y, sizeFlags );
1864
1865 wxSize size = wxDefaultSize;
1866 if ( width == wxDefaultCoord )
1867 {
1868 if ( sizeFlags & wxSIZE_AUTO_WIDTH )
1869 {
1870 size = DoGetBestSize();
1871 width = size.x;
1872 }
1873 else
1874 {
1875 // just take the current one
1876 width = currentW;
1877 }
1878 }
1879
1880 if ( height == wxDefaultCoord )
1881 {
1882 if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
1883 {
1884 if ( size.x == wxDefaultCoord )
1885 size = DoGetBestSize();
1886 // else: already called DoGetBestSize() above
1887
1888 height = size.y;
1889 }
1890 else
1891 {
1892 // just take the current one
1893 height = currentH;
1894 }
1895 }
1896
1897 DoMoveWindow( x, y, width, height );
1898 }
1899
1900 wxPoint wxWindowMac::GetClientAreaOrigin() const
1901 {
1902 RgnHandle rgn = NewRgn() ;
1903 Rect content ;
1904 if ( m_peer->GetRegion( kControlContentMetaPart , rgn ) == noErr )
1905 {
1906 GetRegionBounds( rgn , &content ) ;
1907 }
1908 else
1909 {
1910 content.left =
1911 content.top = 0 ;
1912 }
1913
1914 DisposeRgn( rgn ) ;
1915
1916 return wxPoint( content.left + MacGetLeftBorderSize() , content.top + MacGetTopBorderSize() );
1917 }
1918
1919 void wxWindowMac::DoSetClientSize(int clientwidth, int clientheight)
1920 {
1921 if ( clientwidth != wxDefaultCoord || clientheight != wxDefaultCoord )
1922 {
1923 int currentclientwidth , currentclientheight ;
1924 int currentwidth , currentheight ;
1925
1926 GetClientSize( &currentclientwidth , &currentclientheight ) ;
1927 GetSize( &currentwidth , &currentheight ) ;
1928
1929 DoSetSize( wxDefaultCoord , wxDefaultCoord , currentwidth + clientwidth - currentclientwidth ,
1930 currentheight + clientheight - currentclientheight , wxSIZE_USE_EXISTING ) ;
1931 }
1932 }
1933
1934 void wxWindowMac::SetLabel(const wxString& title)
1935 {
1936 m_label = title ;
1937
1938 if ( m_peer && m_peer->Ok() )
1939 m_peer->SetLabel( wxStripMenuCodes(m_label, wxStrip_Mnemonics) ) ;
1940
1941 // do not trigger refreshes upon invisible and possible partly created objects
1942 if ( MacIsReallyShown() )
1943 Refresh() ;
1944 }
1945
1946 wxString wxWindowMac::GetLabel() const
1947 {
1948 return m_label ;
1949 }
1950
1951 bool wxWindowMac::Show(bool show)
1952 {
1953 if ( !wxWindowBase::Show(show) )
1954 return false;
1955
1956 if ( m_peer )
1957 m_peer->SetVisibility( show , true ) ;
1958
1959 return true;
1960 }
1961
1962 void wxWindowMac::DoEnable(bool enable)
1963 {
1964 m_peer->Enable( enable ) ;
1965 }
1966
1967 //
1968 // status change notifications
1969 //
1970
1971 void wxWindowMac::MacVisibilityChanged()
1972 {
1973 }
1974
1975 void wxWindowMac::MacHiliteChanged()
1976 {
1977 }
1978
1979 void wxWindowMac::MacEnabledStateChanged()
1980 {
1981 OnEnabled( m_peer->IsEnabled() );
1982 }
1983
1984 //
1985 // status queries on the inherited window's state
1986 //
1987
1988 bool wxWindowMac::MacIsReallyShown()
1989 {
1990 // only under OSX the visibility of the TLW is taken into account
1991 if ( m_isBeingDeleted )
1992 return false ;
1993
1994 #if TARGET_API_MAC_OSX
1995 if ( m_peer && m_peer->Ok() )
1996 return m_peer->IsVisible();
1997 #endif
1998
1999 wxWindow* win = this ;
2000 while ( win->IsShown() )
2001 {
2002 if ( win->IsTopLevel() )
2003 return true ;
2004
2005 win = win->GetParent() ;
2006 if ( win == NULL )
2007 return true ;
2008 }
2009
2010 return false ;
2011 }
2012
2013 bool wxWindowMac::MacIsReallyEnabled()
2014 {
2015 return m_peer->IsEnabled() ;
2016 }
2017
2018 bool wxWindowMac::MacIsReallyHilited()
2019 {
2020 return m_peer->IsActive();
2021 }
2022
2023 void wxWindowMac::MacFlashInvalidAreas()
2024 {
2025 #if TARGET_API_MAC_OSX
2026 HIViewFlashDirtyArea( (WindowRef) MacGetTopLevelWindowRef() ) ;
2027 #endif
2028 }
2029
2030 int wxWindowMac::GetCharHeight() const
2031 {
2032 wxClientDC dc( (wxWindowMac*)this ) ;
2033
2034 return dc.GetCharHeight() ;
2035 }
2036
2037 int wxWindowMac::GetCharWidth() const
2038 {
2039 wxClientDC dc( (wxWindowMac*)this ) ;
2040
2041 return dc.GetCharWidth() ;
2042 }
2043
2044 void wxWindowMac::GetTextExtent(const wxString& string, int *x, int *y,
2045 int *descent, int *externalLeading, const wxFont *theFont ) const
2046 {
2047 const wxFont *fontToUse = theFont;
2048 if ( !fontToUse )
2049 fontToUse = &m_font;
2050
2051 wxClientDC dc( (wxWindowMac*) this ) ;
2052 wxCoord lx,ly,ld,le ;
2053 dc.GetTextExtent( string , &lx , &ly , &ld, &le, (wxFont *)fontToUse ) ;
2054 if ( externalLeading )
2055 *externalLeading = le ;
2056 if ( descent )
2057 *descent = ld ;
2058 if ( x )
2059 *x = lx ;
2060 if ( y )
2061 *y = ly ;
2062 }
2063
2064 /*
2065 * Rect is given in client coordinates, for further reading, read wxTopLevelWindowMac::InvalidateRect
2066 * we always intersect with the entire window, not only with the client area
2067 */
2068
2069 void wxWindowMac::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
2070 {
2071 if ( m_peer == NULL )
2072 return ;
2073
2074 if ( !MacIsReallyShown() )
2075 return ;
2076
2077 if ( rect )
2078 {
2079 Rect r ;
2080
2081 wxMacRectToNative( rect , &r ) ;
2082 m_peer->SetNeedsDisplay( &r ) ;
2083 }
2084 else
2085 {
2086 m_peer->SetNeedsDisplay() ;
2087 }
2088 }
2089
2090 void wxWindowMac::Freeze()
2091 {
2092 #if TARGET_API_MAC_OSX
2093 if ( !m_frozenness++ )
2094 {
2095 if ( m_peer && m_peer->Ok() )
2096 m_peer->SetDrawingEnabled( false ) ;
2097 }
2098 #endif
2099 }
2100
2101 void wxWindowMac::Thaw()
2102 {
2103 #if TARGET_API_MAC_OSX
2104 wxASSERT_MSG( m_frozenness > 0, wxT("Thaw() without matching Freeze()") );
2105
2106 if ( !--m_frozenness )
2107 {
2108 if ( m_peer && m_peer->Ok() )
2109 {
2110 m_peer->SetDrawingEnabled( true ) ;
2111 m_peer->InvalidateWithChildren() ;
2112 }
2113 }
2114 #endif
2115 }
2116
2117 bool wxWindowMac::IsFrozen() const
2118 {
2119 return m_frozenness != 0;
2120 }
2121
2122 wxWindowMac *wxGetActiveWindow()
2123 {
2124 // actually this is a windows-only concept
2125 return NULL;
2126 }
2127
2128 // Coordinates relative to the window
2129 void wxWindowMac::WarpPointer(int WXUNUSED(x_pos), int WXUNUSED(y_pos))
2130 {
2131 // We really don't move the mouse programmatically under Mac.
2132 }
2133
2134 void wxWindowMac::OnEraseBackground(wxEraseEvent& event)
2135 {
2136 if ( MacGetTopLevelWindow() == NULL )
2137 return ;
2138 /*
2139 #if TARGET_API_MAC_OSX
2140 if ( !m_backgroundColour.Ok() || GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT )
2141 {
2142 }
2143 else
2144 #endif
2145 */
2146 if ( GetBackgroundStyle() == wxBG_STYLE_COLOUR )
2147 {
2148 event.GetDC()->Clear() ;
2149 }
2150 else
2151 {
2152 event.Skip() ;
2153 }
2154 }
2155
2156 void wxWindowMac::OnNcPaint( wxNcPaintEvent& event )
2157 {
2158 event.Skip() ;
2159 }
2160
2161 int wxWindowMac::GetScrollPos(int orient) const
2162 {
2163 if ( orient == wxHORIZONTAL )
2164 {
2165 if ( m_hScrollBar )
2166 return m_hScrollBar->GetThumbPosition() ;
2167 }
2168 else
2169 {
2170 if ( m_vScrollBar )
2171 return m_vScrollBar->GetThumbPosition() ;
2172 }
2173
2174 return 0;
2175 }
2176
2177 // This now returns the whole range, not just the number
2178 // of positions that we can scroll.
2179 int wxWindowMac::GetScrollRange(int orient) const
2180 {
2181 if ( orient == wxHORIZONTAL )
2182 {
2183 if ( m_hScrollBar )
2184 return m_hScrollBar->GetRange() ;
2185 }
2186 else
2187 {
2188 if ( m_vScrollBar )
2189 return m_vScrollBar->GetRange() ;
2190 }
2191
2192 return 0;
2193 }
2194
2195 int wxWindowMac::GetScrollThumb(int orient) const
2196 {
2197 if ( orient == wxHORIZONTAL )
2198 {
2199 if ( m_hScrollBar )
2200 return m_hScrollBar->GetThumbSize() ;
2201 }
2202 else
2203 {
2204 if ( m_vScrollBar )
2205 return m_vScrollBar->GetThumbSize() ;
2206 }
2207
2208 return 0;
2209 }
2210
2211 void wxWindowMac::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
2212 {
2213 if ( orient == wxHORIZONTAL )
2214 {
2215 if ( m_hScrollBar )
2216 m_hScrollBar->SetThumbPosition( pos ) ;
2217 }
2218 else
2219 {
2220 if ( m_vScrollBar )
2221 m_vScrollBar->SetThumbPosition( pos ) ;
2222 }
2223 }
2224
2225 void
2226 wxWindowMac::AlwaysShowScrollbars(bool hflag, bool vflag)
2227 {
2228 bool needVisibilityUpdate = false;
2229
2230 if ( m_hScrollBarAlwaysShown != hflag )
2231 {
2232 m_hScrollBarAlwaysShown = hflag;
2233 needVisibilityUpdate = true;
2234 }
2235
2236 if ( m_vScrollBarAlwaysShown != vflag )
2237 {
2238 m_vScrollBarAlwaysShown = vflag;
2239 needVisibilityUpdate = true;
2240 }
2241
2242 if ( needVisibilityUpdate )
2243 DoUpdateScrollbarVisibility();
2244 }
2245
2246 //
2247 // we draw borders and grow boxes, are already set up and clipped in the current port / cgContextRef
2248 // our own window origin is at leftOrigin/rightOrigin
2249 //
2250
2251 void wxWindowMac::MacPaintGrowBox()
2252 {
2253 if ( IsTopLevel() )
2254 return ;
2255
2256 if ( MacHasScrollBarCorner() )
2257 {
2258 Rect rect ;
2259
2260 CGContextRef cgContext = (CGContextRef) MacGetCGContextRef() ;
2261 wxASSERT( cgContext ) ;
2262
2263 m_peer->GetRect( &rect ) ;
2264
2265 int size = m_hScrollBar ? m_hScrollBar->GetSize().y : ( m_vScrollBar ? m_vScrollBar->GetSize().x : MAC_SCROLLBAR_SIZE ) ;
2266 CGRect cgrect = CGRectMake( rect.right - size , rect.bottom - size , size , size ) ;
2267 CGPoint cgpoint = CGPointMake( rect.right - size , rect.bottom - size ) ;
2268 CGContextSaveGState( cgContext );
2269
2270 if ( m_backgroundColour.Ok() )
2271 {
2272 CGContextSetFillColorWithColor( cgContext, m_backgroundColour.GetCGColor() );
2273 }
2274 else
2275 {
2276 CGContextSetRGBFillColor( cgContext, 1.0, 1.0 , 1.0 , 1.0 );
2277 }
2278 CGContextFillRect( cgContext, cgrect );
2279 CGContextRestoreGState( cgContext );
2280 }
2281 }
2282
2283 void wxWindowMac::MacPaintBorders( int WXUNUSED(leftOrigin) , int WXUNUSED(rightOrigin) )
2284 {
2285 if ( IsTopLevel() )
2286 return ;
2287
2288 Rect rect ;
2289 bool hasFocus = m_peer->NeedsFocusRect() && m_peer->HasFocus() ;
2290
2291 // back to the surrounding frame rectangle
2292 m_peer->GetRect( &rect ) ;
2293 InsetRect( &rect, -1 , -1 ) ;
2294
2295 {
2296 CGRect cgrect = CGRectMake( rect.left , rect.top , rect.right - rect.left ,
2297 rect.bottom - rect.top ) ;
2298
2299 HIThemeFrameDrawInfo info ;
2300 memset( &info, 0 , sizeof(info) ) ;
2301
2302 info.version = 0 ;
2303 info.kind = 0 ;
2304 info.state = IsEnabled() ? kThemeStateActive : kThemeStateInactive ;
2305 info.isFocused = hasFocus ;
2306
2307 CGContextRef cgContext = (CGContextRef) GetParent()->MacGetCGContextRef() ;
2308 wxASSERT( cgContext ) ;
2309
2310 if ( HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER) || HasFlag(wxDOUBLE_BORDER) )
2311 {
2312 info.kind = kHIThemeFrameTextFieldSquare ;
2313 HIThemeDrawFrame( &cgrect , &info , cgContext , kHIThemeOrientationNormal ) ;
2314 }
2315 else if ( HasFlag(wxSIMPLE_BORDER) )
2316 {
2317 info.kind = kHIThemeFrameListBox ;
2318 HIThemeDrawFrame( &cgrect , &info , cgContext , kHIThemeOrientationNormal ) ;
2319 }
2320 else if ( hasFocus )
2321 {
2322 HIThemeDrawFocusRect( &cgrect , true , cgContext , kHIThemeOrientationNormal ) ;
2323 }
2324 #if 0 // TODO REMOVE now done in a separate call earlier in drawing the window itself
2325 m_peer->GetRect( &rect ) ;
2326 if ( MacHasScrollBarCorner() )
2327 {
2328 int variant = (m_hScrollBar == NULL ? m_vScrollBar : m_hScrollBar ) ->GetWindowVariant();
2329 int size = m_hScrollBar ? m_hScrollBar->GetSize().y : ( m_vScrollBar ? m_vScrollBar->GetSize().x : MAC_SCROLLBAR_SIZE ) ;
2330 CGRect cgrect = CGRectMake( rect.right - size , rect.bottom - size , size , size ) ;
2331 CGPoint cgpoint = CGPointMake( rect.right - size , rect.bottom - size ) ;
2332 HIThemeGrowBoxDrawInfo info ;
2333 memset( &info, 0, sizeof(info) ) ;
2334 info.version = 0 ;
2335 info.state = IsEnabled() ? kThemeStateActive : kThemeStateInactive ;
2336 info.kind = kHIThemeGrowBoxKindNone ;
2337 // contrary to the docs ...SizeSmall does not work
2338 info.size = kHIThemeGrowBoxSizeNormal ;
2339 info.direction = 0 ;
2340 HIThemeDrawGrowBox( &cgpoint , &info , cgContext , kHIThemeOrientationNormal ) ;
2341 }
2342 #endif
2343 }
2344 }
2345
2346 void wxWindowMac::RemoveChild( wxWindowBase *child )
2347 {
2348 if ( child == m_hScrollBar )
2349 m_hScrollBar = NULL ;
2350 if ( child == m_vScrollBar )
2351 m_vScrollBar = NULL ;
2352
2353 wxWindowBase::RemoveChild( child ) ;
2354 }
2355
2356 void wxWindowMac::DoUpdateScrollbarVisibility()
2357 {
2358 bool triggerSizeEvent = false;
2359
2360 if ( m_hScrollBar )
2361 {
2362 bool showHScrollBar = m_hScrollBarAlwaysShown || m_hScrollBar->IsNeeded();
2363
2364 if ( m_hScrollBar->IsShown() != showHScrollBar )
2365 {
2366 m_hScrollBar->Show( showHScrollBar );
2367 triggerSizeEvent = true;
2368 }
2369 }
2370
2371 if ( m_vScrollBar)
2372 {
2373 bool showVScrollBar = m_vScrollBarAlwaysShown || m_vScrollBar->IsNeeded();
2374
2375 if ( m_vScrollBar->IsShown() != showVScrollBar )
2376 {
2377 m_vScrollBar->Show( showVScrollBar ) ;
2378 triggerSizeEvent = true;
2379 }
2380 }
2381
2382 MacRepositionScrollBars() ;
2383 if ( triggerSizeEvent )
2384 {
2385 wxSizeEvent event(GetSize(), m_windowId);
2386 event.SetEventObject(this);
2387 GetEventHandler()->ProcessEvent(event);
2388 }
2389 }
2390
2391 // New function that will replace some of the above.
2392 void wxWindowMac::SetScrollbar(int orient, int pos, int thumb,
2393 int range, bool refresh)
2394 {
2395 if ( orient == wxHORIZONTAL && m_hScrollBar )
2396 m_hScrollBar->SetScrollbar(pos, thumb, range, thumb, refresh);
2397 else if ( orient == wxVERTICAL && m_vScrollBar )
2398 m_vScrollBar->SetScrollbar(pos, thumb, range, thumb, refresh);
2399
2400 DoUpdateScrollbarVisibility();
2401 }
2402
2403 // Does a physical scroll
2404 void wxWindowMac::ScrollWindow(int dx, int dy, const wxRect *rect)
2405 {
2406 if ( dx == 0 && dy == 0 )
2407 return ;
2408
2409 int width , height ;
2410 GetClientSize( &width , &height ) ;
2411
2412 {
2413 // note there currently is a bug in OSX which makes inefficient refreshes in case an entire control
2414 // area is scrolled, this does not occur if width and height are 2 pixels less,
2415 // TODO: write optimal workaround
2416 wxRect scrollrect( MacGetLeftBorderSize() , MacGetTopBorderSize() , width , height ) ;
2417 if ( rect )
2418 scrollrect.Intersect( *rect ) ;
2419
2420 if ( m_peer->GetNeedsDisplay() )
2421 {
2422 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
2423 // in case there is already a pending redraw on that area
2424 // either immediate redraw or full invalidate
2425 #if 1
2426 // is the better overall solution, as it does not slow down scrolling
2427 m_peer->SetNeedsDisplay() ;
2428 #else
2429 // this would be the preferred version for fast drawing controls
2430 HIViewRender(m_peer->GetControlRef()) ;
2431 #endif
2432 }
2433
2434 // as the native control might be not a 0/0 wx window coordinates, we have to offset
2435 scrollrect.Offset( -MacGetLeftBorderSize() , -MacGetTopBorderSize() ) ;
2436 m_peer->ScrollRect( &scrollrect , dx , dy ) ;
2437
2438 #if 0
2439 // this would be the preferred version for fast drawing controls
2440 HIViewRender(m_peer->GetControlRef()) ;
2441 #endif
2442 }
2443
2444 wxWindowMac *child;
2445 int x, y, w, h;
2446 for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext())
2447 {
2448 child = node->GetData();
2449 if (child == NULL)
2450 continue;
2451 if (child == m_vScrollBar)
2452 continue;
2453 if (child == m_hScrollBar)
2454 continue;
2455 if (child->IsTopLevel())
2456 continue;
2457
2458 child->GetPosition( &x, &y );
2459 child->GetSize( &w, &h );
2460 if (rect)
2461 {
2462 wxRect rc( x, y, w, h );
2463 if (rect->Intersects( rc ))
2464 child->SetSize( x + dx, y + dy, w, h, wxSIZE_AUTO|wxSIZE_ALLOW_MINUS_ONE );
2465 }
2466 else
2467 {
2468 child->SetSize( x + dx, y + dy, w, h, wxSIZE_AUTO|wxSIZE_ALLOW_MINUS_ONE );
2469 }
2470 }
2471 }
2472
2473 void wxWindowMac::MacOnScroll( wxScrollEvent &event )
2474 {
2475 if ( event.GetEventObject() == m_vScrollBar || event.GetEventObject() == m_hScrollBar )
2476 {
2477 wxScrollWinEvent wevent;
2478 wevent.SetPosition(event.GetPosition());
2479 wevent.SetOrientation(event.GetOrientation());
2480 wevent.SetEventObject(this);
2481
2482 if (event.GetEventType() == wxEVT_SCROLL_TOP)
2483 wevent.SetEventType( wxEVT_SCROLLWIN_TOP );
2484 else if (event.GetEventType() == wxEVT_SCROLL_BOTTOM)
2485 wevent.SetEventType( wxEVT_SCROLLWIN_BOTTOM );
2486 else if (event.GetEventType() == wxEVT_SCROLL_LINEUP)
2487 wevent.SetEventType( wxEVT_SCROLLWIN_LINEUP );
2488 else if (event.GetEventType() == wxEVT_SCROLL_LINEDOWN)
2489 wevent.SetEventType( wxEVT_SCROLLWIN_LINEDOWN );
2490 else if (event.GetEventType() == wxEVT_SCROLL_PAGEUP)
2491 wevent.SetEventType( wxEVT_SCROLLWIN_PAGEUP );
2492 else if (event.GetEventType() == wxEVT_SCROLL_PAGEDOWN)
2493 wevent.SetEventType( wxEVT_SCROLLWIN_PAGEDOWN );
2494 else if (event.GetEventType() == wxEVT_SCROLL_THUMBTRACK)
2495 wevent.SetEventType( wxEVT_SCROLLWIN_THUMBTRACK );
2496 else if (event.GetEventType() == wxEVT_SCROLL_THUMBRELEASE)
2497 wevent.SetEventType( wxEVT_SCROLLWIN_THUMBRELEASE );
2498
2499 GetEventHandler()->ProcessEvent(wevent);
2500 }
2501 }
2502
2503 // Get the window with the focus
2504 wxWindowMac *wxWindowBase::DoFindFocus()
2505 {
2506 ControlRef control ;
2507 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
2508 return wxFindControlFromMacControl( control ) ;
2509 }
2510
2511 void wxWindowMac::OnSetFocus( wxFocusEvent& event )
2512 {
2513 // panel wants to track the window which was the last to have focus in it,
2514 // so we want to set ourselves as the window which last had focus
2515 //
2516 // notice that it's also important to do it upwards the tree because
2517 // otherwise when the top level panel gets focus, it won't set it back to
2518 // us, but to some other sibling
2519
2520 // CS: don't know if this is still needed:
2521 //wxChildFocusEvent eventFocus(this);
2522 //(void)GetEventHandler()->ProcessEvent(eventFocus);
2523
2524 if ( MacGetTopLevelWindow() && m_peer->NeedsFocusRect() )
2525 {
2526 GetParent()->Refresh() ;
2527 wxMacWindowStateSaver sv( this ) ;
2528 Rect rect ;
2529
2530 m_peer->GetRect( &rect ) ;
2531 // on the surrounding frame
2532 InsetRect( &rect, -1 , -1 ) ;
2533
2534 wxTopLevelWindowMac* top = MacGetTopLevelWindow();
2535 if ( top )
2536 {
2537 wxPoint pt(0, 0) ;
2538 wxMacControl::Convert( &pt , GetParent()->m_peer , top->m_peer ) ;
2539 rect.left += pt.x ;
2540 rect.right += pt.x ;
2541 rect.top += pt.y ;
2542 rect.bottom += pt.y ;
2543 }
2544
2545 bool bIsFocusEvent = (event.GetEventType() == wxEVT_SET_FOCUS);
2546 DrawThemeFocusRect( &rect , bIsFocusEvent ) ;
2547 if ( !bIsFocusEvent )
2548 {
2549 // as this erases part of the frame we have to redraw borders
2550 // and because our z-ordering is not always correct (staticboxes)
2551 // we have to invalidate things, we cannot simple redraw
2552 MacInvalidateBorders() ;
2553 }
2554 }
2555
2556 event.Skip();
2557 }
2558
2559 void wxWindowMac::OnInternalIdle()
2560 {
2561 // This calls the UI-update mechanism (querying windows for
2562 // menu/toolbar/control state information)
2563 if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
2564 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
2565 }
2566
2567 // Raise the window to the top of the Z order
2568 void wxWindowMac::Raise()
2569 {
2570 m_peer->SetZOrder( true , NULL ) ;
2571 }
2572
2573 // Lower the window to the bottom of the Z order
2574 void wxWindowMac::Lower()
2575 {
2576 m_peer->SetZOrder( false , NULL ) ;
2577 }
2578
2579 // static wxWindow *gs_lastWhich = NULL;
2580
2581 bool wxWindowMac::MacSetupCursor( const wxPoint& pt )
2582 {
2583 // first trigger a set cursor event
2584
2585 wxPoint clientorigin = GetClientAreaOrigin() ;
2586 wxSize clientsize = GetClientSize() ;
2587 wxCursor cursor ;
2588 if ( wxRect2DInt( clientorigin.x , clientorigin.y , clientsize.x , clientsize.y ).Contains( wxPoint2DInt( pt ) ) )
2589 {
2590 wxSetCursorEvent event( pt.x , pt.y );
2591
2592 bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
2593 if ( processedEvtSetCursor && event.HasCursor() )
2594 {
2595 cursor = event.GetCursor() ;
2596 }
2597 else
2598 {
2599 // the test for processedEvtSetCursor is here to prevent using m_cursor
2600 // if the user code caught EVT_SET_CURSOR() and returned nothing from
2601 // it - this is a way to say that our cursor shouldn't be used for this
2602 // point
2603 if ( !processedEvtSetCursor && m_cursor.Ok() )
2604 cursor = m_cursor ;
2605
2606 if ( !wxIsBusy() && !GetParent() )
2607 cursor = *wxSTANDARD_CURSOR ;
2608 }
2609
2610 if ( cursor.Ok() )
2611 cursor.MacInstall() ;
2612 }
2613
2614 return cursor.Ok() ;
2615 }
2616
2617 wxString wxWindowMac::MacGetToolTipString( wxPoint &WXUNUSED(pt) )
2618 {
2619 #if wxUSE_TOOLTIPS
2620 if ( m_tooltip )
2621 return m_tooltip->GetTip() ;
2622 #endif
2623
2624 return wxEmptyString ;
2625 }
2626
2627 void wxWindowMac::ClearBackground()
2628 {
2629 Refresh() ;
2630 Update() ;
2631 }
2632
2633 void wxWindowMac::Update()
2634 {
2635 wxTopLevelWindowMac* top = MacGetTopLevelWindow();
2636 if (top)
2637 top->MacPerformUpdates() ;
2638 }
2639
2640 wxTopLevelWindowMac* wxWindowMac::MacGetTopLevelWindow() const
2641 {
2642 wxTopLevelWindowMac* win = NULL ;
2643 WindowRef window = (WindowRef) MacGetTopLevelWindowRef() ;
2644 if ( window )
2645 win = wxFindWinFromMacWindow( window ) ;
2646
2647 return win ;
2648 }
2649
2650 const wxRect& wxWindowMac::MacGetClippedClientRect() const
2651 {
2652 MacUpdateClippedRects() ;
2653
2654 return m_cachedClippedClientRect ;
2655 }
2656
2657 const wxRect& wxWindowMac::MacGetClippedRect() const
2658 {
2659 MacUpdateClippedRects() ;
2660
2661 return m_cachedClippedRect ;
2662 }
2663
2664 const wxRect&wxWindowMac:: MacGetClippedRectWithOuterStructure() const
2665 {
2666 MacUpdateClippedRects() ;
2667
2668 return m_cachedClippedRectWithOuterStructure ;
2669 }
2670
2671 const wxRegion& wxWindowMac::MacGetVisibleRegion( bool includeOuterStructures )
2672 {
2673 static wxRegion emptyrgn ;
2674
2675 if ( !m_isBeingDeleted && MacIsReallyShown() /*m_peer->IsVisible() */ )
2676 {
2677 MacUpdateClippedRects() ;
2678 if ( includeOuterStructures )
2679 return m_cachedClippedRegionWithOuterStructure ;
2680 else
2681 return m_cachedClippedRegion ;
2682 }
2683 else
2684 {
2685 return emptyrgn ;
2686 }
2687 }
2688
2689 void wxWindowMac::MacUpdateClippedRects() const
2690 {
2691 if ( m_cachedClippedRectValid )
2692 return ;
2693
2694 // includeOuterStructures is true if we try to draw somthing like a focus ring etc.
2695 // also a window dc uses this, in this case we only clip in the hierarchy for hard
2696 // borders like a scrollwindow, splitter etc otherwise we end up in a paranoia having
2697 // to add focus borders everywhere
2698
2699 Rect r, rIncludingOuterStructures ;
2700
2701 m_peer->GetRect( &r ) ;
2702 r.left -= MacGetLeftBorderSize() ;
2703 r.top -= MacGetTopBorderSize() ;
2704 r.bottom += MacGetBottomBorderSize() ;
2705 r.right += MacGetRightBorderSize() ;
2706
2707 r.right -= r.left ;
2708 r.bottom -= r.top ;
2709 r.left = 0 ;
2710 r.top = 0 ;
2711
2712 rIncludingOuterStructures = r ;
2713 InsetRect( &rIncludingOuterStructures , -4 , -4 ) ;
2714
2715 wxRect cl = GetClientRect() ;
2716 Rect rClient = { cl.y , cl.x , cl.y + cl.height , cl.x + cl.width } ;
2717
2718 int x , y ;
2719 wxSize size ;
2720 const wxWindow* child = this ;
2721 const wxWindow* parent = NULL ;
2722
2723 while ( !child->IsTopLevel() && ( parent = child->GetParent() ) != NULL )
2724 {
2725 if ( parent->MacIsChildOfClientArea(child) )
2726 {
2727 size = parent->GetClientSize() ;
2728 wxPoint origin = parent->GetClientAreaOrigin() ;
2729 x = origin.x ;
2730 y = origin.y ;
2731 }
2732 else
2733 {
2734 // this will be true for scrollbars, toolbars etc.
2735 size = parent->GetSize() ;
2736 y = parent->MacGetTopBorderSize() ;
2737 x = parent->MacGetLeftBorderSize() ;
2738 size.x -= parent->MacGetLeftBorderSize() + parent->MacGetRightBorderSize() ;
2739 size.y -= parent->MacGetTopBorderSize() + parent->MacGetBottomBorderSize() ;
2740 }
2741
2742 parent->MacWindowToRootWindow( &x, &y ) ;
2743 MacRootWindowToWindow( &x , &y ) ;
2744
2745 Rect rparent = { y , x , y + size.y , x + size.x } ;
2746
2747 // the wxwindow and client rects will always be clipped
2748 SectRect( &r , &rparent , &r ) ;
2749 SectRect( &rClient , &rparent , &rClient ) ;
2750
2751 // the structure only at 'hard' borders
2752 if ( parent->MacClipChildren() ||
2753 ( parent->GetParent() && parent->GetParent()->MacClipGrandChildren() ) )
2754 {
2755 SectRect( &rIncludingOuterStructures , &rparent , &rIncludingOuterStructures ) ;
2756 }
2757
2758 child = parent ;
2759 }
2760
2761 m_cachedClippedRect = wxRect( r.left , r.top , r.right - r.left , r.bottom - r.top ) ;
2762 m_cachedClippedClientRect = wxRect( rClient.left , rClient.top ,
2763 rClient.right - rClient.left , rClient.bottom - rClient.top ) ;
2764 m_cachedClippedRectWithOuterStructure = wxRect(
2765 rIncludingOuterStructures.left , rIncludingOuterStructures.top ,
2766 rIncludingOuterStructures.right - rIncludingOuterStructures.left ,
2767 rIncludingOuterStructures.bottom - rIncludingOuterStructures.top ) ;
2768
2769 m_cachedClippedRegionWithOuterStructure = wxRegion( m_cachedClippedRectWithOuterStructure ) ;
2770 m_cachedClippedRegion = wxRegion( m_cachedClippedRect ) ;
2771 m_cachedClippedClientRegion = wxRegion( m_cachedClippedClientRect ) ;
2772
2773 m_cachedClippedRectValid = true ;
2774 }
2775
2776 /*
2777 This function must not change the updatergn !
2778 */
2779 bool wxWindowMac::MacDoRedraw( void* updatergnr , long time )
2780 {
2781 bool handled = false ;
2782 Rect updatebounds ;
2783 RgnHandle updatergn = (RgnHandle) updatergnr ;
2784 GetRegionBounds( updatergn , &updatebounds ) ;
2785
2786 // wxLogDebug(wxT("update for %s bounds %d, %d, %d, %d"), wxString(GetClassInfo()->GetClassName()).c_str(), updatebounds.left, updatebounds.top , updatebounds.right , updatebounds.bottom ) ;
2787
2788 if ( !EmptyRgn(updatergn) )
2789 {
2790 RgnHandle newupdate = NewRgn() ;
2791 wxSize point = GetClientSize() ;
2792 wxPoint origin = GetClientAreaOrigin() ;
2793 SetRectRgn( newupdate , origin.x , origin.y , origin.x + point.x , origin.y + point.y ) ;
2794 SectRgn( newupdate , updatergn , newupdate ) ;
2795
2796 // first send an erase event to the entire update area
2797 {
2798 // for the toplevel window this really is the entire area
2799 // for all the others only their client area, otherwise they
2800 // might be drawing with full alpha and eg put blue into
2801 // the grow-box area of a scrolled window (scroll sample)
2802 wxDC* dc = new wxWindowDC(this);
2803 if ( IsTopLevel() )
2804 dc->SetClippingRegion(wxRegion(HIShapeCreateWithQDRgn(updatergn)));
2805 else
2806 dc->SetClippingRegion(wxRegion(HIShapeCreateWithQDRgn(newupdate)));
2807
2808 wxEraseEvent eevent( GetId(), dc );
2809 eevent.SetEventObject( this );
2810 GetEventHandler()->ProcessEvent( eevent );
2811 delete dc ;
2812 }
2813
2814 MacPaintGrowBox();
2815
2816 // calculate a client-origin version of the update rgn and set m_updateRegion to that
2817 OffsetRgn( newupdate , -origin.x , -origin.y ) ;
2818 m_updateRegion = wxRegion(HIShapeCreateWithQDRgn(newupdate)) ;
2819 DisposeRgn( newupdate ) ;
2820
2821 if ( !m_updateRegion.Empty() )
2822 {
2823 // paint the window itself
2824
2825 wxPaintEvent event;
2826 event.SetTimestamp(time);
2827 event.SetEventObject(this);
2828 GetEventHandler()->ProcessEvent(event);
2829 handled = true ;
2830 }
2831
2832 // now we cannot rely on having its borders drawn by a window itself, as it does not
2833 // get the updateRgn wide enough to always do so, so we do it from the parent
2834 // this would also be the place to draw any custom backgrounds for native controls
2835 // in Composited windowing
2836 wxPoint clientOrigin = GetClientAreaOrigin() ;
2837
2838 wxWindowMac *child;
2839 int x, y, w, h;
2840 for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext())
2841 {
2842 child = node->GetData();
2843 if (child == NULL)
2844 continue;
2845 if (child == m_vScrollBar)
2846 continue;
2847 if (child == m_hScrollBar)
2848 continue;
2849 if (child->IsTopLevel())
2850 continue;
2851 if (!child->IsShown())
2852 continue;
2853
2854 // only draw those in the update region (add a safety margin of 10 pixels for shadow effects
2855
2856 child->GetPosition( &x, &y );
2857 child->GetSize( &w, &h );
2858 Rect childRect = { y , x , y + h , x + w } ;
2859 OffsetRect( &childRect , clientOrigin.x , clientOrigin.y ) ;
2860 InsetRect( &childRect , -10 , -10) ;
2861
2862 if ( RectInRgn( &childRect , updatergn ) )
2863 {
2864 // paint custom borders
2865 wxNcPaintEvent eventNc( child->GetId() );
2866 eventNc.SetEventObject( child );
2867 if ( !child->GetEventHandler()->ProcessEvent( eventNc ) )
2868 {
2869 child->MacPaintBorders(0, 0) ;
2870 }
2871 }
2872 }
2873 }
2874
2875 return handled ;
2876 }
2877
2878
2879 WXWindow wxWindowMac::MacGetTopLevelWindowRef() const
2880 {
2881 wxWindowMac *iter = (wxWindowMac*)this ;
2882
2883 while ( iter )
2884 {
2885 if ( iter->IsTopLevel() )
2886 {
2887 wxTopLevelWindow* toplevel = wxDynamicCast(iter,wxTopLevelWindow);
2888 if ( toplevel )
2889 return toplevel->MacGetWindowRef();
2890 #if wxUSE_POPUPWIN
2891 wxPopupWindow* popupwin = wxDynamicCast(iter,wxPopupWindow);
2892 if ( popupwin )
2893 return popupwin->MacGetPopupWindowRef();
2894 #endif
2895 }
2896 iter = iter->GetParent() ;
2897 }
2898
2899 return NULL ;
2900 }
2901
2902 bool wxWindowMac::MacHasScrollBarCorner() const
2903 {
2904 /* Returns whether the scroll bars in a wxScrolledWindow should be
2905 * shortened. Scroll bars should be shortened if either:
2906 *
2907 * - both scroll bars are visible, or
2908 *
2909 * - there is a resize box in the parent frame's corner and this
2910 * window shares the bottom and right edge with the parent
2911 * frame.
2912 */
2913
2914 if ( m_hScrollBar == NULL && m_vScrollBar == NULL )
2915 return false;
2916
2917 if ( ( m_hScrollBar && m_hScrollBar->IsShown() )
2918 && ( m_vScrollBar && m_vScrollBar->IsShown() ) )
2919 {
2920 // Both scroll bars visible
2921 return true;
2922 }
2923 else
2924 {
2925 wxPoint thisWindowBottomRight = GetScreenRect().GetBottomRight();
2926
2927 for ( const wxWindow *win = this; win; win = win->GetParent() )
2928 {
2929 const wxFrame *frame = wxDynamicCast( win, wxFrame ) ;
2930 if ( frame )
2931 {
2932 if ( frame->GetWindowStyleFlag() & wxRESIZE_BORDER )
2933 {
2934 // Parent frame has resize handle
2935 wxPoint frameBottomRight = frame->GetScreenRect().GetBottomRight();
2936
2937 // Note: allow for some wiggle room here as wxMac's
2938 // window rect calculations seem to be imprecise
2939 if ( abs( thisWindowBottomRight.x - frameBottomRight.x ) <= 2
2940 && abs( thisWindowBottomRight.y - frameBottomRight.y ) <= 2 )
2941 {
2942 // Parent frame has resize handle and shares
2943 // right bottom corner
2944 return true ;
2945 }
2946 else
2947 {
2948 // Parent frame has resize handle but doesn't
2949 // share right bottom corner
2950 return false ;
2951 }
2952 }
2953 else
2954 {
2955 // Parent frame doesn't have resize handle
2956 return false ;
2957 }
2958 }
2959 }
2960
2961 // No parent frame found
2962 return false ;
2963 }
2964 }
2965
2966 void wxWindowMac::MacCreateScrollBars( long style )
2967 {
2968 wxASSERT_MSG( m_vScrollBar == NULL && m_hScrollBar == NULL , wxT("attempt to create window twice") ) ;
2969
2970 if ( style & ( wxVSCROLL | wxHSCROLL ) )
2971 {
2972 int scrlsize = MAC_SCROLLBAR_SIZE ;
2973 if ( GetWindowVariant() == wxWINDOW_VARIANT_SMALL || GetWindowVariant() == wxWINDOW_VARIANT_MINI )
2974 {
2975 scrlsize = MAC_SMALL_SCROLLBAR_SIZE ;
2976 }
2977
2978 int adjust = MacHasScrollBarCorner() ? scrlsize - 1: 0 ;
2979 int width, height ;
2980 GetClientSize( &width , &height ) ;
2981
2982 wxPoint vPoint(width - scrlsize, 0) ;
2983 wxSize vSize(scrlsize, height - adjust) ;
2984 wxPoint hPoint(0, height - scrlsize) ;
2985 wxSize hSize(width - adjust, scrlsize) ;
2986
2987 // we have to set the min size to a smaller value, otherwise they cannot get smaller (InitialSize sets MinSize)
2988 if ( style & wxVSCROLL )
2989 {
2990 m_vScrollBar = new wxScrollBar((wxWindow*)this, wxID_ANY, vPoint, vSize , wxVERTICAL);
2991 m_vScrollBar->SetMinSize( wxDefaultSize );
2992 }
2993
2994 if ( style & wxHSCROLL )
2995 {
2996 m_hScrollBar = new wxScrollBar((wxWindow*)this, wxID_ANY, hPoint, hSize , wxHORIZONTAL);
2997 m_hScrollBar->SetMinSize( wxDefaultSize );
2998 }
2999 }
3000
3001 // because the create does not take into account the client area origin
3002 // we might have a real position shift
3003 MacRepositionScrollBars() ;
3004 }
3005
3006 bool wxWindowMac::MacIsChildOfClientArea( const wxWindow* child ) const
3007 {
3008 bool result = ((child == NULL) || ((child != m_hScrollBar) && (child != m_vScrollBar)));
3009
3010 return result ;
3011 }
3012
3013 void wxWindowMac::MacRepositionScrollBars()
3014 {
3015 if ( !m_hScrollBar && !m_vScrollBar )
3016 return ;
3017
3018 int scrlsize = m_hScrollBar ? m_hScrollBar->GetSize().y : ( m_vScrollBar ? m_vScrollBar->GetSize().x : MAC_SCROLLBAR_SIZE ) ;
3019 int adjust = MacHasScrollBarCorner() ? scrlsize - 1 : 0 ;
3020
3021 // get real client area
3022 int width, height ;
3023 GetSize( &width , &height );
3024
3025 width -= MacGetLeftBorderSize() + MacGetRightBorderSize();
3026 height -= MacGetTopBorderSize() + MacGetBottomBorderSize();
3027
3028 wxPoint vPoint( width - scrlsize, 0 ) ;
3029 wxSize vSize( scrlsize, height - adjust ) ;
3030 wxPoint hPoint( 0 , height - scrlsize ) ;
3031 wxSize hSize( width - adjust, scrlsize ) ;
3032
3033 #if 0
3034 int x = 0, y = 0, w, h ;
3035 GetSize( &w , &h ) ;
3036
3037 MacClientToRootWindow( &x , &y ) ;
3038 MacClientToRootWindow( &w , &h ) ;
3039
3040 wxWindowMac *iter = (wxWindowMac*)this ;
3041
3042 int totW = 10000 , totH = 10000;
3043 while ( iter )
3044 {
3045 if ( iter->IsTopLevel() )
3046 {
3047 iter->GetSize( &totW , &totH ) ;
3048 break ;
3049 }
3050
3051 iter = iter->GetParent() ;
3052 }
3053
3054 if ( x == 0 )
3055 {
3056 hPoint.x = -1 ;
3057 hSize.x += 1 ;
3058 }
3059 if ( y == 0 )
3060 {
3061 vPoint.y = -1 ;
3062 vSize.y += 1 ;
3063 }
3064
3065 if ( w - x >= totW )
3066 {
3067 hSize.x += 1 ;
3068 vPoint.x += 1 ;
3069 }
3070 if ( h - y >= totH )
3071 {
3072 vSize.y += 1 ;
3073 hPoint.y += 1 ;
3074 }
3075 #endif
3076
3077 if ( m_vScrollBar )
3078 m_vScrollBar->SetSize( vPoint.x , vPoint.y, vSize.x, vSize.y , wxSIZE_ALLOW_MINUS_ONE );
3079 if ( m_hScrollBar )
3080 m_hScrollBar->SetSize( hPoint.x , hPoint.y, hSize.x, hSize.y, wxSIZE_ALLOW_MINUS_ONE );
3081 }
3082
3083 bool wxWindowMac::AcceptsFocus() const
3084 {
3085 return MacCanFocus() && wxWindowBase::AcceptsFocus();
3086 }
3087
3088 void wxWindowMac::MacSuperChangedPosition()
3089 {
3090 // only window-absolute structures have to be moved i.e. controls
3091
3092 m_cachedClippedRectValid = false ;
3093
3094 wxWindowMac *child;
3095 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3096 while ( node )
3097 {
3098 child = node->GetData();
3099 child->MacSuperChangedPosition() ;
3100
3101 node = node->GetNext();
3102 }
3103 }
3104
3105 void wxWindowMac::MacTopLevelWindowChangedPosition()
3106 {
3107 // only screen-absolute structures have to be moved i.e. glcanvas
3108
3109 wxWindowMac *child;
3110 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3111 while ( node )
3112 {
3113 child = node->GetData();
3114 child->MacTopLevelWindowChangedPosition() ;
3115
3116 node = node->GetNext();
3117 }
3118 }
3119
3120 long wxWindowMac::MacGetLeftBorderSize() const
3121 {
3122 if ( IsTopLevel() )
3123 return 0 ;
3124
3125 SInt32 border = 0 ;
3126
3127 if (HasFlag(wxRAISED_BORDER) || HasFlag( wxSUNKEN_BORDER) || HasFlag(wxDOUBLE_BORDER))
3128 {
3129 // this metric is only the 'outset' outside the simple frame rect
3130 GetThemeMetric( kThemeMetricEditTextFrameOutset , &border ) ;
3131 border += 1 ;
3132 }
3133 else if (HasFlag(wxSIMPLE_BORDER))
3134 {
3135 // this metric is only the 'outset' outside the simple frame rect
3136 GetThemeMetric( kThemeMetricListBoxFrameOutset , &border ) ;
3137 border += 1 ;
3138 }
3139
3140 return border ;
3141 }
3142
3143 long wxWindowMac::MacGetRightBorderSize() const
3144 {
3145 // they are all symmetric in mac themes
3146 return MacGetLeftBorderSize() ;
3147 }
3148
3149 long wxWindowMac::MacGetTopBorderSize() const
3150 {
3151 // they are all symmetric in mac themes
3152 return MacGetLeftBorderSize() ;
3153 }
3154
3155 long wxWindowMac::MacGetBottomBorderSize() const
3156 {
3157 // they are all symmetric in mac themes
3158 return MacGetLeftBorderSize() ;
3159 }
3160
3161 long wxWindowMac::MacRemoveBordersFromStyle( long style )
3162 {
3163 return style & ~wxBORDER_MASK ;
3164 }
3165
3166 // Find the wxWindowMac at the current mouse position, returning the mouse
3167 // position.
3168 wxWindowMac * wxFindWindowAtPointer( wxPoint& pt )
3169 {
3170 pt = wxGetMousePosition();
3171 wxWindowMac* found = wxFindWindowAtPoint(pt);
3172
3173 return found;
3174 }
3175
3176 // Get the current mouse position.
3177 wxPoint wxGetMousePosition()
3178 {
3179 int x, y;
3180
3181 wxGetMousePosition( &x, &y );
3182
3183 return wxPoint(x, y);
3184 }
3185
3186 void wxWindowMac::OnMouseEvent( wxMouseEvent &event )
3187 {
3188 if ( event.GetEventType() == wxEVT_RIGHT_DOWN )
3189 {
3190 // copied from wxGTK : CS
3191 // VZ: shouldn't we move this to base class then?
3192
3193 // generate a "context menu" event: this is similar to wxEVT_RIGHT_DOWN
3194 // except that:
3195 //
3196 // (a) it's a command event and so is propagated to the parent
3197 // (b) under MSW it can be generated from kbd too
3198 // (c) it uses screen coords (because of (a))
3199 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU,
3200 this->GetId(),
3201 this->ClientToScreen(event.GetPosition()));
3202 if ( ! GetEventHandler()->ProcessEvent(evtCtx) )
3203 event.Skip() ;
3204 }
3205 else
3206 {
3207 event.Skip() ;
3208 }
3209 }
3210
3211 void wxWindowMac::OnPaint( wxPaintEvent & WXUNUSED(event) )
3212 {
3213 if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL
3214 && GetBackgroundStyle() != wxBG_STYLE_TRANSPARENT )
3215 CallNextEventHandler(
3216 (EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() ,
3217 (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
3218 }
3219
3220 void wxWindowMac::MacHandleControlClick(WXWidget WXUNUSED(control),
3221 wxInt16 WXUNUSED(controlpart),
3222 bool WXUNUSED(mouseStillDown))
3223 {
3224 }
3225
3226 Rect wxMacGetBoundsForControl( wxWindow* window , const wxPoint& pos , const wxSize &size , bool adjustForOrigin )
3227 {
3228 int x, y, w, h ;
3229
3230 window->MacGetBoundsForControl( pos , size , x , y, w, h , adjustForOrigin ) ;
3231 Rect bounds = { y, x, y + h, x + w };
3232
3233 return bounds ;
3234 }
3235
3236 wxInt32 wxWindowMac::MacControlHit(WXEVENTHANDLERREF WXUNUSED(handler) , WXEVENTREF WXUNUSED(event) )
3237 {
3238 return eventNotHandledErr ;
3239 }
3240
3241 bool wxWindowMac::Reparent(wxWindowBase *newParentBase)
3242 {
3243 wxWindowMac *newParent = (wxWindowMac *)newParentBase;
3244 if ( !wxWindowBase::Reparent(newParent) )
3245 return false;
3246
3247 // copied from MacPostControlCreate
3248 ControlRef container = (ControlRef) GetParent()->GetHandle() ;
3249
3250 wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
3251
3252 ::EmbedControl( m_peer->GetControlRef() , container ) ;
3253
3254 return true;
3255 }
3256
3257 bool wxWindowMac::SetTransparent(wxByte alpha)
3258 {
3259 SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
3260
3261 if ( alpha != m_macAlpha )
3262 {
3263 m_macAlpha = alpha ;
3264 Refresh() ;
3265 }
3266 return true ;
3267 }
3268
3269
3270 bool wxWindowMac::CanSetTransparent()
3271 {
3272 return true ;
3273 }
3274
3275 wxByte wxWindowMac::GetTransparent() const
3276 {
3277 return m_macAlpha ;
3278 }