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