]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/window.cpp
graphics context additions (work in progress for cocoa integration) and merging graph...
[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
2119 {
2120 event.Skip() ;
2121 }
2122 }
2123
2124 void wxWindowMac::OnNcPaint( wxNcPaintEvent& event )
2125 {
2126 event.Skip() ;
2127 }
2128
2129 int wxWindowMac::GetScrollPos(int orient) const
2130 {
2131 if ( orient == wxHORIZONTAL )
2132 {
2133 if ( m_hScrollBar )
2134 return m_hScrollBar->GetThumbPosition() ;
2135 }
2136 else
2137 {
2138 if ( m_vScrollBar )
2139 return m_vScrollBar->GetThumbPosition() ;
2140 }
2141
2142 return 0;
2143 }
2144
2145 // This now returns the whole range, not just the number
2146 // of positions that we can scroll.
2147 int wxWindowMac::GetScrollRange(int orient) const
2148 {
2149 if ( orient == wxHORIZONTAL )
2150 {
2151 if ( m_hScrollBar )
2152 return m_hScrollBar->GetRange() ;
2153 }
2154 else
2155 {
2156 if ( m_vScrollBar )
2157 return m_vScrollBar->GetRange() ;
2158 }
2159
2160 return 0;
2161 }
2162
2163 int wxWindowMac::GetScrollThumb(int orient) const
2164 {
2165 if ( orient == wxHORIZONTAL )
2166 {
2167 if ( m_hScrollBar )
2168 return m_hScrollBar->GetThumbSize() ;
2169 }
2170 else
2171 {
2172 if ( m_vScrollBar )
2173 return m_vScrollBar->GetThumbSize() ;
2174 }
2175
2176 return 0;
2177 }
2178
2179 void wxWindowMac::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
2180 {
2181 if ( orient == wxHORIZONTAL )
2182 {
2183 if ( m_hScrollBar )
2184 m_hScrollBar->SetThumbPosition( pos ) ;
2185 }
2186 else
2187 {
2188 if ( m_vScrollBar )
2189 m_vScrollBar->SetThumbPosition( pos ) ;
2190 }
2191 }
2192
2193 void
2194 wxWindowMac::AlwaysShowScrollbars(bool hflag, bool vflag)
2195 {
2196 bool needVisibilityUpdate = false;
2197
2198 if ( m_hScrollBarAlwaysShown != hflag )
2199 {
2200 m_hScrollBarAlwaysShown = hflag;
2201 needVisibilityUpdate = true;
2202 }
2203
2204 if ( m_vScrollBarAlwaysShown != vflag )
2205 {
2206 m_vScrollBarAlwaysShown = vflag;
2207 needVisibilityUpdate = true;
2208 }
2209
2210 if ( needVisibilityUpdate )
2211 DoUpdateScrollbarVisibility();
2212 }
2213
2214 //
2215 // we draw borders and grow boxes, are already set up and clipped in the current port / cgContextRef
2216 // our own window origin is at leftOrigin/rightOrigin
2217 //
2218
2219 void wxWindowMac::MacPaintGrowBox()
2220 {
2221 if ( IsTopLevel() )
2222 return ;
2223
2224 if ( MacHasScrollBarCorner() )
2225 {
2226 Rect rect ;
2227
2228 CGContextRef cgContext = (CGContextRef) MacGetCGContextRef() ;
2229 wxASSERT( cgContext ) ;
2230
2231 m_peer->GetRect( &rect ) ;
2232
2233 int size = m_hScrollBar ? m_hScrollBar->GetSize().y : ( m_vScrollBar ? m_vScrollBar->GetSize().x : MAC_SCROLLBAR_SIZE ) ;
2234 CGRect cgrect = CGRectMake( rect.right - size , rect.bottom - size , size , size ) ;
2235 CGPoint cgpoint = CGPointMake( rect.right - size , rect.bottom - size ) ;
2236 CGContextSaveGState( cgContext );
2237
2238 if ( m_backgroundColour.Ok() )
2239 {
2240 CGContextSetFillColorWithColor( cgContext, m_backgroundColour.GetCGColor() );
2241 }
2242 else
2243 {
2244 CGContextSetRGBFillColor( cgContext, 1.0, 1.0 , 1.0 , 1.0 );
2245 }
2246 CGContextFillRect( cgContext, cgrect );
2247 CGContextRestoreGState( cgContext );
2248 }
2249 }
2250
2251 void wxWindowMac::MacPaintBorders( int WXUNUSED(leftOrigin) , int WXUNUSED(rightOrigin) )
2252 {
2253 if ( IsTopLevel() )
2254 return ;
2255
2256 Rect rect ;
2257 bool hasFocus = m_peer->NeedsFocusRect() && m_peer->HasFocus() ;
2258
2259 // back to the surrounding frame rectangle
2260 m_peer->GetRect( &rect ) ;
2261 InsetRect( &rect, -1 , -1 ) ;
2262
2263 {
2264 CGRect cgrect = CGRectMake( rect.left , rect.top , rect.right - rect.left ,
2265 rect.bottom - rect.top ) ;
2266
2267 HIThemeFrameDrawInfo info ;
2268 memset( &info, 0 , sizeof(info) ) ;
2269
2270 info.version = 0 ;
2271 info.kind = 0 ;
2272 info.state = IsEnabled() ? kThemeStateActive : kThemeStateInactive ;
2273 info.isFocused = hasFocus ;
2274
2275 CGContextRef cgContext = (CGContextRef) GetParent()->MacGetCGContextRef() ;
2276 wxASSERT( cgContext ) ;
2277
2278 if ( HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER) || HasFlag(wxDOUBLE_BORDER) )
2279 {
2280 info.kind = kHIThemeFrameTextFieldSquare ;
2281 HIThemeDrawFrame( &cgrect , &info , cgContext , kHIThemeOrientationNormal ) ;
2282 }
2283 else if ( HasFlag(wxSIMPLE_BORDER) )
2284 {
2285 info.kind = kHIThemeFrameListBox ;
2286 HIThemeDrawFrame( &cgrect , &info , cgContext , kHIThemeOrientationNormal ) ;
2287 }
2288 else if ( hasFocus )
2289 {
2290 HIThemeDrawFocusRect( &cgrect , true , cgContext , kHIThemeOrientationNormal ) ;
2291 }
2292 #if 0 // TODO REMOVE now done in a separate call earlier in drawing the window itself
2293 m_peer->GetRect( &rect ) ;
2294 if ( MacHasScrollBarCorner() )
2295 {
2296 int variant = (m_hScrollBar == NULL ? m_vScrollBar : m_hScrollBar ) ->GetWindowVariant();
2297 int size = m_hScrollBar ? m_hScrollBar->GetSize().y : ( m_vScrollBar ? m_vScrollBar->GetSize().x : MAC_SCROLLBAR_SIZE ) ;
2298 CGRect cgrect = CGRectMake( rect.right - size , rect.bottom - size , size , size ) ;
2299 CGPoint cgpoint = CGPointMake( rect.right - size , rect.bottom - size ) ;
2300 HIThemeGrowBoxDrawInfo info ;
2301 memset( &info, 0, sizeof(info) ) ;
2302 info.version = 0 ;
2303 info.state = IsEnabled() ? kThemeStateActive : kThemeStateInactive ;
2304 info.kind = kHIThemeGrowBoxKindNone ;
2305 // contrary to the docs ...SizeSmall does not work
2306 info.size = kHIThemeGrowBoxSizeNormal ;
2307 info.direction = 0 ;
2308 HIThemeDrawGrowBox( &cgpoint , &info , cgContext , kHIThemeOrientationNormal ) ;
2309 }
2310 #endif
2311 }
2312 }
2313
2314 void wxWindowMac::RemoveChild( wxWindowBase *child )
2315 {
2316 if ( child == m_hScrollBar )
2317 m_hScrollBar = NULL ;
2318 if ( child == m_vScrollBar )
2319 m_vScrollBar = NULL ;
2320
2321 wxWindowBase::RemoveChild( child ) ;
2322 }
2323
2324 void wxWindowMac::DoUpdateScrollbarVisibility()
2325 {
2326 bool triggerSizeEvent = false;
2327
2328 if ( m_hScrollBar )
2329 {
2330 bool showHScrollBar = m_hScrollBarAlwaysShown || m_hScrollBar->IsNeeded();
2331
2332 if ( m_hScrollBar->IsShown() != showHScrollBar )
2333 {
2334 m_hScrollBar->Show( showHScrollBar );
2335 triggerSizeEvent = true;
2336 }
2337 }
2338
2339 if ( m_vScrollBar)
2340 {
2341 bool showVScrollBar = m_vScrollBarAlwaysShown || m_vScrollBar->IsNeeded();
2342
2343 if ( m_vScrollBar->IsShown() != showVScrollBar )
2344 {
2345 m_vScrollBar->Show( showVScrollBar ) ;
2346 triggerSizeEvent = true;
2347 }
2348 }
2349
2350 MacRepositionScrollBars() ;
2351 if ( triggerSizeEvent )
2352 {
2353 wxSizeEvent event(GetSize(), m_windowId);
2354 event.SetEventObject(this);
2355 HandleWindowEvent(event);
2356 }
2357 }
2358
2359 // New function that will replace some of the above.
2360 void wxWindowMac::SetScrollbar(int orient, int pos, int thumb,
2361 int range, bool refresh)
2362 {
2363 if ( orient == wxHORIZONTAL && m_hScrollBar )
2364 m_hScrollBar->SetScrollbar(pos, thumb, range, thumb, refresh);
2365 else if ( orient == wxVERTICAL && m_vScrollBar )
2366 m_vScrollBar->SetScrollbar(pos, thumb, range, thumb, refresh);
2367
2368 DoUpdateScrollbarVisibility();
2369 }
2370
2371 // Does a physical scroll
2372 void wxWindowMac::ScrollWindow(int dx, int dy, const wxRect *rect)
2373 {
2374 if ( dx == 0 && dy == 0 )
2375 return ;
2376
2377 int width , height ;
2378 GetClientSize( &width , &height ) ;
2379
2380 {
2381 // note there currently is a bug in OSX which makes inefficient refreshes in case an entire control
2382 // area is scrolled, this does not occur if width and height are 2 pixels less,
2383 // TODO: write optimal workaround
2384 wxRect scrollrect( MacGetLeftBorderSize() , MacGetTopBorderSize() , width , height ) ;
2385 if ( rect )
2386 scrollrect.Intersect( *rect ) ;
2387
2388 if ( m_peer->GetNeedsDisplay() )
2389 {
2390 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
2391 // in case there is already a pending redraw on that area
2392 // either immediate redraw or full invalidate
2393 #if 1
2394 // is the better overall solution, as it does not slow down scrolling
2395 m_peer->SetNeedsDisplay() ;
2396 #else
2397 // this would be the preferred version for fast drawing controls
2398 HIViewRender(m_peer->GetControlRef()) ;
2399 #endif
2400 }
2401
2402 // as the native control might be not a 0/0 wx window coordinates, we have to offset
2403 scrollrect.Offset( -MacGetLeftBorderSize() , -MacGetTopBorderSize() ) ;
2404 m_peer->ScrollRect( &scrollrect , dx , dy ) ;
2405
2406 #if 0
2407 // this would be the preferred version for fast drawing controls
2408 HIViewRender(m_peer->GetControlRef()) ;
2409 #endif
2410 }
2411
2412 wxWindowMac *child;
2413 int x, y, w, h;
2414 for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext())
2415 {
2416 child = node->GetData();
2417 if (child == NULL)
2418 continue;
2419 if (child == m_vScrollBar)
2420 continue;
2421 if (child == m_hScrollBar)
2422 continue;
2423 if (child->IsTopLevel())
2424 continue;
2425
2426 child->GetPosition( &x, &y );
2427 child->GetSize( &w, &h );
2428 if (rect)
2429 {
2430 wxRect rc( x, y, w, h );
2431 if (rect->Intersects( rc ))
2432 child->SetSize( x + dx, y + dy, w, h, wxSIZE_AUTO|wxSIZE_ALLOW_MINUS_ONE );
2433 }
2434 else
2435 {
2436 child->SetSize( x + dx, y + dy, w, h, wxSIZE_AUTO|wxSIZE_ALLOW_MINUS_ONE );
2437 }
2438 }
2439 }
2440
2441 void wxWindowMac::MacOnScroll( wxScrollEvent &event )
2442 {
2443 if ( event.GetEventObject() == m_vScrollBar || event.GetEventObject() == m_hScrollBar )
2444 {
2445 wxScrollWinEvent wevent;
2446 wevent.SetPosition(event.GetPosition());
2447 wevent.SetOrientation(event.GetOrientation());
2448 wevent.SetEventObject(this);
2449
2450 if (event.GetEventType() == wxEVT_SCROLL_TOP)
2451 wevent.SetEventType( wxEVT_SCROLLWIN_TOP );
2452 else if (event.GetEventType() == wxEVT_SCROLL_BOTTOM)
2453 wevent.SetEventType( wxEVT_SCROLLWIN_BOTTOM );
2454 else if (event.GetEventType() == wxEVT_SCROLL_LINEUP)
2455 wevent.SetEventType( wxEVT_SCROLLWIN_LINEUP );
2456 else if (event.GetEventType() == wxEVT_SCROLL_LINEDOWN)
2457 wevent.SetEventType( wxEVT_SCROLLWIN_LINEDOWN );
2458 else if (event.GetEventType() == wxEVT_SCROLL_PAGEUP)
2459 wevent.SetEventType( wxEVT_SCROLLWIN_PAGEUP );
2460 else if (event.GetEventType() == wxEVT_SCROLL_PAGEDOWN)
2461 wevent.SetEventType( wxEVT_SCROLLWIN_PAGEDOWN );
2462 else if (event.GetEventType() == wxEVT_SCROLL_THUMBTRACK)
2463 wevent.SetEventType( wxEVT_SCROLLWIN_THUMBTRACK );
2464 else if (event.GetEventType() == wxEVT_SCROLL_THUMBRELEASE)
2465 wevent.SetEventType( wxEVT_SCROLLWIN_THUMBRELEASE );
2466
2467 HandleWindowEvent(wevent);
2468 }
2469 }
2470
2471 // Get the window with the focus
2472 wxWindowMac *wxWindowBase::DoFindFocus()
2473 {
2474 ControlRef control ;
2475 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
2476 return wxFindControlFromMacControl( control ) ;
2477 }
2478
2479 void wxWindowMac::OnInternalIdle()
2480 {
2481 // This calls the UI-update mechanism (querying windows for
2482 // menu/toolbar/control state information)
2483 if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
2484 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
2485 }
2486
2487 // Raise the window to the top of the Z order
2488 void wxWindowMac::Raise()
2489 {
2490 m_peer->SetZOrder( true , NULL ) ;
2491 }
2492
2493 // Lower the window to the bottom of the Z order
2494 void wxWindowMac::Lower()
2495 {
2496 m_peer->SetZOrder( false , NULL ) ;
2497 }
2498
2499 // static wxWindow *gs_lastWhich = NULL;
2500
2501 bool wxWindowMac::MacSetupCursor( const wxPoint& pt )
2502 {
2503 // first trigger a set cursor event
2504
2505 wxPoint clientorigin = GetClientAreaOrigin() ;
2506 wxSize clientsize = GetClientSize() ;
2507 wxCursor cursor ;
2508 if ( wxRect2DInt( clientorigin.x , clientorigin.y , clientsize.x , clientsize.y ).Contains( wxPoint2DInt( pt ) ) )
2509 {
2510 wxSetCursorEvent event( pt.x , pt.y );
2511
2512 bool processedEvtSetCursor = HandleWindowEvent(event);
2513 if ( processedEvtSetCursor && event.HasCursor() )
2514 {
2515 cursor = event.GetCursor() ;
2516 }
2517 else
2518 {
2519 // the test for processedEvtSetCursor is here to prevent using m_cursor
2520 // if the user code caught EVT_SET_CURSOR() and returned nothing from
2521 // it - this is a way to say that our cursor shouldn't be used for this
2522 // point
2523 if ( !processedEvtSetCursor && m_cursor.Ok() )
2524 cursor = m_cursor ;
2525
2526 if ( !wxIsBusy() && !GetParent() )
2527 cursor = *wxSTANDARD_CURSOR ;
2528 }
2529
2530 if ( cursor.Ok() )
2531 cursor.MacInstall() ;
2532 }
2533
2534 return cursor.Ok() ;
2535 }
2536
2537 wxString wxWindowMac::MacGetToolTipString( wxPoint &WXUNUSED(pt) )
2538 {
2539 #if wxUSE_TOOLTIPS
2540 if ( m_tooltip )
2541 return m_tooltip->GetTip() ;
2542 #endif
2543
2544 return wxEmptyString ;
2545 }
2546
2547 void wxWindowMac::ClearBackground()
2548 {
2549 Refresh() ;
2550 Update() ;
2551 }
2552
2553 void wxWindowMac::Update()
2554 {
2555 wxTopLevelWindowMac* top = MacGetTopLevelWindow();
2556 if (top)
2557 top->MacPerformUpdates() ;
2558 }
2559
2560 wxTopLevelWindowMac* wxWindowMac::MacGetTopLevelWindow() const
2561 {
2562 wxTopLevelWindowMac* win = NULL ;
2563 WindowRef window = (WindowRef) MacGetTopLevelWindowRef() ;
2564 if ( window )
2565 win = wxFindWinFromMacWindow( window ) ;
2566
2567 return win ;
2568 }
2569
2570 const wxRect& wxWindowMac::MacGetClippedClientRect() const
2571 {
2572 MacUpdateClippedRects() ;
2573
2574 return m_cachedClippedClientRect ;
2575 }
2576
2577 const wxRect& wxWindowMac::MacGetClippedRect() const
2578 {
2579 MacUpdateClippedRects() ;
2580
2581 return m_cachedClippedRect ;
2582 }
2583
2584 const wxRect&wxWindowMac:: MacGetClippedRectWithOuterStructure() const
2585 {
2586 MacUpdateClippedRects() ;
2587
2588 return m_cachedClippedRectWithOuterStructure ;
2589 }
2590
2591 const wxRegion& wxWindowMac::MacGetVisibleRegion( bool includeOuterStructures )
2592 {
2593 static wxRegion emptyrgn ;
2594
2595 if ( !m_isBeingDeleted && IsShownOnScreen() )
2596 {
2597 MacUpdateClippedRects() ;
2598 if ( includeOuterStructures )
2599 return m_cachedClippedRegionWithOuterStructure ;
2600 else
2601 return m_cachedClippedRegion ;
2602 }
2603 else
2604 {
2605 return emptyrgn ;
2606 }
2607 }
2608
2609 void wxWindowMac::MacUpdateClippedRects() const
2610 {
2611 if ( m_cachedClippedRectValid )
2612 return ;
2613
2614 // includeOuterStructures is true if we try to draw somthing like a focus ring etc.
2615 // also a window dc uses this, in this case we only clip in the hierarchy for hard
2616 // borders like a scrollwindow, splitter etc otherwise we end up in a paranoia having
2617 // to add focus borders everywhere
2618
2619 Rect r, rIncludingOuterStructures ;
2620
2621 m_peer->GetRect( &r ) ;
2622 r.left -= MacGetLeftBorderSize() ;
2623 r.top -= MacGetTopBorderSize() ;
2624 r.bottom += MacGetBottomBorderSize() ;
2625 r.right += MacGetRightBorderSize() ;
2626
2627 r.right -= r.left ;
2628 r.bottom -= r.top ;
2629 r.left = 0 ;
2630 r.top = 0 ;
2631
2632 rIncludingOuterStructures = r ;
2633 InsetRect( &rIncludingOuterStructures , -4 , -4 ) ;
2634
2635 wxRect cl = GetClientRect() ;
2636 Rect rClient = { cl.y , cl.x , cl.y + cl.height , cl.x + cl.width } ;
2637
2638 int x , y ;
2639 wxSize size ;
2640 const wxWindow* child = this ;
2641 const wxWindow* parent = NULL ;
2642
2643 while ( !child->IsTopLevel() && ( parent = child->GetParent() ) != NULL )
2644 {
2645 if ( parent->MacIsChildOfClientArea(child) )
2646 {
2647 size = parent->GetClientSize() ;
2648 wxPoint origin = parent->GetClientAreaOrigin() ;
2649 x = origin.x ;
2650 y = origin.y ;
2651 }
2652 else
2653 {
2654 // this will be true for scrollbars, toolbars etc.
2655 size = parent->GetSize() ;
2656 y = parent->MacGetTopBorderSize() ;
2657 x = parent->MacGetLeftBorderSize() ;
2658 size.x -= parent->MacGetLeftBorderSize() + parent->MacGetRightBorderSize() ;
2659 size.y -= parent->MacGetTopBorderSize() + parent->MacGetBottomBorderSize() ;
2660 }
2661
2662 parent->MacWindowToRootWindow( &x, &y ) ;
2663 MacRootWindowToWindow( &x , &y ) ;
2664
2665 Rect rparent = { y , x , y + size.y , x + size.x } ;
2666
2667 // the wxwindow and client rects will always be clipped
2668 SectRect( &r , &rparent , &r ) ;
2669 SectRect( &rClient , &rparent , &rClient ) ;
2670
2671 // the structure only at 'hard' borders
2672 if ( parent->MacClipChildren() ||
2673 ( parent->GetParent() && parent->GetParent()->MacClipGrandChildren() ) )
2674 {
2675 SectRect( &rIncludingOuterStructures , &rparent , &rIncludingOuterStructures ) ;
2676 }
2677
2678 child = parent ;
2679 }
2680
2681 m_cachedClippedRect = wxRect( r.left , r.top , r.right - r.left , r.bottom - r.top ) ;
2682 m_cachedClippedClientRect = wxRect( rClient.left , rClient.top ,
2683 rClient.right - rClient.left , rClient.bottom - rClient.top ) ;
2684 m_cachedClippedRectWithOuterStructure = wxRect(
2685 rIncludingOuterStructures.left , rIncludingOuterStructures.top ,
2686 rIncludingOuterStructures.right - rIncludingOuterStructures.left ,
2687 rIncludingOuterStructures.bottom - rIncludingOuterStructures.top ) ;
2688
2689 m_cachedClippedRegionWithOuterStructure = wxRegion( m_cachedClippedRectWithOuterStructure ) ;
2690 m_cachedClippedRegion = wxRegion( m_cachedClippedRect ) ;
2691 m_cachedClippedClientRegion = wxRegion( m_cachedClippedClientRect ) ;
2692
2693 m_cachedClippedRectValid = true ;
2694 }
2695
2696 /*
2697 This function must not change the updatergn !
2698 */
2699 bool wxWindowMac::MacDoRedraw( void* updatergnr , long time )
2700 {
2701 bool handled = false ;
2702 Rect updatebounds ;
2703 RgnHandle updatergn = (RgnHandle) updatergnr ;
2704 GetRegionBounds( updatergn , &updatebounds ) ;
2705
2706 // wxLogDebug(wxT("update for %s bounds %d, %d, %d, %d"), wxString(GetClassInfo()->GetClassName()).c_str(), updatebounds.left, updatebounds.top , updatebounds.right , updatebounds.bottom ) ;
2707
2708 if ( !EmptyRgn(updatergn) )
2709 {
2710 RgnHandle newupdate = NewRgn() ;
2711 wxSize point = GetClientSize() ;
2712 wxPoint origin = GetClientAreaOrigin() ;
2713 SetRectRgn( newupdate , origin.x , origin.y , origin.x + point.x , origin.y + point.y ) ;
2714 SectRgn( newupdate , updatergn , newupdate ) ;
2715
2716 // first send an erase event to the entire update area
2717 {
2718 // for the toplevel window this really is the entire area
2719 // for all the others only their client area, otherwise they
2720 // might be drawing with full alpha and eg put blue into
2721 // the grow-box area of a scrolled window (scroll sample)
2722 wxDC* dc = new wxWindowDC(this);
2723 if ( IsTopLevel() )
2724 dc->SetClippingRegion(wxRegion(HIShapeCreateWithQDRgn(updatergn)));
2725 else
2726 dc->SetClippingRegion(wxRegion(HIShapeCreateWithQDRgn(newupdate)));
2727
2728 wxEraseEvent eevent( GetId(), dc );
2729 eevent.SetEventObject( this );
2730 HandleWindowEvent( eevent );
2731 delete dc ;
2732 }
2733
2734 MacPaintGrowBox();
2735
2736 // calculate a client-origin version of the update rgn and set m_updateRegion to that
2737 OffsetRgn( newupdate , -origin.x , -origin.y ) ;
2738 m_updateRegion = wxRegion(HIShapeCreateWithQDRgn(newupdate)) ;
2739 DisposeRgn( newupdate ) ;
2740
2741 if ( !m_updateRegion.Empty() )
2742 {
2743 // paint the window itself
2744
2745 wxPaintEvent event;
2746 event.SetTimestamp(time);
2747 event.SetEventObject(this);
2748 HandleWindowEvent(event);
2749 handled = true ;
2750 }
2751
2752 // now we cannot rely on having its borders drawn by a window itself, as it does not
2753 // get the updateRgn wide enough to always do so, so we do it from the parent
2754 // this would also be the place to draw any custom backgrounds for native controls
2755 // in Composited windowing
2756 wxPoint clientOrigin = GetClientAreaOrigin() ;
2757
2758 wxWindowMac *child;
2759 int x, y, w, h;
2760 for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext())
2761 {
2762 child = node->GetData();
2763 if (child == NULL)
2764 continue;
2765 if (child == m_vScrollBar)
2766 continue;
2767 if (child == m_hScrollBar)
2768 continue;
2769 if (child->IsTopLevel())
2770 continue;
2771 if (!child->IsShown())
2772 continue;
2773
2774 // only draw those in the update region (add a safety margin of 10 pixels for shadow effects
2775
2776 child->GetPosition( &x, &y );
2777 child->GetSize( &w, &h );
2778 Rect childRect = { y , x , y + h , x + w } ;
2779 OffsetRect( &childRect , clientOrigin.x , clientOrigin.y ) ;
2780 InsetRect( &childRect , -10 , -10) ;
2781
2782 if ( RectInRgn( &childRect , updatergn ) )
2783 {
2784 // paint custom borders
2785 wxNcPaintEvent eventNc( child->GetId() );
2786 eventNc.SetEventObject( child );
2787 if ( !child->HandleWindowEvent( eventNc ) )
2788 {
2789 child->MacPaintBorders(0, 0) ;
2790 }
2791 }
2792 }
2793 }
2794
2795 return handled ;
2796 }
2797
2798
2799 WXWindow wxWindowMac::MacGetTopLevelWindowRef() const
2800 {
2801 wxWindowMac *iter = (wxWindowMac*)this ;
2802
2803 while ( iter )
2804 {
2805 if ( iter->IsTopLevel() )
2806 {
2807 wxTopLevelWindow* toplevel = wxDynamicCast(iter,wxTopLevelWindow);
2808 if ( toplevel )
2809 return toplevel->MacGetWindowRef();
2810 #if wxUSE_POPUPWIN
2811 wxPopupWindow* popupwin = wxDynamicCast(iter,wxPopupWindow);
2812 if ( popupwin )
2813 return popupwin->MacGetPopupWindowRef();
2814 #endif
2815 }
2816 iter = iter->GetParent() ;
2817 }
2818
2819 return NULL ;
2820 }
2821
2822 bool wxWindowMac::MacHasScrollBarCorner() const
2823 {
2824 /* Returns whether the scroll bars in a wxScrolledWindow should be
2825 * shortened. Scroll bars should be shortened if either:
2826 *
2827 * - both scroll bars are visible, or
2828 *
2829 * - there is a resize box in the parent frame's corner and this
2830 * window shares the bottom and right edge with the parent
2831 * frame.
2832 */
2833
2834 if ( m_hScrollBar == NULL && m_vScrollBar == NULL )
2835 return false;
2836
2837 if ( ( m_hScrollBar && m_hScrollBar->IsShown() )
2838 && ( m_vScrollBar && m_vScrollBar->IsShown() ) )
2839 {
2840 // Both scroll bars visible
2841 return true;
2842 }
2843 else
2844 {
2845 wxPoint thisWindowBottomRight = GetScreenRect().GetBottomRight();
2846
2847 for ( const wxWindow *win = this; win; win = win->GetParent() )
2848 {
2849 const wxFrame *frame = wxDynamicCast( win, wxFrame ) ;
2850 if ( frame )
2851 {
2852 if ( frame->GetWindowStyleFlag() & wxRESIZE_BORDER )
2853 {
2854 // Parent frame has resize handle
2855 wxPoint frameBottomRight = frame->GetScreenRect().GetBottomRight();
2856
2857 // Note: allow for some wiggle room here as wxMac's
2858 // window rect calculations seem to be imprecise
2859 if ( abs( thisWindowBottomRight.x - frameBottomRight.x ) <= 2
2860 && abs( thisWindowBottomRight.y - frameBottomRight.y ) <= 2 )
2861 {
2862 // Parent frame has resize handle and shares
2863 // right bottom corner
2864 return true ;
2865 }
2866 else
2867 {
2868 // Parent frame has resize handle but doesn't
2869 // share right bottom corner
2870 return false ;
2871 }
2872 }
2873 else
2874 {
2875 // Parent frame doesn't have resize handle
2876 return false ;
2877 }
2878 }
2879 }
2880
2881 // No parent frame found
2882 return false ;
2883 }
2884 }
2885
2886 void wxWindowMac::MacCreateScrollBars( long style )
2887 {
2888 wxASSERT_MSG( m_vScrollBar == NULL && m_hScrollBar == NULL , wxT("attempt to create window twice") ) ;
2889
2890 if ( style & ( wxVSCROLL | wxHSCROLL ) )
2891 {
2892 int scrlsize = MAC_SCROLLBAR_SIZE ;
2893 if ( GetWindowVariant() == wxWINDOW_VARIANT_SMALL || GetWindowVariant() == wxWINDOW_VARIANT_MINI )
2894 {
2895 scrlsize = MAC_SMALL_SCROLLBAR_SIZE ;
2896 }
2897
2898 int adjust = MacHasScrollBarCorner() ? scrlsize - 1: 0 ;
2899 int width, height ;
2900 GetClientSize( &width , &height ) ;
2901
2902 wxPoint vPoint(width - scrlsize, 0) ;
2903 wxSize vSize(scrlsize, height - adjust) ;
2904 wxPoint hPoint(0, height - scrlsize) ;
2905 wxSize hSize(width - adjust, scrlsize) ;
2906
2907 // we have to set the min size to a smaller value, otherwise they cannot get smaller (InitialSize sets MinSize)
2908 if ( style & wxVSCROLL )
2909 {
2910 m_vScrollBar = new wxScrollBar((wxWindow*)this, wxID_ANY, vPoint, vSize , wxVERTICAL);
2911 m_vScrollBar->SetMinSize( wxDefaultSize );
2912 }
2913
2914 if ( style & wxHSCROLL )
2915 {
2916 m_hScrollBar = new wxScrollBar((wxWindow*)this, wxID_ANY, hPoint, hSize , wxHORIZONTAL);
2917 m_hScrollBar->SetMinSize( wxDefaultSize );
2918 }
2919 }
2920
2921 // because the create does not take into account the client area origin
2922 // we might have a real position shift
2923 MacRepositionScrollBars() ;
2924 }
2925
2926 bool wxWindowMac::MacIsChildOfClientArea( const wxWindow* child ) const
2927 {
2928 bool result = ((child == NULL) || ((child != m_hScrollBar) && (child != m_vScrollBar)));
2929
2930 return result ;
2931 }
2932
2933 void wxWindowMac::MacRepositionScrollBars()
2934 {
2935 if ( !m_hScrollBar && !m_vScrollBar )
2936 return ;
2937
2938 int scrlsize = m_hScrollBar ? m_hScrollBar->GetSize().y : ( m_vScrollBar ? m_vScrollBar->GetSize().x : MAC_SCROLLBAR_SIZE ) ;
2939 int adjust = MacHasScrollBarCorner() ? scrlsize - 1 : 0 ;
2940
2941 // get real client area
2942 int width, height ;
2943 GetSize( &width , &height );
2944
2945 width -= MacGetLeftBorderSize() + MacGetRightBorderSize();
2946 height -= MacGetTopBorderSize() + MacGetBottomBorderSize();
2947
2948 wxPoint vPoint( width - scrlsize, 0 ) ;
2949 wxSize vSize( scrlsize, height - adjust ) ;
2950 wxPoint hPoint( 0 , height - scrlsize ) ;
2951 wxSize hSize( width - adjust, scrlsize ) ;
2952
2953 #if 0
2954 int x = 0, y = 0, w, h ;
2955 GetSize( &w , &h ) ;
2956
2957 MacClientToRootWindow( &x , &y ) ;
2958 MacClientToRootWindow( &w , &h ) ;
2959
2960 wxWindowMac *iter = (wxWindowMac*)this ;
2961
2962 int totW = 10000 , totH = 10000;
2963 while ( iter )
2964 {
2965 if ( iter->IsTopLevel() )
2966 {
2967 iter->GetSize( &totW , &totH ) ;
2968 break ;
2969 }
2970
2971 iter = iter->GetParent() ;
2972 }
2973
2974 if ( x == 0 )
2975 {
2976 hPoint.x = -1 ;
2977 hSize.x += 1 ;
2978 }
2979 if ( y == 0 )
2980 {
2981 vPoint.y = -1 ;
2982 vSize.y += 1 ;
2983 }
2984
2985 if ( w - x >= totW )
2986 {
2987 hSize.x += 1 ;
2988 vPoint.x += 1 ;
2989 }
2990 if ( h - y >= totH )
2991 {
2992 vSize.y += 1 ;
2993 hPoint.y += 1 ;
2994 }
2995 #endif
2996
2997 if ( m_vScrollBar )
2998 m_vScrollBar->SetSize( vPoint.x , vPoint.y, vSize.x, vSize.y , wxSIZE_ALLOW_MINUS_ONE );
2999 if ( m_hScrollBar )
3000 m_hScrollBar->SetSize( hPoint.x , hPoint.y, hSize.x, hSize.y, wxSIZE_ALLOW_MINUS_ONE );
3001 }
3002
3003 bool wxWindowMac::AcceptsFocus() const
3004 {
3005 return MacCanFocus() && wxWindowBase::AcceptsFocus();
3006 }
3007
3008 void wxWindowMac::MacSuperChangedPosition()
3009 {
3010 // only window-absolute structures have to be moved i.e. controls
3011
3012 m_cachedClippedRectValid = false ;
3013
3014 wxWindowMac *child;
3015 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3016 while ( node )
3017 {
3018 child = node->GetData();
3019 child->MacSuperChangedPosition() ;
3020
3021 node = node->GetNext();
3022 }
3023 }
3024
3025 void wxWindowMac::MacTopLevelWindowChangedPosition()
3026 {
3027 // only screen-absolute structures have to be moved i.e. glcanvas
3028
3029 wxWindowMac *child;
3030 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3031 while ( node )
3032 {
3033 child = node->GetData();
3034 child->MacTopLevelWindowChangedPosition() ;
3035
3036 node = node->GetNext();
3037 }
3038 }
3039
3040 long wxWindowMac::MacGetLeftBorderSize() const
3041 {
3042 if ( IsTopLevel() )
3043 return 0 ;
3044
3045 SInt32 border = 0 ;
3046
3047 if (HasFlag(wxRAISED_BORDER) || HasFlag( wxSUNKEN_BORDER) || HasFlag(wxDOUBLE_BORDER))
3048 {
3049 // this metric is only the 'outset' outside the simple frame rect
3050 GetThemeMetric( kThemeMetricEditTextFrameOutset , &border ) ;
3051 border += 1 ;
3052 }
3053 else if (HasFlag(wxSIMPLE_BORDER))
3054 {
3055 // this metric is only the 'outset' outside the simple frame rect
3056 GetThemeMetric( kThemeMetricListBoxFrameOutset , &border ) ;
3057 border += 1 ;
3058 }
3059
3060 return border ;
3061 }
3062
3063 long wxWindowMac::MacGetRightBorderSize() const
3064 {
3065 // they are all symmetric in mac themes
3066 return MacGetLeftBorderSize() ;
3067 }
3068
3069 long wxWindowMac::MacGetTopBorderSize() const
3070 {
3071 // they are all symmetric in mac themes
3072 return MacGetLeftBorderSize() ;
3073 }
3074
3075 long wxWindowMac::MacGetBottomBorderSize() const
3076 {
3077 // they are all symmetric in mac themes
3078 return MacGetLeftBorderSize() ;
3079 }
3080
3081 long wxWindowMac::MacRemoveBordersFromStyle( long style )
3082 {
3083 return style & ~wxBORDER_MASK ;
3084 }
3085
3086 // Find the wxWindowMac at the current mouse position, returning the mouse
3087 // position.
3088 wxWindowMac * wxFindWindowAtPointer( wxPoint& pt )
3089 {
3090 pt = wxGetMousePosition();
3091 wxWindowMac* found = wxFindWindowAtPoint(pt);
3092
3093 return found;
3094 }
3095
3096 // Get the current mouse position.
3097 wxPoint wxGetMousePosition()
3098 {
3099 int x, y;
3100
3101 wxGetMousePosition( &x, &y );
3102
3103 return wxPoint(x, y);
3104 }
3105
3106 void wxWindowMac::OnMouseEvent( wxMouseEvent &event )
3107 {
3108 if ( event.GetEventType() == wxEVT_RIGHT_DOWN )
3109 {
3110 // copied from wxGTK : CS
3111 // VZ: shouldn't we move this to base class then?
3112
3113 // generate a "context menu" event: this is similar to wxEVT_RIGHT_DOWN
3114 // except that:
3115 //
3116 // (a) it's a command event and so is propagated to the parent
3117 // (b) under MSW it can be generated from kbd too
3118 // (c) it uses screen coords (because of (a))
3119 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU,
3120 this->GetId(),
3121 this->ClientToScreen(event.GetPosition()));
3122 evtCtx.SetEventObject(this);
3123 if ( ! HandleWindowEvent(evtCtx) )
3124 event.Skip() ;
3125 }
3126 else
3127 {
3128 event.Skip() ;
3129 }
3130 }
3131
3132 void wxWindowMac::OnPaint( wxPaintEvent & WXUNUSED(event) )
3133 {
3134 if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL
3135 && GetBackgroundStyle() != wxBG_STYLE_TRANSPARENT )
3136 CallNextEventHandler(
3137 (EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() ,
3138 (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
3139 }
3140
3141 void wxWindowMac::MacHandleControlClick(WXWidget WXUNUSED(control),
3142 wxInt16 WXUNUSED(controlpart),
3143 bool WXUNUSED(mouseStillDown))
3144 {
3145 }
3146
3147 Rect wxMacGetBoundsForControl( wxWindow* window , const wxPoint& pos , const wxSize &size , bool adjustForOrigin )
3148 {
3149 int x, y, w, h ;
3150
3151 window->MacGetBoundsForControl( pos , size , x , y, w, h , adjustForOrigin ) ;
3152 Rect bounds = { y, x, y + h, x + w };
3153
3154 return bounds ;
3155 }
3156
3157 wxInt32 wxWindowMac::MacControlHit(WXEVENTHANDLERREF WXUNUSED(handler) , WXEVENTREF WXUNUSED(event) )
3158 {
3159 return eventNotHandledErr ;
3160 }
3161
3162 bool wxWindowMac::Reparent(wxWindowBase *newParentBase)
3163 {
3164 wxWindowMac *newParent = (wxWindowMac *)newParentBase;
3165 if ( !wxWindowBase::Reparent(newParent) )
3166 return false;
3167
3168 // copied from MacPostControlCreate
3169 ControlRef container = (ControlRef) GetParent()->GetHandle() ;
3170
3171 wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
3172
3173 ::EmbedControl( m_peer->GetControlRef() , container ) ;
3174
3175 return true;
3176 }
3177
3178 bool wxWindowMac::SetTransparent(wxByte alpha)
3179 {
3180 SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
3181
3182 if ( alpha != m_macAlpha )
3183 {
3184 m_macAlpha = alpha ;
3185 Refresh() ;
3186 }
3187 return true ;
3188 }
3189
3190
3191 bool wxWindowMac::CanSetTransparent()
3192 {
3193 return true ;
3194 }
3195
3196 wxByte wxWindowMac::GetTransparent() const
3197 {
3198 return m_macAlpha ;
3199 }
3200
3201 bool wxWindowMac::IsShownOnScreen() const
3202 {
3203 #if TARGET_API_MAC_OSX
3204 if ( m_peer && m_peer->Ok() )
3205 {
3206 bool peerVis = m_peer->IsVisible();
3207 bool wxVis = wxWindowBase::IsShownOnScreen();
3208 if( peerVis != wxVis )
3209 {
3210 // CS : put a breakpoint here to investigate differences
3211 // between native an wx visibilities
3212 // the only place where I've encountered them until now
3213 // are the hiding/showing sequences where the vis-changed event is
3214 // first sent to the innermost control, while wx does things
3215 // from the outmost control
3216 wxVis = wxWindowBase::IsShownOnScreen();
3217 return wxVis;
3218 }
3219
3220 return m_peer->IsVisible();
3221 }
3222 #endif
3223
3224 return wxWindowBase::IsShownOnScreen();
3225 }