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