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