]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/window.cpp
fixed wxListCtrl::RefreshItem(s) - it didn't update anything before
[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 // we need a valid font for the encodings
890 wxWindowBase::SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
891 }
892
893 wxWindowMac::~wxWindowMac()
894 {
895 SendDestroyEvent();
896
897 m_isBeingDeleted = true;
898
899 MacInvalidateBorders() ;
900
901 #ifndef __WXUNIVERSAL__
902 // VS: make sure there's no wxFrame with last focus set to us:
903 for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
904 {
905 wxFrame *frame = wxDynamicCast(win, wxFrame);
906 if ( frame )
907 {
908 if ( frame->GetLastFocus() == this )
909 frame->SetLastFocus((wxWindow*)NULL);
910 break;
911 }
912 }
913 #endif
914
915 // destroy children before destroying this window itself
916 DestroyChildren();
917
918 // wxRemoveMacControlAssociation( this ) ;
919 // If we delete an item, we should initialize the parent panel,
920 // because it could now be invalid.
921 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
922 if ( tlw )
923 {
924 if ( tlw->GetDefaultItem() == (wxButton*) this)
925 tlw->SetDefaultItem(NULL);
926 }
927
928 if ( m_peer && m_peer->Ok() )
929 {
930 // in case the callback might be called during destruction
931 wxRemoveMacControlAssociation( this) ;
932 ::RemoveEventHandler( (EventHandlerRef ) m_macControlEventHandler ) ;
933 // we currently are not using this hook
934 // ::SetControlColorProc( *m_peer , NULL ) ;
935 m_peer->Dispose() ;
936 }
937
938 if ( g_MacLastWindow == this )
939 g_MacLastWindow = NULL ;
940
941 #ifndef __WXUNIVERSAL__
942 wxFrame* frame = wxDynamicCast( wxGetTopLevelParent( (wxWindow*)this ) , wxFrame ) ;
943 if ( frame )
944 {
945 if ( frame->GetLastFocus() == this )
946 frame->SetLastFocus( NULL ) ;
947 }
948 #endif
949
950 // delete our drop target if we've got one
951 #if wxUSE_DRAG_AND_DROP
952 if ( m_dropTarget != NULL )
953 {
954 delete m_dropTarget;
955 m_dropTarget = NULL;
956 }
957 #endif
958
959 delete m_peer ;
960 }
961
962 WXWidget wxWindowMac::GetHandle() const
963 {
964 return (WXWidget) m_peer->GetControlRef() ;
965 }
966
967 void wxWindowMac::MacInstallEventHandler( WXWidget control )
968 {
969 wxAssociateControlWithMacControl( (ControlRef) control , this ) ;
970 InstallControlEventHandler( (ControlRef)control , GetwxMacWindowEventHandlerUPP(),
971 GetEventTypeCount(eventList), eventList, this,
972 (EventHandlerRef *)&m_macControlEventHandler);
973 }
974
975 // Constructor
976 bool wxWindowMac::Create(wxWindowMac *parent,
977 wxWindowID id,
978 const wxPoint& pos,
979 const wxSize& size,
980 long style,
981 const wxString& name)
982 {
983 wxCHECK_MSG( parent, false, wxT("can't create wxWindowMac without parent") );
984
985 if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
986 return false;
987
988 m_windowVariant = parent->GetWindowVariant() ;
989
990 if ( m_macIsUserPane )
991 {
992 Rect bounds = wxMacGetBoundsForControl( this , pos , size ) ;
993
994 UInt32 features = 0
995 | kControlSupportsEmbedding
996 | kControlSupportsLiveFeedback
997 | kControlGetsFocusOnClick
998 // | kControlHasSpecialBackground
999 // | kControlSupportsCalcBestRect
1000 | kControlHandlesTracking
1001 | kControlSupportsFocus
1002 | kControlWantsActivate
1003 | kControlWantsIdle ;
1004
1005 m_peer = new wxMacControl(this) ;
1006 OSStatus err =::CreateUserPaneControl( MAC_WXHWND(GetParent()->MacGetTopLevelWindowRef()) , &bounds, features , m_peer->GetControlRefAddr() );
1007 verify_noerr( err );
1008
1009 MacPostControlCreate(pos, size) ;
1010 }
1011
1012 #ifndef __WXUNIVERSAL__
1013 // Don't give scrollbars to wxControls unless they ask for them
1014 if ( (! IsKindOf(CLASSINFO(wxControl)) && ! IsKindOf(CLASSINFO(wxStatusBar)))
1015 || (IsKindOf(CLASSINFO(wxControl)) && ((style & wxHSCROLL) || (style & wxVSCROLL))))
1016 {
1017 MacCreateScrollBars( style ) ;
1018 }
1019 #endif
1020
1021 wxWindowCreateEvent event(this);
1022 GetEventHandler()->AddPendingEvent(event);
1023
1024 return true;
1025 }
1026
1027 void wxWindowMac::MacChildAdded()
1028 {
1029 if ( m_vScrollBar )
1030 m_vScrollBar->Raise() ;
1031 if ( m_hScrollBar )
1032 m_hScrollBar->Raise() ;
1033 }
1034
1035 void wxWindowMac::MacPostControlCreate(const wxPoint& WXUNUSED(pos), const wxSize& size)
1036 {
1037 wxASSERT_MSG( m_peer != NULL && m_peer->Ok() , wxT("No valid mac control") ) ;
1038
1039 m_peer->SetReference( (URefCon) this ) ;
1040 GetParent()->AddChild( this );
1041
1042 MacInstallEventHandler( (WXWidget) m_peer->GetControlRef() );
1043
1044 ControlRef container = (ControlRef) GetParent()->GetHandle() ;
1045 wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
1046 ::EmbedControl( m_peer->GetControlRef() , container ) ;
1047 GetParent()->MacChildAdded() ;
1048
1049 // adjust font, controlsize etc
1050 DoSetWindowVariant( m_windowVariant ) ;
1051
1052 m_peer->SetLabel( wxStripMenuCodes(m_label, wxStrip_Mnemonics) ) ;
1053
1054 if (!m_macIsUserPane)
1055 SetInitialSize(size);
1056
1057 SetCursor( *wxSTANDARD_CURSOR ) ;
1058 }
1059
1060 void wxWindowMac::DoSetWindowVariant( wxWindowVariant variant )
1061 {
1062 // Don't assert, in case we set the window variant before
1063 // the window is created
1064 // wxASSERT( m_peer->Ok() ) ;
1065
1066 m_windowVariant = variant ;
1067
1068 if (m_peer == NULL || !m_peer->Ok())
1069 return;
1070
1071 ControlSize size ;
1072 ThemeFontID themeFont = kThemeSystemFont ;
1073
1074 // we will get that from the settings later
1075 // and make this NORMAL later, but first
1076 // we have a few calculations that we must fix
1077
1078 switch ( variant )
1079 {
1080 case wxWINDOW_VARIANT_NORMAL :
1081 size = kControlSizeNormal;
1082 themeFont = kThemeSystemFont ;
1083 break ;
1084
1085 case wxWINDOW_VARIANT_SMALL :
1086 size = kControlSizeSmall;
1087 themeFont = kThemeSmallSystemFont ;
1088 break ;
1089
1090 case wxWINDOW_VARIANT_MINI :
1091 // not always defined in the headers
1092 size = 3 ;
1093 themeFont = 109 ;
1094 break ;
1095
1096 case wxWINDOW_VARIANT_LARGE :
1097 size = kControlSizeLarge;
1098 themeFont = kThemeSystemFont ;
1099 break ;
1100
1101 default:
1102 wxFAIL_MSG(_T("unexpected window variant"));
1103 break ;
1104 }
1105
1106 m_peer->SetData<ControlSize>(kControlEntireControl, kControlSizeTag, &size ) ;
1107
1108 wxFont font ;
1109 font.MacCreateFromThemeFont( themeFont ) ;
1110 SetFont( font ) ;
1111 }
1112
1113 void wxWindowMac::MacUpdateControlFont()
1114 {
1115 m_peer->SetFont( GetFont() , GetForegroundColour() , GetWindowStyle() ) ;
1116 // do not trigger refreshes upon invisible and possible partly created objects
1117 if ( IsShownOnScreen() )
1118 Refresh() ;
1119 }
1120
1121 bool wxWindowMac::SetFont(const wxFont& font)
1122 {
1123 bool retval = wxWindowBase::SetFont( font );
1124
1125 MacUpdateControlFont() ;
1126
1127 return retval;
1128 }
1129
1130 bool wxWindowMac::SetForegroundColour(const wxColour& col )
1131 {
1132 bool retval = wxWindowBase::SetForegroundColour( col );
1133
1134 if (retval)
1135 MacUpdateControlFont();
1136
1137 return retval;
1138 }
1139
1140 bool wxWindowMac::SetBackgroundColour(const wxColour& col )
1141 {
1142 if ( !wxWindowBase::SetBackgroundColour(col) && m_hasBgCol )
1143 return false ;
1144
1145 m_peer->SetBackgroundColour( col ) ;
1146
1147 return true ;
1148 }
1149
1150 bool wxWindowMac::MacCanFocus() const
1151 {
1152 // TODO : evaluate performance hits by looking up this value, eventually cache the results for a 1 sec or so
1153 // CAUTION : the value returned currently is 0 or 2, I've also found values of 1 having the same meaning,
1154 // but the value range is nowhere documented
1155 Boolean keyExistsAndHasValidFormat ;
1156 CFIndex fullKeyboardAccess = CFPreferencesGetAppIntegerValue( CFSTR("AppleKeyboardUIMode" ) ,
1157 kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat );
1158
1159 if ( keyExistsAndHasValidFormat && fullKeyboardAccess > 0 )
1160 {
1161 return true ;
1162 }
1163 else
1164 {
1165 UInt32 features = 0 ;
1166 m_peer->GetFeatures( &features ) ;
1167
1168 return features & ( kControlSupportsFocus | kControlGetsFocusOnClick ) ;
1169 }
1170 }
1171
1172 void wxWindowMac::SetFocus()
1173 {
1174 if ( !AcceptsFocus() )
1175 return ;
1176
1177 wxWindow* former = FindFocus() ;
1178 if ( former == this )
1179 return ;
1180
1181 // as we cannot rely on the control features to find out whether we are in full keyboard mode,
1182 // we can only leave in case of an error
1183 OSStatus err = m_peer->SetFocus( kControlFocusNextPart ) ;
1184 if ( err == errCouldntSetFocus )
1185 return ;
1186
1187 SetUserFocusWindow( (WindowRef)MacGetTopLevelWindowRef() );
1188 }
1189
1190 void wxWindowMac::DoCaptureMouse()
1191 {
1192 wxApp::s_captureWindow = this ;
1193 }
1194
1195 wxWindow * wxWindowBase::GetCapture()
1196 {
1197 return wxApp::s_captureWindow ;
1198 }
1199
1200 void wxWindowMac::DoReleaseMouse()
1201 {
1202 wxApp::s_captureWindow = NULL ;
1203 }
1204
1205 #if wxUSE_DRAG_AND_DROP
1206
1207 void wxWindowMac::SetDropTarget(wxDropTarget *pDropTarget)
1208 {
1209 if ( m_dropTarget != NULL )
1210 delete m_dropTarget;
1211
1212 m_dropTarget = pDropTarget;
1213 if ( m_dropTarget != NULL )
1214 {
1215 // TODO:
1216 }
1217 }
1218
1219 #endif
1220
1221 // Old-style File Manager Drag & Drop
1222 void wxWindowMac::DragAcceptFiles(bool WXUNUSED(accept))
1223 {
1224 // TODO:
1225 }
1226
1227 // Returns the size of the native control. In the case of the toplevel window
1228 // this is the content area root control
1229
1230 void wxWindowMac::MacGetPositionAndSizeFromControl(int& WXUNUSED(x),
1231 int& WXUNUSED(y),
1232 int& WXUNUSED(w),
1233 int& WXUNUSED(h)) const
1234 {
1235 wxFAIL_MSG( wxT("Not currently supported") ) ;
1236 }
1237
1238 // From a wx position / size calculate the appropriate size of the native control
1239
1240 bool wxWindowMac::MacGetBoundsForControl(
1241 const wxPoint& pos,
1242 const wxSize& size,
1243 int& x, int& y,
1244 int& w, int& h , bool adjustOrigin ) const
1245 {
1246 // the desired size, minus the border pixels gives the correct size of the control
1247 x = (int)pos.x;
1248 y = (int)pos.y;
1249
1250 // TODO: the default calls may be used as soon as PostCreateControl Is moved here
1251 w = wxMax(size.x, 0) ; // WidthDefault( size.x );
1252 h = wxMax(size.y, 0) ; // HeightDefault( size.y ) ;
1253
1254 x += MacGetLeftBorderSize() ;
1255 y += MacGetTopBorderSize() ;
1256 w -= MacGetLeftBorderSize() + MacGetRightBorderSize() ;
1257 h -= MacGetTopBorderSize() + MacGetBottomBorderSize() ;
1258
1259 if ( adjustOrigin )
1260 AdjustForParentClientOrigin( x , y ) ;
1261
1262 // this is in window relative coordinate, as this parent may have a border, its physical position is offset by this border
1263 if ( !GetParent()->IsTopLevel() )
1264 {
1265 x -= GetParent()->MacGetLeftBorderSize() ;
1266 y -= GetParent()->MacGetTopBorderSize() ;
1267 }
1268
1269 return true ;
1270 }
1271
1272 // Get window size (not client size)
1273 void wxWindowMac::DoGetSize(int *x, int *y) const
1274 {
1275 Rect bounds ;
1276 m_peer->GetRect( &bounds ) ;
1277
1278 if (x)
1279 *x = bounds.right - bounds.left + MacGetLeftBorderSize() + MacGetRightBorderSize() ;
1280 if (y)
1281 *y = bounds.bottom - bounds.top + MacGetTopBorderSize() + MacGetBottomBorderSize() ;
1282 }
1283
1284 // get the position of the bounds of this window in client coordinates of its parent
1285 void wxWindowMac::DoGetPosition(int *x, int *y) const
1286 {
1287 Rect bounds ;
1288 m_peer->GetRect( &bounds ) ;
1289
1290 int x1 = bounds.left ;
1291 int y1 = bounds.top ;
1292
1293 // get the wx window position from the native one
1294 x1 -= MacGetLeftBorderSize() ;
1295 y1 -= MacGetTopBorderSize() ;
1296
1297 if ( !IsTopLevel() )
1298 {
1299 wxWindow *parent = GetParent();
1300 if ( parent )
1301 {
1302 // we must first adjust it to be in window coordinates of the parent,
1303 // as otherwise it gets lost by the ClientAreaOrigin fix
1304 x1 += parent->MacGetLeftBorderSize() ;
1305 y1 += parent->MacGetTopBorderSize() ;
1306
1307 // and now to client coordinates
1308 wxPoint pt(parent->GetClientAreaOrigin());
1309 x1 -= pt.x ;
1310 y1 -= pt.y ;
1311 }
1312 }
1313
1314 if (x)
1315 *x = x1 ;
1316 if (y)
1317 *y = y1 ;
1318 }
1319
1320 void wxWindowMac::DoScreenToClient(int *x, int *y) const
1321 {
1322 WindowRef window = (WindowRef) MacGetTopLevelWindowRef() ;
1323 wxCHECK_RET( window , wxT("TopLevel Window missing") ) ;
1324
1325 Point localwhere = { 0, 0 } ;
1326
1327 if (x)
1328 localwhere.h = *x ;
1329 if (y)
1330 localwhere.v = *y ;
1331
1332 wxMacGlobalToLocal( window , &localwhere ) ;
1333
1334 if (x)
1335 *x = localwhere.h ;
1336 if (y)
1337 *y = localwhere.v ;
1338
1339 MacRootWindowToWindow( x , y ) ;
1340
1341 wxPoint origin = GetClientAreaOrigin() ;
1342 if (x)
1343 *x -= origin.x ;
1344 if (y)
1345 *y -= origin.y ;
1346 }
1347
1348 void wxWindowMac::DoClientToScreen(int *x, int *y) const
1349 {
1350 WindowRef window = (WindowRef) MacGetTopLevelWindowRef() ;
1351 wxCHECK_RET( window , wxT("TopLevel window missing") ) ;
1352
1353 wxPoint origin = GetClientAreaOrigin() ;
1354 if (x)
1355 *x += origin.x ;
1356 if (y)
1357 *y += origin.y ;
1358
1359 MacWindowToRootWindow( x , y ) ;
1360
1361 Point localwhere = { 0, 0 };
1362 if (x)
1363 localwhere.h = *x ;
1364 if (y)
1365 localwhere.v = *y ;
1366
1367 wxMacLocalToGlobal( window, &localwhere ) ;
1368
1369 if (x)
1370 *x = localwhere.h ;
1371 if (y)
1372 *y = localwhere.v ;
1373 }
1374
1375 void wxWindowMac::MacClientToRootWindow( int *x , int *y ) const
1376 {
1377 wxPoint origin = GetClientAreaOrigin() ;
1378 if (x)
1379 *x += origin.x ;
1380 if (y)
1381 *y += origin.y ;
1382
1383 MacWindowToRootWindow( x , y ) ;
1384 }
1385
1386 void wxWindowMac::MacRootWindowToClient( int *x , int *y ) const
1387 {
1388 MacRootWindowToWindow( x , y ) ;
1389
1390 wxPoint origin = GetClientAreaOrigin() ;
1391 if (x)
1392 *x -= origin.x ;
1393 if (y)
1394 *y -= origin.y ;
1395 }
1396
1397 void wxWindowMac::MacWindowToRootWindow( int *x , int *y ) const
1398 {
1399 wxPoint pt ;
1400
1401 if (x)
1402 pt.x = *x ;
1403 if (y)
1404 pt.y = *y ;
1405
1406 if ( !IsTopLevel() )
1407 {
1408 wxTopLevelWindowMac* top = MacGetTopLevelWindow();
1409 if (top)
1410 {
1411 pt.x -= MacGetLeftBorderSize() ;
1412 pt.y -= MacGetTopBorderSize() ;
1413 wxMacControl::Convert( &pt , m_peer , top->m_peer ) ;
1414 }
1415 }
1416
1417 if (x)
1418 *x = (int) pt.x ;
1419 if (y)
1420 *y = (int) pt.y ;
1421 }
1422
1423 void wxWindowMac::MacWindowToRootWindow( short *x , short *y ) const
1424 {
1425 int x1 , y1 ;
1426
1427 if (x)
1428 x1 = *x ;
1429 if (y)
1430 y1 = *y ;
1431
1432 MacWindowToRootWindow( &x1 , &y1 ) ;
1433
1434 if (x)
1435 *x = x1 ;
1436 if (y)
1437 *y = y1 ;
1438 }
1439
1440 void wxWindowMac::MacRootWindowToWindow( int *x , int *y ) const
1441 {
1442 wxPoint pt ;
1443
1444 if (x)
1445 pt.x = *x ;
1446 if (y)
1447 pt.y = *y ;
1448
1449 if ( !IsTopLevel() )
1450 {
1451 wxTopLevelWindowMac* top = MacGetTopLevelWindow();
1452 if (top)
1453 {
1454 wxMacControl::Convert( &pt , top->m_peer , m_peer ) ;
1455 pt.x += MacGetLeftBorderSize() ;
1456 pt.y += MacGetTopBorderSize() ;
1457 }
1458 }
1459
1460 if (x)
1461 *x = (int) pt.x ;
1462 if (y)
1463 *y = (int) pt.y ;
1464 }
1465
1466 void wxWindowMac::MacRootWindowToWindow( short *x , short *y ) const
1467 {
1468 int x1 , y1 ;
1469
1470 if (x)
1471 x1 = *x ;
1472 if (y)
1473 y1 = *y ;
1474
1475 MacRootWindowToWindow( &x1 , &y1 ) ;
1476
1477 if (x)
1478 *x = x1 ;
1479 if (y)
1480 *y = y1 ;
1481 }
1482
1483 void wxWindowMac::MacGetContentAreaInset( int &left , int &top , int &right , int &bottom )
1484 {
1485 RgnHandle rgn = NewRgn() ;
1486
1487 if ( m_peer->GetRegion( kControlContentMetaPart , rgn ) == noErr )
1488 {
1489 Rect structure, content ;
1490
1491 GetRegionBounds( rgn , &content ) ;
1492 m_peer->GetRect( &structure ) ;
1493 OffsetRect( &structure, -structure.left , -structure.top ) ;
1494
1495 left = content.left - structure.left ;
1496 top = content.top - structure.top ;
1497 right = structure.right - content.right ;
1498 bottom = structure.bottom - content.bottom ;
1499 }
1500 else
1501 {
1502 left = top = right = bottom = 0 ;
1503 }
1504
1505 DisposeRgn( rgn ) ;
1506 }
1507
1508 wxSize wxWindowMac::DoGetSizeFromClientSize( const wxSize & size ) const
1509 {
1510 wxSize sizeTotal = size;
1511
1512 RgnHandle rgn = NewRgn() ;
1513 if ( m_peer->GetRegion( kControlContentMetaPart , rgn ) == noErr )
1514 {
1515 Rect content, structure ;
1516 GetRegionBounds( rgn , &content ) ;
1517 m_peer->GetRect( &structure ) ;
1518
1519 // structure is in parent coordinates, but we only need width and height, so it's ok
1520
1521 sizeTotal.x += (structure.right - structure.left) - (content.right - content.left) ;
1522 sizeTotal.y += (structure.bottom - structure.top) - (content.bottom - content.top) ;
1523 }
1524
1525 DisposeRgn( rgn ) ;
1526
1527 sizeTotal.x += MacGetLeftBorderSize() + MacGetRightBorderSize() ;
1528 sizeTotal.y += MacGetTopBorderSize() + MacGetBottomBorderSize() ;
1529
1530 return sizeTotal;
1531 }
1532
1533 // Get size *available for subwindows* i.e. excluding menu bar etc.
1534 void wxWindowMac::DoGetClientSize( int *x, int *y ) const
1535 {
1536 int ww, hh;
1537
1538 RgnHandle rgn = NewRgn() ;
1539 Rect content ;
1540 if ( m_peer->GetRegion( kControlContentMetaPart , rgn ) == noErr )
1541 GetRegionBounds( rgn , &content ) ;
1542 else
1543 m_peer->GetRect( &content ) ;
1544 DisposeRgn( rgn ) ;
1545
1546 ww = content.right - content.left ;
1547 hh = content.bottom - content.top ;
1548
1549 if (m_hScrollBar && m_hScrollBar->IsShown() )
1550 hh -= m_hScrollBar->GetSize().y ;
1551
1552 if (m_vScrollBar && m_vScrollBar->IsShown() )
1553 ww -= m_vScrollBar->GetSize().x ;
1554
1555 if (x)
1556 *x = ww;
1557 if (y)
1558 *y = hh;
1559 }
1560
1561 bool wxWindowMac::SetCursor(const wxCursor& cursor)
1562 {
1563 if (m_cursor.IsSameAs(cursor))
1564 return false;
1565
1566 if (!cursor.IsOk())
1567 {
1568 if ( ! wxWindowBase::SetCursor( *wxSTANDARD_CURSOR ) )
1569 return false ;
1570 }
1571 else
1572 {
1573 if ( ! wxWindowBase::SetCursor( cursor ) )
1574 return false ;
1575 }
1576
1577 wxASSERT_MSG( m_cursor.Ok(),
1578 wxT("cursor must be valid after call to the base version"));
1579
1580 wxWindowMac *mouseWin = 0 ;
1581 {
1582 wxTopLevelWindowMac *tlw = MacGetTopLevelWindow() ;
1583 WindowRef window = (WindowRef) ( tlw ? tlw->MacGetWindowRef() : 0 ) ;
1584
1585 ControlPartCode part ;
1586 ControlRef control ;
1587 Point pt ;
1588 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
1589 HIPoint hiPoint ;
1590 HIGetMousePosition(kHICoordSpaceWindow, window, &hiPoint);
1591 pt.h = hiPoint.x;
1592 pt.v = hiPoint.y;
1593 #else
1594 GetGlobalMouse( &pt );
1595 int x = pt.h;
1596 int y = pt.v;
1597 ScreenToClient(&x, &y);
1598 pt.h = x;
1599 pt.v = y;
1600 #endif
1601 control = FindControlUnderMouse( pt , window , &part ) ;
1602 if ( control )
1603 mouseWin = wxFindControlFromMacControl( control ) ;
1604
1605 }
1606
1607 if ( mouseWin == this && !wxIsBusy() )
1608 m_cursor.MacInstall() ;
1609
1610 return true ;
1611 }
1612
1613 #if wxUSE_MENUS
1614 bool wxWindowMac::DoPopupMenu(wxMenu *menu, int x, int y)
1615 {
1616 #ifndef __WXUNIVERSAL__
1617 menu->SetInvokingWindow((wxWindow*)this);
1618 menu->UpdateUI();
1619
1620 if ( x == wxDefaultCoord && y == wxDefaultCoord )
1621 {
1622 wxPoint mouse = wxGetMousePosition();
1623 x = mouse.x;
1624 y = mouse.y;
1625 }
1626 else
1627 {
1628 ClientToScreen( &x , &y ) ;
1629 }
1630
1631 menu->MacBeforeDisplay( true ) ;
1632 long menuResult = ::PopUpMenuSelect((MenuHandle) menu->GetHMenu() , y, x, 0) ;
1633 if ( HiWord(menuResult) != 0 )
1634 {
1635 MenuCommand macid;
1636 GetMenuItemCommandID( GetMenuHandle(HiWord(menuResult)) , LoWord(menuResult) , &macid );
1637 int id = wxMacCommandToId( macid );
1638 wxMenuItem* item = NULL ;
1639 wxMenu* realmenu ;
1640 item = menu->FindItem( id, &realmenu ) ;
1641 if ( item )
1642 {
1643 if (item->IsCheckable())
1644 item->Check( !item->IsChecked() ) ;
1645
1646 menu->SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) ;
1647 }
1648 }
1649
1650 menu->MacAfterDisplay( true ) ;
1651 menu->SetInvokingWindow( NULL );
1652
1653 return true;
1654 #else
1655 // actually this shouldn't be called, because universal is having its own implementation
1656 return false;
1657 #endif
1658 }
1659 #endif
1660
1661 // ----------------------------------------------------------------------------
1662 // tooltips
1663 // ----------------------------------------------------------------------------
1664
1665 #if wxUSE_TOOLTIPS
1666
1667 void wxWindowMac::DoSetToolTip(wxToolTip *tooltip)
1668 {
1669 wxWindowBase::DoSetToolTip(tooltip);
1670
1671 if ( m_tooltip )
1672 m_tooltip->SetWindow(this);
1673 }
1674
1675 #endif
1676
1677 void wxWindowMac::MacInvalidateBorders()
1678 {
1679 if ( m_peer == NULL )
1680 return ;
1681
1682 bool vis = IsShownOnScreen() ;
1683 if ( !vis )
1684 return ;
1685
1686 int outerBorder = MacGetLeftBorderSize() ;
1687 if ( m_peer->NeedsFocusRect() /* && m_peer->HasFocus() */ )
1688 outerBorder += 4 ;
1689
1690 if ( outerBorder == 0 )
1691 return ;
1692
1693 // now we know that we have something to do at all
1694
1695 // as the borders are drawn on the parent we have to properly invalidate all these areas
1696 RgnHandle updateInner , updateOuter;
1697 Rect rect ;
1698
1699 // this rectangle is in HIViewCoordinates under OSX and in Window Coordinates under Carbon
1700 updateInner = NewRgn() ;
1701 updateOuter = NewRgn() ;
1702
1703 m_peer->GetRect( &rect ) ;
1704 RectRgn( updateInner, &rect ) ;
1705 InsetRect( &rect , -outerBorder , -outerBorder ) ;
1706 RectRgn( updateOuter, &rect ) ;
1707 DiffRgn( updateOuter, updateInner , updateOuter ) ;
1708
1709 GetParent()->m_peer->SetNeedsDisplay( updateOuter ) ;
1710
1711 DisposeRgn( updateOuter ) ;
1712 DisposeRgn( updateInner ) ;
1713 }
1714
1715 void wxWindowMac::DoMoveWindow(int x, int y, int width, int height)
1716 {
1717 // this is never called for a toplevel window, so we know we have a parent
1718 int former_x , former_y , former_w, former_h ;
1719
1720 // Get true coordinates of former position
1721 DoGetPosition( &former_x , &former_y ) ;
1722 DoGetSize( &former_w , &former_h ) ;
1723
1724 wxWindow *parent = GetParent();
1725 if ( parent )
1726 {
1727 wxPoint pt(parent->GetClientAreaOrigin());
1728 former_x += pt.x ;
1729 former_y += pt.y ;
1730 }
1731
1732 int actualWidth = width ;
1733 int actualHeight = height ;
1734 int actualX = x;
1735 int actualY = y;
1736
1737 if ((m_minWidth != -1) && (actualWidth < m_minWidth))
1738 actualWidth = m_minWidth;
1739 if ((m_minHeight != -1) && (actualHeight < m_minHeight))
1740 actualHeight = m_minHeight;
1741 if ((m_maxWidth != -1) && (actualWidth > m_maxWidth))
1742 actualWidth = m_maxWidth;
1743 if ((m_maxHeight != -1) && (actualHeight > m_maxHeight))
1744 actualHeight = m_maxHeight;
1745
1746 bool doMove = false, doResize = false ;
1747
1748 if ( actualX != former_x || actualY != former_y )
1749 doMove = true ;
1750
1751 if ( actualWidth != former_w || actualHeight != former_h )
1752 doResize = true ;
1753
1754 if ( doMove || doResize )
1755 {
1756 // as the borders are drawn outside the native control, we adjust now
1757
1758 wxRect bounds( wxPoint( actualX + MacGetLeftBorderSize() ,actualY + MacGetTopBorderSize() ),
1759 wxSize( actualWidth - (MacGetLeftBorderSize() + MacGetRightBorderSize()) ,
1760 actualHeight - (MacGetTopBorderSize() + MacGetBottomBorderSize()) ) ) ;
1761
1762 Rect r ;
1763 wxMacRectToNative( &bounds , &r ) ;
1764
1765 if ( !GetParent()->IsTopLevel() )
1766 wxMacWindowToNative( GetParent() , &r ) ;
1767
1768 MacInvalidateBorders() ;
1769
1770 m_cachedClippedRectValid = false ;
1771 m_peer->SetRect( &r ) ;
1772
1773 wxWindowMac::MacSuperChangedPosition() ; // like this only children will be notified
1774
1775 MacInvalidateBorders() ;
1776
1777 MacRepositionScrollBars() ;
1778 if ( doMove )
1779 {
1780 wxPoint point(actualX, actualY);
1781 wxMoveEvent event(point, m_windowId);
1782 event.SetEventObject(this);
1783 HandleWindowEvent(event) ;
1784 }
1785
1786 if ( doResize )
1787 {
1788 MacRepositionScrollBars() ;
1789 wxSize size(actualWidth, actualHeight);
1790 wxSizeEvent event(size, m_windowId);
1791 event.SetEventObject(this);
1792 HandleWindowEvent(event);
1793 }
1794 }
1795 }
1796
1797 wxSize wxWindowMac::DoGetBestSize() const
1798 {
1799 if ( m_macIsUserPane || IsTopLevel() )
1800 return wxWindowBase::DoGetBestSize() ;
1801
1802 Rect bestsize = { 0 , 0 , 0 , 0 } ;
1803 int bestWidth, bestHeight ;
1804
1805 m_peer->GetBestRect( &bestsize ) ;
1806 if ( EmptyRect( &bestsize ) )
1807 {
1808 bestsize.left =
1809 bestsize.top = 0 ;
1810 bestsize.right =
1811 bestsize.bottom = 16 ;
1812
1813 if ( IsKindOf( CLASSINFO( wxScrollBar ) ) )
1814 {
1815 bestsize.bottom = 16 ;
1816 }
1817 #if wxUSE_SPINBTN
1818 else if ( IsKindOf( CLASSINFO( wxSpinButton ) ) )
1819 {
1820 bestsize.bottom = 24 ;
1821 }
1822 #endif
1823 else
1824 {
1825 // return wxWindowBase::DoGetBestSize() ;
1826 }
1827 }
1828
1829 bestWidth = bestsize.right - bestsize.left ;
1830 bestHeight = bestsize.bottom - bestsize.top ;
1831 if ( bestHeight < 10 )
1832 bestHeight = 13 ;
1833
1834 return wxSize(bestWidth, bestHeight);
1835 }
1836
1837 // set the size of the window: if the dimensions are positive, just use them,
1838 // but if any of them is equal to -1, it means that we must find the value for
1839 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
1840 // which case -1 is a valid value for x and y)
1841 //
1842 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
1843 // the width/height to best suit our contents, otherwise we reuse the current
1844 // width/height
1845 void wxWindowMac::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1846 {
1847 // get the current size and position...
1848 int currentX, currentY;
1849 int currentW, currentH;
1850
1851 GetPosition(&currentX, &currentY);
1852 GetSize(&currentW, &currentH);
1853
1854 // ... and don't do anything (avoiding flicker) if it's already ok
1855 if ( x == currentX && y == currentY &&
1856 width == currentW && height == currentH && ( height != -1 && width != -1 ) )
1857 {
1858 // TODO: REMOVE
1859 MacRepositionScrollBars() ; // we might have a real position shift
1860
1861 return;
1862 }
1863
1864 if ( !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
1865 {
1866 if ( x == wxDefaultCoord )
1867 x = currentX;
1868 if ( y == wxDefaultCoord )
1869 y = currentY;
1870 }
1871
1872 AdjustForParentClientOrigin( x, y, sizeFlags );
1873
1874 wxSize size = wxDefaultSize;
1875 if ( width == wxDefaultCoord )
1876 {
1877 if ( sizeFlags & wxSIZE_AUTO_WIDTH )
1878 {
1879 size = DoGetBestSize();
1880 width = size.x;
1881 }
1882 else
1883 {
1884 // just take the current one
1885 width = currentW;
1886 }
1887 }
1888
1889 if ( height == wxDefaultCoord )
1890 {
1891 if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
1892 {
1893 if ( size.x == wxDefaultCoord )
1894 size = DoGetBestSize();
1895 // else: already called DoGetBestSize() above
1896
1897 height = size.y;
1898 }
1899 else
1900 {
1901 // just take the current one
1902 height = currentH;
1903 }
1904 }
1905
1906 DoMoveWindow( x, y, width, height );
1907 }
1908
1909 wxPoint wxWindowMac::GetClientAreaOrigin() const
1910 {
1911 RgnHandle rgn = NewRgn() ;
1912 Rect content ;
1913 if ( m_peer->GetRegion( kControlContentMetaPart , rgn ) == noErr )
1914 {
1915 GetRegionBounds( rgn , &content ) ;
1916 }
1917 else
1918 {
1919 content.left =
1920 content.top = 0 ;
1921 }
1922
1923 DisposeRgn( rgn ) ;
1924
1925 return wxPoint( content.left + MacGetLeftBorderSize() , content.top + MacGetTopBorderSize() );
1926 }
1927
1928 void wxWindowMac::DoSetClientSize(int clientwidth, int clientheight)
1929 {
1930 if ( clientwidth != wxDefaultCoord || clientheight != wxDefaultCoord )
1931 {
1932 int currentclientwidth , currentclientheight ;
1933 int currentwidth , currentheight ;
1934
1935 GetClientSize( &currentclientwidth , &currentclientheight ) ;
1936 GetSize( &currentwidth , &currentheight ) ;
1937
1938 DoSetSize( wxDefaultCoord , wxDefaultCoord , currentwidth + clientwidth - currentclientwidth ,
1939 currentheight + clientheight - currentclientheight , wxSIZE_USE_EXISTING ) ;
1940 }
1941 }
1942
1943 void wxWindowMac::SetLabel(const wxString& title)
1944 {
1945 m_label = title ;
1946
1947 if ( m_peer && m_peer->Ok() )
1948 m_peer->SetLabel( wxStripMenuCodes(m_label, wxStrip_Mnemonics) ) ;
1949
1950 // do not trigger refreshes upon invisible and possible partly created objects
1951 if ( IsShownOnScreen() )
1952 Refresh() ;
1953 }
1954
1955 wxString wxWindowMac::GetLabel() const
1956 {
1957 return m_label ;
1958 }
1959
1960 bool wxWindowMac::Show(bool show)
1961 {
1962 if ( !wxWindowBase::Show(show) )
1963 return false;
1964
1965 if ( m_peer )
1966 m_peer->SetVisibility( show , true ) ;
1967
1968 return true;
1969 }
1970
1971 void wxWindowMac::DoEnable(bool enable)
1972 {
1973 m_peer->Enable( enable ) ;
1974 }
1975
1976 //
1977 // status change notifications
1978 //
1979
1980 void wxWindowMac::MacVisibilityChanged()
1981 {
1982 }
1983
1984 void wxWindowMac::MacHiliteChanged()
1985 {
1986 }
1987
1988 void wxWindowMac::MacEnabledStateChanged()
1989 {
1990 OnEnabled( m_peer->IsEnabled() );
1991 }
1992
1993 //
1994 // status queries on the inherited window's state
1995 //
1996
1997 bool wxWindowMac::MacIsReallyEnabled()
1998 {
1999 return m_peer->IsEnabled() ;
2000 }
2001
2002 bool wxWindowMac::MacIsReallyHilited()
2003 {
2004 return m_peer->IsActive();
2005 }
2006
2007 void wxWindowMac::MacFlashInvalidAreas()
2008 {
2009 #if TARGET_API_MAC_OSX
2010 HIViewFlashDirtyArea( (WindowRef) MacGetTopLevelWindowRef() ) ;
2011 #endif
2012 }
2013
2014 int wxWindowMac::GetCharHeight() const
2015 {
2016 wxClientDC dc( (wxWindowMac*)this ) ;
2017
2018 return dc.GetCharHeight() ;
2019 }
2020
2021 int wxWindowMac::GetCharWidth() const
2022 {
2023 wxClientDC dc( (wxWindowMac*)this ) ;
2024
2025 return dc.GetCharWidth() ;
2026 }
2027
2028 void wxWindowMac::GetTextExtent(const wxString& string, int *x, int *y,
2029 int *descent, int *externalLeading, const wxFont *theFont ) const
2030 {
2031 const wxFont *fontToUse = theFont;
2032 if ( !fontToUse )
2033 fontToUse = &m_font;
2034
2035 wxClientDC dc( (wxWindowMac*) this ) ;
2036 wxCoord lx,ly,ld,le ;
2037 dc.GetTextExtent( string , &lx , &ly , &ld, &le, (wxFont *)fontToUse ) ;
2038 if ( externalLeading )
2039 *externalLeading = le ;
2040 if ( descent )
2041 *descent = ld ;
2042 if ( x )
2043 *x = lx ;
2044 if ( y )
2045 *y = ly ;
2046 }
2047
2048 /*
2049 * Rect is given in client coordinates, for further reading, read wxTopLevelWindowMac::InvalidateRect
2050 * we always intersect with the entire window, not only with the client area
2051 */
2052
2053 void wxWindowMac::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
2054 {
2055 if ( m_peer == NULL )
2056 return ;
2057
2058 if ( !IsShownOnScreen() )
2059 return ;
2060
2061 if ( rect )
2062 {
2063 Rect r ;
2064
2065 wxMacRectToNative( rect , &r ) ;
2066 m_peer->SetNeedsDisplay( &r ) ;
2067 }
2068 else
2069 {
2070 m_peer->SetNeedsDisplay() ;
2071 }
2072 }
2073
2074 void wxWindowMac::DoFreeze()
2075 {
2076 #if TARGET_API_MAC_OSX
2077 if ( m_peer && m_peer->Ok() )
2078 m_peer->SetDrawingEnabled( false ) ;
2079 #endif
2080 }
2081
2082 void wxWindowMac::DoThaw()
2083 {
2084 #if TARGET_API_MAC_OSX
2085 if ( m_peer && m_peer->Ok() )
2086 {
2087 m_peer->SetDrawingEnabled( true ) ;
2088 m_peer->InvalidateWithChildren() ;
2089 }
2090 #endif
2091 }
2092
2093 wxWindowMac *wxGetActiveWindow()
2094 {
2095 // actually this is a windows-only concept
2096 return NULL;
2097 }
2098
2099 // Coordinates relative to the window
2100 void wxWindowMac::WarpPointer(int WXUNUSED(x_pos), int WXUNUSED(y_pos))
2101 {
2102 // We really don't move the mouse programmatically under Mac.
2103 }
2104
2105 void wxWindowMac::OnEraseBackground(wxEraseEvent& event)
2106 {
2107 if ( MacGetTopLevelWindow() == NULL )
2108 return ;
2109 /*
2110 #if TARGET_API_MAC_OSX
2111 if ( !m_backgroundColour.Ok() || GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT )
2112 {
2113 }
2114 else
2115 #endif
2116 */
2117 if ( GetBackgroundStyle() == wxBG_STYLE_COLOUR )
2118 {
2119 event.GetDC()->Clear() ;
2120 }
2121 else
2122 {
2123 event.Skip() ;
2124 }
2125 }
2126
2127 void wxWindowMac::OnNcPaint( wxNcPaintEvent& event )
2128 {
2129 event.Skip() ;
2130 }
2131
2132 int wxWindowMac::GetScrollPos(int orient) const
2133 {
2134 if ( orient == wxHORIZONTAL )
2135 {
2136 if ( m_hScrollBar )
2137 return m_hScrollBar->GetThumbPosition() ;
2138 }
2139 else
2140 {
2141 if ( m_vScrollBar )
2142 return m_vScrollBar->GetThumbPosition() ;
2143 }
2144
2145 return 0;
2146 }
2147
2148 // This now returns the whole range, not just the number
2149 // of positions that we can scroll.
2150 int wxWindowMac::GetScrollRange(int orient) const
2151 {
2152 if ( orient == wxHORIZONTAL )
2153 {
2154 if ( m_hScrollBar )
2155 return m_hScrollBar->GetRange() ;
2156 }
2157 else
2158 {
2159 if ( m_vScrollBar )
2160 return m_vScrollBar->GetRange() ;
2161 }
2162
2163 return 0;
2164 }
2165
2166 int wxWindowMac::GetScrollThumb(int orient) const
2167 {
2168 if ( orient == wxHORIZONTAL )
2169 {
2170 if ( m_hScrollBar )
2171 return m_hScrollBar->GetThumbSize() ;
2172 }
2173 else
2174 {
2175 if ( m_vScrollBar )
2176 return m_vScrollBar->GetThumbSize() ;
2177 }
2178
2179 return 0;
2180 }
2181
2182 void wxWindowMac::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
2183 {
2184 if ( orient == wxHORIZONTAL )
2185 {
2186 if ( m_hScrollBar )
2187 m_hScrollBar->SetThumbPosition( pos ) ;
2188 }
2189 else
2190 {
2191 if ( m_vScrollBar )
2192 m_vScrollBar->SetThumbPosition( pos ) ;
2193 }
2194 }
2195
2196 void
2197 wxWindowMac::AlwaysShowScrollbars(bool hflag, bool vflag)
2198 {
2199 bool needVisibilityUpdate = false;
2200
2201 if ( m_hScrollBarAlwaysShown != hflag )
2202 {
2203 m_hScrollBarAlwaysShown = hflag;
2204 needVisibilityUpdate = true;
2205 }
2206
2207 if ( m_vScrollBarAlwaysShown != vflag )
2208 {
2209 m_vScrollBarAlwaysShown = vflag;
2210 needVisibilityUpdate = true;
2211 }
2212
2213 if ( needVisibilityUpdate )
2214 DoUpdateScrollbarVisibility();
2215 }
2216
2217 //
2218 // we draw borders and grow boxes, are already set up and clipped in the current port / cgContextRef
2219 // our own window origin is at leftOrigin/rightOrigin
2220 //
2221
2222 void wxWindowMac::MacPaintGrowBox()
2223 {
2224 if ( IsTopLevel() )
2225 return ;
2226
2227 if ( MacHasScrollBarCorner() )
2228 {
2229 Rect rect ;
2230
2231 CGContextRef cgContext = (CGContextRef) MacGetCGContextRef() ;
2232 wxASSERT( cgContext ) ;
2233
2234 m_peer->GetRect( &rect ) ;
2235
2236 int size = m_hScrollBar ? m_hScrollBar->GetSize().y : ( m_vScrollBar ? m_vScrollBar->GetSize().x : MAC_SCROLLBAR_SIZE ) ;
2237 CGRect cgrect = CGRectMake( rect.right - size , rect.bottom - size , size , size ) ;
2238 CGPoint cgpoint = CGPointMake( rect.right - size , rect.bottom - size ) ;
2239 CGContextSaveGState( cgContext );
2240
2241 if ( m_backgroundColour.Ok() )
2242 {
2243 CGContextSetFillColorWithColor( cgContext, m_backgroundColour.GetCGColor() );
2244 }
2245 else
2246 {
2247 CGContextSetRGBFillColor( cgContext, 1.0, 1.0 , 1.0 , 1.0 );
2248 }
2249 CGContextFillRect( cgContext, cgrect );
2250 CGContextRestoreGState( cgContext );
2251 }
2252 }
2253
2254 void wxWindowMac::MacPaintBorders( int WXUNUSED(leftOrigin) , int WXUNUSED(rightOrigin) )
2255 {
2256 if ( IsTopLevel() )
2257 return ;
2258
2259 Rect rect ;
2260 bool hasFocus = m_peer->NeedsFocusRect() && m_peer->HasFocus() ;
2261
2262 // back to the surrounding frame rectangle
2263 m_peer->GetRect( &rect ) ;
2264 InsetRect( &rect, -1 , -1 ) ;
2265
2266 {
2267 CGRect cgrect = CGRectMake( rect.left , rect.top , rect.right - rect.left ,
2268 rect.bottom - rect.top ) ;
2269
2270 HIThemeFrameDrawInfo info ;
2271 memset( &info, 0 , sizeof(info) ) ;
2272
2273 info.version = 0 ;
2274 info.kind = 0 ;
2275 info.state = IsEnabled() ? kThemeStateActive : kThemeStateInactive ;
2276 info.isFocused = hasFocus ;
2277
2278 CGContextRef cgContext = (CGContextRef) GetParent()->MacGetCGContextRef() ;
2279 wxASSERT( cgContext ) ;
2280
2281 if ( HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER) || HasFlag(wxDOUBLE_BORDER) )
2282 {
2283 info.kind = kHIThemeFrameTextFieldSquare ;
2284 HIThemeDrawFrame( &cgrect , &info , cgContext , kHIThemeOrientationNormal ) ;
2285 }
2286 else if ( HasFlag(wxSIMPLE_BORDER) )
2287 {
2288 info.kind = kHIThemeFrameListBox ;
2289 HIThemeDrawFrame( &cgrect , &info , cgContext , kHIThemeOrientationNormal ) ;
2290 }
2291 else if ( hasFocus )
2292 {
2293 HIThemeDrawFocusRect( &cgrect , true , cgContext , kHIThemeOrientationNormal ) ;
2294 }
2295 #if 0 // TODO REMOVE now done in a separate call earlier in drawing the window itself
2296 m_peer->GetRect( &rect ) ;
2297 if ( MacHasScrollBarCorner() )
2298 {
2299 int variant = (m_hScrollBar == NULL ? m_vScrollBar : m_hScrollBar ) ->GetWindowVariant();
2300 int size = m_hScrollBar ? m_hScrollBar->GetSize().y : ( m_vScrollBar ? m_vScrollBar->GetSize().x : MAC_SCROLLBAR_SIZE ) ;
2301 CGRect cgrect = CGRectMake( rect.right - size , rect.bottom - size , size , size ) ;
2302 CGPoint cgpoint = CGPointMake( rect.right - size , rect.bottom - size ) ;
2303 HIThemeGrowBoxDrawInfo info ;
2304 memset( &info, 0, sizeof(info) ) ;
2305 info.version = 0 ;
2306 info.state = IsEnabled() ? kThemeStateActive : kThemeStateInactive ;
2307 info.kind = kHIThemeGrowBoxKindNone ;
2308 // contrary to the docs ...SizeSmall does not work
2309 info.size = kHIThemeGrowBoxSizeNormal ;
2310 info.direction = 0 ;
2311 HIThemeDrawGrowBox( &cgpoint , &info , cgContext , kHIThemeOrientationNormal ) ;
2312 }
2313 #endif
2314 }
2315 }
2316
2317 void wxWindowMac::RemoveChild( wxWindowBase *child )
2318 {
2319 if ( child == m_hScrollBar )
2320 m_hScrollBar = NULL ;
2321 if ( child == m_vScrollBar )
2322 m_vScrollBar = NULL ;
2323
2324 wxWindowBase::RemoveChild( child ) ;
2325 }
2326
2327 void wxWindowMac::DoUpdateScrollbarVisibility()
2328 {
2329 bool triggerSizeEvent = false;
2330
2331 if ( m_hScrollBar )
2332 {
2333 bool showHScrollBar = m_hScrollBarAlwaysShown || m_hScrollBar->IsNeeded();
2334
2335 if ( m_hScrollBar->IsShown() != showHScrollBar )
2336 {
2337 m_hScrollBar->Show( showHScrollBar );
2338 triggerSizeEvent = true;
2339 }
2340 }
2341
2342 if ( m_vScrollBar)
2343 {
2344 bool showVScrollBar = m_vScrollBarAlwaysShown || m_vScrollBar->IsNeeded();
2345
2346 if ( m_vScrollBar->IsShown() != showVScrollBar )
2347 {
2348 m_vScrollBar->Show( showVScrollBar ) ;
2349 triggerSizeEvent = true;
2350 }
2351 }
2352
2353 MacRepositionScrollBars() ;
2354 if ( triggerSizeEvent )
2355 {
2356 wxSizeEvent event(GetSize(), m_windowId);
2357 event.SetEventObject(this);
2358 HandleWindowEvent(event);
2359 }
2360 }
2361
2362 // New function that will replace some of the above.
2363 void wxWindowMac::SetScrollbar(int orient, int pos, int thumb,
2364 int range, bool refresh)
2365 {
2366 if ( orient == wxHORIZONTAL && m_hScrollBar )
2367 m_hScrollBar->SetScrollbar(pos, thumb, range, thumb, refresh);
2368 else if ( orient == wxVERTICAL && m_vScrollBar )
2369 m_vScrollBar->SetScrollbar(pos, thumb, range, thumb, refresh);
2370
2371 DoUpdateScrollbarVisibility();
2372 }
2373
2374 // Does a physical scroll
2375 void wxWindowMac::ScrollWindow(int dx, int dy, const wxRect *rect)
2376 {
2377 if ( dx == 0 && dy == 0 )
2378 return ;
2379
2380 int width , height ;
2381 GetClientSize( &width , &height ) ;
2382
2383 {
2384 // note there currently is a bug in OSX which makes inefficient refreshes in case an entire control
2385 // area is scrolled, this does not occur if width and height are 2 pixels less,
2386 // TODO: write optimal workaround
2387 wxRect scrollrect( MacGetLeftBorderSize() , MacGetTopBorderSize() , width , height ) ;
2388 if ( rect )
2389 scrollrect.Intersect( *rect ) ;
2390
2391 if ( m_peer->GetNeedsDisplay() )
2392 {
2393 // because HIViewScrollRect does not scroll the already invalidated area we have two options:
2394 // in case there is already a pending redraw on that area
2395 // either immediate redraw or full invalidate
2396 #if 1
2397 // is the better overall solution, as it does not slow down scrolling
2398 m_peer->SetNeedsDisplay() ;
2399 #else
2400 // this would be the preferred version for fast drawing controls
2401 HIViewRender(m_peer->GetControlRef()) ;
2402 #endif
2403 }
2404
2405 // as the native control might be not a 0/0 wx window coordinates, we have to offset
2406 scrollrect.Offset( -MacGetLeftBorderSize() , -MacGetTopBorderSize() ) ;
2407 m_peer->ScrollRect( &scrollrect , dx , dy ) ;
2408
2409 #if 0
2410 // this would be the preferred version for fast drawing controls
2411 HIViewRender(m_peer->GetControlRef()) ;
2412 #endif
2413 }
2414
2415 wxWindowMac *child;
2416 int x, y, w, h;
2417 for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext())
2418 {
2419 child = node->GetData();
2420 if (child == NULL)
2421 continue;
2422 if (child == m_vScrollBar)
2423 continue;
2424 if (child == m_hScrollBar)
2425 continue;
2426 if (child->IsTopLevel())
2427 continue;
2428
2429 child->GetPosition( &x, &y );
2430 child->GetSize( &w, &h );
2431 if (rect)
2432 {
2433 wxRect rc( x, y, w, h );
2434 if (rect->Intersects( rc ))
2435 child->SetSize( x + dx, y + dy, w, h, wxSIZE_AUTO|wxSIZE_ALLOW_MINUS_ONE );
2436 }
2437 else
2438 {
2439 child->SetSize( x + dx, y + dy, w, h, wxSIZE_AUTO|wxSIZE_ALLOW_MINUS_ONE );
2440 }
2441 }
2442 }
2443
2444 void wxWindowMac::MacOnScroll( wxScrollEvent &event )
2445 {
2446 if ( event.GetEventObject() == m_vScrollBar || event.GetEventObject() == m_hScrollBar )
2447 {
2448 wxScrollWinEvent wevent;
2449 wevent.SetPosition(event.GetPosition());
2450 wevent.SetOrientation(event.GetOrientation());
2451 wevent.SetEventObject(this);
2452
2453 if (event.GetEventType() == wxEVT_SCROLL_TOP)
2454 wevent.SetEventType( wxEVT_SCROLLWIN_TOP );
2455 else if (event.GetEventType() == wxEVT_SCROLL_BOTTOM)
2456 wevent.SetEventType( wxEVT_SCROLLWIN_BOTTOM );
2457 else if (event.GetEventType() == wxEVT_SCROLL_LINEUP)
2458 wevent.SetEventType( wxEVT_SCROLLWIN_LINEUP );
2459 else if (event.GetEventType() == wxEVT_SCROLL_LINEDOWN)
2460 wevent.SetEventType( wxEVT_SCROLLWIN_LINEDOWN );
2461 else if (event.GetEventType() == wxEVT_SCROLL_PAGEUP)
2462 wevent.SetEventType( wxEVT_SCROLLWIN_PAGEUP );
2463 else if (event.GetEventType() == wxEVT_SCROLL_PAGEDOWN)
2464 wevent.SetEventType( wxEVT_SCROLLWIN_PAGEDOWN );
2465 else if (event.GetEventType() == wxEVT_SCROLL_THUMBTRACK)
2466 wevent.SetEventType( wxEVT_SCROLLWIN_THUMBTRACK );
2467 else if (event.GetEventType() == wxEVT_SCROLL_THUMBRELEASE)
2468 wevent.SetEventType( wxEVT_SCROLLWIN_THUMBRELEASE );
2469
2470 HandleWindowEvent(wevent);
2471 }
2472 }
2473
2474 // Get the window with the focus
2475 wxWindowMac *wxWindowBase::DoFindFocus()
2476 {
2477 ControlRef control ;
2478 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
2479 return wxFindControlFromMacControl( control ) ;
2480 }
2481
2482 void wxWindowMac::OnInternalIdle()
2483 {
2484 // This calls the UI-update mechanism (querying windows for
2485 // menu/toolbar/control state information)
2486 if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
2487 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
2488 }
2489
2490 // Raise the window to the top of the Z order
2491 void wxWindowMac::Raise()
2492 {
2493 m_peer->SetZOrder( true , NULL ) ;
2494 }
2495
2496 // Lower the window to the bottom of the Z order
2497 void wxWindowMac::Lower()
2498 {
2499 m_peer->SetZOrder( false , NULL ) ;
2500 }
2501
2502 // static wxWindow *gs_lastWhich = NULL;
2503
2504 bool wxWindowMac::MacSetupCursor( const wxPoint& pt )
2505 {
2506 // first trigger a set cursor event
2507
2508 wxPoint clientorigin = GetClientAreaOrigin() ;
2509 wxSize clientsize = GetClientSize() ;
2510 wxCursor cursor ;
2511 if ( wxRect2DInt( clientorigin.x , clientorigin.y , clientsize.x , clientsize.y ).Contains( wxPoint2DInt( pt ) ) )
2512 {
2513 wxSetCursorEvent event( pt.x , pt.y );
2514
2515 bool processedEvtSetCursor = HandleWindowEvent(event);
2516 if ( processedEvtSetCursor && event.HasCursor() )
2517 {
2518 cursor = event.GetCursor() ;
2519 }
2520 else
2521 {
2522 // the test for processedEvtSetCursor is here to prevent using m_cursor
2523 // if the user code caught EVT_SET_CURSOR() and returned nothing from
2524 // it - this is a way to say that our cursor shouldn't be used for this
2525 // point
2526 if ( !processedEvtSetCursor && m_cursor.Ok() )
2527 cursor = m_cursor ;
2528
2529 if ( !wxIsBusy() && !GetParent() )
2530 cursor = *wxSTANDARD_CURSOR ;
2531 }
2532
2533 if ( cursor.Ok() )
2534 cursor.MacInstall() ;
2535 }
2536
2537 return cursor.Ok() ;
2538 }
2539
2540 wxString wxWindowMac::MacGetToolTipString( wxPoint &WXUNUSED(pt) )
2541 {
2542 #if wxUSE_TOOLTIPS
2543 if ( m_tooltip )
2544 return m_tooltip->GetTip() ;
2545 #endif
2546
2547 return wxEmptyString ;
2548 }
2549
2550 void wxWindowMac::ClearBackground()
2551 {
2552 Refresh() ;
2553 Update() ;
2554 }
2555
2556 void wxWindowMac::Update()
2557 {
2558 wxTopLevelWindowMac* top = MacGetTopLevelWindow();
2559 if (top)
2560 top->MacPerformUpdates() ;
2561 }
2562
2563 wxTopLevelWindowMac* wxWindowMac::MacGetTopLevelWindow() const
2564 {
2565 wxTopLevelWindowMac* win = NULL ;
2566 WindowRef window = (WindowRef) MacGetTopLevelWindowRef() ;
2567 if ( window )
2568 win = wxFindWinFromMacWindow( window ) ;
2569
2570 return win ;
2571 }
2572
2573 const wxRect& wxWindowMac::MacGetClippedClientRect() const
2574 {
2575 MacUpdateClippedRects() ;
2576
2577 return m_cachedClippedClientRect ;
2578 }
2579
2580 const wxRect& wxWindowMac::MacGetClippedRect() const
2581 {
2582 MacUpdateClippedRects() ;
2583
2584 return m_cachedClippedRect ;
2585 }
2586
2587 const wxRect&wxWindowMac:: MacGetClippedRectWithOuterStructure() const
2588 {
2589 MacUpdateClippedRects() ;
2590
2591 return m_cachedClippedRectWithOuterStructure ;
2592 }
2593
2594 const wxRegion& wxWindowMac::MacGetVisibleRegion( bool includeOuterStructures )
2595 {
2596 static wxRegion emptyrgn ;
2597
2598 if ( !m_isBeingDeleted && IsShownOnScreen() )
2599 {
2600 MacUpdateClippedRects() ;
2601 if ( includeOuterStructures )
2602 return m_cachedClippedRegionWithOuterStructure ;
2603 else
2604 return m_cachedClippedRegion ;
2605 }
2606 else
2607 {
2608 return emptyrgn ;
2609 }
2610 }
2611
2612 void wxWindowMac::MacUpdateClippedRects() const
2613 {
2614 if ( m_cachedClippedRectValid )
2615 return ;
2616
2617 // includeOuterStructures is true if we try to draw somthing like a focus ring etc.
2618 // also a window dc uses this, in this case we only clip in the hierarchy for hard
2619 // borders like a scrollwindow, splitter etc otherwise we end up in a paranoia having
2620 // to add focus borders everywhere
2621
2622 Rect r, rIncludingOuterStructures ;
2623
2624 m_peer->GetRect( &r ) ;
2625 r.left -= MacGetLeftBorderSize() ;
2626 r.top -= MacGetTopBorderSize() ;
2627 r.bottom += MacGetBottomBorderSize() ;
2628 r.right += MacGetRightBorderSize() ;
2629
2630 r.right -= r.left ;
2631 r.bottom -= r.top ;
2632 r.left = 0 ;
2633 r.top = 0 ;
2634
2635 rIncludingOuterStructures = r ;
2636 InsetRect( &rIncludingOuterStructures , -4 , -4 ) ;
2637
2638 wxRect cl = GetClientRect() ;
2639 Rect rClient = { cl.y , cl.x , cl.y + cl.height , cl.x + cl.width } ;
2640
2641 int x , y ;
2642 wxSize size ;
2643 const wxWindow* child = this ;
2644 const wxWindow* parent = NULL ;
2645
2646 while ( !child->IsTopLevel() && ( parent = child->GetParent() ) != NULL )
2647 {
2648 if ( parent->MacIsChildOfClientArea(child) )
2649 {
2650 size = parent->GetClientSize() ;
2651 wxPoint origin = parent->GetClientAreaOrigin() ;
2652 x = origin.x ;
2653 y = origin.y ;
2654 }
2655 else
2656 {
2657 // this will be true for scrollbars, toolbars etc.
2658 size = parent->GetSize() ;
2659 y = parent->MacGetTopBorderSize() ;
2660 x = parent->MacGetLeftBorderSize() ;
2661 size.x -= parent->MacGetLeftBorderSize() + parent->MacGetRightBorderSize() ;
2662 size.y -= parent->MacGetTopBorderSize() + parent->MacGetBottomBorderSize() ;
2663 }
2664
2665 parent->MacWindowToRootWindow( &x, &y ) ;
2666 MacRootWindowToWindow( &x , &y ) ;
2667
2668 Rect rparent = { y , x , y + size.y , x + size.x } ;
2669
2670 // the wxwindow and client rects will always be clipped
2671 SectRect( &r , &rparent , &r ) ;
2672 SectRect( &rClient , &rparent , &rClient ) ;
2673
2674 // the structure only at 'hard' borders
2675 if ( parent->MacClipChildren() ||
2676 ( parent->GetParent() && parent->GetParent()->MacClipGrandChildren() ) )
2677 {
2678 SectRect( &rIncludingOuterStructures , &rparent , &rIncludingOuterStructures ) ;
2679 }
2680
2681 child = parent ;
2682 }
2683
2684 m_cachedClippedRect = wxRect( r.left , r.top , r.right - r.left , r.bottom - r.top ) ;
2685 m_cachedClippedClientRect = wxRect( rClient.left , rClient.top ,
2686 rClient.right - rClient.left , rClient.bottom - rClient.top ) ;
2687 m_cachedClippedRectWithOuterStructure = wxRect(
2688 rIncludingOuterStructures.left , rIncludingOuterStructures.top ,
2689 rIncludingOuterStructures.right - rIncludingOuterStructures.left ,
2690 rIncludingOuterStructures.bottom - rIncludingOuterStructures.top ) ;
2691
2692 m_cachedClippedRegionWithOuterStructure = wxRegion( m_cachedClippedRectWithOuterStructure ) ;
2693 m_cachedClippedRegion = wxRegion( m_cachedClippedRect ) ;
2694 m_cachedClippedClientRegion = wxRegion( m_cachedClippedClientRect ) ;
2695
2696 m_cachedClippedRectValid = true ;
2697 }
2698
2699 /*
2700 This function must not change the updatergn !
2701 */
2702 bool wxWindowMac::MacDoRedraw( void* updatergnr , long time )
2703 {
2704 bool handled = false ;
2705 Rect updatebounds ;
2706 RgnHandle updatergn = (RgnHandle) updatergnr ;
2707 GetRegionBounds( updatergn , &updatebounds ) ;
2708
2709 // wxLogDebug(wxT("update for %s bounds %d, %d, %d, %d"), wxString(GetClassInfo()->GetClassName()).c_str(), updatebounds.left, updatebounds.top , updatebounds.right , updatebounds.bottom ) ;
2710
2711 if ( !EmptyRgn(updatergn) )
2712 {
2713 RgnHandle newupdate = NewRgn() ;
2714 wxSize point = GetClientSize() ;
2715 wxPoint origin = GetClientAreaOrigin() ;
2716 SetRectRgn( newupdate , origin.x , origin.y , origin.x + point.x , origin.y + point.y ) ;
2717 SectRgn( newupdate , updatergn , newupdate ) ;
2718
2719 // first send an erase event to the entire update area
2720 {
2721 // for the toplevel window this really is the entire area
2722 // for all the others only their client area, otherwise they
2723 // might be drawing with full alpha and eg put blue into
2724 // the grow-box area of a scrolled window (scroll sample)
2725 wxDC* dc = new wxWindowDC(this);
2726 if ( IsTopLevel() )
2727 dc->SetClippingRegion(wxRegion(HIShapeCreateWithQDRgn(updatergn)));
2728 else
2729 dc->SetClippingRegion(wxRegion(HIShapeCreateWithQDRgn(newupdate)));
2730
2731 wxEraseEvent eevent( GetId(), dc );
2732 eevent.SetEventObject( this );
2733 HandleWindowEvent( eevent );
2734 delete dc ;
2735 }
2736
2737 MacPaintGrowBox();
2738
2739 // calculate a client-origin version of the update rgn and set m_updateRegion to that
2740 OffsetRgn( newupdate , -origin.x , -origin.y ) ;
2741 m_updateRegion = wxRegion(HIShapeCreateWithQDRgn(newupdate)) ;
2742 DisposeRgn( newupdate ) ;
2743
2744 if ( !m_updateRegion.Empty() )
2745 {
2746 // paint the window itself
2747
2748 wxPaintEvent event;
2749 event.SetTimestamp(time);
2750 event.SetEventObject(this);
2751 HandleWindowEvent(event);
2752 handled = true ;
2753 }
2754
2755 // now we cannot rely on having its borders drawn by a window itself, as it does not
2756 // get the updateRgn wide enough to always do so, so we do it from the parent
2757 // this would also be the place to draw any custom backgrounds for native controls
2758 // in Composited windowing
2759 wxPoint clientOrigin = GetClientAreaOrigin() ;
2760
2761 wxWindowMac *child;
2762 int x, y, w, h;
2763 for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext())
2764 {
2765 child = node->GetData();
2766 if (child == NULL)
2767 continue;
2768 if (child == m_vScrollBar)
2769 continue;
2770 if (child == m_hScrollBar)
2771 continue;
2772 if (child->IsTopLevel())
2773 continue;
2774 if (!child->IsShown())
2775 continue;
2776
2777 // only draw those in the update region (add a safety margin of 10 pixels for shadow effects
2778
2779 child->GetPosition( &x, &y );
2780 child->GetSize( &w, &h );
2781 Rect childRect = { y , x , y + h , x + w } ;
2782 OffsetRect( &childRect , clientOrigin.x , clientOrigin.y ) ;
2783 InsetRect( &childRect , -10 , -10) ;
2784
2785 if ( RectInRgn( &childRect , updatergn ) )
2786 {
2787 // paint custom borders
2788 wxNcPaintEvent eventNc( child->GetId() );
2789 eventNc.SetEventObject( child );
2790 if ( !child->HandleWindowEvent( eventNc ) )
2791 {
2792 child->MacPaintBorders(0, 0) ;
2793 }
2794 }
2795 }
2796 }
2797
2798 return handled ;
2799 }
2800
2801
2802 WXWindow wxWindowMac::MacGetTopLevelWindowRef() const
2803 {
2804 wxWindowMac *iter = (wxWindowMac*)this ;
2805
2806 while ( iter )
2807 {
2808 if ( iter->IsTopLevel() )
2809 {
2810 wxTopLevelWindow* toplevel = wxDynamicCast(iter,wxTopLevelWindow);
2811 if ( toplevel )
2812 return toplevel->MacGetWindowRef();
2813 #if wxUSE_POPUPWIN
2814 wxPopupWindow* popupwin = wxDynamicCast(iter,wxPopupWindow);
2815 if ( popupwin )
2816 return popupwin->MacGetPopupWindowRef();
2817 #endif
2818 }
2819 iter = iter->GetParent() ;
2820 }
2821
2822 return NULL ;
2823 }
2824
2825 bool wxWindowMac::MacHasScrollBarCorner() const
2826 {
2827 /* Returns whether the scroll bars in a wxScrolledWindow should be
2828 * shortened. Scroll bars should be shortened if either:
2829 *
2830 * - both scroll bars are visible, or
2831 *
2832 * - there is a resize box in the parent frame's corner and this
2833 * window shares the bottom and right edge with the parent
2834 * frame.
2835 */
2836
2837 if ( m_hScrollBar == NULL && m_vScrollBar == NULL )
2838 return false;
2839
2840 if ( ( m_hScrollBar && m_hScrollBar->IsShown() )
2841 && ( m_vScrollBar && m_vScrollBar->IsShown() ) )
2842 {
2843 // Both scroll bars visible
2844 return true;
2845 }
2846 else
2847 {
2848 wxPoint thisWindowBottomRight = GetScreenRect().GetBottomRight();
2849
2850 for ( const wxWindow *win = this; win; win = win->GetParent() )
2851 {
2852 const wxFrame *frame = wxDynamicCast( win, wxFrame ) ;
2853 if ( frame )
2854 {
2855 if ( frame->GetWindowStyleFlag() & wxRESIZE_BORDER )
2856 {
2857 // Parent frame has resize handle
2858 wxPoint frameBottomRight = frame->GetScreenRect().GetBottomRight();
2859
2860 // Note: allow for some wiggle room here as wxMac's
2861 // window rect calculations seem to be imprecise
2862 if ( abs( thisWindowBottomRight.x - frameBottomRight.x ) <= 2
2863 && abs( thisWindowBottomRight.y - frameBottomRight.y ) <= 2 )
2864 {
2865 // Parent frame has resize handle and shares
2866 // right bottom corner
2867 return true ;
2868 }
2869 else
2870 {
2871 // Parent frame has resize handle but doesn't
2872 // share right bottom corner
2873 return false ;
2874 }
2875 }
2876 else
2877 {
2878 // Parent frame doesn't have resize handle
2879 return false ;
2880 }
2881 }
2882 }
2883
2884 // No parent frame found
2885 return false ;
2886 }
2887 }
2888
2889 void wxWindowMac::MacCreateScrollBars( long style )
2890 {
2891 wxASSERT_MSG( m_vScrollBar == NULL && m_hScrollBar == NULL , wxT("attempt to create window twice") ) ;
2892
2893 if ( style & ( wxVSCROLL | wxHSCROLL ) )
2894 {
2895 int scrlsize = MAC_SCROLLBAR_SIZE ;
2896 if ( GetWindowVariant() == wxWINDOW_VARIANT_SMALL || GetWindowVariant() == wxWINDOW_VARIANT_MINI )
2897 {
2898 scrlsize = MAC_SMALL_SCROLLBAR_SIZE ;
2899 }
2900
2901 int adjust = MacHasScrollBarCorner() ? scrlsize - 1: 0 ;
2902 int width, height ;
2903 GetClientSize( &width , &height ) ;
2904
2905 wxPoint vPoint(width - scrlsize, 0) ;
2906 wxSize vSize(scrlsize, height - adjust) ;
2907 wxPoint hPoint(0, height - scrlsize) ;
2908 wxSize hSize(width - adjust, scrlsize) ;
2909
2910 // we have to set the min size to a smaller value, otherwise they cannot get smaller (InitialSize sets MinSize)
2911 if ( style & wxVSCROLL )
2912 {
2913 m_vScrollBar = new wxScrollBar((wxWindow*)this, wxID_ANY, vPoint, vSize , wxVERTICAL);
2914 m_vScrollBar->SetMinSize( wxDefaultSize );
2915 }
2916
2917 if ( style & wxHSCROLL )
2918 {
2919 m_hScrollBar = new wxScrollBar((wxWindow*)this, wxID_ANY, hPoint, hSize , wxHORIZONTAL);
2920 m_hScrollBar->SetMinSize( wxDefaultSize );
2921 }
2922 }
2923
2924 // because the create does not take into account the client area origin
2925 // we might have a real position shift
2926 MacRepositionScrollBars() ;
2927 }
2928
2929 bool wxWindowMac::MacIsChildOfClientArea( const wxWindow* child ) const
2930 {
2931 bool result = ((child == NULL) || ((child != m_hScrollBar) && (child != m_vScrollBar)));
2932
2933 return result ;
2934 }
2935
2936 void wxWindowMac::MacRepositionScrollBars()
2937 {
2938 if ( !m_hScrollBar && !m_vScrollBar )
2939 return ;
2940
2941 int scrlsize = m_hScrollBar ? m_hScrollBar->GetSize().y : ( m_vScrollBar ? m_vScrollBar->GetSize().x : MAC_SCROLLBAR_SIZE ) ;
2942 int adjust = MacHasScrollBarCorner() ? scrlsize - 1 : 0 ;
2943
2944 // get real client area
2945 int width, height ;
2946 GetSize( &width , &height );
2947
2948 width -= MacGetLeftBorderSize() + MacGetRightBorderSize();
2949 height -= MacGetTopBorderSize() + MacGetBottomBorderSize();
2950
2951 wxPoint vPoint( width - scrlsize, 0 ) ;
2952 wxSize vSize( scrlsize, height - adjust ) ;
2953 wxPoint hPoint( 0 , height - scrlsize ) ;
2954 wxSize hSize( width - adjust, scrlsize ) ;
2955
2956 #if 0
2957 int x = 0, y = 0, w, h ;
2958 GetSize( &w , &h ) ;
2959
2960 MacClientToRootWindow( &x , &y ) ;
2961 MacClientToRootWindow( &w , &h ) ;
2962
2963 wxWindowMac *iter = (wxWindowMac*)this ;
2964
2965 int totW = 10000 , totH = 10000;
2966 while ( iter )
2967 {
2968 if ( iter->IsTopLevel() )
2969 {
2970 iter->GetSize( &totW , &totH ) ;
2971 break ;
2972 }
2973
2974 iter = iter->GetParent() ;
2975 }
2976
2977 if ( x == 0 )
2978 {
2979 hPoint.x = -1 ;
2980 hSize.x += 1 ;
2981 }
2982 if ( y == 0 )
2983 {
2984 vPoint.y = -1 ;
2985 vSize.y += 1 ;
2986 }
2987
2988 if ( w - x >= totW )
2989 {
2990 hSize.x += 1 ;
2991 vPoint.x += 1 ;
2992 }
2993 if ( h - y >= totH )
2994 {
2995 vSize.y += 1 ;
2996 hPoint.y += 1 ;
2997 }
2998 #endif
2999
3000 if ( m_vScrollBar )
3001 m_vScrollBar->SetSize( vPoint.x , vPoint.y, vSize.x, vSize.y , wxSIZE_ALLOW_MINUS_ONE );
3002 if ( m_hScrollBar )
3003 m_hScrollBar->SetSize( hPoint.x , hPoint.y, hSize.x, hSize.y, wxSIZE_ALLOW_MINUS_ONE );
3004 }
3005
3006 bool wxWindowMac::AcceptsFocus() const
3007 {
3008 return MacCanFocus() && wxWindowBase::AcceptsFocus();
3009 }
3010
3011 void wxWindowMac::MacSuperChangedPosition()
3012 {
3013 // only window-absolute structures have to be moved i.e. controls
3014
3015 m_cachedClippedRectValid = false ;
3016
3017 wxWindowMac *child;
3018 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3019 while ( node )
3020 {
3021 child = node->GetData();
3022 child->MacSuperChangedPosition() ;
3023
3024 node = node->GetNext();
3025 }
3026 }
3027
3028 void wxWindowMac::MacTopLevelWindowChangedPosition()
3029 {
3030 // only screen-absolute structures have to be moved i.e. glcanvas
3031
3032 wxWindowMac *child;
3033 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3034 while ( node )
3035 {
3036 child = node->GetData();
3037 child->MacTopLevelWindowChangedPosition() ;
3038
3039 node = node->GetNext();
3040 }
3041 }
3042
3043 long wxWindowMac::MacGetLeftBorderSize() const
3044 {
3045 if ( IsTopLevel() )
3046 return 0 ;
3047
3048 SInt32 border = 0 ;
3049
3050 if (HasFlag(wxRAISED_BORDER) || HasFlag( wxSUNKEN_BORDER) || HasFlag(wxDOUBLE_BORDER))
3051 {
3052 // this metric is only the 'outset' outside the simple frame rect
3053 GetThemeMetric( kThemeMetricEditTextFrameOutset , &border ) ;
3054 border += 1 ;
3055 }
3056 else if (HasFlag(wxSIMPLE_BORDER))
3057 {
3058 // this metric is only the 'outset' outside the simple frame rect
3059 GetThemeMetric( kThemeMetricListBoxFrameOutset , &border ) ;
3060 border += 1 ;
3061 }
3062
3063 return border ;
3064 }
3065
3066 long wxWindowMac::MacGetRightBorderSize() const
3067 {
3068 // they are all symmetric in mac themes
3069 return MacGetLeftBorderSize() ;
3070 }
3071
3072 long wxWindowMac::MacGetTopBorderSize() const
3073 {
3074 // they are all symmetric in mac themes
3075 return MacGetLeftBorderSize() ;
3076 }
3077
3078 long wxWindowMac::MacGetBottomBorderSize() const
3079 {
3080 // they are all symmetric in mac themes
3081 return MacGetLeftBorderSize() ;
3082 }
3083
3084 long wxWindowMac::MacRemoveBordersFromStyle( long style )
3085 {
3086 return style & ~wxBORDER_MASK ;
3087 }
3088
3089 // Find the wxWindowMac at the current mouse position, returning the mouse
3090 // position.
3091 wxWindowMac * wxFindWindowAtPointer( wxPoint& pt )
3092 {
3093 pt = wxGetMousePosition();
3094 wxWindowMac* found = wxFindWindowAtPoint(pt);
3095
3096 return found;
3097 }
3098
3099 // Get the current mouse position.
3100 wxPoint wxGetMousePosition()
3101 {
3102 int x, y;
3103
3104 wxGetMousePosition( &x, &y );
3105
3106 return wxPoint(x, y);
3107 }
3108
3109 void wxWindowMac::OnMouseEvent( wxMouseEvent &event )
3110 {
3111 if ( event.GetEventType() == wxEVT_RIGHT_DOWN )
3112 {
3113 // copied from wxGTK : CS
3114 // VZ: shouldn't we move this to base class then?
3115
3116 // generate a "context menu" event: this is similar to wxEVT_RIGHT_DOWN
3117 // except that:
3118 //
3119 // (a) it's a command event and so is propagated to the parent
3120 // (b) under MSW it can be generated from kbd too
3121 // (c) it uses screen coords (because of (a))
3122 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU,
3123 this->GetId(),
3124 this->ClientToScreen(event.GetPosition()));
3125 evtCtx.SetEventObject(this);
3126 if ( ! HandleWindowEvent(evtCtx) )
3127 event.Skip() ;
3128 }
3129 else
3130 {
3131 event.Skip() ;
3132 }
3133 }
3134
3135 void wxWindowMac::OnPaint( wxPaintEvent & WXUNUSED(event) )
3136 {
3137 if ( wxTheApp->MacGetCurrentEvent() != NULL && wxTheApp->MacGetCurrentEventHandlerCallRef() != NULL
3138 && GetBackgroundStyle() != wxBG_STYLE_TRANSPARENT )
3139 CallNextEventHandler(
3140 (EventHandlerCallRef)wxTheApp->MacGetCurrentEventHandlerCallRef() ,
3141 (EventRef) wxTheApp->MacGetCurrentEvent() ) ;
3142 }
3143
3144 void wxWindowMac::MacHandleControlClick(WXWidget WXUNUSED(control),
3145 wxInt16 WXUNUSED(controlpart),
3146 bool WXUNUSED(mouseStillDown))
3147 {
3148 }
3149
3150 Rect wxMacGetBoundsForControl( wxWindow* window , const wxPoint& pos , const wxSize &size , bool adjustForOrigin )
3151 {
3152 int x, y, w, h ;
3153
3154 window->MacGetBoundsForControl( pos , size , x , y, w, h , adjustForOrigin ) ;
3155 Rect bounds = { y, x, y + h, x + w };
3156
3157 return bounds ;
3158 }
3159
3160 wxInt32 wxWindowMac::MacControlHit(WXEVENTHANDLERREF WXUNUSED(handler) , WXEVENTREF WXUNUSED(event) )
3161 {
3162 return eventNotHandledErr ;
3163 }
3164
3165 bool wxWindowMac::Reparent(wxWindowBase *newParentBase)
3166 {
3167 wxWindowMac *newParent = (wxWindowMac *)newParentBase;
3168 if ( !wxWindowBase::Reparent(newParent) )
3169 return false;
3170
3171 // copied from MacPostControlCreate
3172 ControlRef container = (ControlRef) GetParent()->GetHandle() ;
3173
3174 wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
3175
3176 ::EmbedControl( m_peer->GetControlRef() , container ) ;
3177
3178 return true;
3179 }
3180
3181 bool wxWindowMac::SetTransparent(wxByte alpha)
3182 {
3183 SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
3184
3185 if ( alpha != m_macAlpha )
3186 {
3187 m_macAlpha = alpha ;
3188 Refresh() ;
3189 }
3190 return true ;
3191 }
3192
3193
3194 bool wxWindowMac::CanSetTransparent()
3195 {
3196 return true ;
3197 }
3198
3199 wxByte wxWindowMac::GetTransparent() const
3200 {
3201 return m_macAlpha ;
3202 }
3203
3204 bool wxWindowMac::IsShownOnScreen() const
3205 {
3206 #if TARGET_API_MAC_OSX
3207 if ( m_peer && m_peer->Ok() )
3208 {
3209 bool peerVis = m_peer->IsVisible();
3210 bool wxVis = wxWindowBase::IsShownOnScreen();
3211 if( peerVis != wxVis )
3212 {
3213 // CS : put a breakpoint here to investigate differences
3214 // between native an wx visibilities
3215 // the only place where I've encountered them until now
3216 // are the hiding/showing sequences where the vis-changed event is
3217 // first sent to the innermost control, while wx does things
3218 // from the outmost control
3219 wxVis = wxWindowBase::IsShownOnScreen();
3220 return wxVis;
3221 }
3222
3223 return m_peer->IsVisible();
3224 }
3225 #endif
3226
3227 return wxWindowBase::IsShownOnScreen();
3228 }