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