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