1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/mac/carbon/dcclient.cpp
3// Purpose:     wxClientDC class
4// Author:      Stefan Csomor
5// Modified by:
6// Created:     01/02/97
7// RCS-ID:      $Id: dcclient.cpp 53969 2008-06-04 04:35:11Z SC $
8// Copyright:   (c) Stefan Csomor
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#include "wx/dcclient.h"
15
16#ifndef WX_PRECOMP
17    #include "wx/log.h"
18    #include "wx/window.h"
19    #include "wx/dcmemory.h"
20    #include "wx/settings.h"
21    #include "wx/toplevel.h"
22    #include "wx/math.h"
23    #include "wx/region.h"
24#endif
25
26#include "wx/graphics.h"
27#include "wx/rawbmp.h"
28#include "wx/mac/private.h"
29
30//-----------------------------------------------------------------------------
31// constants
32//-----------------------------------------------------------------------------
33
34//-----------------------------------------------------------------------------
35// wxPaintDC
36//-----------------------------------------------------------------------------
37
38IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
39IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
40IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
41
42/*
43 * wxWindowDC
44 */
45
46#include "wx/mac/uma.h"
47#include "wx/notebook.h"
48#include "wx/tabctrl.h"
49
50
51static wxBrush MacGetBackgroundBrush( wxWindow* window )
52{
53    wxBrush bkdBrush = window->MacGetBackgroundBrush() ;
54
55#if !TARGET_API_MAC_OSX
56    // transparency cannot be handled by the OS when not using composited windows
57    wxWindow* parent = window->GetParent() ;
58
59    // if we have some 'pseudo' transparency
60    if ( ! bkdBrush.Ok() || bkdBrush.GetStyle() == wxTRANSPARENT || window->GetBackgroundColour() == wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE ) )
61    {
62        // walk up until we find something
63        while ( parent != NULL )
64        {
65            if ( parent->GetBackgroundColour() != wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE ) )
66            {
67                // if we have any other colours in the hierarchy
68                bkdBrush.SetColour( parent->GetBackgroundColour() ) ;
69                break ;
70            }
71
72            if ( parent->IsKindOf( CLASSINFO(wxTopLevelWindow) ) )
73            {
74                bkdBrush = parent->MacGetBackgroundBrush() ;
75                break ;
76            }
77
78            if ( parent->IsKindOf( CLASSINFO( wxNotebook ) )
79#if wxUSE_TAB_DIALOG
80                 || parent->IsKindOf( CLASSINFO( wxTabCtrl ) )
81#endif // wxUSE_TAB_DIALOG
82                )
83            {
84                Rect extent = { 0 , 0 , 0 , 0 } ;
85                int x , y ;
86                x = y = 0 ;
87                wxSize size = parent->GetSize() ;
88                parent->MacClientToRootWindow( &x , &y ) ;
89                extent.left = x ;
90                extent.top = y ;
91                extent.top-- ;
92                extent.right = x + size.x ;
93                extent.bottom = y + size.y ;
94                bkdBrush.MacSetThemeBackground( kThemeBackgroundTabPane , (WXRECTPTR) &extent ) ;
95                break ;
96            }
97
98            parent = parent->GetParent() ;
99        }
100    }
101
102    if ( !bkdBrush.Ok() || bkdBrush.GetStyle() == wxTRANSPARENT )
103    {
104        // if we did not find something, use a default
105        bkdBrush.MacSetTheme( kThemeBrushDialogBackgroundActive ) ;
106    }
107#endif
108
109    return bkdBrush ;
110}
111
112wxWindowDC::wxWindowDC()
113{
114    m_window = NULL ;
115#if wxMAC_USE_CORE_GRAPHICS
116    m_release = false;
117#endif
118}
119
120wxWindowDC::wxWindowDC(wxWindow *window)
121{
122    m_window = window ;
123    WindowRef rootwindow = (WindowRef) window->MacGetTopLevelWindowRef() ;
124    if (!rootwindow)
125        return;
126
127    m_ok = true ;
128
129#if wxMAC_USE_CORE_GRAPHICS
130    m_window->GetSize( &m_width , &m_height);
131    if ( !m_window->IsShownOnScreen() )
132        m_width = m_height = 0;
133
134    CGContextRef cg = (CGContextRef) window->MacGetCGContextRef();
135    m_release = false;
136    if ( cg == NULL )
137    {
138        SetGraphicsContext( wxGraphicsContext::Create( window ) ) ;
139    }
140    else
141    {
142        CGContextSaveGState( cg );
143        m_release = true ;
144        // make sure the context is having its origin at the wx-window coordinates of the
145        // view (read at the top of window.cpp about the differences)
146        if ( window->MacGetLeftBorderSize() != 0 || window->MacGetTopBorderSize() != 0 )
147            CGContextTranslateCTM( cg , -window->MacGetLeftBorderSize() , -window->MacGetTopBorderSize() );
148
149        SetGraphicsContext( wxGraphicsContext::CreateFromNative( cg ) );
150    }
151    SetClippingRegion( 0 , 0 , m_width , m_height ) ;
152#else
153    int x , y ;
154    x = y = 0 ;
155    window->MacWindowToRootWindow( &x , &y ) ;
156    m_macLocalOrigin.x = x ;
157    m_macLocalOrigin.y = y ;
158    m_macPort = UMAGetWindowPort( rootwindow ) ;
159
160    CopyRgn( (RgnHandle) window->MacGetVisibleRegion(true).GetWXHRGN() , (RgnHandle) m_macBoundaryClipRgn ) ;
161    OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , m_macLocalOrigin.x , m_macLocalOrigin.y ) ;
162    CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
163#endif
164    SetBackground(MacGetBackgroundBrush(window));
165
166    SetFont( window->GetFont() ) ;
167}
168
169wxWindowDC::~wxWindowDC()
170{
171#if wxMAC_USE_CORE_GRAPHICS
172    if ( m_release )
173    {
174        // this must not necessarily be the current context, we must restore the state of the
175        // cg we started with above (before the CGContextTranslateCTM call)
176        CGContextRef cg = (CGContextRef) m_window->MacGetCGContextRef();
177        CGContextRestoreGState(cg);
178    }
179#endif
180}
181
182void wxWindowDC::DoGetSize( int* width, int* height ) const
183{
184#if wxMAC_USE_CORE_GRAPHICS
185    if ( width )
186        *width = m_width;
187    if ( height )
188        *height = m_height;
189#else
190    wxCHECK_RET( m_window, _T("GetSize() doesn't work without window") );
191    m_window->GetSize(width, height);
192#endif
193}
194
195wxBitmap wxWindowDC::DoGetAsBitmap(const wxRect *subrect) const
196{
197#if wxMAC_USE_CORE_GRAPHICS
198    if (!m_window)
199        return wxNullBitmap;
200
201    ControlRef handle = (ControlRef) m_window->GetHandle();
202    if ( !handle )
203        return wxNullBitmap;
204
205    HIRect rect;
206    CGImageRef image;
207    CGContextRef context;
208    void* data;
209
210    size_t bytesPerRow;
211
212    HIViewCreateOffscreenImage( handle, 0, &rect, &image);
213
214    int width = subrect != NULL ? subrect->width : (int)rect.size.width;
215    int height = subrect !=  NULL ? subrect->height : (int)rect.size.height ;
216
217    wxBitmap bmp = wxBitmap(width, height, 32);
218
219    context = (CGContextRef)bmp.GetHBITMAP();
220
221    CGContextSaveGState(context);
222
223    CGContextTranslateCTM( context, 0,  height );
224    CGContextScaleCTM( context, 1, -1 );
225
226    if ( subrect )
227        rect = CGRectOffset( rect, -subrect->x, -subrect->y ) ;
228    CGContextDrawImage( context, rect, image );
229
230    CGContextRestoreGState(context);
231
232    return bmp;
233#else
234    return wxNullBitmap;
235#endif
236}
237
238/*
239 * wxClientDC
240 */
241
242wxClientDC::wxClientDC()
243{
244    m_window = NULL ;
245}
246
247#if wxMAC_USE_CORE_GRAPHICS
248wxClientDC::wxClientDC(wxWindow *window) :
249    wxWindowDC( window )
250{
251    wxCHECK_RET( window, _T("invalid window in wxClientDC") );
252    wxPoint origin = window->GetClientAreaOrigin() ;
253    m_window->GetClientSize( &m_width , &m_height);
254    if ( !m_window->IsShownOnScreen() )
255        m_width = m_height = 0;
256    SetDeviceOrigin( origin.x, origin.y );
257    SetClippingRegion( 0 , 0 , m_width , m_height ) ;
258}
259#else
260wxClientDC::wxClientDC(wxWindow *window)
261{
262    wxCHECK_RET( window, _T("invalid window in wxClientDC") );
263    m_window = window ;
264    wxTopLevelWindowMac* rootwindow = window->MacGetTopLevelWindow() ;
265    if (!rootwindow)
266        return;
267
268    WindowRef windowref = (WindowRef) rootwindow->MacGetWindowRef() ;
269    wxPoint origin = window->GetClientAreaOrigin() ;
270    wxSize size = window->GetClientSize() ;
271    int x , y ;
272    x = origin.x ;
273    y = origin.y ;
274    window->MacWindowToRootWindow( &x , &y ) ;
275    m_macPort = UMAGetWindowPort( windowref ) ;
276    m_ok = true ;
277
278    m_macLocalOrigin.x = x ;
279    m_macLocalOrigin.y = y ;
280    SetRectRgn( (RgnHandle) m_macBoundaryClipRgn , origin.x , origin.y , origin.x + size.x , origin.y + size.y ) ;
281    SectRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) window->MacGetVisibleRegion().GetWXHRGN() , (RgnHandle) m_macBoundaryClipRgn ) ;
282    OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , -origin.x , -origin.y ) ;
283    OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , m_macLocalOrigin.x , m_macLocalOrigin.y ) ;
284    CopyRgn( (RgnHandle) m_macBoundaryClipRgn ,(RgnHandle)  m_macCurrentClipRgn ) ;
285
286    SetBackground(MacGetBackgroundBrush(window));
287    SetFont( window->GetFont() ) ;
288}
289#endif
290
291wxClientDC::~wxClientDC()
292{
293}
294
295#if !wxMAC_USE_CORE_GRAPHICS
296void wxClientDC::DoGetSize(int *width, int *height) const
297{
298    wxCHECK_RET( m_window, _T("GetSize() doesn't work without window") );
299
300    m_window->GetClientSize( width, height );
301}
302#endif
303
304/*
305 * wxPaintDC
306 */
307
308wxPaintDC::wxPaintDC()
309{
310    m_window = NULL ;
311}
312
313#if wxMAC_USE_CORE_GRAPHICS
314wxPaintDC::wxPaintDC(wxWindow *window) :
315    wxWindowDC( window )
316{
317    wxPoint origin = window->GetClientAreaOrigin() ;
318    m_window->GetClientSize( &m_width , &m_height);
319    SetDeviceOrigin( origin.x, origin.y );
320    SetClippingRegion( 0 , 0 , m_width , m_height ) ;
321}
322#else
323wxPaintDC::wxPaintDC(wxWindow *window)
324{
325    m_window = window ;
326    wxTopLevelWindowMac* rootwindow = window->MacGetTopLevelWindow() ;
327    WindowRef windowref = (WindowRef) rootwindow->MacGetWindowRef() ;
328    wxPoint origin = window->GetClientAreaOrigin() ;
329    wxSize size = window->GetClientSize() ;
330    int x , y ;
331    x = origin.x ;
332    y = origin.y ;
333    window->MacWindowToRootWindow( &x , &y ) ;
334    m_macPort = UMAGetWindowPort( windowref ) ;
335    m_ok = true ;
336
337#if wxMAC_USE_CORE_GRAPHICS
338    if ( window->MacGetCGContextRef() )
339    {
340        m_graphicContext = new wxMacCGContext( (CGContextRef) window->MacGetCGContextRef() ) ;
341        m_graphicContext->SetPen( m_pen ) ;
342        m_graphicContext->SetBrush( m_brush ) ;
343        SetClippingRegion( 0 , 0 , size.x , size.y ) ;
344        SetBackground(MacGetBackgroundBrush(window));
345    }
346    else
347    {
348        wxLogDebug(wxT("You cannot create a wxPaintDC outside an OS-draw event") ) ;
349        m_graphicContext = NULL ;
350    }
351    // there is no out-of-order drawing on OSX
352#else
353    m_macLocalOrigin.x = x ;
354    m_macLocalOrigin.y = y ;
355    SetRectRgn( (RgnHandle) m_macBoundaryClipRgn , origin.x , origin.y , origin.x + size.x , origin.y + size.y ) ;
356    SectRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) window->MacGetVisibleRegion().GetWXHRGN() , (RgnHandle) m_macBoundaryClipRgn ) ;
357    OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , -origin.x , -origin.y ) ;
358    SectRgn( (RgnHandle) m_macBoundaryClipRgn  , (RgnHandle) window->GetUpdateRegion().GetWXHRGN() , (RgnHandle) m_macBoundaryClipRgn ) ;
359    OffsetRgn( (RgnHandle) m_macBoundaryClipRgn , m_macLocalOrigin.x , m_macLocalOrigin.y ) ;
360    CopyRgn( (RgnHandle) m_macBoundaryClipRgn , (RgnHandle) m_macCurrentClipRgn ) ;
361    SetBackground(MacGetBackgroundBrush(window));
362#endif
363
364    SetFont( window->GetFont() ) ;
365}
366#endif
367
368wxPaintDC::~wxPaintDC()
369{
370}
371
372#if !wxMAC_USE_CORE_GRAPHICS
373void wxPaintDC::DoGetSize(int *width, int *height) const
374{
375    wxCHECK_RET( m_window, _T("GetSize() doesn't work without window") );
376
377    m_window->GetClientSize( width, height );
378}
379#endif
380