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