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