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