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