This doesn't work anyhow, so it's better to prevent the code doing this from compiling instead of getting run-time asserts or worse. Also simplify construction of these events inside wxWidgets by passing the window itself to the ctor instead of passing just its ID and calling SetEventObject() separately later. For consistency, do the same thing for wxNcPaintEvent too.
1827 lines
52 KiB
C++
1827 lines
52 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/x11/window.cpp
|
|
// Purpose: wxWindow
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 17/09/98
|
|
// Copyright: (c) Julian Smart
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// for compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#if defined(__BORLANDC__)
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include "wx/window.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/hash.h"
|
|
#include "wx/log.h"
|
|
#include "wx/app.h"
|
|
#include "wx/utils.h"
|
|
#include "wx/panel.h"
|
|
#include "wx/frame.h"
|
|
#include "wx/dc.h"
|
|
#include "wx/dcclient.h"
|
|
#include "wx/button.h"
|
|
#include "wx/menu.h"
|
|
#include "wx/dialog.h"
|
|
#include "wx/timer.h"
|
|
#include "wx/settings.h"
|
|
#include "wx/msgdlg.h"
|
|
#include "wx/scrolbar.h"
|
|
#include "wx/listbox.h"
|
|
#include "wx/scrolwin.h"
|
|
#include "wx/layout.h"
|
|
#include "wx/menuitem.h"
|
|
#include "wx/module.h"
|
|
#endif
|
|
|
|
#include "wx/fontutil.h"
|
|
#include "wx/univ/renderer.h"
|
|
|
|
#if wxUSE_DRAG_AND_DROP
|
|
#include "wx/dnd.h"
|
|
#endif
|
|
|
|
#include "wx/unix/utilsx11.h"
|
|
|
|
#include "wx/x11/private.h"
|
|
#include "X11/Xutil.h"
|
|
|
|
#include <string.h>
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// global variables for this module
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static wxWindowX11* g_captureWindow = NULL;
|
|
static GC g_eraseGC;
|
|
// the window that is about to be focused after currently focused
|
|
// one looses focus:
|
|
static wxWindow* gs_toBeFocusedWindow = NULL;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// macros
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#define event_left_is_down(x) ((x)->xbutton.state & Button1Mask)
|
|
#define event_middle_is_down(x) ((x)->xbutton.state & Button2Mask)
|
|
#define event_right_is_down(x) ((x)->xbutton.state & Button3Mask)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// event tables
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxIMPLEMENT_ABSTRACT_CLASS(wxWindowX11, wxWindowBase);
|
|
|
|
wxBEGIN_EVENT_TABLE(wxWindowX11, wxWindowBase)
|
|
EVT_SYS_COLOUR_CHANGED(wxWindowX11::OnSysColourChanged)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// helper functions
|
|
// ----------------------------------------------------------------------------
|
|
|
|
namespace
|
|
{
|
|
|
|
// Passing size with a 0 component to X11 functions results in a BadValue X
|
|
// error, so ensure we never do it by using the smallest valid size instead.
|
|
inline void EnsureValidXWindowSize(int& x, int& y)
|
|
{
|
|
if ( x <= 0 )
|
|
x = 1;
|
|
if ( y <= 0 )
|
|
y = 1;
|
|
}
|
|
|
|
inline void EnsureValidXWindowSize(wxSize& size)
|
|
{
|
|
EnsureValidXWindowSize(size.x, size.y);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// constructors
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxWindowX11::Init()
|
|
{
|
|
// X11-specific
|
|
m_mainWindow = (WXWindow) 0;
|
|
m_clientWindow = (WXWindow) 0;
|
|
m_insertIntoMain = false;
|
|
m_updateNcArea = false;
|
|
|
|
m_winCaptured = false;
|
|
m_needsInputFocus = false;
|
|
m_isShown = true;
|
|
m_lastTS = 0;
|
|
m_lastButton = 0;
|
|
}
|
|
|
|
// real construction (Init() must have been called before!)
|
|
bool wxWindowX11::Create(wxWindow *parent, wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name)
|
|
{
|
|
wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
|
|
|
|
// Get default border
|
|
wxBorder border = GetBorder(style);
|
|
style &= ~wxBORDER_MASK;
|
|
style |= border;
|
|
|
|
CreateBase(parent, id, pos, size, style, wxDefaultValidator, name);
|
|
|
|
parent->AddChild(this);
|
|
|
|
Display *xdisplay = (Display*) wxGlobalDisplay();
|
|
int xscreen = DefaultScreen( xdisplay );
|
|
Visual *xvisual = DefaultVisual( xdisplay, xscreen );
|
|
Colormap cm = DefaultColormap( xdisplay, xscreen );
|
|
|
|
m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
|
|
m_backgroundColour.CalcPixel( (WXColormap) cm );
|
|
|
|
m_foregroundColour = *wxBLACK;
|
|
m_foregroundColour.CalcPixel( (WXColormap) cm );
|
|
|
|
Window xparent = (Window) parent->GetClientAreaWindow();
|
|
|
|
// Add window's own scrollbars to main window, not to client window
|
|
if (parent->GetInsertIntoMain())
|
|
{
|
|
// wxLogDebug( "Inserted into main: %s", GetName().c_str() );
|
|
xparent = (Window) parent->X11GetMainWindow();
|
|
}
|
|
|
|
wxSize size2(size);
|
|
EnsureValidXWindowSize(size2);
|
|
|
|
wxPoint pos2(pos);
|
|
if (pos2.x == wxDefaultCoord)
|
|
pos2.x = 0;
|
|
if (pos2.y == wxDefaultCoord)
|
|
pos2.y = 0;
|
|
|
|
AdjustForParentClientOrigin(pos2.x, pos2.y);
|
|
|
|
#if wxUSE_TWO_WINDOWS
|
|
bool need_two_windows =
|
|
((( wxSUNKEN_BORDER | wxBORDER_THEME | wxRAISED_BORDER | wxSIMPLE_BORDER | wxHSCROLL | wxVSCROLL ) & m_windowStyle) != 0);
|
|
#else
|
|
bool need_two_windows = false;
|
|
#endif
|
|
|
|
#if !wxUSE_NANOX
|
|
XSetWindowAttributes xattributes;
|
|
long xattributes_mask = 0;
|
|
|
|
xattributes_mask |= CWBackPixel;
|
|
xattributes.background_pixel = m_backgroundColour.GetPixel();
|
|
|
|
xattributes_mask |= CWBorderPixel;
|
|
xattributes.border_pixel = BlackPixel( xdisplay, xscreen );
|
|
|
|
xattributes_mask |= CWEventMask;
|
|
#endif
|
|
|
|
if (need_two_windows)
|
|
{
|
|
#if wxUSE_NANOX
|
|
long backColor, foreColor;
|
|
backColor = GR_RGB(m_backgroundColour.Red(), m_backgroundColour.Green(), m_backgroundColour.Blue());
|
|
foreColor = GR_RGB(m_foregroundColour.Red(), m_foregroundColour.Green(), m_foregroundColour.Blue());
|
|
|
|
Window xwindow = XCreateWindowWithColor( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
|
|
0, 0, InputOutput, xvisual, backColor, foreColor);
|
|
XSelectInput( xdisplay, xwindow,
|
|
GR_EVENT_MASK_CLOSE_REQ | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
|
ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
|
|
KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
|
|
PropertyChangeMask );
|
|
|
|
#else
|
|
// Normal X11
|
|
xattributes.event_mask =
|
|
ExposureMask | StructureNotifyMask | ColormapChangeMask;
|
|
|
|
Window xwindow = XCreateWindow( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
|
|
0, DefaultDepth(xdisplay,xscreen), InputOutput, xvisual, xattributes_mask, &xattributes );
|
|
|
|
#endif
|
|
|
|
XSetWindowBackgroundPixmap( xdisplay, xwindow, None );
|
|
|
|
m_mainWindow = (WXWindow) xwindow;
|
|
wxAddWindowToTable( xwindow, (wxWindow*) this );
|
|
|
|
XMapWindow( xdisplay, xwindow );
|
|
|
|
#if !wxUSE_NANOX
|
|
xattributes.event_mask =
|
|
ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
|
ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
|
|
KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
|
|
PropertyChangeMask | VisibilityChangeMask ;
|
|
|
|
if (!HasFlag( wxFULL_REPAINT_ON_RESIZE ))
|
|
{
|
|
xattributes_mask |= CWBitGravity;
|
|
xattributes.bit_gravity = StaticGravity;
|
|
}
|
|
#endif
|
|
|
|
if (HasFlag(wxSUNKEN_BORDER) || HasFlag(wxRAISED_BORDER) || HasFlag(wxBORDER_THEME))
|
|
{
|
|
pos2.x = 2;
|
|
pos2.y = 2;
|
|
size2.x -= 4;
|
|
size2.y -= 4;
|
|
}
|
|
else if (HasFlag( wxSIMPLE_BORDER ))
|
|
{
|
|
pos2.x = 1;
|
|
pos2.y = 1;
|
|
size2.x -= 2;
|
|
size2.y -= 2;
|
|
}
|
|
else
|
|
{
|
|
pos2.x = 0;
|
|
pos2.y = 0;
|
|
}
|
|
|
|
// Make again sure the size is nonzero.
|
|
EnsureValidXWindowSize(size2);
|
|
|
|
#if wxUSE_NANOX
|
|
backColor = GR_RGB(m_backgroundColour.Red(), m_backgroundColour.Green(), m_backgroundColour.Blue());
|
|
foreColor = GR_RGB(m_foregroundColour.Red(), m_foregroundColour.Green(), m_foregroundColour.Blue());
|
|
|
|
xwindow = XCreateWindowWithColor( xdisplay, xwindow, pos2.x, pos2.y, size2.x, size2.y,
|
|
0, 0, InputOutput, xvisual, backColor, foreColor);
|
|
XSelectInput( xdisplay, xwindow,
|
|
GR_EVENT_MASK_CLOSE_REQ | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
|
ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
|
|
KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
|
|
PropertyChangeMask );
|
|
|
|
#else
|
|
xwindow = XCreateWindow( xdisplay, xwindow, pos2.x, pos2.y, size2.x, size2.y,
|
|
0, DefaultDepth(xdisplay,xscreen), InputOutput, xvisual, xattributes_mask, &xattributes );
|
|
#endif
|
|
|
|
XSetWindowBackgroundPixmap( xdisplay, xwindow, None );
|
|
|
|
m_clientWindow = (WXWindow) xwindow;
|
|
wxAddClientWindowToTable( xwindow, (wxWindow*) this );
|
|
|
|
XMapWindow( xdisplay, xwindow );
|
|
}
|
|
else
|
|
{
|
|
// wxLogDebug( "No two windows needed %s", GetName().c_str() );
|
|
#if wxUSE_NANOX
|
|
long backColor, foreColor;
|
|
backColor = GR_RGB(m_backgroundColour.Red(), m_backgroundColour.Green(), m_backgroundColour.Blue());
|
|
foreColor = GR_RGB(m_foregroundColour.Red(), m_foregroundColour.Green(), m_foregroundColour.Blue());
|
|
|
|
Window xwindow = XCreateWindowWithColor( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
|
|
0, 0, InputOutput, xvisual, backColor, foreColor);
|
|
XSelectInput( xdisplay, xwindow,
|
|
GR_EVENT_MASK_CLOSE_REQ | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
|
ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
|
|
KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
|
|
PropertyChangeMask );
|
|
|
|
#else
|
|
xattributes.event_mask =
|
|
ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
|
ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
|
|
KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
|
|
PropertyChangeMask | VisibilityChangeMask ;
|
|
|
|
if (!HasFlag( wxFULL_REPAINT_ON_RESIZE ))
|
|
{
|
|
xattributes_mask |= CWBitGravity;
|
|
xattributes.bit_gravity = NorthWestGravity;
|
|
}
|
|
|
|
Window xwindow = XCreateWindow( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
|
|
0, DefaultDepth(xdisplay,xscreen), InputOutput, xvisual, xattributes_mask, &xattributes );
|
|
#endif
|
|
|
|
XSetWindowBackgroundPixmap( xdisplay, xwindow, None );
|
|
|
|
m_mainWindow = (WXWindow) xwindow;
|
|
m_clientWindow = m_mainWindow;
|
|
wxAddWindowToTable( xwindow, (wxWindow*) this );
|
|
|
|
XMapWindow( xdisplay, xwindow );
|
|
}
|
|
|
|
// Is a subwindow, so map immediately
|
|
m_isShown = true;
|
|
|
|
// Without this, the cursor may not be restored properly (e.g. in splitter
|
|
// sample).
|
|
SetCursor(*wxSTANDARD_CURSOR);
|
|
SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
|
|
|
// Don't call this, it can have nasty repercussions for composite controls,
|
|
// for example
|
|
// SetSize(pos.x, pos.y, size.x, size.y);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Destructor
|
|
wxWindowX11::~wxWindowX11()
|
|
{
|
|
SendDestroyEvent();
|
|
|
|
if (g_captureWindow == this)
|
|
g_captureWindow = NULL;
|
|
|
|
if ( DoFindFocus() == this )
|
|
KillFocus();
|
|
|
|
DestroyChildren();
|
|
|
|
if (m_clientWindow != m_mainWindow)
|
|
{
|
|
// Destroy the client window
|
|
Window xwindow = (Window) m_clientWindow;
|
|
wxDeleteClientWindowFromTable( xwindow );
|
|
XDestroyWindow( wxGlobalDisplay(), xwindow );
|
|
m_clientWindow = NULL;
|
|
}
|
|
|
|
// Destroy the window
|
|
if ( m_mainWindow )
|
|
{
|
|
Window xwindow = (Window) m_mainWindow;
|
|
wxDeleteWindowFromTable( xwindow );
|
|
XDestroyWindow( wxGlobalDisplay(), xwindow );
|
|
m_mainWindow = NULL;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// basic operations
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void wxWindowX11::SetFocus()
|
|
{
|
|
Window xwindow = (Window) m_clientWindow;
|
|
|
|
wxCHECK_RET( xwindow, wxT("invalid window") );
|
|
|
|
// Don't assert; we might be trying to set the focus for a panel
|
|
// with only static controls, so the panel returns false from AcceptsFocus.
|
|
// The app should be not be expected to deal with this.
|
|
if (!AcceptsFocus())
|
|
return;
|
|
|
|
wxWindow* focusedWindow = DoFindFocus();
|
|
|
|
if ( focusedWindow == (wxWindow*)this )
|
|
return; // nothing to do, focused already
|
|
|
|
if ( focusedWindow )
|
|
{
|
|
gs_toBeFocusedWindow = (wxWindow*)this;
|
|
focusedWindow->KillFocus();
|
|
gs_toBeFocusedWindow = NULL;
|
|
}
|
|
|
|
#if 0
|
|
if (GetName() == "scrollBar")
|
|
{
|
|
char *crash = NULL;
|
|
*crash = 0;
|
|
}
|
|
#endif
|
|
|
|
XWindowAttributes wa;
|
|
XGetWindowAttributes(wxGlobalDisplay(), xwindow, &wa);
|
|
|
|
if (wa.map_state == IsViewable)
|
|
{
|
|
wxLogTrace( wxT("focus"), wxT("wxWindowX11::SetFocus: %s"), GetClassInfo()->GetClassName());
|
|
// XSetInputFocus( wxGlobalDisplay(), xwindow, RevertToParent, CurrentTime );
|
|
XSetInputFocus( wxGlobalDisplay(), xwindow, RevertToNone, CurrentTime );
|
|
m_needsInputFocus = false;
|
|
}
|
|
else
|
|
{
|
|
m_needsInputFocus = true;
|
|
}
|
|
|
|
// notify the parent keeping track of focus for the kbd navigation
|
|
// purposes that we got it
|
|
wxChildFocusEvent eventFocus((wxWindow*)this);
|
|
HandleWindowEvent(eventFocus);
|
|
|
|
wxFocusEvent event(wxEVT_SET_FOCUS, GetId());
|
|
event.SetEventObject(this);
|
|
event.SetWindow((wxWindow*)xwindow);
|
|
HandleWindowEvent(event);
|
|
|
|
}
|
|
|
|
// Kill focus
|
|
void wxWindowX11::KillFocus()
|
|
{
|
|
wxCHECK_RET( DoFindFocus() == this,
|
|
"killing focus on window that doesn't have it" );
|
|
|
|
if ( m_isBeingDeleted )
|
|
return; // don't send any events from dtor
|
|
|
|
wxFocusEvent event(wxEVT_KILL_FOCUS, GetId());
|
|
event.SetEventObject(this);
|
|
event.SetWindow(gs_toBeFocusedWindow);
|
|
HandleWindowEvent(event);
|
|
}
|
|
|
|
// Get the window with the focus
|
|
wxWindow *wxWindowBase::DoFindFocus()
|
|
{
|
|
Window xfocus = (Window) 0;
|
|
int revert = 0;
|
|
|
|
XGetInputFocus( wxGlobalDisplay(), &xfocus, &revert);
|
|
if (xfocus)
|
|
{
|
|
wxWindow *win = wxGetWindowFromTable( xfocus );
|
|
if (!win)
|
|
{
|
|
win = wxGetClientWindowFromTable( xfocus );
|
|
}
|
|
|
|
return win;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Enabling/disabling handled by event loop, and not sending events
|
|
// if disabled.
|
|
bool wxWindowX11::Enable(bool enable)
|
|
{
|
|
if ( !wxWindowBase::Enable(enable) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxWindowX11::Show(bool show)
|
|
{
|
|
wxWindowBase::Show(show);
|
|
|
|
Window xwindow = (Window) m_mainWindow;
|
|
Display *xdisp = wxGlobalDisplay();
|
|
if (show)
|
|
{
|
|
// wxLogDebug( "Mapping window of type %s", GetName().c_str() );
|
|
XMapWindow(xdisp, xwindow);
|
|
}
|
|
else
|
|
{
|
|
// wxLogDebug( "Unmapping window of type %s", GetName().c_str() );
|
|
XUnmapWindow(xdisp, xwindow);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Raise the window to the top of the Z order
|
|
void wxWindowX11::Raise()
|
|
{
|
|
if (m_mainWindow)
|
|
XRaiseWindow( wxGlobalDisplay(), (Window) m_mainWindow );
|
|
}
|
|
|
|
// Lower the window to the bottom of the Z order
|
|
void wxWindowX11::Lower()
|
|
{
|
|
if (m_mainWindow)
|
|
XLowerWindow( wxGlobalDisplay(), (Window) m_mainWindow );
|
|
}
|
|
|
|
void wxWindowX11::DoCaptureMouse()
|
|
{
|
|
if ((g_captureWindow != NULL) && (g_captureWindow != this))
|
|
{
|
|
wxFAIL_MSG(wxT("Trying to capture before mouse released."));
|
|
|
|
// Core dump now
|
|
int *tmp = NULL;
|
|
(*tmp) = 1;
|
|
return;
|
|
}
|
|
|
|
if (m_winCaptured)
|
|
return;
|
|
|
|
Window xwindow = (Window) m_clientWindow;
|
|
|
|
wxCHECK_RET( xwindow, wxT("invalid window") );
|
|
|
|
g_captureWindow = (wxWindow*) this;
|
|
|
|
if (xwindow)
|
|
{
|
|
int res = XGrabPointer(wxGlobalDisplay(), xwindow,
|
|
FALSE,
|
|
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask,
|
|
GrabModeAsync,
|
|
GrabModeAsync,
|
|
None,
|
|
None, /* cursor */ // TODO: This may need to be set to the cursor of this window
|
|
CurrentTime );
|
|
|
|
if (res != GrabSuccess)
|
|
{
|
|
wxString msg;
|
|
msg.Printf(wxT("Failed to grab pointer for window %s"), this->GetClassInfo()->GetClassName());
|
|
wxLogDebug(msg);
|
|
if (res == GrabNotViewable)
|
|
{
|
|
wxLogDebug( wxT("This is not a viewable window - perhaps not shown yet?") );
|
|
}
|
|
|
|
g_captureWindow = NULL;
|
|
return;
|
|
}
|
|
|
|
m_winCaptured = true;
|
|
}
|
|
}
|
|
|
|
void wxWindowX11::DoReleaseMouse()
|
|
{
|
|
g_captureWindow = NULL;
|
|
|
|
if ( !m_winCaptured )
|
|
return;
|
|
|
|
Window xwindow = (Window) m_clientWindow;
|
|
|
|
if (xwindow)
|
|
{
|
|
XUngrabPointer( wxGlobalDisplay(), CurrentTime );
|
|
}
|
|
|
|
// wxLogDebug( "Ungrabbed pointer in %s", GetName().c_str() );
|
|
|
|
m_winCaptured = false;
|
|
}
|
|
|
|
bool wxWindowX11::SetFont(const wxFont& font)
|
|
{
|
|
if ( !wxWindowBase::SetFont(font) )
|
|
{
|
|
// nothing to do
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxWindowX11::SetCursor(const wxCursor& cursor)
|
|
{
|
|
if ( !wxWindowBase::SetCursor(cursor) )
|
|
{
|
|
// no change
|
|
return false;
|
|
}
|
|
|
|
Window xwindow = (Window) m_clientWindow;
|
|
|
|
wxCHECK_MSG( xwindow, false, wxT("invalid window") );
|
|
|
|
wxCursor cursorToUse;
|
|
if (m_cursor.IsOk())
|
|
cursorToUse = m_cursor;
|
|
else
|
|
cursorToUse = *wxSTANDARD_CURSOR;
|
|
|
|
Cursor xcursor = (Cursor) cursorToUse.GetCursor();
|
|
|
|
XDefineCursor( wxGlobalDisplay(), xwindow, xcursor );
|
|
|
|
return true;
|
|
}
|
|
|
|
// Coordinates relative to the window
|
|
void wxWindowX11::WarpPointer (int x, int y)
|
|
{
|
|
Window xwindow = (Window) m_clientWindow;
|
|
|
|
wxCHECK_RET( xwindow, wxT("invalid window") );
|
|
|
|
XWarpPointer( wxGlobalDisplay(), None, xwindow, 0, 0, 0, 0, x, y);
|
|
}
|
|
|
|
// Does a physical scroll
|
|
void wxWindowX11::ScrollWindow(int dx, int dy, const wxRect *rect)
|
|
{
|
|
// No scrolling requested.
|
|
if ((dx == 0) && (dy == 0)) return;
|
|
|
|
if (!m_updateRegion.IsEmpty())
|
|
{
|
|
m_updateRegion.Offset( dx, dy );
|
|
|
|
int cw = 0;
|
|
int ch = 0;
|
|
GetSize( &cw, &ch ); // GetClientSize() ??
|
|
m_updateRegion.Intersect( 0, 0, cw, ch );
|
|
}
|
|
|
|
if (!m_clearRegion.IsEmpty())
|
|
{
|
|
m_clearRegion.Offset( dx, dy );
|
|
|
|
int cw = 0;
|
|
int ch = 0;
|
|
GetSize( &cw, &ch ); // GetClientSize() ??
|
|
m_clearRegion.Intersect( 0, 0, cw, ch );
|
|
}
|
|
|
|
Window xwindow = (Window) GetClientAreaWindow();
|
|
|
|
wxCHECK_RET( xwindow, wxT("invalid window") );
|
|
|
|
Display *xdisplay = wxGlobalDisplay();
|
|
|
|
GC xgc = XCreateGC( xdisplay, xwindow, 0, NULL );
|
|
XSetGraphicsExposures( xdisplay, xgc, True );
|
|
|
|
int s_x = 0;
|
|
int s_y = 0;
|
|
int cw;
|
|
int ch;
|
|
if (rect)
|
|
{
|
|
s_x = rect->x;
|
|
s_y = rect->y;
|
|
|
|
cw = rect->width;
|
|
ch = rect->height;
|
|
}
|
|
else
|
|
{
|
|
s_x = 0;
|
|
s_y = 0;
|
|
GetClientSize( &cw, &ch );
|
|
}
|
|
|
|
#if wxUSE_TWO_WINDOWS
|
|
wxPoint offset( 0,0 );
|
|
#else
|
|
wxPoint offset = GetClientAreaOrigin();
|
|
s_x += offset.x;
|
|
s_y += offset.y;
|
|
#endif
|
|
|
|
int w = cw - abs(dx);
|
|
int h = ch - abs(dy);
|
|
|
|
if ((h < 0) || (w < 0))
|
|
{
|
|
Refresh();
|
|
}
|
|
else
|
|
{
|
|
wxRect rect;
|
|
if (dx < 0) rect.x = cw+dx + offset.x; else rect.x = s_x;
|
|
if (dy < 0) rect.y = ch+dy + offset.y; else rect.y = s_y;
|
|
if (dy != 0) rect.width = cw; else rect.width = abs(dx);
|
|
if (dx != 0) rect.height = ch; else rect.height = abs(dy);
|
|
|
|
int d_x = s_x;
|
|
int d_y = s_y;
|
|
|
|
if (dx < 0) s_x += -dx;
|
|
if (dy < 0) s_y += -dy;
|
|
if (dx > 0) d_x += dx + offset.x;
|
|
if (dy > 0) d_y += dy + offset.y;
|
|
|
|
XCopyArea( xdisplay, xwindow, xwindow, xgc, s_x, s_y, w, h, d_x, d_y );
|
|
|
|
// 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 );
|
|
|
|
// wxLogDebug( "Update: %d %d %d %d", rect.x, rect.y, rect.width, rect.height );
|
|
|
|
m_updateRegion.Union( rect );
|
|
m_clearRegion.Union( rect );
|
|
}
|
|
|
|
XFreeGC( xdisplay, xgc );
|
|
|
|
// Move Clients, but not the scrollbars
|
|
// FIXME: There may be a better method to move a lot of Windows within X11
|
|
wxScrollBar *sbH = ((wxWindow *) this)->GetScrollbar( wxHORIZONTAL );
|
|
wxScrollBar *sbV = ((wxWindow *) this)->GetScrollbar( wxVERTICAL );
|
|
wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
|
|
while ( node )
|
|
{
|
|
// Only propagate to non-top-level windows
|
|
wxWindow *win = node->GetData();
|
|
if ( win->GetParent() && win != sbH && win != sbV )
|
|
{
|
|
wxPoint pos = win->GetPosition();
|
|
// Add the delta to the old Position
|
|
pos.x += dx;
|
|
pos.y += dy;
|
|
win->SetPosition(pos);
|
|
}
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// drag and drop
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#if wxUSE_DRAG_AND_DROP
|
|
|
|
void wxWindowX11::SetDropTarget(wxDropTarget * WXUNUSED(pDropTarget))
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
#endif
|
|
|
|
// Old style file-manager drag&drop
|
|
void wxWindowX11::DragAcceptFiles(bool WXUNUSED(accept))
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// tooltips
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#if wxUSE_TOOLTIPS
|
|
|
|
void wxWindowX11::DoSetToolTip(wxToolTip * WXUNUSED(tooltip))
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
#endif // wxUSE_TOOLTIPS
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// moving and resizing
|
|
// ---------------------------------------------------------------------------
|
|
|
|
bool wxWindowX11::PreResize()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Get total size
|
|
void wxWindowX11::DoGetSize(int *x, int *y) const
|
|
{
|
|
Window xwindow = (Window) m_mainWindow;
|
|
|
|
wxCHECK_RET( xwindow, wxT("invalid window") );
|
|
|
|
//XSync(wxGlobalDisplay(), False);
|
|
|
|
XWindowAttributes attr;
|
|
Status status = XGetWindowAttributes( wxGlobalDisplay(), xwindow, &attr );
|
|
wxASSERT(status);
|
|
|
|
if (status)
|
|
{
|
|
*x = attr.width /* + 2*m_borderSize */ ;
|
|
*y = attr.height /* + 2*m_borderSize */ ;
|
|
}
|
|
}
|
|
|
|
void wxWindowX11::DoGetPosition(int *x, int *y) const
|
|
{
|
|
Window window = (Window) m_mainWindow;
|
|
if (window)
|
|
{
|
|
//XSync(wxGlobalDisplay(), False);
|
|
XWindowAttributes attr;
|
|
Status status = XGetWindowAttributes(wxGlobalDisplay(), window, & attr);
|
|
wxASSERT(status);
|
|
|
|
if (status)
|
|
{
|
|
*x = attr.x;
|
|
*y = attr.y;
|
|
|
|
// We may be faking the client origin. So a window that's really at (0, 30)
|
|
// may appear (to wxWin apps) to be at (0, 0).
|
|
if (GetParent())
|
|
{
|
|
wxPoint pt(GetParent()->GetClientAreaOrigin());
|
|
*x -= pt.x;
|
|
*y -= pt.y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxWindowX11::DoScreenToClient(int *x, int *y) const
|
|
{
|
|
Display *display = wxGlobalDisplay();
|
|
Window rootWindow = RootWindowOfScreen(DefaultScreenOfDisplay(display));
|
|
Window thisWindow = (Window) m_clientWindow;
|
|
|
|
Window childWindow;
|
|
int xx = x ? *x : 0;
|
|
int yy = y ? *y : 0;
|
|
XTranslateCoordinates(display, rootWindow, thisWindow,
|
|
xx, yy, x ? x : &xx, y ? y : &yy,
|
|
&childWindow);
|
|
}
|
|
|
|
void wxWindowX11::DoClientToScreen(int *x, int *y) const
|
|
{
|
|
Display *display = wxGlobalDisplay();
|
|
Window rootWindow = RootWindowOfScreen(DefaultScreenOfDisplay(display));
|
|
Window thisWindow = (Window) m_clientWindow;
|
|
|
|
Window childWindow;
|
|
int xx = x ? *x : 0;
|
|
int yy = y ? *y : 0;
|
|
XTranslateCoordinates(display, thisWindow, rootWindow,
|
|
xx, yy, x ? x : &xx, y ? y : &yy,
|
|
&childWindow);
|
|
}
|
|
|
|
|
|
// Get size *available for subwindows* i.e. excluding menu bar etc.
|
|
void wxWindowX11::DoGetClientSize(int *x, int *y) const
|
|
{
|
|
Window window = (Window) m_mainWindow;
|
|
|
|
if (window)
|
|
{
|
|
XWindowAttributes attr;
|
|
Status status = XGetWindowAttributes( wxGlobalDisplay(), window, &attr );
|
|
wxASSERT(status);
|
|
|
|
if (status)
|
|
{
|
|
*x = attr.width ;
|
|
*y = attr.height ;
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxWindowX11::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
|
{
|
|
// wxLogDebug("DoSetSize: %s (%ld) %d, %d %dx%d", GetClassInfo()->GetClassName(), GetId(), x, y, width, height);
|
|
|
|
Window xwindow = (Window) m_mainWindow;
|
|
|
|
wxCHECK_RET( xwindow, wxT("invalid window") );
|
|
|
|
XWindowAttributes attr;
|
|
Status status = XGetWindowAttributes( wxGlobalDisplay(), xwindow, &attr );
|
|
wxCHECK_RET( status, wxT("invalid window attributes") );
|
|
|
|
int new_x = attr.x;
|
|
int new_y = attr.y;
|
|
int new_w = attr.width;
|
|
int new_h = attr.height;
|
|
|
|
if (x != wxDefaultCoord || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
|
|
{
|
|
int yy = 0;
|
|
AdjustForParentClientOrigin( x, yy, sizeFlags);
|
|
new_x = x;
|
|
}
|
|
if (y != wxDefaultCoord || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
|
|
{
|
|
int xx = 0;
|
|
AdjustForParentClientOrigin( xx, y, sizeFlags);
|
|
new_y = y;
|
|
}
|
|
if (width != wxDefaultCoord)
|
|
{
|
|
new_w = width;
|
|
}
|
|
if (height != wxDefaultCoord)
|
|
{
|
|
new_h = height;
|
|
}
|
|
|
|
EnsureValidXWindowSize(new_w, new_h);
|
|
DoMoveWindow( new_x, new_y, new_w, new_h );
|
|
}
|
|
|
|
void wxWindowX11::DoSetClientSize(int width, int height)
|
|
{
|
|
// wxLogDebug("DoSetClientSize: %s (%ld) %dx%d", GetClassInfo()->GetClassName(), GetId(), width, height);
|
|
|
|
Window xwindow = (Window) m_mainWindow;
|
|
|
|
wxCHECK_RET( xwindow, wxT("invalid window") );
|
|
|
|
EnsureValidXWindowSize(width, height);
|
|
XResizeWindow( wxGlobalDisplay(), xwindow, width, height );
|
|
|
|
if (m_mainWindow != m_clientWindow)
|
|
{
|
|
xwindow = (Window) m_clientWindow;
|
|
|
|
wxWindow *window = (wxWindow*) this;
|
|
wxRenderer *renderer = window->GetRenderer();
|
|
if (renderer)
|
|
{
|
|
wxRect border = renderer->GetBorderDimensions( (wxBorder)(m_windowStyle & wxBORDER_MASK) );
|
|
width -= border.x + border.width;
|
|
height -= border.y + border.height;
|
|
}
|
|
|
|
EnsureValidXWindowSize(width, height);
|
|
XResizeWindow( wxGlobalDisplay(), xwindow, width, height );
|
|
}
|
|
}
|
|
|
|
void wxWindowX11::DoMoveWindow(int x, int y, int width, int height)
|
|
{
|
|
Window xwindow = (Window) m_mainWindow;
|
|
|
|
wxCHECK_RET( xwindow, wxT("invalid window") );
|
|
|
|
#if !wxUSE_NANOX
|
|
|
|
XMoveResizeWindow( wxGlobalDisplay(), xwindow, x, y, width, height );
|
|
if (m_mainWindow != m_clientWindow)
|
|
{
|
|
xwindow = (Window) m_clientWindow;
|
|
|
|
wxWindow *window = (wxWindow*) this;
|
|
wxRenderer *renderer = window->GetRenderer();
|
|
if (renderer)
|
|
{
|
|
wxRect border = renderer->GetBorderDimensions( (wxBorder)(m_windowStyle & wxBORDER_MASK) );
|
|
x = border.x;
|
|
y = border.y;
|
|
width -= border.x + border.width;
|
|
height -= border.y + border.height;
|
|
}
|
|
else
|
|
{
|
|
x = 0;
|
|
y = 0;
|
|
}
|
|
|
|
wxScrollBar *sb = window->GetScrollbar( wxHORIZONTAL );
|
|
if (sb && sb->IsShown())
|
|
{
|
|
wxSize size = sb->GetSize();
|
|
height -= size.y;
|
|
}
|
|
sb = window->GetScrollbar( wxVERTICAL );
|
|
if (sb && sb->IsShown())
|
|
{
|
|
wxSize size = sb->GetSize();
|
|
width -= size.x;
|
|
}
|
|
|
|
XMoveResizeWindow( wxGlobalDisplay(), xwindow, x, y, wxMax(1, width), wxMax(1, height) );
|
|
}
|
|
|
|
#else
|
|
|
|
XWindowChanges windowChanges;
|
|
windowChanges.x = x;
|
|
windowChanges.y = y;
|
|
windowChanges.width = width;
|
|
windowChanges.height = height;
|
|
windowChanges.stack_mode = 0;
|
|
int valueMask = CWX | CWY | CWWidth | CWHeight;
|
|
|
|
XConfigureWindow( wxGlobalDisplay(), xwindow, valueMask, &windowChanges );
|
|
|
|
#endif
|
|
}
|
|
|
|
void wxWindowX11::DoSetSizeHints(int minW, int minH, int maxW, int maxH, int incW, int incH)
|
|
{
|
|
m_minWidth = minW;
|
|
m_minHeight = minH;
|
|
m_maxWidth = maxW;
|
|
m_maxHeight = maxH;
|
|
|
|
#if !wxUSE_NANOX
|
|
XSizeHints sizeHints;
|
|
sizeHints.flags = 0;
|
|
|
|
if (minW > -1 && minH > -1)
|
|
{
|
|
sizeHints.flags |= PMinSize;
|
|
sizeHints.min_width = minW;
|
|
sizeHints.min_height = minH;
|
|
}
|
|
if (maxW > -1 && maxH > -1)
|
|
{
|
|
sizeHints.flags |= PMaxSize;
|
|
sizeHints.max_width = maxW;
|
|
sizeHints.max_height = maxH;
|
|
}
|
|
if (incW > -1 && incH > -1)
|
|
{
|
|
sizeHints.flags |= PResizeInc;
|
|
sizeHints.width_inc = incW;
|
|
sizeHints.height_inc = incH;
|
|
}
|
|
|
|
XSetWMNormalHints(wxGlobalDisplay(), (Window) m_mainWindow, &sizeHints );
|
|
#endif
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// text metrics
|
|
// ---------------------------------------------------------------------------
|
|
|
|
int wxWindowX11::GetCharHeight() const
|
|
{
|
|
wxFont font(GetFont());
|
|
wxCHECK_MSG( font.IsOk(), 0, wxT("valid window font needed") );
|
|
|
|
#if wxUSE_UNICODE
|
|
// There should be an easier way.
|
|
PangoLayout *layout = pango_layout_new( wxTheApp->GetPangoContext() );
|
|
pango_layout_set_font_description( layout, font.GetNativeFontInfo()->description );
|
|
pango_layout_set_text(layout, "H", 1 );
|
|
int w,h;
|
|
pango_layout_get_pixel_size(layout, &w, &h);
|
|
g_object_unref( G_OBJECT( layout ) );
|
|
|
|
return h;
|
|
#else
|
|
WXFontStructPtr pFontStruct = font.GetFontStruct(1.0, wxGlobalDisplay());
|
|
|
|
int direction, ascent, descent;
|
|
XCharStruct overall;
|
|
XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
|
|
&descent, &overall);
|
|
|
|
// return (overall.ascent + overall.descent);
|
|
return (ascent + descent);
|
|
#endif
|
|
}
|
|
|
|
int wxWindowX11::GetCharWidth() const
|
|
{
|
|
wxFont font(GetFont());
|
|
wxCHECK_MSG( font.IsOk(), 0, wxT("valid window font needed") );
|
|
|
|
#if wxUSE_UNICODE
|
|
// There should be an easier way.
|
|
PangoLayout *layout = pango_layout_new( wxTheApp->GetPangoContext() );
|
|
pango_layout_set_font_description( layout, font.GetNativeFontInfo()->description );
|
|
pango_layout_set_text(layout, "H", 1 );
|
|
int w,h;
|
|
pango_layout_get_pixel_size(layout, &w, &h);
|
|
g_object_unref( G_OBJECT( layout ) );
|
|
|
|
return w;
|
|
#else
|
|
WXFontStructPtr pFontStruct = font.GetFontStruct(1.0, wxGlobalDisplay());
|
|
|
|
int direction, ascent, descent;
|
|
XCharStruct overall;
|
|
XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
|
|
&descent, &overall);
|
|
|
|
return overall.width;
|
|
#endif
|
|
}
|
|
|
|
void wxWindowX11::DoGetTextExtent(const wxString& string,
|
|
int *x, int *y,
|
|
int *descent,
|
|
int *externalLeading,
|
|
const wxFont *theFont) const
|
|
{
|
|
wxFont fontToUse = GetFont();
|
|
if (theFont) fontToUse = *theFont;
|
|
|
|
wxCHECK_RET( fontToUse.IsOk(), wxT("invalid font") );
|
|
|
|
if (string.empty())
|
|
{
|
|
if (x) (*x) = 0;
|
|
if (y) (*y) = 0;
|
|
return;
|
|
}
|
|
|
|
#if wxUSE_UNICODE
|
|
PangoLayout *layout = pango_layout_new( wxTheApp->GetPangoContext() );
|
|
|
|
PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
|
|
pango_layout_set_font_description(layout, desc);
|
|
|
|
const wxCharBuffer data = wxConvUTF8.cWC2MB( string.wc_str() );
|
|
pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
|
|
|
|
PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
|
|
|
|
|
|
PangoRectangle rect;
|
|
pango_layout_line_get_extents(line, NULL, &rect);
|
|
|
|
if (x) (*x) = (wxCoord) (rect.width / PANGO_SCALE);
|
|
if (y) (*y) = (wxCoord) (rect.height / PANGO_SCALE);
|
|
if (descent)
|
|
{
|
|
// Do something about metrics here
|
|
(*descent) = 0;
|
|
}
|
|
if (externalLeading) (*externalLeading) = 0; // ??
|
|
|
|
g_object_unref( G_OBJECT( layout ) );
|
|
#else
|
|
WXFontStructPtr pFontStruct = fontToUse.GetFontStruct(1.0, wxGlobalDisplay());
|
|
|
|
int direction, ascent, descent2;
|
|
XCharStruct overall;
|
|
int slen = string.length();
|
|
|
|
XTextExtents((XFontStruct*) pFontStruct, (const char*) string.c_str(), slen,
|
|
&direction, &ascent, &descent2, &overall);
|
|
|
|
if ( x )
|
|
*x = (overall.width);
|
|
if ( y )
|
|
*y = (ascent + descent2);
|
|
if (descent)
|
|
*descent = descent2;
|
|
if (externalLeading)
|
|
*externalLeading = 0;
|
|
#endif
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// painting
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxWindowX11::Refresh(bool eraseBack, const wxRect *rect)
|
|
{
|
|
if (eraseBack)
|
|
{
|
|
if (rect)
|
|
{
|
|
// Schedule for later Updating in ::Update() or ::OnInternalIdle().
|
|
m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
|
|
}
|
|
else
|
|
{
|
|
int height,width;
|
|
GetSize( &width, &height );
|
|
|
|
// Schedule for later Updating in ::Update() or ::OnInternalIdle().
|
|
m_clearRegion.Clear();
|
|
m_clearRegion.Union( 0, 0, width, height );
|
|
}
|
|
}
|
|
|
|
if (rect)
|
|
{
|
|
// Schedule for later Updating in ::Update() or ::OnInternalIdle().
|
|
m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
|
|
}
|
|
else
|
|
{
|
|
int height,width;
|
|
GetSize( &width, &height );
|
|
|
|
// Schedule for later Updating in ::Update() or ::OnInternalIdle().
|
|
m_updateRegion.Clear();
|
|
m_updateRegion.Union( 0, 0, width, height );
|
|
}
|
|
}
|
|
|
|
void wxWindowX11::Update()
|
|
{
|
|
if (m_updateNcArea)
|
|
{
|
|
// wxLogDebug("wxWindowX11::UpdateNC: %s", GetClassInfo()->GetClassName());
|
|
// Send nc paint events.
|
|
SendNcPaintEvents();
|
|
}
|
|
|
|
if (!m_updateRegion.IsEmpty())
|
|
{
|
|
// wxLogDebug("wxWindowX11::Update: %s", GetClassInfo()->GetClassName());
|
|
// Actually send erase events.
|
|
SendEraseEvents();
|
|
|
|
// Actually send paint events.
|
|
SendPaintEvents();
|
|
}
|
|
}
|
|
|
|
void wxWindowX11::SendEraseEvents()
|
|
{
|
|
if (m_clearRegion.IsEmpty()) return;
|
|
|
|
wxClientDC dc( (wxWindow*)this );
|
|
dc.SetDeviceClippingRegion( m_clearRegion );
|
|
|
|
wxEraseEvent erase_event( GetId(), &dc );
|
|
erase_event.SetEventObject( this );
|
|
|
|
if (!HandleWindowEvent(erase_event) )
|
|
{
|
|
Display *xdisplay = wxGlobalDisplay();
|
|
Window xwindow = (Window) GetClientAreaWindow();
|
|
XSetForeground( xdisplay, g_eraseGC, m_backgroundColour.GetPixel() );
|
|
|
|
wxRegionIterator upd( m_clearRegion );
|
|
while (upd)
|
|
{
|
|
XFillRectangle( xdisplay, xwindow, g_eraseGC,
|
|
upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
|
|
upd ++;
|
|
}
|
|
}
|
|
|
|
m_clearRegion.Clear();
|
|
}
|
|
|
|
void wxWindowX11::SendPaintEvents()
|
|
{
|
|
// wxLogDebug("SendPaintEvents: %s (%ld)", GetClassInfo()->GetClassName(), GetId());
|
|
|
|
m_clipPaintRegion = true;
|
|
|
|
wxPaintEvent paint_event( this );
|
|
HandleWindowEvent( paint_event );
|
|
|
|
m_updateRegion.Clear();
|
|
|
|
m_clipPaintRegion = false;
|
|
}
|
|
|
|
void wxWindowX11::SendNcPaintEvents()
|
|
{
|
|
wxWindow *window = (wxWindow*) this;
|
|
|
|
// All this for drawing the small square between the scrollbars.
|
|
int width = 0;
|
|
int height = 0;
|
|
int x = 0;
|
|
int y = 0;
|
|
wxScrollBar *sb = window->GetScrollbar( wxHORIZONTAL );
|
|
if (sb && sb->IsShown())
|
|
{
|
|
height = sb->GetSize().y;
|
|
y = sb->GetPosition().y;
|
|
|
|
sb = window->GetScrollbar( wxVERTICAL );
|
|
if (sb && sb->IsShown())
|
|
{
|
|
width = sb->GetSize().x;
|
|
x = sb->GetPosition().x;
|
|
|
|
Display *xdisplay = wxGlobalDisplay();
|
|
Window xwindow = (Window) X11GetMainWindow();
|
|
Colormap cm = (Colormap) wxTheApp->GetMainColormap( wxGetDisplay() );
|
|
wxColour colour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
|
|
colour.CalcPixel( (WXColormap) cm );
|
|
|
|
XSetForeground( xdisplay, g_eraseGC, colour.GetPixel() );
|
|
|
|
XFillRectangle( xdisplay, xwindow, g_eraseGC, x, y, width, height );
|
|
}
|
|
}
|
|
|
|
wxNcPaintEvent nc_paint_event( this );
|
|
HandleWindowEvent( nc_paint_event );
|
|
|
|
m_updateNcArea = false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// event handlers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Responds to colour changes: passes event on to children.
|
|
void wxWindowX11::OnSysColourChanged(wxSysColourChangedEvent& event)
|
|
{
|
|
wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
|
|
while ( node )
|
|
{
|
|
// Only propagate to non-top-level windows
|
|
wxWindow *win = node->GetData();
|
|
if ( win->GetParent() )
|
|
{
|
|
wxSysColourChangedEvent event2;
|
|
event.SetEventObject(win);
|
|
win->HandleWindowEvent(event2);
|
|
}
|
|
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
// See handler for InFocus case in app.cpp for details.
|
|
wxWindow* g_GettingFocus = NULL;
|
|
|
|
void wxWindowX11::OnInternalIdle()
|
|
{
|
|
// Update invalidated regions.
|
|
Update();
|
|
|
|
wxWindowBase::OnInternalIdle();
|
|
|
|
// Set the input focus if couldn't do it before
|
|
if (m_needsInputFocus)
|
|
{
|
|
#if 0
|
|
wxString msg;
|
|
msg.Printf("Setting focus for %s from OnInternalIdle\n", GetClassInfo()->GetClassName());
|
|
printf(msg.c_str());
|
|
#endif
|
|
SetFocus();
|
|
|
|
// If it couldn't set the focus now, there's
|
|
// no point in trying again.
|
|
m_needsInputFocus = false;
|
|
}
|
|
g_GettingFocus = NULL;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// function which maintain the global hash table mapping Widgets to wxWidgets
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static bool DoAddWindowToTable(wxWindowHash *hash, Window w, wxWindow *win)
|
|
{
|
|
if ( !hash->insert(wxWindowHash::value_type(w, win)).second )
|
|
{
|
|
wxLogDebug( wxT("Widget table clash: new widget is 0x%08x, %s"),
|
|
(unsigned int)w, win->GetClassInfo()->GetClassName());
|
|
return false;
|
|
}
|
|
|
|
wxLogTrace( wxT("widget"), wxT("XWindow 0x%08x <-> window %p (%s)"),
|
|
(unsigned int) w, win, win->GetClassInfo()->GetClassName());
|
|
|
|
return true;
|
|
}
|
|
|
|
static inline wxWindow *DoGetWindowFromTable(wxWindowHash *hash, Window w)
|
|
{
|
|
wxWindowHash::iterator i = hash->find(w);
|
|
return i == hash->end() ? NULL : i->second;
|
|
}
|
|
|
|
static inline void DoDeleteWindowFromTable(wxWindowHash *hash, Window w)
|
|
{
|
|
wxLogTrace( wxT("widget"), wxT("XWindow 0x%08x deleted"), (unsigned int) w);
|
|
|
|
hash->erase(w);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// public wrappers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool wxAddWindowToTable(Window w, wxWindow *win)
|
|
{
|
|
return DoAddWindowToTable(wxWidgetHashTable, w, win);
|
|
}
|
|
|
|
wxWindow *wxGetWindowFromTable(Window w)
|
|
{
|
|
return DoGetWindowFromTable(wxWidgetHashTable, w);
|
|
}
|
|
|
|
void wxDeleteWindowFromTable(Window w)
|
|
{
|
|
DoDeleteWindowFromTable(wxWidgetHashTable, w);
|
|
}
|
|
|
|
bool wxAddClientWindowToTable(Window w, wxWindow *win)
|
|
{
|
|
return DoAddWindowToTable(wxClientWidgetHashTable, w, win);
|
|
}
|
|
|
|
wxWindow *wxGetClientWindowFromTable(Window w)
|
|
{
|
|
return DoGetWindowFromTable(wxClientWidgetHashTable, w);
|
|
}
|
|
|
|
void wxDeleteClientWindowFromTable(Window w)
|
|
{
|
|
DoDeleteWindowFromTable(wxClientWidgetHashTable, w);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// X11-specific accessors
|
|
// ----------------------------------------------------------------------------
|
|
|
|
WXWindow wxWindowX11::X11GetMainWindow() const
|
|
{
|
|
return m_mainWindow;
|
|
}
|
|
|
|
WXWindow wxWindowX11::GetClientAreaWindow() const
|
|
{
|
|
return m_clientWindow;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// TranslateXXXEvent() functions
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool wxTranslateMouseEvent(wxMouseEvent& wxevent,
|
|
wxWindow *win,
|
|
Window WXUNUSED(window),
|
|
XEvent *xevent)
|
|
{
|
|
switch (XEventGetType(xevent))
|
|
{
|
|
case EnterNotify:
|
|
case LeaveNotify:
|
|
case ButtonPress:
|
|
case ButtonRelease:
|
|
case MotionNotify:
|
|
{
|
|
wxEventType eventType = wxEVT_NULL;
|
|
|
|
if (XEventGetType(xevent) == EnterNotify)
|
|
{
|
|
//if (local_event.xcrossing.mode!=NotifyNormal)
|
|
// return ; // Ignore grab events
|
|
eventType = wxEVT_ENTER_WINDOW;
|
|
// canvas->GetEventHandler()->OnSetFocus();
|
|
}
|
|
else if (XEventGetType(xevent) == LeaveNotify)
|
|
{
|
|
//if (local_event.xcrossingr.mode!=NotifyNormal)
|
|
// return ; // Ignore grab events
|
|
eventType = wxEVT_LEAVE_WINDOW;
|
|
// canvas->GetEventHandler()->OnKillFocus();
|
|
}
|
|
else if (XEventGetType(xevent) == MotionNotify)
|
|
{
|
|
eventType = wxEVT_MOTION;
|
|
}
|
|
else if (XEventGetType(xevent) == ButtonPress)
|
|
{
|
|
wxevent.SetTimestamp(XButtonEventGetTime(xevent));
|
|
int button = 0;
|
|
if (XButtonEventLChanged(xevent))
|
|
{
|
|
eventType = wxEVT_LEFT_DOWN;
|
|
button = 1;
|
|
}
|
|
else if (XButtonEventMChanged(xevent))
|
|
{
|
|
eventType = wxEVT_MIDDLE_DOWN;
|
|
button = 2;
|
|
}
|
|
else if (XButtonEventRChanged(xevent))
|
|
{
|
|
eventType = wxEVT_RIGHT_DOWN;
|
|
button = 3;
|
|
}
|
|
else if ( xevent->xbutton.button == Button4 ||
|
|
xevent->xbutton.button == Button5 )
|
|
{
|
|
// this is the same value as used under wxMSW
|
|
static const int WHEEL_DELTA = 120;
|
|
|
|
eventType = wxEVT_MOUSEWHEEL;
|
|
button = xevent->xbutton.button;
|
|
|
|
wxevent.m_linesPerAction = 3;
|
|
wxevent.m_columnsPerAction = 3;
|
|
wxevent.m_wheelDelta = WHEEL_DELTA;
|
|
|
|
// Button 4 means mousewheel up, 5 means down
|
|
wxevent.m_wheelRotation = button == Button4 ? WHEEL_DELTA
|
|
: -WHEEL_DELTA;
|
|
}
|
|
|
|
// check for a double click
|
|
// TODO: where can we get this value from?
|
|
//long dclickTime = XtGetMultiClickTime(wxGlobalDisplay());
|
|
long dclickTime = 200;
|
|
long ts = wxevent.GetTimestamp();
|
|
|
|
int buttonLast = win->GetLastClickedButton();
|
|
long lastTS = win->GetLastClickTime();
|
|
if ( buttonLast && buttonLast == button && (ts - lastTS) < dclickTime )
|
|
{
|
|
// I have a dclick
|
|
win->SetLastClick(0, ts);
|
|
if ( eventType == wxEVT_LEFT_DOWN )
|
|
eventType = wxEVT_LEFT_DCLICK;
|
|
else if ( eventType == wxEVT_MIDDLE_DOWN )
|
|
eventType = wxEVT_MIDDLE_DCLICK;
|
|
else if ( eventType == wxEVT_RIGHT_DOWN )
|
|
eventType = wxEVT_RIGHT_DCLICK;
|
|
}
|
|
else
|
|
{
|
|
// not fast enough or different button
|
|
win->SetLastClick(button, ts);
|
|
}
|
|
}
|
|
else if (XEventGetType(xevent) == ButtonRelease)
|
|
{
|
|
if (XButtonEventLChanged(xevent))
|
|
{
|
|
eventType = wxEVT_LEFT_UP;
|
|
}
|
|
else if (XButtonEventMChanged(xevent))
|
|
{
|
|
eventType = wxEVT_MIDDLE_UP;
|
|
}
|
|
else if (XButtonEventRChanged(xevent))
|
|
{
|
|
eventType = wxEVT_RIGHT_UP;
|
|
}
|
|
else return false;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
wxevent.SetEventType(eventType);
|
|
|
|
wxevent.m_x = XButtonEventGetX(xevent);
|
|
wxevent.m_y = XButtonEventGetY(xevent);
|
|
|
|
wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN)
|
|
|| (XButtonEventLIsDown(xevent)
|
|
&& (eventType != wxEVT_LEFT_UP)));
|
|
wxevent.m_middleDown = ((eventType == wxEVT_MIDDLE_DOWN)
|
|
|| (XButtonEventMIsDown(xevent)
|
|
&& (eventType != wxEVT_MIDDLE_UP)));
|
|
wxevent.m_rightDown = ((eventType == wxEVT_RIGHT_DOWN)
|
|
|| (XButtonEventRIsDown (xevent)
|
|
&& (eventType != wxEVT_RIGHT_UP)));
|
|
|
|
wxevent.m_shiftDown = XButtonEventShiftIsDown(xevent);
|
|
wxevent.m_controlDown = XButtonEventCtrlIsDown(xevent);
|
|
wxevent.m_altDown = XButtonEventAltIsDown(xevent);
|
|
wxevent.m_metaDown = XButtonEventMetaIsDown(xevent);
|
|
|
|
wxevent.SetId(win->GetId());
|
|
wxevent.SetEventObject(win);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool wxTranslateKeyEvent(wxKeyEvent& wxevent, wxWindow *win, Window WXUNUSED(win), XEvent *xevent, bool isAscii)
|
|
{
|
|
switch (XEventGetType(xevent))
|
|
{
|
|
case KeyPress:
|
|
case KeyRelease:
|
|
{
|
|
char buf[20];
|
|
|
|
KeySym keySym;
|
|
(void) XLookupString ((XKeyEvent *) xevent, buf, 20, &keySym, NULL);
|
|
#if wxUSE_UNICODE
|
|
int id = wxUnicodeCharXToWX(keySym);
|
|
#else
|
|
int id = wxCharCodeXToWX(keySym);
|
|
#endif
|
|
// id may be WXK_xxx code - these are outside ASCII range, so we
|
|
// can't just use toupper() on id.
|
|
// Only change this if we want the raw key that was pressed,
|
|
// and don't change it if we want an ASCII value.
|
|
if (!isAscii && (id >= 'a' && id <= 'z'))
|
|
{
|
|
id = id + 'A' - 'a';
|
|
}
|
|
|
|
wxevent.m_shiftDown = XKeyEventShiftIsDown(xevent);
|
|
wxevent.m_controlDown = XKeyEventCtrlIsDown(xevent);
|
|
wxevent.m_altDown = XKeyEventAltIsDown(xevent);
|
|
wxevent.m_metaDown = XKeyEventMetaIsDown(xevent);
|
|
wxevent.SetEventObject(win);
|
|
#if wxUSE_UNICODE
|
|
wxevent.m_uniChar = id;
|
|
#endif
|
|
wxevent.m_keyCode = id;
|
|
|
|
wxevent.SetTimestamp(XKeyEventGetTime(xevent));
|
|
|
|
wxevent.m_x = XKeyEventGetX(xevent);
|
|
wxevent.m_y = XKeyEventGetY(xevent);
|
|
|
|
return id > -1;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Colour stuff
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool wxWindowX11::SetBackgroundColour(const wxColour& col)
|
|
{
|
|
if ( !wxWindowBase::SetBackgroundColour(col) )
|
|
return false;
|
|
|
|
if ( !m_backgroundColour.IsOk() )
|
|
{
|
|
// Reset to the default colour as we must have a valid background.
|
|
m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
|
|
}
|
|
|
|
Display *xdisplay = (Display*) wxGlobalDisplay();
|
|
int xscreen = DefaultScreen( xdisplay );
|
|
Colormap cm = DefaultColormap( xdisplay, xscreen );
|
|
|
|
m_backgroundColour.CalcPixel( (WXColormap) cm );
|
|
|
|
// We don't set the background colour as we paint
|
|
// the background ourselves.
|
|
// XSetWindowBackground( xdisplay, (Window) m_clientWindow, m_backgroundColour.GetPixel() );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxWindowX11::SetForegroundColour(const wxColour& col)
|
|
{
|
|
if ( !wxWindowBase::SetForegroundColour(col) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// global functions
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxWindow *wxGetActiveWindow()
|
|
{
|
|
return wxGetTopLevelParent(wxWindow::FindFocus());
|
|
}
|
|
|
|
/* static */
|
|
wxWindow *wxWindowBase::GetCapture()
|
|
{
|
|
return (wxWindow *)g_captureWindow;
|
|
}
|
|
|
|
|
|
// Find the wxWindow at the current mouse position, returning the mouse
|
|
// position.
|
|
wxWindow* wxFindWindowAtPointer(wxPoint& pt)
|
|
{
|
|
pt = wxGetMousePosition();
|
|
return wxFindWindowAtPoint(pt);
|
|
}
|
|
|
|
void wxGetMouseState(int& rootX, int& rootY, unsigned& maskReturn)
|
|
{
|
|
#if wxUSE_NANOX
|
|
/* TODO */
|
|
rootX = rootY = 0;
|
|
maskReturn = 0;
|
|
#else
|
|
Display *display = wxGlobalDisplay();
|
|
Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
|
|
Window rootReturn, childReturn;
|
|
int winX, winY;
|
|
|
|
XQueryPointer (display,
|
|
rootWindow,
|
|
&rootReturn,
|
|
&childReturn,
|
|
&rootX, &rootY, &winX, &winY, &maskReturn);
|
|
#endif
|
|
}
|
|
|
|
// Get the current mouse position.
|
|
wxPoint wxGetMousePosition()
|
|
{
|
|
int x, y;
|
|
unsigned mask;
|
|
|
|
wxGetMouseState(x, y, mask);
|
|
return wxPoint(x, y);
|
|
}
|
|
|
|
wxMouseState wxGetMouseState()
|
|
{
|
|
wxMouseState ms;
|
|
int x, y;
|
|
unsigned mask;
|
|
|
|
wxGetMouseState(x, y, mask);
|
|
|
|
ms.SetX(x);
|
|
ms.SetY(y);
|
|
|
|
ms.SetLeftDown(mask & Button1Mask);
|
|
ms.SetMiddleDown(mask & Button2Mask);
|
|
ms.SetRightDown(mask & Button3Mask);
|
|
|
|
ms.SetControlDown(mask & ControlMask);
|
|
ms.SetShiftDown(mask & ShiftMask);
|
|
ms.SetAltDown(mask & Mod3Mask);
|
|
ms.SetMetaDown(mask & Mod1Mask);
|
|
|
|
return ms;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxNoOptimize: switch off size optimization
|
|
// ----------------------------------------------------------------------------
|
|
|
|
int wxNoOptimize::ms_count = 0;
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxDCModule
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class wxWinModule : public wxModule
|
|
{
|
|
public:
|
|
wxWinModule()
|
|
{
|
|
// we must be cleaned up before the display is closed
|
|
AddDependency(wxClassInfo::FindClass(wxT("wxX11DisplayModule")));
|
|
}
|
|
|
|
virtual bool OnInit();
|
|
virtual void OnExit();
|
|
|
|
private:
|
|
wxDECLARE_DYNAMIC_CLASS(wxWinModule);
|
|
};
|
|
|
|
wxIMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule);
|
|
|
|
bool wxWinModule::OnInit()
|
|
{
|
|
Display *xdisplay = wxGlobalDisplay();
|
|
if ( !xdisplay )
|
|
{
|
|
// This module may be linked into a console program when using
|
|
// monolithic library and in this case it's perfectly normal not to
|
|
// have a display, so just return without doing anything and avoid
|
|
// crashing below.
|
|
return true;
|
|
}
|
|
|
|
int xscreen = DefaultScreen( xdisplay );
|
|
Window xroot = RootWindow( xdisplay, xscreen );
|
|
g_eraseGC = XCreateGC( xdisplay, xroot, 0, NULL );
|
|
XSetFillStyle( xdisplay, g_eraseGC, FillSolid );
|
|
|
|
return true;
|
|
}
|
|
|
|
void wxWinModule::OnExit()
|
|
{
|
|
Display *xdisplay = wxGlobalDisplay();
|
|
XFreeGC( xdisplay, g_eraseGC );
|
|
}
|