9c22b9581861932804010d24b3b3496678eaec5c
[wxWidgets.git] / src / mac / carbon / utils.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/utils.cpp
3 // Purpose: Various utilities
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/utils.h"
15 #include "wx/app.h"
16 #include "wx/apptrait.h"
17
18 #if wxUSE_GUI
19 #include "wx/mac/uma.h"
20 #include "wx/font.h"
21 #include "wx/toplevel.h"
22 #else
23 #include "wx/intl.h"
24 #endif
25
26 #include <ctype.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32
33 #include "MoreFilesX.h"
34
35 #ifndef __DARWIN__
36 #include <Threads.h>
37 #include <Sound.h>
38 #endif
39
40 #if wxUSE_GUI
41 #if TARGET_API_MAC_OSX
42 #include <CoreServices/CoreServices.h>
43 #else
44 #include <DriverServices.h>
45 #include <Multiprocessing.h>
46 #endif
47
48 #ifdef __DARWIN__
49 #include <Carbon/Carbon.h>
50 #else
51 #include <ATSUnicode.h>
52 #include <TextCommon.h>
53 #include <TextEncodingConverter.h>
54 #endif
55 #endif // wxUSE_GUI
56
57 #include "wx/mac/private.h"
58
59 #if defined(__MWERKS__) && wxUSE_UNICODE
60 #include <wtime.h>
61 #endif
62
63 // ---------------------------------------------------------------------------
64 // code used in both base and GUI compilation
65 // ---------------------------------------------------------------------------
66
67 // our OS version is the same in non GUI and GUI cases
68 static int DoGetOSVersion(int *majorVsn, int *minorVsn)
69 {
70 long theSystem ;
71
72 // are there x-platform conventions ?
73
74 Gestalt(gestaltSystemVersion, &theSystem) ;
75 if (minorVsn != NULL)
76 *minorVsn = (theSystem & 0xFF) ;
77
78 if (majorVsn != NULL)
79 *majorVsn = (theSystem >> 8) ;
80
81 #ifdef __DARWIN__
82 return wxMAC_DARWIN;
83 #else
84 return wxMAC;
85 #endif
86 }
87
88
89 #if wxUSE_BASE
90
91 // ----------------------------------------------------------------------------
92 // debugging support
93 // ----------------------------------------------------------------------------
94
95 #if defined(__WXDEBUG__) && defined(__WXMAC__) && !defined(__DARWIN__) && defined(__MWERKS__) && (__MWERKS__ >= 0x2400)
96
97 // MetroNub stuff doesn't seem to work in CodeWarrior 5.3 Carbon builds...
98
99 #ifndef __MetroNubUtils__
100 #include "MetroNubUtils.h"
101 #endif
102
103 #ifndef __GESTALT__
104 #include <Gestalt.h>
105 #endif
106
107 #if TARGET_API_MAC_CARBON
108
109 #include <CodeFragments.h>
110
111 extern "C" long CallUniversalProc(UniversalProcPtr theProcPtr, ProcInfoType procInfo, ...);
112
113 ProcPtr gCallUniversalProc_Proc = NULL;
114
115 #endif
116
117 static MetroNubUserEntryBlock* gMetroNubEntry = NULL;
118
119 static long fRunOnce = false;
120
121
122 Boolean IsMetroNubInstalled()
123 {
124 if (!fRunOnce)
125 {
126 long result, value;
127
128 fRunOnce = true;
129 gMetroNubEntry = NULL;
130
131 if (Gestalt(gestaltSystemVersion, &value) == noErr && value < 0x1000)
132 {
133 // look for MetroNub's Gestalt selector
134 if (Gestalt(kMetroNubUserSignature, &result) == noErr)
135 {
136 #if TARGET_API_MAC_CARBON
137 if (gCallUniversalProc_Proc == NULL)
138 {
139 CFragConnectionID connectionID;
140 Ptr mainAddress;
141 Str255 errorString;
142 ProcPtr symbolAddress;
143 OSErr err;
144 CFragSymbolClass symbolClass;
145
146 symbolAddress = NULL;
147 err = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kFindCFrag,
148 &connectionID, &mainAddress, errorString);
149
150 if (err != noErr)
151 {
152 gCallUniversalProc_Proc = NULL;
153 goto end;
154 }
155
156 err = FindSymbol(connectionID, "\pCallUniversalProc",
157 (Ptr *) &gCallUniversalProc_Proc, &symbolClass);
158
159 if (err != noErr)
160 {
161 gCallUniversalProc_Proc = NULL;
162 goto end;
163 }
164 }
165 #endif
166
167 {
168 MetroNubUserEntryBlock* block = (MetroNubUserEntryBlock *)result;
169
170 // make sure the version of the API is compatible
171 if (block->apiLowVersion <= kMetroNubUserAPIVersion &&
172 kMetroNubUserAPIVersion <= block->apiHiVersion)
173 {
174 // success!
175 gMetroNubEntry = block;
176 }
177 }
178 }
179 }
180 }
181
182 end:
183
184 #if TARGET_API_MAC_CARBON
185 return (gMetroNubEntry != NULL && gCallUniversalProc_Proc != NULL);
186 #else
187 return (gMetroNubEntry != NULL);
188 #endif
189 }
190
191 Boolean IsMWDebuggerRunning()
192 {
193 if (IsMetroNubInstalled())
194 return CallIsDebuggerRunningProc(gMetroNubEntry->isDebuggerRunning);
195
196 return false;
197 }
198
199 Boolean AmIBeingMWDebugged()
200 {
201 if (IsMetroNubInstalled())
202 return CallAmIBeingDebuggedProc(gMetroNubEntry->amIBeingDebugged);
203
204 return false;
205 }
206
207 extern bool WXDLLEXPORT wxIsDebuggerRunning()
208 {
209 return IsMWDebuggerRunning() && AmIBeingMWDebugged();
210 }
211
212 #else
213
214 extern bool WXDLLEXPORT wxIsDebuggerRunning()
215 {
216 return false;
217 }
218
219 #endif // defined(__WXMAC__) && !defined(__DARWIN__) && (__MWERKS__ >= 0x2400)
220
221
222 #ifndef __DARWIN__
223 // defined in unix/utilsunx.cpp for Mac OS X
224
225 // get full hostname (with domain name if possible)
226 bool wxGetFullHostName(wxChar *buf, int maxSize)
227 {
228 return wxGetHostName(buf, maxSize);
229 }
230
231 // Get user ID e.g. jacs
232 bool wxGetUserId(wxChar *buf, int maxSize)
233 {
234 return wxGetUserName( buf , maxSize ) ;
235 }
236
237 const wxChar* wxGetHomeDir(wxString *pstr)
238 {
239 *pstr = wxMacFindFolder( (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder ) ;
240 return pstr->c_str() ;
241 }
242
243 // Get hostname only (without domain name)
244 bool wxGetHostName(wxChar *buf, int maxSize)
245 {
246 // Gets Chooser name of user by examining a System resource.
247 buf[0] = 0 ;
248
249 const short kComputerNameID = -16413;
250
251 short oldResFile = CurResFile() ;
252 UseResFile(0);
253 StringHandle chooserName = (StringHandle)::GetString(kComputerNameID);
254 UseResFile(oldResFile);
255
256 if (chooserName && *chooserName)
257 {
258 HLock( (Handle) chooserName ) ;
259 wxString name = wxMacMakeStringFromPascal( *chooserName ) ;
260 HUnlock( (Handle) chooserName ) ;
261 ReleaseResource( (Handle) chooserName ) ;
262 wxStrncpy( buf , name , maxSize - 1 ) ;
263 }
264
265 return true;
266 }
267
268 // Get user name e.g. Stefan Csomor
269 bool wxGetUserName(wxChar *buf, int maxSize)
270 {
271 // Gets Chooser name of user by examining a System resource.
272 buf[0] = 0 ;
273
274 const short kChooserNameID = -16096;
275
276 short oldResFile = CurResFile() ;
277 UseResFile(0);
278 StringHandle chooserName = (StringHandle)::GetString(kChooserNameID);
279 UseResFile(oldResFile);
280
281 if (chooserName && *chooserName)
282 {
283 HLock( (Handle) chooserName ) ;
284 wxString name = wxMacMakeStringFromPascal( *chooserName ) ;
285 HUnlock( (Handle) chooserName ) ;
286 ReleaseResource( (Handle) chooserName ) ;
287 wxStrncpy( buf , name , maxSize - 1 ) ;
288 }
289
290 return true;
291 }
292
293 int wxKill(long pid, wxSignal sig , wxKillError *rc, int flags)
294 {
295 // TODO
296 return 0;
297 }
298
299 WXDLLEXPORT bool wxGetEnv(const wxString& var, wxString *value)
300 {
301 // TODO : under classic there is no environement support, under X yes
302 return false ;
303 }
304
305 // set the env var name to the given value, return true on success
306 WXDLLEXPORT bool wxSetEnv(const wxString& var, const wxChar *value)
307 {
308 // TODO : under classic there is no environement support, under X yes
309 return false ;
310 }
311
312 // Execute a program in an Interactive Shell
313 bool wxShell(const wxString& command)
314 {
315 // TODO
316 return false;
317 }
318
319 // Shutdown or reboot the PC
320 bool wxShutdown(wxShutdownFlags wFlags)
321 {
322 // TODO
323 return false;
324 }
325
326 wxPowerType wxGetPowerType()
327 {
328 // TODO
329 return wxPOWER_UNKNOWN;
330 }
331
332 wxBatteryState wxGetBatteryState()
333 {
334 // TODO
335 return wxBATTERY_UNKNOWN_STATE;
336 }
337
338 // Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
339 wxMemorySize wxGetFreeMemory()
340 {
341 return (wxMemorySize)FreeMem() ;
342 }
343
344 #ifndef __DARWIN__
345
346 void wxMicroSleep(unsigned long microseconds)
347 {
348 AbsoluteTime wakeup = AddDurationToAbsolute( microseconds * durationMicrosecond , UpTime());
349 MPDelayUntil( & wakeup);
350 }
351
352 void wxMilliSleep(unsigned long milliseconds)
353 {
354 AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime());
355 MPDelayUntil( & wakeup);
356 }
357
358 void wxSleep(int nSecs)
359 {
360 wxMilliSleep(1000*nSecs);
361 }
362
363 #endif
364
365 // Consume all events until no more left
366 void wxFlushEvents()
367 {
368 }
369
370 #endif // !__DARWIN__
371
372 // Emit a beeeeeep
373 void wxBell()
374 {
375 SysBeep(30);
376 }
377
378 wxToolkitInfo& wxConsoleAppTraits::GetToolkitInfo()
379 {
380 static wxToolkitInfo info;
381
382 info.os = DoGetOSVersion(&info.versionMajor, &info.versionMinor);
383 info.name = _T("wxBase");
384
385 return info;
386 }
387
388 #endif // wxUSE_BASE
389
390 #if wxUSE_GUI
391
392 wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
393 {
394 static wxToolkitInfo info;
395
396 info.os = DoGetOSVersion(&info.versionMajor, &info.versionMinor);
397 info.shortName = _T("mac");
398 info.name = _T("wxMac");
399
400 #ifdef __WXUNIVERSAL__
401 info.shortName << _T("univ");
402 info.name << _T("/wxUniversal");
403 #endif
404
405 return info;
406 }
407
408 // Reading and writing resources (eg WIN.INI, .Xdefaults)
409 #if wxUSE_RESOURCES
410 bool wxWriteResource(const wxString& section, const wxString& entry, const wxString& value, const wxString& file)
411 {
412 // TODO
413 return false;
414 }
415
416 bool wxWriteResource(const wxString& section, const wxString& entry, float value, const wxString& file)
417 {
418 wxString buf;
419 buf.Printf(wxT("%.4f"), value);
420
421 return wxWriteResource(section, entry, buf, file);
422 }
423
424 bool wxWriteResource(const wxString& section, const wxString& entry, long value, const wxString& file)
425 {
426 wxString buf;
427 buf.Printf(wxT("%ld"), value);
428
429 return wxWriteResource(section, entry, buf, file);
430 }
431
432 bool wxWriteResource(const wxString& section, const wxString& entry, int value, const wxString& file)
433 {
434 wxString buf;
435 buf.Printf(wxT("%d"), value);
436
437 return wxWriteResource(section, entry, buf, file);
438 }
439
440 bool wxGetResource(const wxString& section, const wxString& entry, char **value, const wxString& file)
441 {
442 // TODO
443 return false;
444 }
445
446 bool wxGetResource(const wxString& section, const wxString& entry, float *value, const wxString& file)
447 {
448 char *s = NULL;
449 bool succ = wxGetResource(section, entry, (char **)&s, file);
450 if (succ)
451 {
452 *value = (float)strtod(s, NULL);
453 delete[] s;
454 }
455
456 return succ;
457 }
458
459 bool wxGetResource(const wxString& section, const wxString& entry, long *value, const wxString& file)
460 {
461 char *s = NULL;
462 bool succ = wxGetResource(section, entry, (char **)&s, file);
463 if (succ)
464 {
465 *value = strtol(s, NULL, 10);
466 delete[] s;
467 }
468
469 return succ;
470 }
471
472 bool wxGetResource(const wxString& section, const wxString& entry, int *value, const wxString& file)
473 {
474 char *s = NULL;
475 bool succ = wxGetResource(section, entry, (char **)&s, file);
476 if (succ)
477 {
478 *value = (int)strtol(s, NULL, 10);
479 delete[] s;
480 }
481
482 return succ;
483 }
484 #endif // wxUSE_RESOURCES
485
486 int gs_wxBusyCursorCount = 0;
487 extern wxCursor gMacCurrentCursor ;
488 wxCursor gMacStoredActiveCursor ;
489
490 // Set the cursor to the busy cursor for all windows
491 void wxBeginBusyCursor(const wxCursor *cursor)
492 {
493 if (gs_wxBusyCursorCount++ == 0)
494 {
495 gMacStoredActiveCursor = gMacCurrentCursor ;
496 cursor->MacInstall() ;
497 }
498 //else: nothing to do, already set
499 }
500
501 // Restore cursor to normal
502 void wxEndBusyCursor()
503 {
504 wxCHECK_RET( gs_wxBusyCursorCount > 0,
505 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
506
507 if (--gs_wxBusyCursorCount == 0)
508 {
509 gMacStoredActiveCursor.MacInstall() ;
510 gMacStoredActiveCursor = wxNullCursor ;
511 }
512 }
513
514 // true if we're between the above two calls
515 bool wxIsBusy()
516 {
517 return (gs_wxBusyCursorCount > 0);
518 }
519
520 #endif // wxUSE_GUI
521
522 #if wxUSE_BASE
523
524 wxString wxMacFindFolderNoSeparator( short vol,
525 OSType folderType,
526 Boolean createFolder)
527 {
528 FSRef fsRef ;
529 wxString strDir ;
530
531 if ( FSFindFolder( vol, folderType, createFolder, &fsRef) == noErr)
532 {
533 strDir = wxMacFSRefToPath( &fsRef );
534 }
535
536 return strDir ;
537 }
538
539 wxString wxMacFindFolder( short vol,
540 OSType folderType,
541 Boolean createFolder)
542 {
543 return wxMacFindFolderNoSeparator(vol, folderType, createFolder) + wxFILE_SEP_PATH;
544 }
545
546 #endif // wxUSE_BASE
547
548 #if wxUSE_GUI
549
550 // Check whether this window wants to process messages, e.g. Stop button
551 // in long calculations.
552 bool wxCheckForInterrupt(wxWindow *wnd)
553 {
554 // TODO
555 return false;
556 }
557
558 void wxGetMousePosition( int* x, int* y )
559 {
560 Point pt ;
561
562 GetMouse( &pt ) ;
563 LocalToGlobal( &pt ) ;
564 *x = pt.h ;
565 *y = pt.v ;
566 };
567
568 // Return true if we have a colour display
569 bool wxColourDisplay()
570 {
571 return true;
572 }
573
574 // Returns depth of screen
575 int wxDisplayDepth()
576 {
577 Rect globRect ;
578 SetRect(&globRect, -32760, -32760, 32760, 32760);
579 GDHandle theMaxDevice;
580
581 int theDepth = 8;
582 theMaxDevice = GetMaxDevice(&globRect);
583 if (theMaxDevice != NULL)
584 theDepth = (**(**theMaxDevice).gdPMap).pixelSize;
585
586 return theDepth ;
587 }
588
589 // Get size of display
590 void wxDisplaySize(int *width, int *height)
591 {
592 BitMap screenBits;
593 GetQDGlobalsScreenBits( &screenBits );
594
595 if (width != NULL)
596 *width = screenBits.bounds.right - screenBits.bounds.left ;
597
598 if (height != NULL)
599 *height = screenBits.bounds.bottom - screenBits.bounds.top ;
600 }
601
602 void wxDisplaySizeMM(int *width, int *height)
603 {
604 wxDisplaySize(width, height);
605 // on mac 72 is fixed (at least now ;-)
606 float cvPt2Mm = 25.4 / 72;
607
608 if (width != NULL)
609 *width = int( *width * cvPt2Mm );
610
611 if (height != NULL)
612 *height = int( *height * cvPt2Mm );
613 }
614
615 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
616 {
617 Rect r ;
618
619 GetAvailableWindowPositioningBounds( GetMainDevice() , &r ) ;
620 if ( x )
621 *x = r.left ;
622 if ( y )
623 *y = r.top ;
624 if ( width )
625 *width = r.right - r.left ;
626 if ( height )
627 *height = r.bottom - r.top ;
628 }
629
630 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
631 {
632 return wxGenericFindWindowAtPoint(pt);
633 }
634
635 #endif // wxUSE_GUI
636
637 #if wxUSE_BASE
638
639 wxString wxGetOsDescription()
640 {
641 #ifdef WXWIN_OS_DESCRIPTION
642 // use configure generated description if available
643 return wxString(wxT("MacOS (")) + wxT(WXWIN_OS_DESCRIPTION) + wxString(wxT(")"));
644 #else
645 return wxT("MacOS") ; //TODO:define further
646 #endif
647 }
648
649 #ifndef __DARWIN__
650 wxChar *wxGetUserHome (const wxString& user)
651 {
652 // TODO
653 return NULL;
654 }
655
656 bool wxGetDiskSpace(const wxString& path, wxDiskspaceSize_t *pTotal, wxDiskspaceSize_t *pFree)
657 {
658 if ( path.empty() )
659 return false;
660
661 wxString p = path ;
662 if (p[0u] == ':' )
663 p = wxGetCwd() + p ;
664
665 int pos = p.Find(':') ;
666 if ( pos != wxNOT_FOUND )
667 p = p.Mid(1,pos) ;
668
669 p = p + wxT(":") ;
670
671 OSErr err = noErr ;
672
673 FSRef fsRef ;
674 err = wxMacPathToFSRef( p , &fsRef ) ;
675 if ( noErr == err )
676 {
677 FSVolumeRefNum vRefNum ;
678 err = FSGetVRefNum( &fsRef , &vRefNum ) ;
679 if ( noErr == err )
680 {
681 UInt64 freeBytes , totalBytes ;
682 err = FSGetVInfo( vRefNum , NULL , &freeBytes , &totalBytes ) ;
683 if ( noErr == err )
684 {
685 if ( pTotal )
686 *pTotal = wxDiskspaceSize_t( totalBytes ) ;
687 if ( pFree )
688 *pFree = wxDiskspaceSize_t( freeBytes ) ;
689 }
690 }
691 }
692
693 return err == noErr ;
694 }
695 #endif // !__DARWIN__
696
697 //---------------------------------------------------------------------------
698 // wxMac Specific utility functions
699 //---------------------------------------------------------------------------
700
701 void wxMacStringToPascal( const wxString&from , StringPtr to )
702 {
703 wxCharBuffer buf = from.mb_str( wxConvLocal ) ;
704 int len = strlen(buf) ;
705
706 if ( len > 255 )
707 len = 255 ;
708 to[0] = len ;
709 memcpy( (char*) &to[1] , buf , len ) ;
710 }
711
712 wxString wxMacMakeStringFromPascal( ConstStringPtr from )
713 {
714 return wxString( (char*) &from[1] , wxConvLocal , from[0] ) ;
715 }
716
717 // ----------------------------------------------------------------------------
718 // Common Event Support
719 // ----------------------------------------------------------------------------
720
721 extern ProcessSerialNumber gAppProcess ;
722
723 void wxMacWakeUp()
724 {
725 ProcessSerialNumber psn ;
726 Boolean isSame ;
727 psn.highLongOfPSN = 0 ;
728 psn.lowLongOfPSN = kCurrentProcess ;
729 SameProcess( &gAppProcess , &psn , &isSame ) ;
730 if ( isSame )
731 {
732 #if TARGET_CARBON
733 OSStatus err = noErr ;
734
735 #if 0
736 // lead sometimes to race conditions, although all calls used should be thread safe ...
737 static wxMacCarbonEvent s_wakeupEvent ;
738 if ( !s_wakeupEvent.IsValid() )
739 {
740 err = s_wakeupEvent.Create( 'WXMC', 'WXMC', GetCurrentEventTime(),
741 kEventAttributeNone ) ;
742 }
743 if ( err == noErr )
744 {
745
746 if ( IsEventInQueue( GetMainEventQueue() , s_wakeupEvent ) )
747 return ;
748 s_wakeupEvent.SetCurrentTime() ;
749 err = PostEventToQueue(GetMainEventQueue(), s_wakeupEvent,
750 kEventPriorityHigh );
751 }
752 #else
753 wxMacCarbonEvent wakeupEvent ;
754 wakeupEvent.Create( 'WXMC', 'WXMC', GetCurrentEventTime(),
755 kEventAttributeNone ) ;
756 err = PostEventToQueue(GetMainEventQueue(), wakeupEvent,
757 kEventPriorityHigh );
758 #endif
759 #else
760 PostEvent( nullEvent , 0 ) ;
761 #endif
762 }
763 else
764 {
765 WakeUpProcess( &gAppProcess ) ;
766 }
767 }
768
769 #endif // wxUSE_BASE
770
771 #if wxUSE_GUI
772
773 // ----------------------------------------------------------------------------
774 // Native Struct Conversions
775 // ----------------------------------------------------------------------------
776
777 void wxMacRectToNative( const wxRect *wx , Rect *n )
778 {
779 n->left = wx->x ;
780 n->top = wx->y ;
781 n->right = wx->x + wx->width ;
782 n->bottom = wx->y + wx->height ;
783 }
784
785 void wxMacNativeToRect( const Rect *n , wxRect* wx )
786 {
787 wx->x = n->left ;
788 wx->y = n->top ;
789 wx->width = n->right - n->left ;
790 wx->height = n->bottom - n->top ;
791 }
792
793 void wxMacPointToNative( const wxPoint* wx , Point *n )
794 {
795 n->h = wx->x ;
796 n->v = wx->y ;
797 }
798
799 void wxMacNativeToPoint( const Point *n , wxPoint* wx )
800 {
801 wx->x = n->h ;
802 wx->y = n->v ;
803 }
804
805 // ----------------------------------------------------------------------------
806 // Carbon Event Support
807 // ----------------------------------------------------------------------------
808
809 OSStatus wxMacCarbonEvent::GetParameter(EventParamName inName, EventParamType inDesiredType, UInt32 inBufferSize, void * outData)
810 {
811 return ::GetEventParameter( m_eventRef , inName , inDesiredType , NULL , inBufferSize , NULL , outData ) ;
812 }
813
814 OSStatus wxMacCarbonEvent::SetParameter(EventParamName inName, EventParamType inType, UInt32 inBufferSize, const void * inData)
815 {
816 return ::SetEventParameter( m_eventRef , inName , inType , inBufferSize , inData ) ;
817 }
818
819 // ----------------------------------------------------------------------------
820 // Control Access Support
821 // ----------------------------------------------------------------------------
822
823 wxMacControl::wxMacControl(wxWindow* peer , bool isRootControl )
824 {
825 Init() ;
826 m_peer = peer ;
827 m_isRootControl = isRootControl ;
828 m_isCompositing = peer->MacGetTopLevelWindow()->MacUsesCompositing() ;
829 }
830
831 wxMacControl::wxMacControl( wxWindow* peer , ControlRef control )
832 {
833 Init() ;
834 m_peer = peer ;
835 m_isCompositing = peer->MacGetTopLevelWindow()->MacUsesCompositing() ;
836 m_controlRef = control ;
837 }
838
839 wxMacControl::wxMacControl( wxWindow* peer , WXWidget control )
840 {
841 Init() ;
842 m_peer = peer ;
843 m_isCompositing = peer->MacGetTopLevelWindow()->MacUsesCompositing() ;
844 m_controlRef = (ControlRef) control ;
845 }
846
847 wxMacControl::~wxMacControl()
848 {
849 }
850
851 void wxMacControl::Init()
852 {
853 m_peer = NULL ;
854 m_controlRef = NULL ;
855 m_needsFocusRect = false ;
856 m_isCompositing = false ;
857 m_isRootControl = false ;
858 }
859
860 void wxMacControl::Dispose()
861 {
862 ::DisposeControl( m_controlRef ) ;
863 m_controlRef = NULL ;
864 }
865
866 void wxMacControl::SetReference( SInt32 data )
867 {
868 SetControlReference( m_controlRef , data ) ;
869 }
870
871 OSStatus wxMacControl::GetData(ControlPartCode inPartCode , ResType inTag , Size inBufferSize , void * inOutBuffer , Size * outActualSize ) const
872 {
873 return ::GetControlData( m_controlRef , inPartCode , inTag , inBufferSize , inOutBuffer , outActualSize ) ;
874 }
875
876 OSStatus wxMacControl::GetDataSize(ControlPartCode inPartCode , ResType inTag , Size * outActualSize ) const
877 {
878 return ::GetControlDataSize( m_controlRef , inPartCode , inTag , outActualSize ) ;
879 }
880
881 OSStatus wxMacControl::SetData(ControlPartCode inPartCode , ResType inTag , Size inSize , const void * inData)
882 {
883 return ::SetControlData( m_controlRef , inPartCode , inTag , inSize , inData ) ;
884 }
885
886 OSStatus wxMacControl::SendEvent( EventRef event , OptionBits inOptions )
887 {
888 #if TARGET_API_MAC_OSX
889 return SendEventToEventTargetWithOptions( event,
890 HIObjectGetEventTarget( (HIObjectRef) m_controlRef ), inOptions );
891 #else
892 #pragma unused(inOptions)
893 return SendEventToEventTarget(event,GetControlEventTarget( m_controlRef ) ) ;
894 #endif
895 }
896
897 OSStatus wxMacControl::SendHICommand( HICommand &command , OptionBits inOptions )
898 {
899 wxMacCarbonEvent event( kEventClassCommand , kEventCommandProcess ) ;
900
901 event.SetParameter<HICommand>(kEventParamDirectObject,command) ;
902
903 return SendEvent( event , inOptions ) ;
904 }
905
906 OSStatus wxMacControl::SendHICommand( UInt32 commandID , OptionBits inOptions )
907 {
908 HICommand command ;
909
910 memset( &command, 0 , sizeof(command) ) ;
911 command.commandID = commandID ;
912 return SendHICommand( command , inOptions ) ;
913 }
914
915 void wxMacControl::Flash( ControlPartCode part , UInt32 ticks )
916 {
917 unsigned long finalTicks ;
918
919 HiliteControl( m_controlRef , part ) ;
920 Delay( ticks , &finalTicks ) ;
921 HiliteControl( m_controlRef , kControlNoPart ) ;
922 }
923
924 SInt32 wxMacControl::GetValue() const
925 {
926 return ::GetControl32BitValue( m_controlRef ) ;
927 }
928
929 SInt32 wxMacControl::GetMaximum() const
930 {
931 return ::GetControl32BitMaximum( m_controlRef ) ;
932 }
933
934 SInt32 wxMacControl::GetMinimum() const
935 {
936 return ::GetControl32BitMinimum( m_controlRef ) ;
937 }
938
939 void wxMacControl::SetValue( SInt32 v )
940 {
941 ::SetControl32BitValue( m_controlRef , v ) ;
942 }
943
944 void wxMacControl::SetMinimum( SInt32 v )
945 {
946 ::SetControl32BitMinimum( m_controlRef , v ) ;
947 }
948
949 void wxMacControl::SetMaximum( SInt32 v )
950 {
951 ::SetControl32BitMaximum( m_controlRef , v ) ;
952 }
953
954 void wxMacControl::SetValueAndRange( SInt32 value , SInt32 minimum , SInt32 maximum )
955 {
956 ::SetControl32BitMinimum( m_controlRef , minimum ) ;
957 ::SetControl32BitMaximum( m_controlRef , maximum ) ;
958 ::SetControl32BitValue( m_controlRef , value ) ;
959 }
960
961 OSStatus wxMacControl::SetFocus( ControlFocusPart focusPart )
962 {
963 return SetKeyboardFocus( GetControlOwner( m_controlRef ), m_controlRef, focusPart ) ;
964 }
965
966 bool wxMacControl::HasFocus() const
967 {
968 ControlRef control ;
969 GetKeyboardFocus( GetUserFocusWindow() , &control ) ;
970 return control == m_controlRef ;
971 }
972
973 void wxMacControl::SetNeedsFocusRect( bool needs )
974 {
975 m_needsFocusRect = needs ;
976 }
977
978 bool wxMacControl::NeedsFocusRect() const
979 {
980 return m_needsFocusRect ;
981 }
982
983 void wxMacControl::VisibilityChanged(bool shown)
984 {
985 }
986
987 void wxMacControl::SuperChangedPosition()
988 {
989 }
990
991 void wxMacControl::SetFont( const wxFont & font , const wxColour& foreground , long windowStyle )
992 {
993 m_font = font ;
994 ControlFontStyleRec fontStyle;
995 if ( font.MacGetThemeFontID() != kThemeCurrentPortFont )
996 {
997 switch ( font.MacGetThemeFontID() )
998 {
999 case kThemeSmallSystemFont :
1000 fontStyle.font = kControlFontSmallSystemFont ;
1001 break ;
1002
1003 case 109 : // mini font
1004 fontStyle.font = -5 ;
1005 break ;
1006
1007 case kThemeSystemFont :
1008 fontStyle.font = kControlFontBigSystemFont ;
1009 break ;
1010
1011 default :
1012 fontStyle.font = kControlFontBigSystemFont ;
1013 break ;
1014 }
1015
1016 fontStyle.flags = kControlUseFontMask ;
1017 }
1018 else
1019 {
1020 fontStyle.font = font.MacGetFontNum() ;
1021 fontStyle.style = font.MacGetFontStyle() ;
1022 fontStyle.size = font.MacGetFontSize() ;
1023 fontStyle.flags = kControlUseFontMask | kControlUseFaceMask | kControlUseSizeMask ;
1024 }
1025
1026 fontStyle.just = teJustLeft ;
1027 fontStyle.flags |= kControlUseJustMask ;
1028 if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_CENTER_HORIZONTAL )
1029 fontStyle.just = teJustCenter ;
1030 else if ( ( windowStyle & wxALIGN_MASK ) & wxALIGN_RIGHT )
1031 fontStyle.just = teJustRight ;
1032
1033
1034 // we only should do this in case of a non-standard color, as otherwise 'disabled' controls
1035 // won't get grayed out by the system anymore
1036
1037 if ( foreground != *wxBLACK )
1038 {
1039 fontStyle.foreColor = MAC_WXCOLORREF( foreground.GetPixel() ) ;
1040 fontStyle.flags |= kControlUseForeColorMask ;
1041 }
1042
1043 ::SetControlFontStyle( m_controlRef , &fontStyle );
1044 }
1045
1046 void wxMacControl::SetBackground( const wxBrush &WXUNUSED(brush) )
1047 {
1048 // TODO
1049 // setting up a color proc is not recommended anymore
1050 }
1051
1052 void wxMacControl::SetRange( SInt32 minimum , SInt32 maximum )
1053 {
1054 ::SetControl32BitMinimum( m_controlRef , minimum ) ;
1055 ::SetControl32BitMaximum( m_controlRef , maximum ) ;
1056 }
1057
1058 short wxMacControl::HandleKey( SInt16 keyCode, SInt16 charCode, EventModifiers modifiers )
1059 {
1060 return HandleControlKey( m_controlRef , keyCode , charCode , modifiers ) ;
1061 }
1062
1063 void wxMacControl::SetActionProc( ControlActionUPP actionProc )
1064 {
1065 SetControlAction( m_controlRef , actionProc ) ;
1066 }
1067
1068 void wxMacControl::SetViewSize( SInt32 viewSize )
1069 {
1070 SetControlViewSize(m_controlRef , viewSize ) ;
1071 }
1072
1073 SInt32 wxMacControl::GetViewSize() const
1074 {
1075 return GetControlViewSize( m_controlRef ) ;
1076 }
1077
1078 bool wxMacControl::IsVisible() const
1079 {
1080 return IsControlVisible( m_controlRef ) ;
1081 }
1082
1083 void wxMacControl::SetVisibility( bool visible , bool redraw )
1084 {
1085 SetControlVisibility( m_controlRef , visible , redraw ) ;
1086 }
1087
1088 bool wxMacControl::IsEnabled() const
1089 {
1090 #if TARGET_API_MAC_OSX
1091 return IsControlEnabled( m_controlRef ) ;
1092 #else
1093 return IsControlActive( m_controlRef ) ;
1094 #endif
1095 }
1096
1097 bool wxMacControl::IsActive() const
1098 {
1099 return IsControlActive( m_controlRef ) ;
1100 }
1101
1102 void wxMacControl::Enable( bool enable )
1103 {
1104 #if TARGET_API_MAC_OSX
1105 if ( enable )
1106 EnableControl( m_controlRef ) ;
1107 else
1108 DisableControl( m_controlRef ) ;
1109 #else
1110 if ( enable )
1111 ActivateControl( m_controlRef ) ;
1112 else
1113 DeactivateControl( m_controlRef ) ;
1114 #endif
1115 }
1116
1117 void wxMacControl::SetDrawingEnabled( bool enable )
1118 {
1119 #if TARGET_API_MAC_OSX
1120 HIViewSetDrawingEnabled( m_controlRef , enable ) ;
1121 #endif
1122 }
1123
1124 #if TARGET_API_MAC_OSX
1125 bool wxMacControl::GetNeedsDisplay() const
1126 {
1127 #if TARGET_API_MAC_OSX
1128 if ( m_isCompositing )
1129 {
1130 return HIViewGetNeedsDisplay( m_controlRef ) ;
1131 }
1132 else
1133 #endif
1134 {
1135 if ( !IsVisible() )
1136 return false ;
1137
1138 Rect controlBounds ;
1139 GetControlBounds( m_controlRef, &controlBounds ) ;
1140 RgnHandle rgn = NewRgn() ;
1141 GetWindowRegion ( GetControlOwner( m_controlRef ) , kWindowUpdateRgn , rgn ) ;
1142 Boolean intersect = RectInRgn ( &controlBounds , rgn ) ;
1143 DisposeRgn( rgn ) ;
1144
1145 return intersect ;
1146 }
1147 }
1148 #endif
1149
1150 void wxMacControl::SetNeedsDisplay( RgnHandle where )
1151 {
1152 if ( !IsVisible() )
1153 return ;
1154
1155 #if TARGET_API_MAC_OSX
1156 if ( m_isCompositing )
1157 {
1158 HIViewSetNeedsDisplayInRegion( m_controlRef , where , true ) ;
1159 }
1160 else
1161 #endif
1162 {
1163 Rect controlBounds ;
1164 GetControlBounds( m_controlRef, &controlBounds ) ;
1165 RgnHandle update = NewRgn() ;
1166 CopyRgn( where , update ) ;
1167 OffsetRgn( update , controlBounds.left , controlBounds.top ) ;
1168 InvalWindowRgn( GetControlOwner( m_controlRef) , update ) ;
1169 }
1170 }
1171
1172 void wxMacControl::SetNeedsDisplay( Rect* where )
1173 {
1174 if ( !IsVisible() )
1175 return ;
1176
1177 #if TARGET_API_MAC_OSX
1178 if ( m_isCompositing )
1179 {
1180 if ( where != NULL )
1181 {
1182 RgnHandle update = NewRgn() ;
1183 RectRgn( update , where ) ;
1184 HIViewSetNeedsDisplayInRegion( m_controlRef , update , true ) ;
1185 DisposeRgn( update ) ;
1186 }
1187 else
1188 HIViewSetNeedsDisplay( m_controlRef , true ) ;
1189 }
1190 else
1191 #endif
1192 {
1193 Rect controlBounds ;
1194
1195 GetControlBounds( m_controlRef, &controlBounds ) ;
1196 if ( where )
1197 {
1198 Rect whereLocal = *where ;
1199 OffsetRect( &whereLocal , controlBounds.left , controlBounds.top ) ;
1200 SectRect( &controlBounds , &whereLocal, &controlBounds ) ;
1201 }
1202
1203 InvalWindowRect( GetControlOwner( m_controlRef) , &controlBounds ) ;
1204 }
1205 }
1206
1207 void wxMacControl::Convert( wxPoint *pt , wxMacControl *from , wxMacControl *to )
1208 {
1209 #if TARGET_API_MAC_OSX
1210 if ( from->m_peer->MacGetTopLevelWindow()->MacUsesCompositing() )
1211 {
1212 HIPoint hiPoint ;
1213
1214 hiPoint.x = pt->x ;
1215 hiPoint.y = pt->y ;
1216 HIViewConvertPoint( &hiPoint , from->m_controlRef , to->m_controlRef ) ;
1217 pt->x = (int)hiPoint.x ;
1218 pt->y = (int)hiPoint.y ;
1219 }
1220 else
1221 #endif
1222 {
1223 Rect fromRect, toRect ;
1224
1225 GetControlBounds( from->m_controlRef , &fromRect ) ;
1226 GetControlBounds( to->m_controlRef , &toRect ) ;
1227 if ( from->m_isRootControl )
1228 fromRect.left = fromRect.top = 0 ;
1229 if ( to->m_isRootControl )
1230 toRect.left = toRect.top = 0 ;
1231
1232 pt->x = pt->x + fromRect.left - toRect.left ;
1233 pt->y = pt->y + fromRect.top - toRect.top ;
1234 }
1235 }
1236
1237 void wxMacControl::SetRect( Rect *r )
1238 {
1239 #if TARGET_API_MAC_OSX
1240 if ( m_isCompositing )
1241 {
1242 //A HIRect is actually a CGRect on OSX - which consists of two structures -
1243 //CGPoint and CGSize, which have two floats each
1244 HIRect hir = { { r->left , r->top }, { r->right - r->left , r->bottom - r->top } } ;
1245 HIViewSetFrame ( m_controlRef , &hir ) ;
1246 // eventuall we might have to do a SetVisibility( false , true ) ;
1247 // before and a SetVisibility( true , true ) ; after
1248 }
1249 else
1250 #endif
1251 {
1252 bool vis = IsVisible() ;
1253 if ( vis )
1254 {
1255 Rect former ;
1256 GetControlBounds( m_controlRef , &former ) ;
1257 InvalWindowRect( GetControlOwner( m_controlRef ) , &former ) ;
1258 }
1259
1260 Rect controlBounds = *r ;
1261
1262 // since the rect passed in is always (even in non-compositing) relative
1263 // to the (native) parent, we have to adjust to window relative here
1264 wxMacControl* parent = m_peer->GetParent()->GetPeer() ;
1265 if ( !parent->m_isRootControl )
1266 {
1267 Rect superRect ;
1268 GetControlBounds( parent->m_controlRef , &superRect ) ;
1269 OffsetRect( &controlBounds , superRect.left , superRect.top ) ;
1270 }
1271
1272 SetControlBounds( m_controlRef , &controlBounds ) ;
1273 if ( vis )
1274 InvalWindowRect( GetControlOwner( m_controlRef ) , &controlBounds ) ;
1275 }
1276 }
1277
1278 void wxMacControl::GetRect( Rect *r )
1279 {
1280 GetControlBounds( m_controlRef , r ) ;
1281 if ( !m_isCompositing )
1282 {
1283 // correct the case of the root control
1284 if ( m_isRootControl )
1285 {
1286 WindowRef wr = GetControlOwner( m_controlRef ) ;
1287 GetWindowBounds( wr , kWindowContentRgn , r ) ;
1288 r->right -= r->left ;
1289 r->bottom -= r->top ;
1290 r->left = 0 ;
1291 r->top = 0 ;
1292 }
1293 else
1294 {
1295 wxMacControl* parent = m_peer->GetParent()->GetPeer() ;
1296 if ( !parent->m_isRootControl )
1297 {
1298 Rect superRect ;
1299 GetControlBounds( parent->m_controlRef , &superRect ) ;
1300 OffsetRect( r , -superRect.left , -superRect.top ) ;
1301 }
1302 }
1303 }
1304 }
1305
1306 void wxMacControl::GetRectInWindowCoords( Rect *r )
1307 {
1308 UMAGetControlBoundsInWindowCoords( m_controlRef , r ) ;
1309 }
1310
1311 void wxMacControl::GetBestRect( Rect *r )
1312 {
1313 short baselineoffset ;
1314
1315 GetBestControlRect( m_controlRef , r , &baselineoffset ) ;
1316 }
1317
1318 void wxMacControl::SetLabel( const wxString &title )
1319 {
1320 wxFontEncoding encoding;
1321
1322 if ( m_font.Ok() )
1323 encoding = m_font.GetEncoding();
1324 else
1325 encoding = wxFont::GetDefaultEncoding();
1326
1327 UMASetControlTitle( m_controlRef , title , encoding ) ;
1328 }
1329
1330 void wxMacControl::GetFeatures( UInt32 * features )
1331 {
1332 GetControlFeatures( m_controlRef , features ) ;
1333 }
1334
1335 OSStatus wxMacControl::GetRegion( ControlPartCode partCode , RgnHandle region )
1336 {
1337 OSStatus err = GetControlRegion( m_controlRef , partCode , region ) ;
1338 if ( !m_isCompositing )
1339 {
1340 if ( !m_isRootControl )
1341 {
1342 Rect r ;
1343
1344 GetControlBounds(m_controlRef, &r ) ;
1345 if ( !EmptyRgn( region ) )
1346 OffsetRgn( region , -r.left , -r.top ) ;
1347 }
1348 }
1349
1350 return err ;
1351 }
1352
1353 OSStatus wxMacControl::SetZOrder( bool above , wxMacControl* other )
1354 {
1355 #if TARGET_API_MAC_OSX
1356 return HIViewSetZOrder( m_controlRef,above ? kHIViewZOrderAbove : kHIViewZOrderBelow,
1357 (other != NULL) ? other->m_controlRef : NULL) ;
1358 #else
1359 return 0 ;
1360 #endif
1361 }
1362
1363 #if TARGET_API_MAC_OSX
1364 // SetNeedsDisplay would not invalidate the children
1365 static void InvalidateControlAndChildren( HIViewRef control )
1366 {
1367 HIViewSetNeedsDisplay( control , true ) ;
1368 UInt16 childrenCount = 0 ;
1369 OSStatus err = CountSubControls( control , &childrenCount ) ;
1370 if ( err == errControlIsNotEmbedder )
1371 return ;
1372
1373 wxASSERT_MSG( err == noErr , wxT("Unexpected error when accessing subcontrols") ) ;
1374
1375 for ( UInt16 i = childrenCount ; i >=1 ; --i )
1376 {
1377 HIViewRef child ;
1378
1379 err = GetIndexedSubControl( control , i , & child ) ;
1380 if ( err == errControlIsNotEmbedder )
1381 return ;
1382
1383 InvalidateControlAndChildren( child ) ;
1384 }
1385 }
1386 #endif
1387
1388 void wxMacControl::InvalidateWithChildren()
1389 {
1390 #if TARGET_API_MAC_OSX
1391 InvalidateControlAndChildren( m_controlRef ) ;
1392 #endif
1393 }
1394
1395 void wxMacControl::ScrollRect( wxRect *r , int dx , int dy )
1396 {
1397 wxASSERT( r != NULL ) ;
1398
1399 #if TARGET_API_MAC_OSX
1400 if ( m_isCompositing )
1401 {
1402 HIRect scrollarea = CGRectMake( r->x , r->y , r->width , r->height) ;
1403 HIViewScrollRect ( m_controlRef , &scrollarea , dx ,dy ) ;
1404 }
1405 else
1406 #endif
1407 {
1408 Rect bounds ;
1409
1410 GetControlBounds( m_controlRef , &bounds ) ;
1411 bounds.left += r->x ;
1412 bounds.top += r->y ;
1413 bounds.bottom = bounds.top + r->height ;
1414 bounds.right = bounds.left + r->width ;
1415 wxMacWindowClipper clip( m_peer ) ;
1416 RgnHandle updateRgn = NewRgn() ;
1417 ::ScrollRect( &bounds , dx , dy , updateRgn ) ;
1418 InvalWindowRgn( GetControlOwner( m_controlRef ) , updateRgn ) ;
1419 DisposeRgn( updateRgn );
1420 }
1421 }
1422
1423 //
1424 // Tab Control
1425 //
1426
1427 OSStatus wxMacControl::SetTabEnabled( SInt16 tabNo , bool enable )
1428 {
1429 return ::SetTabEnabled( m_controlRef , tabNo , enable ) ;
1430 }
1431
1432 //
1433 // Quartz Support
1434 //
1435
1436 #ifdef __WXMAC_OSX__
1437 // snippets from Sketch Sample from Apple :
1438
1439 #define kGenericRGBProfilePathStr "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc"
1440
1441 /*
1442 This function locates, opens, and returns the profile reference for the calibrated
1443 Generic RGB color space. It is up to the caller to call CMCloseProfile when done
1444 with the profile reference this function returns.
1445 */
1446 CMProfileRef wxMacOpenGenericProfile()
1447 {
1448 static CMProfileRef cachedRGBProfileRef = NULL;
1449
1450 // we only create the profile reference once
1451 if (cachedRGBProfileRef == NULL)
1452 {
1453 CMProfileLocation loc;
1454
1455 loc.locType = cmPathBasedProfile;
1456 strcpy(loc.u.pathLoc.path, kGenericRGBProfilePathStr);
1457
1458 verify_noerr( CMOpenProfile(&cachedRGBProfileRef, &loc) );
1459 }
1460
1461 // clone the profile reference so that the caller has their own reference, not our cached one
1462 if (cachedRGBProfileRef)
1463 CMCloneProfileRef(cachedRGBProfileRef);
1464
1465 return cachedRGBProfileRef;
1466 }
1467
1468 /*
1469 Return the generic RGB color space. This is a 'get' function and the caller should
1470 not release the returned value unless the caller retains it first. Usually callers
1471 of this routine will immediately use the returned colorspace with CoreGraphics
1472 so they typically do not need to retain it themselves.
1473
1474 This function creates the generic RGB color space once and hangs onto it so it can
1475 return it whenever this function is called.
1476 */
1477
1478 CGColorSpaceRef wxMacGetGenericRGBColorSpace()
1479 {
1480 static wxMacCFRefHolder<CGColorSpaceRef> genericRGBColorSpace ;
1481
1482 if (genericRGBColorSpace == NULL)
1483 {
1484 if ( UMAGetSystemVersion() >= 0x1040 )
1485 {
1486 genericRGBColorSpace.Set( CGColorSpaceCreateWithName( CFSTR("kCGColorSpaceGenericRGB") ) ) ;
1487 }
1488 else
1489 {
1490 CMProfileRef genericRGBProfile = wxMacOpenGenericProfile();
1491
1492 if (genericRGBProfile)
1493 {
1494 genericRGBColorSpace.Set( CGColorSpaceCreateWithPlatformColorSpace(genericRGBProfile) ) ;
1495
1496 wxASSERT_MSG( genericRGBColorSpace != NULL, wxT("couldn't create the generic RGB color space") ) ;
1497
1498 // we opened the profile so it is up to us to close it
1499 CMCloseProfile(genericRGBProfile);
1500 }
1501 }
1502 }
1503
1504 return genericRGBColorSpace;
1505 }
1506 #endif
1507
1508 wxMacPortSaver::wxMacPortSaver( GrafPtr port )
1509 {
1510 ::GetPort( &m_port ) ;
1511 ::SetPort( port ) ;
1512 }
1513
1514 wxMacPortSaver::~wxMacPortSaver()
1515 {
1516 ::SetPort( m_port ) ;
1517 }
1518
1519 #endif // wxUSE_GUI