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