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