1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/x11/window.cpp
3// Purpose:     wxWindow
4// Author:      Julian Smart
5// Modified by:
6// Created:     17/09/98
7// RCS-ID:      $Id: window.cpp 51785 2008-02-14 11:11:48Z JS $
8// Copyright:   (c) Julian Smart
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// for compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#if defined(__BORLANDC__)
16    #pragma hdrstop
17#endif
18
19// ============================================================================
20// declarations
21// ============================================================================
22
23// ----------------------------------------------------------------------------
24// headers
25// ----------------------------------------------------------------------------
26
27#include "wx/window.h"
28
29#ifndef WX_PRECOMP
30    #include "wx/hash.h"
31    #include "wx/log.h"
32    #include "wx/app.h"
33    #include "wx/utils.h"
34    #include "wx/panel.h"
35    #include "wx/frame.h"
36    #include "wx/dc.h"
37    #include "wx/dcclient.h"
38    #include "wx/button.h"
39    #include "wx/menu.h"
40    #include "wx/dialog.h"
41    #include "wx/timer.h"
42    #include "wx/settings.h"
43    #include "wx/msgdlg.h"
44    #include "wx/scrolbar.h"
45    #include "wx/listbox.h"
46    #include "wx/scrolwin.h"
47    #include "wx/layout.h"
48    #include "wx/menuitem.h"
49    #include "wx/module.h"
50#endif
51
52#include "wx/fontutil.h"
53#include "wx/univ/renderer.h"
54
55#if  wxUSE_DRAG_AND_DROP
56    #include "wx/dnd.h"
57#endif
58
59#include "wx/x11/private.h"
60#include "X11/Xutil.h"
61
62#include <string.h>
63
64// ----------------------------------------------------------------------------
65// global variables for this module
66// ----------------------------------------------------------------------------
67
68static wxWindow* g_captureWindow = NULL;
69static GC g_eraseGC;
70
71// ----------------------------------------------------------------------------
72// macros
73// ----------------------------------------------------------------------------
74
75#define event_left_is_down(x) ((x)->xbutton.state & Button1Mask)
76#define event_middle_is_down(x) ((x)->xbutton.state & Button2Mask)
77#define event_right_is_down(x) ((x)->xbutton.state & Button3Mask)
78
79// ----------------------------------------------------------------------------
80// event tables
81// ----------------------------------------------------------------------------
82
83IMPLEMENT_ABSTRACT_CLASS(wxWindowX11, wxWindowBase)
84
85BEGIN_EVENT_TABLE(wxWindowX11, wxWindowBase)
86    EVT_SYS_COLOUR_CHANGED(wxWindowX11::OnSysColourChanged)
87END_EVENT_TABLE()
88
89// ============================================================================
90// implementation
91// ============================================================================
92
93// ----------------------------------------------------------------------------
94// helper functions
95// ----------------------------------------------------------------------------
96
97// ----------------------------------------------------------------------------
98// constructors
99// ----------------------------------------------------------------------------
100
101void wxWindowX11::Init()
102{
103    // X11-specific
104    m_mainWindow = (WXWindow) 0;
105    m_clientWindow = (WXWindow) 0;
106    m_insertIntoMain = false;
107    m_updateNcArea = false;
108
109    m_winCaptured = false;
110    m_needsInputFocus = false;
111    m_isShown = true;
112    m_lastTS = 0;
113    m_lastButton = 0;
114}
115
116// real construction (Init() must have been called before!)
117bool wxWindowX11::Create(wxWindow *parent, wxWindowID id,
118                         const wxPoint& pos,
119                         const wxSize& size,
120                         long style,
121                         const wxString& name)
122{
123    wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
124
125    CreateBase(parent, id, pos, size, style, wxDefaultValidator, name);
126
127    parent->AddChild(this);
128
129    Display *xdisplay = (Display*) wxGlobalDisplay();
130    int xscreen = DefaultScreen( xdisplay );
131    Visual *xvisual = DefaultVisual( xdisplay, xscreen );
132    Colormap cm = DefaultColormap( xdisplay, xscreen );
133
134    m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
135    m_backgroundColour.CalcPixel( (WXColormap) cm );
136
137    m_foregroundColour = *wxBLACK;
138    m_foregroundColour.CalcPixel( (WXColormap) cm );
139
140    Window xparent = (Window) parent->GetClientAreaWindow();
141
142    // Add window's own scrollbars to main window, not to client window
143    if (parent->GetInsertIntoMain())
144    {
145        // wxLogDebug( "Inserted into main: %s", GetName().c_str() );
146        xparent = (Window) parent->GetMainWindow();
147    }
148
149    // Size (not including the border) must be nonzero (or a Value error results)!
150    // Note: The Xlib manual doesn't mention this restriction of XCreateWindow.
151    wxSize size2(size);
152    if (size2.x <= 0)
153        size2.x = 20;
154    if (size2.y <= 0)
155        size2.y = 20;
156
157    wxPoint pos2(pos);
158    if (pos2.x == wxDefaultCoord)
159        pos2.x = 0;
160    if (pos2.y == wxDefaultCoord)
161        pos2.y = 0;
162
163    AdjustForParentClientOrigin(pos2.x, pos2.y);
164
165#if wxUSE_TWO_WINDOWS
166    bool need_two_windows =
167        ((( wxSUNKEN_BORDER | wxRAISED_BORDER | wxSIMPLE_BORDER | wxHSCROLL | wxVSCROLL ) & m_windowStyle) != 0);
168#else
169    bool need_two_windows = false;
170#endif
171
172#if wxUSE_NANOX
173    long xattributes = 0;
174#else
175    XSetWindowAttributes xattributes;
176    long xattributes_mask = 0;
177
178    xattributes_mask |= CWBackPixel;
179    xattributes.background_pixel = m_backgroundColour.GetPixel();
180
181    xattributes_mask |= CWBorderPixel;
182    xattributes.border_pixel = BlackPixel( xdisplay, xscreen );
183
184    xattributes_mask |= CWEventMask;
185#endif
186
187    if (need_two_windows)
188    {
189#if wxUSE_NANOX
190        long backColor, foreColor;
191        backColor = GR_RGB(m_backgroundColour.Red(), m_backgroundColour.Green(), m_backgroundColour.Blue());
192        foreColor = GR_RGB(m_foregroundColour.Red(), m_foregroundColour.Green(), m_foregroundColour.Blue());
193
194        Window xwindow = XCreateWindowWithColor( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
195                                    0, 0, InputOutput, xvisual, backColor, foreColor);
196        XSelectInput( xdisplay, xwindow,
197          GR_EVENT_MASK_CLOSE_REQ | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
198          ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
199          KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
200                      PropertyChangeMask );
201
202#else
203        // Normal X11
204        xattributes.event_mask =
205            ExposureMask | StructureNotifyMask | ColormapChangeMask;
206
207        Window xwindow = XCreateWindow( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
208            0, DefaultDepth(xdisplay,xscreen), InputOutput, xvisual, xattributes_mask, &xattributes );
209
210#endif
211
212        XSetWindowBackgroundPixmap( xdisplay, xwindow, None );
213
214        m_mainWindow = (WXWindow) xwindow;
215        wxAddWindowToTable( xwindow, (wxWindow*) this );
216
217        XMapWindow( xdisplay, xwindow );
218
219#if !wxUSE_NANOX
220        xattributes.event_mask =
221            ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
222            ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
223            KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
224            PropertyChangeMask | VisibilityChangeMask ;
225
226        if (!HasFlag( wxFULL_REPAINT_ON_RESIZE ))
227        {
228            xattributes_mask |= CWBitGravity;
229            xattributes.bit_gravity = StaticGravity;
230        }
231#endif
232
233        if (HasFlag( wxSUNKEN_BORDER) || HasFlag( wxRAISED_BORDER))
234        {
235            pos2.x = 2;
236            pos2.y = 2;
237            size2.x -= 4;
238            size2.y -= 4;
239        }
240        else if (HasFlag( wxSIMPLE_BORDER ))
241        {
242            pos2.x = 1;
243            pos2.y = 1;
244            size2.x -= 2;
245            size2.y -= 2;
246        }
247        else
248        {
249            pos2.x = 0;
250            pos2.y = 0;
251        }
252
253        // Make again sure the size is nonzero.
254        if (size2.x <= 0)
255            size2.x = 1;
256        if (size2.y <= 0)
257            size2.y = 1;
258
259#if wxUSE_NANOX
260        backColor = GR_RGB(m_backgroundColour.Red(), m_backgroundColour.Green(), m_backgroundColour.Blue());
261        foreColor = GR_RGB(m_foregroundColour.Red(), m_foregroundColour.Green(), m_foregroundColour.Blue());
262
263        xwindow = XCreateWindowWithColor( xdisplay, xwindow, pos2.x, pos2.y, size2.x, size2.y,
264                                    0, 0, InputOutput, xvisual, backColor, foreColor);
265        XSelectInput( xdisplay, xwindow,
266          GR_EVENT_MASK_CLOSE_REQ | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
267          ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
268          KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
269                      PropertyChangeMask );
270
271#else
272        xwindow = XCreateWindow( xdisplay, xwindow, pos2.x, pos2.y, size2.x, size2.y,
273            0, DefaultDepth(xdisplay,xscreen), InputOutput, xvisual, xattributes_mask, &xattributes );
274#endif
275
276        XSetWindowBackgroundPixmap( xdisplay, xwindow, None );
277
278        m_clientWindow = (WXWindow) xwindow;
279        wxAddClientWindowToTable( xwindow, (wxWindow*) this );
280
281        XMapWindow( xdisplay, xwindow );
282    }
283    else
284    {
285        // wxLogDebug( "No two windows needed %s", GetName().c_str() );
286#if wxUSE_NANOX
287        long backColor, foreColor;
288        backColor = GR_RGB(m_backgroundColour.Red(), m_backgroundColour.Green(), m_backgroundColour.Blue());
289        foreColor = GR_RGB(m_foregroundColour.Red(), m_foregroundColour.Green(), m_foregroundColour.Blue());
290
291        Window xwindow = XCreateWindowWithColor( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
292                                    0, 0, InputOutput, xvisual, backColor, foreColor);
293        XSelectInput( xdisplay, xwindow,
294          GR_EVENT_MASK_CLOSE_REQ | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
295          ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
296          KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
297                      PropertyChangeMask );
298
299#else
300        xattributes.event_mask =
301            ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
302            ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
303            KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
304            PropertyChangeMask | VisibilityChangeMask ;
305
306        if (!HasFlag( wxFULL_REPAINT_ON_RESIZE ))
307        {
308            xattributes_mask |= CWBitGravity;
309            xattributes.bit_gravity = NorthWestGravity;
310        }
311
312        Window xwindow = XCreateWindow( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
313            0, DefaultDepth(xdisplay,xscreen), InputOutput, xvisual, xattributes_mask, &xattributes );
314#endif
315
316        XSetWindowBackgroundPixmap( xdisplay, xwindow, None );
317
318        m_mainWindow = (WXWindow) xwindow;
319        m_clientWindow = m_mainWindow;
320        wxAddWindowToTable( xwindow, (wxWindow*) this );
321
322        XMapWindow( xdisplay, xwindow );
323    }
324
325    // Is a subwindow, so map immediately
326    m_isShown = true;
327
328    // Without this, the cursor may not be restored properly (e.g. in splitter
329    // sample).
330    SetCursor(*wxSTANDARD_CURSOR);
331    SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
332
333    // Don't call this, it can have nasty repercussions for composite controls,
334    // for example
335    //    SetSize(pos.x, pos.y, size.x, size.y);
336
337    return true;
338}
339
340// Destructor
341wxWindowX11::~wxWindowX11()
342{
343    SendDestroyEvent();
344
345    if (g_captureWindow == this)
346        g_captureWindow = NULL;
347
348    m_isBeingDeleted = true;
349
350    DestroyChildren();
351
352    if (m_clientWindow != m_mainWindow)
353    {
354        // Destroy the cleint window
355        Window xwindow = (Window) m_clientWindow;
356        wxDeleteClientWindowFromTable( xwindow );
357        XDestroyWindow( wxGlobalDisplay(), xwindow );
358        m_clientWindow = NULL;
359    }
360
361    // Destroy the window
362    if ( m_mainWindow )
363    {
364        Window xwindow = (Window) m_mainWindow;
365        wxDeleteWindowFromTable( xwindow );
366        XDestroyWindow( wxGlobalDisplay(), xwindow );
367        m_mainWindow = NULL;
368    }
369}
370
371// ---------------------------------------------------------------------------
372// basic operations
373// ---------------------------------------------------------------------------
374
375void wxWindowX11::SetFocus()
376{
377    Window xwindow = (Window) m_clientWindow;
378
379    wxCHECK_RET( xwindow, wxT("invalid window") );
380
381    // Don't assert; we might be trying to set the focus for a panel
382    // with only static controls, so the panel returns false from AcceptsFocus.
383    // The app should be not be expected to deal with this.
384    if (!AcceptsFocus())
385        return;
386
387#if 0
388    if (GetName() == "scrollBar")
389    {
390        char *crash = NULL;
391        *crash = 0;
392    }
393#endif
394
395    if (wxWindowIsVisible(xwindow))
396    {
397        wxLogTrace( _T("focus"), _T("wxWindowX11::SetFocus: %s"), GetClassInfo()->GetClassName());
398        //        XSetInputFocus( wxGlobalDisplay(), xwindow, RevertToParent, CurrentTime );
399        XSetInputFocus( wxGlobalDisplay(), xwindow, RevertToNone, CurrentTime );
400        m_needsInputFocus = false;
401    }
402    else
403    {
404        m_needsInputFocus = true;
405    }
406}
407
408// Get the window with the focus
409wxWindow *wxWindowBase::DoFindFocus()
410{
411    Window xfocus = (Window) 0;
412    int revert = 0;
413
414    XGetInputFocus( wxGlobalDisplay(), &xfocus, &revert);
415    if (xfocus)
416    {
417        wxWindow *win = wxGetWindowFromTable( xfocus );
418        if (!win)
419        {
420            win = wxGetClientWindowFromTable( xfocus );
421        }
422
423        return win;
424    }
425
426    return NULL;
427}
428
429// Enabling/disabling handled by event loop, and not sending events
430// if disabled.
431bool wxWindowX11::Enable(bool enable)
432{
433    if ( !wxWindowBase::Enable(enable) )
434        return false;
435
436    return true;
437}
438
439bool wxWindowX11::Show(bool show)
440{
441    wxWindowBase::Show(show);
442
443    Window xwindow = (Window) m_mainWindow;
444    Display *xdisp = wxGlobalDisplay();
445    if (show)
446    {
447        // wxLogDebug( "Mapping window of type %s", GetName().c_str() );
448        XMapWindow(xdisp, xwindow);
449    }
450    else
451    {
452        // wxLogDebug( "Unmapping window of type %s", GetName().c_str() );
453        XUnmapWindow(xdisp, xwindow);
454    }
455
456    return true;
457}
458
459// Raise the window to the top of the Z order
460void wxWindowX11::Raise()
461{
462    if (m_mainWindow)
463        XRaiseWindow( wxGlobalDisplay(), (Window) m_mainWindow );
464}
465
466// Lower the window to the bottom of the Z order
467void wxWindowX11::Lower()
468{
469    if (m_mainWindow)
470        XLowerWindow( wxGlobalDisplay(), (Window) m_mainWindow );
471}
472
473void wxWindowX11::SetLabel(const wxString& WXUNUSED(label))
474{
475    // TODO
476}
477
478wxString wxWindowX11::GetLabel() const
479{
480    // TODO
481    return wxEmptyString;
482}
483
484void wxWindowX11::DoCaptureMouse()
485{
486    if ((g_captureWindow != NULL) && (g_captureWindow != this))
487    {
488        wxFAIL_MSG(wxT("Trying to capture before mouse released."));
489
490        // Core dump now
491        int *tmp = NULL;
492        (*tmp) = 1;
493        return;
494    }
495
496    if (m_winCaptured)
497        return;
498
499    Window xwindow = (Window) m_clientWindow;
500
501    wxCHECK_RET( xwindow, wxT("invalid window") );
502
503    g_captureWindow = (wxWindow*) this;
504
505    if (xwindow)
506    {
507        int res = XGrabPointer(wxGlobalDisplay(), xwindow,
508            FALSE,
509            ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask,
510            GrabModeAsync,
511            GrabModeAsync,
512            None,
513            None, /* cursor */ // TODO: This may need to be set to the cursor of this window
514            CurrentTime );
515
516        if (res != GrabSuccess)
517        {
518            wxString msg;
519            msg.Printf(wxT("Failed to grab pointer for window %s"), this->GetClassInfo()->GetClassName());
520            wxLogDebug(msg);
521            if (res == GrabNotViewable)
522                wxLogDebug( wxT("This is not a viewable window - perhaps not shown yet?") );
523
524            g_captureWindow = NULL;
525            return;
526        }
527
528        m_winCaptured = true;
529    }
530}
531
532void wxWindowX11::DoReleaseMouse()
533{
534    g_captureWindow = NULL;
535
536    if ( !m_winCaptured )
537        return;
538
539    Window xwindow = (Window) m_clientWindow;
540
541    if (xwindow)
542    {
543        XUngrabPointer( wxGlobalDisplay(), CurrentTime );
544    }
545
546    // wxLogDebug( "Ungrabbed pointer in %s", GetName().c_str() );
547
548    m_winCaptured = false;
549}
550
551bool wxWindowX11::SetFont(const wxFont& font)
552{
553    if ( !wxWindowBase::SetFont(font) )
554    {
555        // nothing to do
556        return false;
557    }
558
559    return true;
560}
561
562bool wxWindowX11::SetCursor(const wxCursor& cursor)
563{
564    if ( !wxWindowBase::SetCursor(cursor) )
565    {
566        // no change
567        return false;
568    }
569
570    Window xwindow = (Window) m_clientWindow;
571
572    wxCHECK_MSG( xwindow, false, wxT("invalid window") );
573
574    wxCursor cursorToUse;
575    if (m_cursor.Ok())
576        cursorToUse = m_cursor;
577    else
578        cursorToUse = *wxSTANDARD_CURSOR;
579
580    Cursor xcursor = (Cursor) cursorToUse.GetCursor();
581
582    XDefineCursor( wxGlobalDisplay(), xwindow, xcursor );
583
584    return true;
585}
586
587// Coordinates relative to the window
588void wxWindowX11::WarpPointer (int x, int y)
589{
590    Window xwindow = (Window) m_clientWindow;
591
592    wxCHECK_RET( xwindow, wxT("invalid window") );
593
594    XWarpPointer( wxGlobalDisplay(), None, xwindow, 0, 0, 0, 0, x, y);
595}
596
597// Does a physical scroll
598void wxWindowX11::ScrollWindow(int dx, int dy, const wxRect *rect)
599{
600    // No scrolling requested.
601    if ((dx == 0) && (dy == 0)) return;
602
603    if (!m_updateRegion.IsEmpty())
604    {
605        m_updateRegion.Offset( dx, dy );
606
607        int cw = 0;
608        int ch = 0;
609        GetSize( &cw, &ch );  // GetClientSize() ??
610        m_updateRegion.Intersect( 0, 0, cw, ch );
611    }
612
613    if (!m_clearRegion.IsEmpty())
614    {
615        m_clearRegion.Offset( dx, dy );
616
617        int cw = 0;
618        int ch = 0;
619        GetSize( &cw, &ch );  // GetClientSize() ??
620        m_clearRegion.Intersect( 0, 0, cw, ch );
621    }
622
623    Window xwindow = (Window) GetClientAreaWindow();
624
625    wxCHECK_RET( xwindow, wxT("invalid window") );
626
627    Display *xdisplay = wxGlobalDisplay();
628
629    GC xgc = XCreateGC( xdisplay, xwindow, 0, NULL );
630    XSetGraphicsExposures( xdisplay, xgc, True );
631
632    int s_x = 0;
633    int s_y = 0;
634    int cw;
635    int ch;
636    if (rect)
637    {
638        s_x = rect->x;
639        s_y = rect->y;
640
641        cw = rect->width;
642        ch = rect->height;
643    }
644    else
645    {
646        s_x = 0;
647        s_y = 0;
648        GetClientSize( &cw, &ch );
649    }
650
651#if wxUSE_TWO_WINDOWS
652    wxPoint offset( 0,0 );
653#else
654    wxPoint offset = GetClientAreaOrigin();
655    s_x += offset.x;
656    s_y += offset.y;
657#endif
658
659    int w = cw - abs(dx);
660    int h = ch - abs(dy);
661
662    if ((h < 0) || (w < 0))
663    {
664        Refresh();
665    }
666    else
667    {
668        wxRect rect;
669        if (dx < 0) rect.x = cw+dx + offset.x; else rect.x = s_x;
670        if (dy < 0) rect.y = ch+dy + offset.y; else rect.y = s_y;
671        if (dy != 0) rect.width = cw; else rect.width = abs(dx);
672        if (dx != 0) rect.height = ch; else rect.height = abs(dy);
673
674        int d_x = s_x;
675        int d_y = s_y;
676
677        if (dx < 0) s_x += -dx;
678        if (dy < 0) s_y += -dy;
679        if (dx > 0) d_x += dx + offset.x;
680        if (dy > 0) d_y += dy + offset.y;
681
682        XCopyArea( xdisplay, xwindow, xwindow, xgc, s_x, s_y, w, h, d_x, d_y );
683
684        // wxLogDebug( "Copy: s_x %d s_y %d w %d h %d d_x %d d_y %d", s_x, s_y, w, h, d_x, d_y );
685
686        // wxLogDebug( "Update: %d %d %d %d", rect.x, rect.y, rect.width, rect.height );
687
688        m_updateRegion.Union( rect );
689        m_clearRegion.Union( rect );
690    }
691
692    XFreeGC( xdisplay, xgc );
693
694    // Move Clients, but not the scrollbars
695    // FIXME: There may be a better method to move a lot of Windows within X11
696    wxScrollBar *sbH = ((wxWindow *) this)->GetScrollbar( wxHORIZONTAL );
697    wxScrollBar *sbV = ((wxWindow *) this)->GetScrollbar( wxVERTICAL );
698    wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
699    while ( node )
700    {
701        // Only propagate to non-top-level windows
702        wxWindow *win = node->GetData();
703        if ( win->GetParent() && win != sbH && win != sbV )
704        {
705            wxPoint pos = win->GetPosition();
706            // Add the delta to the old Position
707            pos.x += dx;
708            pos.y += dy;
709            win->SetPosition(pos);
710        }
711        node = node->GetNext();
712    }
713}
714
715// ---------------------------------------------------------------------------
716// drag and drop
717// ---------------------------------------------------------------------------
718
719#if wxUSE_DRAG_AND_DROP
720
721void wxWindowX11::SetDropTarget(wxDropTarget * WXUNUSED(pDropTarget))
722{
723    // TODO
724}
725
726#endif
727
728// Old style file-manager drag&drop
729void wxWindowX11::DragAcceptFiles(bool WXUNUSED(accept))
730{
731    // TODO
732}
733
734// ----------------------------------------------------------------------------
735// tooltips
736// ----------------------------------------------------------------------------
737
738#if wxUSE_TOOLTIPS
739
740void wxWindowX11::DoSetToolTip(wxToolTip * WXUNUSED(tooltip))
741{
742    // TODO
743}
744
745#endif // wxUSE_TOOLTIPS
746
747// ---------------------------------------------------------------------------
748// moving and resizing
749// ---------------------------------------------------------------------------
750
751bool wxWindowX11::PreResize()
752{
753    return true;
754}
755
756// Get total size
757void wxWindowX11::DoGetSize(int *x, int *y) const
758{
759    Window xwindow = (Window) m_mainWindow;
760
761    wxCHECK_RET( xwindow, wxT("invalid window") );
762
763    //XSync(wxGlobalDisplay(), False);
764
765    XWindowAttributes attr;
766    Status status = XGetWindowAttributes( wxGlobalDisplay(), xwindow, &attr );
767    wxASSERT(status);
768
769    if (status)
770    {
771        *x = attr.width /* + 2*m_borderSize */ ;
772        *y = attr.height /* + 2*m_borderSize */ ;
773    }
774}
775
776void wxWindowX11::DoGetPosition(int *x, int *y) const
777{
778    Window window = (Window) m_mainWindow;
779    if (window)
780    {
781        //XSync(wxGlobalDisplay(), False);
782        XWindowAttributes attr;
783        Status status = XGetWindowAttributes(wxGlobalDisplay(), window, & attr);
784        wxASSERT(status);
785
786        if (status)
787        {
788            *x = attr.x;
789            *y = attr.y;
790
791            // We may be faking the client origin. So a window that's really at (0, 30)
792            // may appear (to wxWin apps) to be at (0, 0).
793            if (GetParent())
794            {
795                wxPoint pt(GetParent()->GetClientAreaOrigin());
796                *x -= pt.x;
797                *y -= pt.y;
798            }
799        }
800    }
801}
802
803void wxWindowX11::DoScreenToClient(int *x, int *y) const
804{
805    Display *display = wxGlobalDisplay();
806    Window rootWindow = RootWindowOfScreen(DefaultScreenOfDisplay(display));
807    Window thisWindow = (Window) m_clientWindow;
808
809    Window childWindow;
810    int xx = *x;
811    int yy = *y;
812    XTranslateCoordinates(display, rootWindow, thisWindow, xx, yy, x, y, &childWindow);
813}
814
815void wxWindowX11::DoClientToScreen(int *x, int *y) const
816{
817    Display *display = wxGlobalDisplay();
818    Window rootWindow = RootWindowOfScreen(DefaultScreenOfDisplay(display));
819    Window thisWindow = (Window) m_clientWindow;
820
821    Window childWindow;
822    int xx = *x;
823    int yy = *y;
824    XTranslateCoordinates(display, thisWindow, rootWindow, xx, yy, x, y, &childWindow);
825}
826
827
828// Get size *available for subwindows* i.e. excluding menu bar etc.
829void wxWindowX11::DoGetClientSize(int *x, int *y) const
830{
831    Window window = (Window) m_mainWindow;
832
833    if (window)
834    {
835        XWindowAttributes attr;
836        Status status = XGetWindowAttributes( wxGlobalDisplay(), window, &attr );
837        wxASSERT(status);
838
839        if (status)
840        {
841            *x = attr.width ;
842            *y = attr.height ;
843        }
844    }
845}
846
847void wxWindowX11::DoSetSize(int x, int y, int width, int height, int sizeFlags)
848{
849    //    wxLogDebug("DoSetSize: %s (%ld) %d, %d %dx%d", GetClassInfo()->GetClassName(), GetId(), x, y, width, height);
850
851    Window xwindow = (Window) m_mainWindow;
852
853    wxCHECK_RET( xwindow, wxT("invalid window") );
854
855    XWindowAttributes attr;
856    Status status = XGetWindowAttributes( wxGlobalDisplay(), xwindow, &attr );
857    wxCHECK_RET( status, wxT("invalid window attributes") );
858
859    int new_x = attr.x;
860    int new_y = attr.y;
861    int new_w = attr.width;
862    int new_h = attr.height;
863
864    if (x != wxDefaultCoord || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
865    {
866        int yy = 0;
867        AdjustForParentClientOrigin( x, yy, sizeFlags);
868        new_x = x;
869    }
870    if (y != wxDefaultCoord || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
871    {
872        int xx = 0;
873        AdjustForParentClientOrigin( xx, y, sizeFlags);
874        new_y = y;
875    }
876    if (width != wxDefaultCoord)
877    {
878        new_w = width;
879        if (new_w <= 0)
880            new_w = 20;
881    }
882    if (height != wxDefaultCoord)
883    {
884        new_h = height;
885        if (new_h <= 0)
886            new_h = 20;
887    }
888
889    DoMoveWindow( new_x, new_y, new_w, new_h );
890}
891
892void wxWindowX11::DoSetClientSize(int width, int height)
893{
894    //    wxLogDebug("DoSetClientSize: %s (%ld) %dx%d", GetClassInfo()->GetClassName(), GetId(), width, height);
895
896    Window xwindow = (Window) m_mainWindow;
897
898    wxCHECK_RET( xwindow, wxT("invalid window") );
899
900    XResizeWindow( wxGlobalDisplay(), xwindow, width, height );
901
902    if (m_mainWindow != m_clientWindow)
903    {
904        xwindow = (Window) m_clientWindow;
905
906        wxWindow *window = (wxWindow*) this;
907        wxRenderer *renderer = window->GetRenderer();
908        if (renderer)
909        {
910            wxRect border = renderer->GetBorderDimensions( (wxBorder)(m_windowStyle & wxBORDER_MASK) );
911            width -= border.x + border.width;
912            height -= border.y + border.height;
913        }
914
915        XResizeWindow( wxGlobalDisplay(), xwindow, width, height );
916    }
917}
918
919void wxWindowX11::DoMoveWindow(int x, int y, int width, int height)
920{
921    Window xwindow = (Window) m_mainWindow;
922
923    wxCHECK_RET( xwindow, wxT("invalid window") );
924
925#if !wxUSE_NANOX
926
927    XMoveResizeWindow( wxGlobalDisplay(), xwindow, x, y, width, height );
928    if (m_mainWindow != m_clientWindow)
929    {
930        xwindow = (Window) m_clientWindow;
931
932        wxWindow *window = (wxWindow*) this;
933        wxRenderer *renderer = window->GetRenderer();
934        if (renderer)
935        {
936            wxRect border = renderer->GetBorderDimensions( (wxBorder)(m_windowStyle & wxBORDER_MASK) );
937            x = border.x;
938            y = border.y;
939            width -= border.x + border.width;
940            height -= border.y + border.height;
941        }
942        else
943        {
944            x = 0;
945            y = 0;
946        }
947
948        wxScrollBar *sb = window->GetScrollbar( wxHORIZONTAL );
949        if (sb && sb->IsShown())
950        {
951            wxSize size = sb->GetSize();
952            height -= size.y;
953        }
954        sb = window->GetScrollbar( wxVERTICAL );
955        if (sb && sb->IsShown())
956        {
957            wxSize size = sb->GetSize();
958            width -= size.x;
959        }
960
961        XMoveResizeWindow( wxGlobalDisplay(), xwindow, x, y, wxMax(1, width), wxMax(1, height) );
962    }
963
964#else
965
966    XWindowChanges windowChanges;
967    windowChanges.x = x;
968    windowChanges.y = y;
969    windowChanges.width = width;
970    windowChanges.height = height;
971    windowChanges.stack_mode = 0;
972    int valueMask = CWX | CWY | CWWidth | CWHeight;
973
974    XConfigureWindow( wxGlobalDisplay(), xwindow, valueMask, &windowChanges );
975
976#endif
977}
978
979void wxWindowX11::DoSetSizeHints(int minW, int minH, int maxW, int maxH, int incW, int incH)
980{
981    m_minWidth = minW;
982    m_minHeight = minH;
983    m_maxWidth = maxW;
984    m_maxHeight = maxH;
985
986#if !wxUSE_NANOX
987    XSizeHints sizeHints;
988    sizeHints.flags = 0;
989
990    if (minW > -1 && minH > -1)
991    {
992        sizeHints.flags |= PMinSize;
993        sizeHints.min_width = minW;
994        sizeHints.min_height = minH;
995    }
996    if (maxW > -1 && maxH > -1)
997    {
998        sizeHints.flags |= PMaxSize;
999        sizeHints.max_width = maxW;
1000        sizeHints.max_height = maxH;
1001    }
1002    if (incW > -1 && incH > -1)
1003    {
1004        sizeHints.flags |= PResizeInc;
1005        sizeHints.width_inc = incW;
1006        sizeHints.height_inc = incH;
1007    }
1008
1009    XSetWMNormalHints(wxGlobalDisplay(), (Window) m_mainWindow, &sizeHints );
1010#endif
1011}
1012
1013// ---------------------------------------------------------------------------
1014// text metrics
1015// ---------------------------------------------------------------------------
1016
1017int wxWindowX11::GetCharHeight() const
1018{
1019    wxFont font(GetFont());
1020    wxCHECK_MSG( font.Ok(), 0, wxT("valid window font needed") );
1021
1022#if wxUSE_UNICODE
1023    // There should be an easier way.
1024    PangoLayout *layout = pango_layout_new( wxTheApp->GetPangoContext() );
1025    pango_layout_set_font_description( layout, font.GetNativeFontInfo()->description );
1026    pango_layout_set_text(layout, "H", 1 );
1027    int w,h;
1028    pango_layout_get_pixel_size(layout, &w, &h);
1029    g_object_unref( G_OBJECT( layout ) );
1030
1031    return h;
1032#else
1033    WXFontStructPtr pFontStruct = font.GetFontStruct(1.0, wxGlobalDisplay());
1034
1035    int direction, ascent, descent;
1036    XCharStruct overall;
1037    XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
1038        &descent, &overall);
1039
1040    //  return (overall.ascent + overall.descent);
1041    return (ascent + descent);
1042#endif
1043}
1044
1045int wxWindowX11::GetCharWidth() const
1046{
1047    wxFont font(GetFont());
1048    wxCHECK_MSG( font.Ok(), 0, wxT("valid window font needed") );
1049
1050#if wxUSE_UNICODE
1051    // There should be an easier way.
1052    PangoLayout *layout = pango_layout_new( wxTheApp->GetPangoContext() );
1053    pango_layout_set_font_description( layout, font.GetNativeFontInfo()->description );
1054    pango_layout_set_text(layout, "H", 1 );
1055    int w,h;
1056    pango_layout_get_pixel_size(layout, &w, &h);
1057    g_object_unref( G_OBJECT( layout ) );
1058
1059    return w;
1060#else
1061    WXFontStructPtr pFontStruct = font.GetFontStruct(1.0, wxGlobalDisplay());
1062
1063    int direction, ascent, descent;
1064    XCharStruct overall;
1065    XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
1066        &descent, &overall);
1067
1068    return overall.width;
1069#endif
1070}
1071
1072void wxWindowX11::GetTextExtent(const wxString& string,
1073                                int *x, int *y,
1074                                int *descent, int *externalLeading,
1075                                const wxFont *theFont) const
1076{
1077    wxFont fontToUse = GetFont();
1078    if (theFont) fontToUse = *theFont;
1079
1080    wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
1081
1082    if (string.empty())
1083    {
1084        if (x) (*x) = 0;
1085        if (y) (*y) = 0;
1086        return;
1087    }
1088
1089#if wxUSE_UNICODE
1090    PangoLayout *layout = pango_layout_new( wxTheApp->GetPangoContext() );
1091
1092    PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
1093    pango_layout_set_font_description(layout, desc);
1094
1095    const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
1096    pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
1097
1098    PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
1099
1100
1101    PangoRectangle rect;
1102    pango_layout_line_get_extents(line, NULL, &rect);
1103
1104    if (x) (*x) = (wxCoord) (rect.width / PANGO_SCALE);
1105    if (y) (*y) = (wxCoord) (rect.height / PANGO_SCALE);
1106    if (descent)
1107    {
1108        // Do something about metrics here
1109        (*descent) = 0;
1110    }
1111    if (externalLeading) (*externalLeading) = 0;  // ??
1112
1113    g_object_unref( G_OBJECT( layout ) );
1114#else
1115    WXFontStructPtr pFontStruct = fontToUse.GetFontStruct(1.0, wxGlobalDisplay());
1116
1117    int direction, ascent, descent2;
1118    XCharStruct overall;
1119    int slen = string.length();
1120
1121    XTextExtents((XFontStruct*) pFontStruct, (char*) string.c_str(), slen,
1122                 &direction, &ascent, &descent2, &overall);
1123
1124    if ( x )
1125        *x = (overall.width);
1126    if ( y )
1127        *y = (ascent + descent2);
1128    if (descent)
1129        *descent = descent2;
1130    if (externalLeading)
1131        *externalLeading = 0;
1132#endif
1133}
1134
1135// ----------------------------------------------------------------------------
1136// painting
1137// ----------------------------------------------------------------------------
1138
1139void wxWindowX11::Refresh(bool eraseBack, const wxRect *rect)
1140{
1141    if (eraseBack)
1142    {
1143        if (rect)
1144        {
1145            // Schedule for later Updating in ::Update() or ::OnInternalIdle().
1146            m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
1147        }
1148        else
1149        {
1150            int height,width;
1151            GetSize( &width, &height );
1152
1153            // Schedule for later Updating in ::Update() or ::OnInternalIdle().
1154            m_clearRegion.Clear();
1155            m_clearRegion.Union( 0, 0, width, height );
1156        }
1157    }
1158
1159    if (rect)
1160    {
1161         // Schedule for later Updating in ::Update() or ::OnInternalIdle().
1162         m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
1163    }
1164    else
1165    {
1166        int height,width;
1167        GetSize( &width, &height );
1168
1169        // Schedule for later Updating in ::Update() or ::OnInternalIdle().
1170        m_updateRegion.Clear();
1171        m_updateRegion.Union( 0, 0, width, height );
1172    }
1173}
1174
1175void wxWindowX11::Update()
1176{
1177    if (m_updateNcArea)
1178    {
1179        // wxLogDebug("wxWindowX11::UpdateNC: %s", GetClassInfo()->GetClassName());
1180        // Send nc paint events.
1181        SendNcPaintEvents();
1182    }
1183
1184    if (!m_updateRegion.IsEmpty())
1185    {
1186        // wxLogDebug("wxWindowX11::Update: %s", GetClassInfo()->GetClassName());
1187        // Actually send erase events.
1188        SendEraseEvents();
1189
1190        // Actually send paint events.
1191        SendPaintEvents();
1192    }
1193}
1194
1195void wxWindowX11::SendEraseEvents()
1196{
1197    if (m_clearRegion.IsEmpty()) return;
1198
1199    wxClientDC dc( (wxWindow*)this );
1200    dc.SetClippingRegion( m_clearRegion );
1201
1202    wxEraseEvent erase_event( GetId(), &dc );
1203    erase_event.SetEventObject( this );
1204
1205    if (!GetEventHandler()->ProcessEvent(erase_event) )
1206    {
1207        Display *xdisplay = wxGlobalDisplay();
1208        Window xwindow = (Window) GetClientAreaWindow();
1209        XSetForeground( xdisplay, g_eraseGC, m_backgroundColour.GetPixel() );
1210
1211        wxRegionIterator upd( m_clearRegion );
1212        while (upd)
1213        {
1214            XFillRectangle( xdisplay, xwindow, g_eraseGC,
1215                            upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
1216            upd ++;
1217        }
1218    }
1219
1220    m_clearRegion.Clear();
1221}
1222
1223void wxWindowX11::SendPaintEvents()
1224{
1225    //    wxLogDebug("SendPaintEvents: %s (%ld)", GetClassInfo()->GetClassName(), GetId());
1226
1227    m_clipPaintRegion = true;
1228
1229    wxPaintEvent paint_event( GetId() );
1230    paint_event.SetEventObject( this );
1231    GetEventHandler()->ProcessEvent( paint_event );
1232
1233    m_updateRegion.Clear();
1234
1235    m_clipPaintRegion = false;
1236}
1237
1238void wxWindowX11::SendNcPaintEvents()
1239{
1240    wxWindow *window = (wxWindow*) this;
1241
1242    // All this for drawing the small square between the scrollbars.
1243    int width = 0;
1244    int height = 0;
1245    int x = 0;
1246    int y = 0;
1247    wxScrollBar *sb = window->GetScrollbar( wxHORIZONTAL );
1248    if (sb && sb->IsShown())
1249    {
1250        height = sb->GetSize().y;
1251        y = sb->GetPosition().y;
1252
1253        sb = window->GetScrollbar( wxVERTICAL );
1254        if (sb && sb->IsShown())
1255        {
1256            width = sb->GetSize().x;
1257            x = sb->GetPosition().x;
1258
1259            Display *xdisplay = wxGlobalDisplay();
1260            Window xwindow = (Window) GetMainWindow();
1261            Colormap cm = (Colormap) wxTheApp->GetMainColormap( wxGetDisplay() );
1262            wxColour colour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
1263            colour.CalcPixel( (WXColormap) cm );
1264
1265            XSetForeground( xdisplay, g_eraseGC, colour.GetPixel() );
1266
1267            XFillRectangle( xdisplay, xwindow, g_eraseGC, x, y, width, height );
1268        }
1269    }
1270
1271    wxNcPaintEvent nc_paint_event( GetId() );
1272    nc_paint_event.SetEventObject( this );
1273    GetEventHandler()->ProcessEvent( nc_paint_event );
1274
1275    m_updateNcArea = false;
1276}
1277
1278// ----------------------------------------------------------------------------
1279// event handlers
1280// ----------------------------------------------------------------------------
1281
1282// Responds to colour changes: passes event on to children.
1283void wxWindowX11::OnSysColourChanged(wxSysColourChangedEvent& event)
1284{
1285    wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1286    while ( node )
1287    {
1288        // Only propagate to non-top-level windows
1289        wxWindow *win = node->GetData();
1290        if ( win->GetParent() )
1291        {
1292            wxSysColourChangedEvent event2;
1293            event.SetEventObject(win);
1294            win->GetEventHandler()->ProcessEvent(event2);
1295        }
1296
1297        node = node->GetNext();
1298    }
1299}
1300
1301// See handler for InFocus case in app.cpp for details.
1302wxWindow* g_GettingFocus = NULL;
1303
1304void wxWindowX11::OnInternalIdle()
1305{
1306    // Update invalidated regions.
1307    Update();
1308
1309    // This calls the UI-update mechanism (querying windows for
1310    // menu/toolbar/control state information)
1311    if (wxUpdateUIEvent::CanUpdate((wxWindow*) this) && IsShownOnScreen())
1312        UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
1313
1314    // Set the input focus if couldn't do it before
1315    if (m_needsInputFocus)
1316    {
1317#if 0
1318        wxString msg;
1319        msg.Printf("Setting focus for %s from OnInternalIdle\n", GetClassInfo()->GetClassName());
1320        printf(msg.c_str());
1321#endif
1322        SetFocus();
1323
1324        // If it couldn't set the focus now, there's
1325        // no point in trying again.
1326        m_needsInputFocus = false;
1327    }
1328    g_GettingFocus = NULL;
1329}
1330
1331// ----------------------------------------------------------------------------
1332// function which maintain the global hash table mapping Widgets to wxWidgets
1333// ----------------------------------------------------------------------------
1334
1335static bool DoAddWindowToTable(wxWindowHash *hash, Window w, wxWindow *win)
1336{
1337    if ( !hash->insert(wxWindowHash::value_type(w, win)).second )
1338    {
1339        wxLogDebug( wxT("Widget table clash: new widget is 0x%08x, %s"),
1340                    (unsigned int)w, win->GetClassInfo()->GetClassName());
1341        return false;
1342    }
1343
1344    wxLogTrace( wxT("widget"), wxT("XWindow 0x%08x <-> window %p (%s)"),
1345                (unsigned int) w, win, win->GetClassInfo()->GetClassName());
1346
1347    return true;
1348}
1349
1350static inline wxWindow *DoGetWindowFromTable(wxWindowHash *hash, Window w)
1351{
1352    wxWindowHash::iterator i = hash->find(w);
1353    return i == hash->end() ? NULL : i->second;
1354}
1355
1356static inline void DoDeleteWindowFromTable(wxWindowHash *hash, Window w)
1357{
1358    wxLogTrace( wxT("widget"), wxT("XWindow 0x%08x deleted"), (unsigned int) w);
1359
1360    hash->erase(w);
1361}
1362
1363// ----------------------------------------------------------------------------
1364// public wrappers
1365// ----------------------------------------------------------------------------
1366
1367bool wxAddWindowToTable(Window w, wxWindow *win)
1368{
1369    return DoAddWindowToTable(wxWidgetHashTable, w, win);
1370}
1371
1372wxWindow *wxGetWindowFromTable(Window w)
1373{
1374    return DoGetWindowFromTable(wxWidgetHashTable, w);
1375}
1376
1377void wxDeleteWindowFromTable(Window w)
1378{
1379    DoDeleteWindowFromTable(wxWidgetHashTable, w);
1380}
1381
1382bool wxAddClientWindowToTable(Window w, wxWindow *win)
1383{
1384    return DoAddWindowToTable(wxClientWidgetHashTable, w, win);
1385}
1386
1387wxWindow *wxGetClientWindowFromTable(Window w)
1388{
1389    return DoGetWindowFromTable(wxClientWidgetHashTable, w);
1390}
1391
1392void wxDeleteClientWindowFromTable(Window w)
1393{
1394    DoDeleteWindowFromTable(wxClientWidgetHashTable, w);
1395}
1396
1397// ----------------------------------------------------------------------------
1398// X11-specific accessors
1399// ----------------------------------------------------------------------------
1400
1401WXWindow wxWindowX11::GetMainWindow() const
1402{
1403    return m_mainWindow;
1404}
1405
1406WXWindow wxWindowX11::GetClientAreaWindow() const
1407{
1408    return m_clientWindow;
1409}
1410
1411// ----------------------------------------------------------------------------
1412// TranslateXXXEvent() functions
1413// ----------------------------------------------------------------------------
1414
1415bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Window window, XEvent *xevent)
1416{
1417    switch (XEventGetType(xevent))
1418    {
1419        case EnterNotify:
1420        case LeaveNotify:
1421        case ButtonPress:
1422        case ButtonRelease:
1423        case MotionNotify:
1424        {
1425            wxEventType eventType = wxEVT_NULL;
1426
1427            if (XEventGetType(xevent) == EnterNotify)
1428            {
1429                //if (local_event.xcrossing.mode!=NotifyNormal)
1430                //  return ; // Ignore grab events
1431                eventType = wxEVT_ENTER_WINDOW;
1432                //            canvas->GetEventHandler()->OnSetFocus();
1433            }
1434            else if (XEventGetType(xevent) == LeaveNotify)
1435            {
1436                //if (local_event.xcrossingr.mode!=NotifyNormal)
1437                //  return ; // Ignore grab events
1438                eventType = wxEVT_LEAVE_WINDOW;
1439                //            canvas->GetEventHandler()->OnKillFocus();
1440            }
1441            else if (XEventGetType(xevent) == MotionNotify)
1442            {
1443                eventType = wxEVT_MOTION;
1444            }
1445            else if (XEventGetType(xevent) == ButtonPress)
1446            {
1447                wxevent.SetTimestamp(XButtonEventGetTime(xevent));
1448                int button = 0;
1449                if (XButtonEventLChanged(xevent))
1450                {
1451                    eventType = wxEVT_LEFT_DOWN;
1452                    button = 1;
1453                }
1454                else if (XButtonEventMChanged(xevent))
1455                {
1456                    eventType = wxEVT_MIDDLE_DOWN;
1457                    button = 2;
1458                }
1459                else if (XButtonEventRChanged(xevent))
1460                {
1461                    eventType = wxEVT_RIGHT_DOWN;
1462                    button = 3;
1463                }
1464
1465                // check for a double click
1466                // TODO: where can we get this value from?
1467                //long dclickTime = XtGetMultiClickTime(wxGlobalDisplay());
1468                long dclickTime = 200;
1469                long ts = wxevent.GetTimestamp();
1470
1471                int buttonLast = win->GetLastClickedButton();
1472                long lastTS = win->GetLastClickTime();
1473                if ( buttonLast && buttonLast == button && (ts - lastTS) < dclickTime )
1474                {
1475                    // I have a dclick
1476                    win->SetLastClick(0, ts);
1477                    if ( eventType == wxEVT_LEFT_DOWN )
1478                        eventType = wxEVT_LEFT_DCLICK;
1479                    else if ( eventType == wxEVT_MIDDLE_DOWN )
1480                        eventType = wxEVT_MIDDLE_DCLICK;
1481                    else if ( eventType == wxEVT_RIGHT_DOWN )
1482                        eventType = wxEVT_RIGHT_DCLICK;
1483                }
1484                else
1485                {
1486                    // not fast enough or different button
1487                    win->SetLastClick(button, ts);
1488                }
1489            }
1490            else if (XEventGetType(xevent) == ButtonRelease)
1491            {
1492                if (XButtonEventLChanged(xevent))
1493                {
1494                    eventType = wxEVT_LEFT_UP;
1495                }
1496                else if (XButtonEventMChanged(xevent))
1497                {
1498                    eventType = wxEVT_MIDDLE_UP;
1499                }
1500                else if (XButtonEventRChanged(xevent))
1501                {
1502                    eventType = wxEVT_RIGHT_UP;
1503                }
1504                else return false;
1505            }
1506            else
1507            {
1508                return false;
1509            }
1510
1511            wxevent.SetEventType(eventType);
1512
1513            wxevent.m_x = XButtonEventGetX(xevent);
1514            wxevent.m_y = XButtonEventGetY(xevent);
1515
1516            wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN)
1517                || (XButtonEventLIsDown(xevent)
1518                && (eventType != wxEVT_LEFT_UP)));
1519            wxevent.m_middleDown = ((eventType == wxEVT_MIDDLE_DOWN)
1520                || (XButtonEventMIsDown(xevent)
1521                && (eventType != wxEVT_MIDDLE_UP)));
1522            wxevent.m_rightDown = ((eventType == wxEVT_RIGHT_DOWN)
1523                || (XButtonEventRIsDown (xevent)
1524                && (eventType != wxEVT_RIGHT_UP)));
1525
1526            wxevent.m_shiftDown = XButtonEventShiftIsDown(xevent);
1527            wxevent.m_controlDown = XButtonEventCtrlIsDown(xevent);
1528            wxevent.m_altDown = XButtonEventAltIsDown(xevent);
1529            wxevent.m_metaDown = XButtonEventMetaIsDown(xevent);
1530
1531            wxevent.SetId(win->GetId());
1532            wxevent.SetEventObject(win);
1533
1534            return true;
1535        }
1536    }
1537    return false;
1538}
1539
1540bool wxTranslateKeyEvent(wxKeyEvent& wxevent, wxWindow *win, Window WXUNUSED(win), XEvent *xevent, bool isAscii)
1541{
1542    switch (XEventGetType(xevent))
1543    {
1544    case KeyPress:
1545    case KeyRelease:
1546        {
1547            char buf[20];
1548
1549            KeySym keySym;
1550            (void) XLookupString ((XKeyEvent *) xevent, buf, 20, &keySym, NULL);
1551            int id = wxCharCodeXToWX (keySym);
1552            // id may be WXK_xxx code - these are outside ASCII range, so we
1553            // can't just use toupper() on id.
1554            // Only change this if we want the raw key that was pressed,
1555            // and don't change it if we want an ASCII value.
1556            if (!isAscii && (id >= 'a' && id <= 'z'))
1557            {
1558                id = id + 'A' - 'a';
1559            }
1560
1561            wxevent.m_shiftDown = XKeyEventShiftIsDown(xevent);
1562            wxevent.m_controlDown = XKeyEventCtrlIsDown(xevent);
1563            wxevent.m_altDown = XKeyEventAltIsDown(xevent);
1564            wxevent.m_metaDown = XKeyEventMetaIsDown(xevent);
1565            wxevent.SetEventObject(win);
1566            wxevent.m_keyCode = id;
1567            wxevent.SetTimestamp(XKeyEventGetTime(xevent));
1568
1569            wxevent.m_x = XKeyEventGetX(xevent);
1570            wxevent.m_y = XKeyEventGetY(xevent);
1571
1572            return id > -1;
1573        }
1574    default:
1575        break;
1576    }
1577    return false;
1578}
1579
1580// ----------------------------------------------------------------------------
1581// Colour stuff
1582// ----------------------------------------------------------------------------
1583
1584bool wxWindowX11::SetBackgroundColour(const wxColour& col)
1585{
1586    wxWindowBase::SetBackgroundColour(col);
1587
1588    Display *xdisplay = (Display*) wxGlobalDisplay();
1589    int xscreen = DefaultScreen( xdisplay );
1590    Colormap cm = DefaultColormap( xdisplay, xscreen );
1591
1592    m_backgroundColour.CalcPixel( (WXColormap) cm );
1593
1594    // We don't set the background colour as we paint
1595    // the background ourselves.
1596    // XSetWindowBackground( xdisplay, (Window) m_clientWindow, m_backgroundColour.GetPixel() );
1597
1598    return true;
1599}
1600
1601bool wxWindowX11::SetForegroundColour(const wxColour& col)
1602{
1603    if ( !wxWindowBase::SetForegroundColour(col) )
1604        return false;
1605
1606    return true;
1607}
1608
1609// ----------------------------------------------------------------------------
1610// global functions
1611// ----------------------------------------------------------------------------
1612
1613wxWindow *wxGetActiveWindow()
1614{
1615    // TODO
1616    wxFAIL_MSG(wxT("Not implemented"));
1617    return NULL;
1618}
1619
1620/* static */
1621wxWindow *wxWindowBase::GetCapture()
1622{
1623    return (wxWindow *)g_captureWindow;
1624}
1625
1626
1627// Find the wxWindow at the current mouse position, returning the mouse
1628// position.
1629wxWindow* wxFindWindowAtPointer(wxPoint& pt)
1630{
1631    return wxFindWindowAtPoint(wxGetMousePosition());
1632}
1633
1634void wxGetMouseState(int& rootX, int& rootY, unsigned& maskReturn)
1635{
1636#if wxUSE_NANOX
1637    /* TODO */
1638    rootX = rootY = 0;
1639    maskReturn = 0;
1640#else
1641    Display *display = wxGlobalDisplay();
1642    Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
1643    Window rootReturn, childReturn;
1644    int winX, winY;
1645
1646    XQueryPointer (display,
1647                   rootWindow,
1648                   &rootReturn,
1649                   &childReturn,
1650                   &rootX, &rootY, &winX, &winY, &maskReturn);
1651#endif
1652}
1653
1654// Get the current mouse position.
1655wxPoint wxGetMousePosition()
1656{
1657    int x, y;
1658    unsigned mask;
1659
1660    wxGetMouseState(x, y, mask);
1661    return wxPoint(x, y);
1662}
1663
1664wxMouseState wxGetMouseState()
1665{
1666    wxMouseState ms;
1667    int x, y;
1668    unsigned mask;
1669
1670    wxGetMouseState(x, y, mask);
1671
1672    ms.SetX(x);
1673    ms.SetY(y);
1674
1675    ms.SetLeftDown(mask & Button1Mask);
1676    ms.SetMiddleDown(mask & Button2Mask);
1677    ms.SetRightDown(mask & Button3Mask);
1678
1679    ms.SetControlDown(mask & ControlMask);
1680    ms.SetShiftDown(mask & ShiftMask);
1681    ms.SetAltDown(mask & Mod3Mask);
1682    ms.SetMetaDown(mask & Mod1Mask);
1683
1684    return ms;
1685}
1686
1687
1688// ----------------------------------------------------------------------------
1689// wxNoOptimize: switch off size optimization
1690// ----------------------------------------------------------------------------
1691
1692int wxNoOptimize::ms_count = 0;
1693
1694
1695// ----------------------------------------------------------------------------
1696// wxDCModule
1697// ----------------------------------------------------------------------------
1698
1699class wxWinModule : public wxModule
1700{
1701public:
1702    wxWinModule()
1703    {
1704        // we must be cleaned up before the display is closed
1705        AddDependency(wxClassInfo::FindClass(_T("wxX11DisplayModule")));
1706    }
1707
1708    virtual bool OnInit();
1709    virtual void OnExit();
1710
1711private:
1712    DECLARE_DYNAMIC_CLASS(wxWinModule)
1713};
1714
1715IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
1716
1717bool wxWinModule::OnInit()
1718{
1719    Display *xdisplay = wxGlobalDisplay();
1720    int xscreen = DefaultScreen( xdisplay );
1721    Window xroot = RootWindow( xdisplay, xscreen );
1722    g_eraseGC = XCreateGC( xdisplay, xroot, 0, NULL );
1723    XSetFillStyle( xdisplay, g_eraseGC, FillSolid );
1724
1725    return true;
1726}
1727
1728void wxWinModule::OnExit()
1729{
1730    Display *xdisplay = wxGlobalDisplay();
1731    XFreeGC( xdisplay, g_eraseGC );
1732}
1733