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