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