More tests in erase sample.
[wxWidgets.git] / src / x11 / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: windows.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 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "window.h"
22 #endif
23
24 #include "wx/setup.h"
25 #include "wx/menu.h"
26 #include "wx/dc.h"
27 #include "wx/dcclient.h"
28 #include "wx/utils.h"
29 #include "wx/app.h"
30 #include "wx/panel.h"
31 #include "wx/layout.h"
32 #include "wx/dialog.h"
33 #include "wx/listbox.h"
34 #include "wx/button.h"
35 #include "wx/settings.h"
36 #include "wx/msgdlg.h"
37 #include "wx/frame.h"
38 #include "wx/scrolwin.h"
39 #include "wx/module.h"
40 #include "wx/menuitem.h"
41 #include "wx/log.h"
42
43 #if wxUSE_DRAG_AND_DROP
44 #include "wx/dnd.h"
45 #endif
46
47 #include "wx/x11/private.h"
48 #include "X11/Xutil.h"
49
50 #if wxUSE_NANOX
51 // For wxGetLocalTime, used by XButtonEventGetTime
52 #include "wx/timer.h"
53 #endif
54
55 #include <string.h>
56
57 // ----------------------------------------------------------------------------
58 // global variables for this module
59 // ----------------------------------------------------------------------------
60
61 extern wxHashTable *wxWidgetHashTable;
62 static wxWindow* g_captureWindow = NULL;
63
64 // ----------------------------------------------------------------------------
65 // macros
66 // ----------------------------------------------------------------------------
67
68 #define event_left_is_down(x) ((x)->xbutton.state & Button1Mask)
69 #define event_middle_is_down(x) ((x)->xbutton.state & Button2Mask)
70 #define event_right_is_down(x) ((x)->xbutton.state & Button3Mask)
71
72 // ----------------------------------------------------------------------------
73 // event tables
74 // ----------------------------------------------------------------------------
75
76 IMPLEMENT_ABSTRACT_CLASS(wxWindowX11, wxWindowBase)
77
78 BEGIN_EVENT_TABLE(wxWindowX11, wxWindowBase)
79 EVT_SYS_COLOUR_CHANGED(wxWindowX11::OnSysColourChanged)
80 END_EVENT_TABLE()
81
82 // ============================================================================
83 // implementation
84 // ============================================================================
85
86 // ----------------------------------------------------------------------------
87 // helper functions
88 // ----------------------------------------------------------------------------
89
90 // ----------------------------------------------------------------------------
91 // constructors
92 // ----------------------------------------------------------------------------
93
94 void wxWindowX11::Init()
95 {
96 // generic initializations first
97 InitBase();
98
99 // X11-specific
100 m_mainWidget = (WXWindow) 0;
101 m_winCaptured = FALSE;
102 m_needsInputFocus = FALSE;
103 m_isShown = TRUE;
104 m_isBeingDeleted = FALSE;
105 m_lastTS = 0;
106 m_lastButton = 0;
107 }
108
109 // real construction (Init() must have been called before!)
110 bool wxWindowX11::Create(wxWindow *parent, wxWindowID id,
111 const wxPoint& pos,
112 const wxSize& size,
113 long style,
114 const wxString& name)
115 {
116 wxCHECK_MSG( parent, FALSE, "can't create wxWindow without parent" );
117
118 CreateBase(parent, id, pos, size, style, wxDefaultValidator, name);
119
120 parent->AddChild(this);
121
122 int w = size.GetWidth();
123 int h = size.GetHeight();
124 int x = size.GetX();
125 int y = size.GetY();
126 if (w == -1) w = 20;
127 if (h == -1) h = 20;
128 if (x == -1) x = 0;
129 if (y == -1) y = 0;
130
131 Display *xdisplay = (Display*) wxGlobalDisplay();
132 int xscreen = DefaultScreen( xdisplay );
133 Visual *xvisual = DefaultVisual( xdisplay, xscreen );
134 Colormap cm = DefaultColormap( xdisplay, xscreen );
135
136 m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
137 m_backgroundColour.CalcPixel( (WXColormap) cm );
138
139 m_foregroundColour = *wxBLACK;
140 m_foregroundColour.CalcPixel( (WXColormap) cm );
141
142 Window xparent = (Window) parent->GetMainWindow();
143
144 #if !wxUSE_NANOX
145 XSetWindowAttributes xattributes;
146
147 long xattributes_mask =
148 CWEventMask |
149 CWBorderPixel | CWBackPixel;
150
151 xattributes.background_pixel = m_backgroundColour.GetPixel();
152 xattributes.border_pixel = BlackPixel( xdisplay, xscreen );
153
154 xattributes.event_mask =
155 ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
156 ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
157 KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
158 PropertyChangeMask;
159 #endif
160
161 wxSize size2(size);
162 if (size2.x == -1)
163 size2.x = 20;
164 if (size2.y == -1)
165 size2.y = 20;
166
167 wxPoint pos2(pos);
168 if (pos2.x == -1)
169 pos2.x = 0;
170 if (pos2.y == -1)
171 pos2.y = 0;
172
173 #if wxUSE_NANOX
174 int extraFlags = GR_EVENT_MASK_CLOSE_REQ;
175
176 long backColor, foreColor;
177 backColor = GR_RGB(m_backgroundColour.Red(), m_backgroundColour.Green(), m_backgroundColour.Blue());
178 foreColor = GR_RGB(m_foregroundColour.Red(), m_foregroundColour.Green(), m_foregroundColour.Blue());
179
180 Window xwindow = XCreateWindowWithColor( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
181 0, 0, InputOutput, xvisual, backColor, foreColor);
182 XSelectInput( xdisplay, xwindow,
183 extraFlags | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
184 ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask |
185 KeymapStateMask | FocusChangeMask | ColormapChangeMask | StructureNotifyMask |
186 PropertyChangeMask );
187
188 #else
189
190 Window xwindow = XCreateWindow( xdisplay, xparent, pos2.x, pos2.y, size2.x, size2.y,
191 0, DefaultDepth(xdisplay,xscreen), InputOutput, xvisual, xattributes_mask, &xattributes );
192
193 #endif
194
195 m_mainWidget = (WXWindow) xwindow;
196
197 wxAddWindowToTable( xwindow, (wxWindow*) this );
198
199 // Is a subwindow, so map immediately
200 m_isShown = TRUE;
201 XMapWindow( xdisplay, xwindow );
202
203 // Without this, the cursor may not be restored properly (e.g. in splitter
204 // sample).
205 SetCursor(*wxSTANDARD_CURSOR);
206 SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
207
208 // Set background to None which will prevent X11 from clearing the
209 // background comletely.
210 XSetWindowBackgroundPixmap( xdisplay, xwindow, None );
211
212 // Don't call this, it can have nasty repercussions for composite controls,
213 // for example
214 // SetSize(pos.x, pos.y, size.x, size.y);
215
216 return TRUE;
217 }
218
219 // Destructor
220 wxWindowX11::~wxWindowX11()
221 {
222 if (g_captureWindow == this)
223 g_captureWindow = NULL;
224
225 m_isBeingDeleted = TRUE;
226
227 // X11-specific actions first
228 Window xwindow = (Window) m_mainWidget;
229
230 if (m_parent)
231 m_parent->RemoveChild( this );
232
233 DestroyChildren();
234
235 // Destroy the window
236 if (xwindow)
237 {
238 XSelectInput( wxGlobalDisplay(), xwindow, NoEventMask);
239 wxDeleteWindowFromTable( xwindow );
240 XDestroyWindow( wxGlobalDisplay(), xwindow );
241 m_mainWidget = NULL;
242 }
243 }
244
245 // ---------------------------------------------------------------------------
246 // basic operations
247 // ---------------------------------------------------------------------------
248
249 void wxWindowX11::SetFocus()
250 {
251 Window xwindow = (Window) GetMainWindow();
252
253 wxCHECK_RET( xwindow, wxT("invalid window") );
254
255 if (wxWindowIsVisible(xwindow))
256 {
257 XSetInputFocus( wxGlobalDisplay(), xwindow, RevertToParent, CurrentTime );
258 m_needsInputFocus = FALSE;
259 }
260 else
261 {
262 m_needsInputFocus = TRUE;
263 }
264 }
265
266 // Get the window with the focus
267 wxWindow *wxWindowBase::FindFocus()
268 {
269 Window xfocus = (Window) 0;
270 int revert = 0;
271
272 XGetInputFocus( wxGlobalDisplay(), &xfocus, &revert);
273 if (xfocus)
274 {
275 wxWindow *win = wxGetWindowFromTable( xfocus );
276
277 return win;
278 }
279
280 return NULL;
281 }
282
283 wxWindow *wxWindowX11::GetFocusWidget()
284 {
285 wxWindow *win = (wxWindow*) this;
286 while (!win->IsTopLevel())
287 {
288 win = win->GetParent();
289 if (!win)
290 return (wxWindow*) NULL;
291 }
292
293 return win;
294 }
295
296 // Enabling/disabling handled by event loop, and not sending events
297 // if disabled.
298 bool wxWindowX11::Enable(bool enable)
299 {
300 if ( !wxWindowBase::Enable(enable) )
301 return FALSE;
302
303 return TRUE;
304 }
305
306 bool wxWindowX11::Show(bool show)
307 {
308 wxWindowBase::Show(show);
309
310 Window xwin = (Window) GetXWindow();
311 Display *xdisp = (Display*) GetXDisplay();
312 if (show)
313 {
314 // wxLogDebug( "Mapping window of type %s", GetName().c_str() );
315 XMapWindow(xdisp, xwin);
316 XSync(xdisp, False);
317 }
318 else
319 {
320 // wxLogDebug( "Unmapping window of type %s", GetName().c_str() );
321 XUnmapWindow(xdisp, xwin);
322 }
323
324 return TRUE;
325 }
326
327 // Raise the window to the top of the Z order
328 void wxWindowX11::Raise()
329 {
330 if (m_mainWidget)
331 XRaiseWindow( wxGlobalDisplay(), (Window) m_mainWidget );
332 }
333
334 // Lower the window to the bottom of the Z order
335 void wxWindowX11::Lower()
336 {
337 if (m_mainWidget)
338 XLowerWindow( wxGlobalDisplay(), (Window) m_mainWidget );
339 }
340
341 void wxWindowX11::DoCaptureMouse()
342 {
343 if ((g_captureWindow != NULL) && (g_captureWindow != this))
344 {
345 wxASSERT_MSG(FALSE, "Trying to capture before mouse released.");
346
347 // Core dump now
348 int *tmp = NULL;
349 (*tmp) = 1;
350 return;
351 }
352
353 if (m_winCaptured)
354 return;
355
356 Window xwindow = (Window) GetMainWindow();
357
358 wxCHECK_RET( xwindow, wxT("invalid window") );
359
360 g_captureWindow = (wxWindow*) this;
361
362 if (xwindow)
363 {
364 int res = XGrabPointer(wxGlobalDisplay(), xwindow,
365 FALSE,
366 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask,
367 GrabModeAsync,
368 GrabModeAsync,
369 None,
370 None, /* cursor */ // TODO: This may need to be set to the cursor of this window
371 CurrentTime );
372
373 if (res != GrabSuccess)
374 {
375 wxString msg;
376 msg.Printf("Failed to grab pointer for window %s", this->GetClassInfo()->GetClassName());
377 wxLogDebug(msg);
378 if (res == GrabNotViewable)
379 {
380 wxLogDebug("This is not a viewable window - perhaps not shown yet?");
381 }
382 g_captureWindow = NULL;
383 return;
384 }
385
386 // wxLogDebug("Grabbed pointer in %s", GetName().c_str() );
387
388 #if 0
389 res = XGrabButton(wxGlobalDisplay(), AnyButton, AnyModifier,
390 (Window) GetMainWindow(),
391 FALSE,
392 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
393 GrabModeAsync,
394 GrabModeAsync,
395 None,
396 None);
397
398 if (res != GrabSuccess)
399 {
400 wxLogDebug("Failed to grab mouse buttons.");
401 XUngrabPointer(wxGlobalDisplay(), CurrentTime);
402 return;
403 }
404 #endif
405
406 #if 0
407 res = XGrabKeyboard(wxGlobalDisplay(), (Window) GetMainWindow(),
408 ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask,
409 FALSE,
410 GrabModeAsync,
411 GrabModeAsync,
412 CurrentTime);
413
414 if (res != GrabSuccess)
415 {
416 wxLogDebug("Failed to grab keyboard.");
417 XUngrabPointer(wxGlobalDisplay(), CurrentTime);
418 XUngrabButton(wxGlobalDisplay(), AnyButton, AnyModifier,
419 (Window) GetMainWindow());
420 return;
421 }
422 #endif
423
424 m_winCaptured = TRUE;
425 }
426 }
427
428 void wxWindowX11::DoReleaseMouse()
429 {
430 g_captureWindow = NULL;
431
432 if ( !m_winCaptured )
433 return;
434
435 Window xwindow = (Window) GetMainWindow();
436
437 if (xwindow)
438 {
439 XUngrabPointer( wxGlobalDisplay(), CurrentTime );
440 #if 0
441 XUngrabButton( wxGlobalDisplay(), AnyButton, AnyModifier, xwindow);
442 XUngrabKeyboard( wxGlobalDisplay(), CurrentTime );
443 #endif
444 }
445
446 // wxLogDebug( "Ungrabbed pointer in %s", GetName().c_str() );
447
448 m_winCaptured = FALSE;
449 }
450
451 bool wxWindowX11::SetFont(const wxFont& font)
452 {
453 if ( !wxWindowBase::SetFont(font) )
454 {
455 // nothing to do
456 return FALSE;
457 }
458
459 return TRUE;
460 }
461
462 bool wxWindowX11::SetCursor(const wxCursor& cursor)
463 {
464 if ( !wxWindowBase::SetCursor(cursor) )
465 {
466 // no change
467 return FALSE;
468 }
469
470 Window xwindow = (Window) GetMainWindow();
471
472 wxCHECK_MSG( xwindow, FALSE, wxT("invalid window") );
473
474 wxCursor cursorToUse;
475 if (m_cursor.Ok())
476 cursorToUse = m_cursor;
477 else
478 cursorToUse = *wxSTANDARD_CURSOR;
479
480 Cursor xcursor = (Cursor) cursorToUse.GetCursor();
481
482 XDefineCursor( wxGlobalDisplay(), xwindow, xcursor );
483
484 return TRUE;
485 }
486
487 // Coordinates relative to the window
488 void wxWindowX11::WarpPointer (int x, int y)
489 {
490 Window xwindow = (Window) GetMainWindow();
491
492 wxCHECK_RET( xwindow, wxT("invalid window") );
493
494 XWarpPointer( wxGlobalDisplay(), None, xwindow, 0, 0, 0, 0, x, y);
495 }
496
497 // Does a physical scroll
498 void wxWindowX11::ScrollWindow(int dx, int dy, const wxRect *rect)
499 {
500 // No scrolling requested.
501 if ((dx == 0) && (dy == 0)) return;
502
503 if (!m_updateRegion.IsEmpty())
504 {
505 m_updateRegion.Offset( dx, dy );
506
507 int cw = 0;
508 int ch = 0;
509 GetSize( &cw, &ch ); // GetClientSize() ??
510 m_updateRegion.Intersect( 0, 0, cw, ch );
511 }
512
513 if (!m_clearRegion.IsEmpty())
514 {
515 m_clearRegion.Offset( dx, dy );
516
517 int cw = 0;
518 int ch = 0;
519 GetSize( &cw, &ch ); // GetClientSize() ??
520 m_clearRegion.Intersect( 0, 0, cw, ch );
521 }
522
523 Window xwindow = (Window) GetMainWindow();
524
525 wxCHECK_RET( xwindow, wxT("invalid window") );
526
527 Display *xdisplay = wxGlobalDisplay();
528
529 GC xgc = XCreateGC( xdisplay, xwindow, 0, NULL );
530 XSetGraphicsExposures( xdisplay, xgc, True );
531
532 int s_x = 0;
533 int s_y = 0;
534 int cw;
535 int ch;
536 if (rect)
537 {
538 s_x = rect->x;
539 s_y = rect->y;
540
541 cw = rect->width;
542 ch = rect->height;
543 }
544 else
545 {
546 s_x = 0;
547 s_y = 0;
548 GetClientSize( &cw, &ch );
549 }
550
551 wxPoint offset = GetClientAreaOrigin();
552 s_x += offset.x;
553 s_y += offset.y;
554
555 int w = cw - abs(dx);
556 int h = ch - abs(dy);
557
558 if ((h < 0) || (w < 0))
559 {
560 Refresh();
561 }
562 else
563 {
564 wxRect rect;
565 if (dx < 0) rect.x = cw+dx; else rect.x = s_x;
566 if (dy < 0) rect.y = ch+dy; else rect.y = s_y;
567 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
568 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
569
570 int d_x = s_x;
571 int d_y = s_y;
572
573 if (dx < 0) s_x += -dx;
574 if (dy < 0) s_y += -dy;
575 if (dx > 0) d_x = dx + offset.x;
576 if (dy > 0) d_y = dy + offset.y;
577
578 XCopyArea( xdisplay, xwindow, xwindow, xgc, s_x, s_y, w, h, d_x, d_y );
579
580 // 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 );
581
582 // wxLogDebug( "Update: %d %d %d %d", rect.x, rect.y, rect.width, rect.height );
583
584 m_updateRegion.Union( rect );
585 m_clearRegion.Union( rect );
586 }
587
588 XFreeGC( xdisplay, xgc );
589 }
590
591 // ---------------------------------------------------------------------------
592 // drag and drop
593 // ---------------------------------------------------------------------------
594
595 #if wxUSE_DRAG_AND_DROP
596
597 void wxWindowX11::SetDropTarget(wxDropTarget * WXUNUSED(pDropTarget))
598 {
599 // TODO
600 }
601
602 #endif
603
604 // Old style file-manager drag&drop
605 void wxWindowX11::DragAcceptFiles(bool WXUNUSED(accept))
606 {
607 // TODO
608 }
609
610 // ----------------------------------------------------------------------------
611 // tooltips
612 // ----------------------------------------------------------------------------
613
614 #if wxUSE_TOOLTIPS
615
616 void wxWindowX11::DoSetToolTip(wxToolTip * WXUNUSED(tooltip))
617 {
618 // TODO
619 }
620
621 #endif // wxUSE_TOOLTIPS
622
623 // ---------------------------------------------------------------------------
624 // moving and resizing
625 // ---------------------------------------------------------------------------
626
627 bool wxWindowX11::PreResize()
628 {
629 return TRUE;
630 }
631
632 // Get total size
633 void wxWindowX11::DoGetSize(int *x, int *y) const
634 {
635 Window xwindow = (Window) GetMainWindow();
636
637 wxCHECK_RET( xwindow, wxT("invalid window") );
638
639 XSync(wxGlobalDisplay(), False);
640
641 XWindowAttributes attr;
642 Status status = XGetWindowAttributes( wxGlobalDisplay(), xwindow, &attr );
643 wxASSERT(status);
644
645 if (status)
646 {
647 *x = attr.width /* + 2*m_borderSize */ ;
648 *y = attr.height /* + 2*m_borderSize */ ;
649 }
650 }
651
652 void wxWindowX11::DoGetPosition(int *x, int *y) const
653 {
654 Window window = (Window) m_mainWidget;
655 if (window)
656 {
657 XSync(wxGlobalDisplay(), False);
658 XWindowAttributes attr;
659 Status status = XGetWindowAttributes(wxGlobalDisplay(), window, & attr);
660 wxASSERT(status);
661
662 if (status)
663 {
664 *x = attr.x;
665 *y = attr.y;
666
667 // We may be faking the client origin. So a window that's really at (0, 30)
668 // may appear (to wxWin apps) to be at (0, 0).
669 if (GetParent())
670 {
671 wxPoint pt(GetParent()->GetClientAreaOrigin());
672 *x -= pt.x;
673 *y -= pt.y;
674 }
675 }
676 }
677 }
678
679 void wxWindowX11::DoScreenToClient(int *x, int *y) const
680 {
681 Display *display = wxGlobalDisplay();
682 Window rootWindow = RootWindowOfScreen(DefaultScreenOfDisplay(display));
683 Window thisWindow = (Window) m_mainWidget;
684
685 Window childWindow;
686 int xx = *x;
687 int yy = *y;
688 XTranslateCoordinates(display, rootWindow, thisWindow, xx, yy, x, y, &childWindow);
689 }
690
691 void wxWindowX11::DoClientToScreen(int *x, int *y) const
692 {
693 Display *display = wxGlobalDisplay();
694 Window rootWindow = RootWindowOfScreen(DefaultScreenOfDisplay(display));
695 Window thisWindow = (Window) m_mainWidget;
696
697 Window childWindow;
698 int xx = *x;
699 int yy = *y;
700 XTranslateCoordinates(display, thisWindow, rootWindow, xx, yy, x, y, &childWindow);
701 }
702
703
704 // Get size *available for subwindows* i.e. excluding menu bar etc.
705 void wxWindowX11::DoGetClientSize(int *x, int *y) const
706 {
707 Window window = (Window) m_mainWidget;
708
709 if (window)
710 {
711 XSync(wxGlobalDisplay(), False); // Is this really a good idea?
712 XWindowAttributes attr;
713 Status status = XGetWindowAttributes( wxGlobalDisplay(), window, &attr );
714 wxASSERT(status);
715
716 if (status)
717 {
718 *x = attr.width ;
719 *y = attr.height ;
720 }
721 }
722 }
723
724 void wxWindowX11::DoSetSize(int x, int y, int width, int height, int sizeFlags)
725 {
726 Window xwindow = (Window) GetMainWindow();
727
728 wxCHECK_RET( xwindow, wxT("invalid window") );
729
730 XWindowAttributes attr;
731 Status status = XGetWindowAttributes( wxGlobalDisplay(), xwindow, &attr );
732 wxCHECK_RET( status, wxT("invalid window attributes") );
733
734 int new_x = attr.x;
735 int new_y = attr.y;
736 int new_w = attr.width;
737 int new_h = attr.height;
738
739
740 if (x != -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
741 {
742 int yy = 0;
743 AdjustForParentClientOrigin( x, yy, sizeFlags);
744 new_x = x;
745 }
746 if (y != -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
747 {
748 int xx = 0;
749 AdjustForParentClientOrigin( xx, y, sizeFlags);
750 new_y = y;
751 }
752 if (width != -1)
753 {
754 new_w = width;
755 if (new_w <= 0)
756 new_w = 20;
757 }
758 if (height != -1)
759 {
760 new_h = height;
761 if (new_h <= 0)
762 new_h = 20;
763 }
764
765 DoMoveWindow( new_x, new_y, new_w, new_h );
766 }
767
768 void wxWindowX11::DoSetClientSize(int width, int height)
769 {
770 Window xwindow = (Window) GetMainWindow();
771
772 wxCHECK_RET( xwindow, wxT("invalid window") );
773
774 XWindowAttributes attr;
775 Status status = XGetWindowAttributes( wxGlobalDisplay(), xwindow, &attr );
776 wxCHECK_RET( status, wxT("invalid window attributes") );
777
778 int new_x = attr.x;
779 int new_y = attr.y;
780 int new_w = attr.width;
781 int new_h = attr.height;
782
783 if (width != -1)
784 new_w = width;
785
786 if (height != -1)
787 new_h = height;
788
789 DoMoveWindow( new_x, new_y, new_w, new_h );
790 }
791
792 // For implementation purposes - sometimes decorations make the client area
793 // smaller
794 wxPoint wxWindowX11::GetClientAreaOrigin() const
795 {
796 return wxPoint(0, 0);
797 }
798
799 void wxWindowX11::SetSizeHints(int minW, int minH, int maxW, int maxH, int incW, int incH)
800 {
801 m_minWidth = minW;
802 m_minHeight = minH;
803 m_maxWidth = maxW;
804 m_maxHeight = maxH;
805
806 #if !wxUSE_NANOX
807 XSizeHints sizeHints;
808 sizeHints.flags = 0;
809
810 if (minW > -1 && minH > -1)
811 {
812 sizeHints.flags |= PMinSize;
813 sizeHints.min_width = minW;
814 sizeHints.min_height = minH;
815 }
816 if (maxW > -1 && maxH > -1)
817 {
818 sizeHints.flags |= PMaxSize;
819 sizeHints.max_width = maxW;
820 sizeHints.max_height = maxH;
821 }
822 if (incW > -1 && incH > -1)
823 {
824 sizeHints.flags |= PResizeInc;
825 sizeHints.width_inc = incW;
826 sizeHints.height_inc = incH;
827 }
828
829 XSetWMNormalHints(wxGlobalDisplay(), (Window) GetMainWindow(), & sizeHints);
830 #endif
831 }
832
833 void wxWindowX11::DoMoveWindow(int x, int y, int width, int height)
834 {
835 Window xwindow = (Window) GetMainWindow();
836
837 wxCHECK_RET( xwindow, wxT("invalid window") );
838
839 XWindowChanges windowChanges;
840 windowChanges.x = x;
841 windowChanges.y = y;
842 windowChanges.width = width;
843 windowChanges.height = height;
844 windowChanges.stack_mode = 0;
845 int valueMask = CWX | CWY | CWWidth | CWHeight;
846
847 XConfigureWindow( wxGlobalDisplay(), xwindow, valueMask, &windowChanges );
848 }
849
850 // ---------------------------------------------------------------------------
851 // text metrics
852 // ---------------------------------------------------------------------------
853
854 int wxWindowX11::GetCharHeight() const
855 {
856 wxCHECK_MSG( m_font.Ok(), 0, "valid window font needed" );
857
858 WXFontStructPtr pFontStruct = m_font.GetFontStruct(1.0, GetXDisplay());
859
860 int direction, ascent, descent;
861 XCharStruct overall;
862 XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
863 &descent, &overall);
864
865 // return (overall.ascent + overall.descent);
866 return (ascent + descent);
867 }
868
869 int wxWindowX11::GetCharWidth() const
870 {
871 wxCHECK_MSG( m_font.Ok(), 0, "valid window font needed" );
872
873 WXFontStructPtr pFontStruct = m_font.GetFontStruct(1.0, GetXDisplay());
874
875 int direction, ascent, descent;
876 XCharStruct overall;
877 XTextExtents ((XFontStruct*) pFontStruct, "x", 1, &direction, &ascent,
878 &descent, &overall);
879
880 return overall.width;
881 }
882
883 void wxWindowX11::GetTextExtent(const wxString& string,
884 int *x, int *y,
885 int *descent, int *externalLeading,
886 const wxFont *theFont) const
887 {
888 wxFont fontToUse = m_font;
889 if (theFont) fontToUse = *theFont;
890
891 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
892
893 WXFontStructPtr pFontStruct = fontToUse.GetFontStruct(1.0, GetXDisplay());
894
895 int direction, ascent, descent2;
896 XCharStruct overall;
897 int slen = string.Len();
898
899 #if 0
900 if (use16)
901 XTextExtents16((XFontStruct*) pFontStruct, (XChar2b *) (char*) (const char*) string, slen, &direction,
902 &ascent, &descent2, &overall);
903 #endif
904
905 XTextExtents((XFontStruct*) pFontStruct, (char*) string.c_str(), slen,
906 &direction, &ascent, &descent2, &overall);
907
908 if ( x )
909 *x = (overall.width);
910 if ( y )
911 *y = (ascent + descent2);
912 if (descent)
913 *descent = descent2;
914 if (externalLeading)
915 *externalLeading = 0;
916
917 }
918
919 // ----------------------------------------------------------------------------
920 // painting
921 // ----------------------------------------------------------------------------
922
923 void wxWindowX11::Refresh(bool eraseBack, const wxRect *rect)
924 {
925 if (eraseBack)
926 {
927 if (rect)
928 {
929 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
930 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
931 }
932 else
933 {
934 int height,width;
935 GetSize( &width, &height );
936
937 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
938 m_clearRegion.Clear();
939 m_clearRegion.Union( 0, 0, width, height );
940 }
941 }
942
943 if (rect)
944 {
945 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
946 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
947 }
948 else
949 {
950 int height,width;
951 GetSize( &width, &height );
952
953 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
954 m_updateRegion.Clear();
955 m_updateRegion.Union( 0, 0, width, height );
956 }
957 }
958
959 void wxWindowX11::Update()
960 {
961 if (!m_updateRegion.IsEmpty())
962 {
963 // Actually send erase events.
964 SendEraseEvents();
965
966 // Actually send paint events.
967 SendPaintEvents();
968 }
969 }
970
971 void wxWindowX11::Clear()
972 {
973 wxClientDC dc((wxWindow*) this);
974 wxBrush brush(GetBackgroundColour(), wxSOLID);
975 dc.SetBackground(brush);
976 dc.Clear();
977 }
978
979 void wxWindowX11::SendEraseEvents()
980 {
981 if (!m_clearRegion.IsEmpty())
982 {
983 m_clipPaintRegion = TRUE;
984
985 wxWindowDC dc( (wxWindow*)this );
986 dc.SetClippingRegion( m_clearRegion );
987
988 wxEraseEvent erase_event( GetId(), &dc );
989 erase_event.SetEventObject( this );
990
991 if (!GetEventHandler()->ProcessEvent(erase_event))
992 {
993 Window xwindow = (Window) GetMainWindow();
994 Display *xdisplay = wxGlobalDisplay();
995 GC xgc = XCreateGC( xdisplay, xwindow, 0, NULL );
996 XSetFillStyle( xdisplay, xgc, FillSolid );
997 XSetForeground( xdisplay, xgc, m_backgroundColour.GetPixel() );
998 wxRegionIterator upd( m_clearRegion );
999 while (upd)
1000 {
1001 XFillRectangle( xdisplay, xwindow, xgc,
1002 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
1003 upd ++;
1004 }
1005 XFreeGC( xdisplay, xgc );
1006 }
1007 m_clearRegion.Clear();
1008
1009 m_clipPaintRegion = FALSE;
1010 }
1011 }
1012
1013
1014 void wxWindowX11::SendPaintEvents()
1015 {
1016 m_clipPaintRegion = TRUE;
1017
1018 wxNcPaintEvent nc_paint_event( GetId() );
1019 nc_paint_event.SetEventObject( this );
1020 GetEventHandler()->ProcessEvent( nc_paint_event );
1021
1022 wxPaintEvent paint_event( GetId() );
1023 paint_event.SetEventObject( this );
1024 GetEventHandler()->ProcessEvent( paint_event );
1025
1026 m_updateRegion.Clear();
1027
1028 m_clipPaintRegion = FALSE;
1029 }
1030
1031 // ----------------------------------------------------------------------------
1032 // event handlers
1033 // ----------------------------------------------------------------------------
1034
1035 // Responds to colour changes: passes event on to children.
1036 void wxWindowX11::OnSysColourChanged(wxSysColourChangedEvent& event)
1037 {
1038 wxWindowList::Node *node = GetChildren().GetFirst();
1039 while ( node )
1040 {
1041 // Only propagate to non-top-level windows
1042 wxWindow *win = node->GetData();
1043 if ( win->GetParent() )
1044 {
1045 wxSysColourChangedEvent event2;
1046 event.m_eventObject = win;
1047 win->GetEventHandler()->ProcessEvent(event2);
1048 }
1049
1050 node = node->GetNext();
1051 }
1052 }
1053
1054 void wxWindowX11::OnInternalIdle()
1055 {
1056 // Update invalidated regions.
1057 Update();
1058
1059 // This calls the UI-update mechanism (querying windows for
1060 // menu/toolbar/control state information)
1061 UpdateWindowUI();
1062
1063 // Set the input focus if couldn't do it before
1064 if (m_needsInputFocus)
1065 SetFocus();
1066 }
1067
1068 // ----------------------------------------------------------------------------
1069 // function which maintain the global hash table mapping Widgets to wxWindows
1070 // ----------------------------------------------------------------------------
1071
1072 bool wxAddWindowToTable(Window w, wxWindow *win)
1073 {
1074 wxWindow *oldItem = NULL;
1075 if ((oldItem = (wxWindow *)wxWidgetHashTable->Get ((long) w)))
1076 {
1077 wxLogDebug("Widget table clash: new widget is %ld, %s",
1078 (long)w, win->GetClassInfo()->GetClassName());
1079 return FALSE;
1080 }
1081
1082 wxWidgetHashTable->Put((long) w, win);
1083
1084 wxLogTrace("widget", "XWindow 0x%08x <-> window %p (%s)",
1085 w, win, win->GetClassInfo()->GetClassName());
1086
1087 return TRUE;
1088 }
1089
1090 wxWindow *wxGetWindowFromTable(Window w)
1091 {
1092 return (wxWindow *)wxWidgetHashTable->Get((long) w);
1093 }
1094
1095 void wxDeleteWindowFromTable(Window w)
1096 {
1097 wxWidgetHashTable->Delete((long)w);
1098 }
1099
1100 // ----------------------------------------------------------------------------
1101 // add/remove window from the table
1102 // ----------------------------------------------------------------------------
1103
1104 // ----------------------------------------------------------------------------
1105 // X11-specific accessors
1106 // ----------------------------------------------------------------------------
1107
1108 // Get the underlying X window
1109 WXWindow wxWindowX11::GetXWindow() const
1110 {
1111 return GetMainWindow();
1112 }
1113
1114 // Get the underlying X display
1115 WXDisplay *wxWindowX11::GetXDisplay() const
1116 {
1117 return wxGetDisplay();
1118 }
1119
1120 WXWindow wxWindowX11::GetMainWindow() const
1121 {
1122 return m_mainWidget;
1123 }
1124
1125 // ----------------------------------------------------------------------------
1126 // TranslateXXXEvent() functions
1127 // ----------------------------------------------------------------------------
1128
1129 bool wxTranslateMouseEvent(wxMouseEvent& wxevent, wxWindow *win, Window window, XEvent *xevent)
1130 {
1131 switch (XEventGetType(xevent))
1132 {
1133 case EnterNotify:
1134 case LeaveNotify:
1135 case ButtonPress:
1136 case ButtonRelease:
1137 case MotionNotify:
1138 {
1139 wxEventType eventType = wxEVT_NULL;
1140
1141 if (XEventGetType(xevent) == EnterNotify)
1142 {
1143 //if (local_event.xcrossing.mode!=NotifyNormal)
1144 // return ; // Ignore grab events
1145 eventType = wxEVT_ENTER_WINDOW;
1146 // canvas->GetEventHandler()->OnSetFocus();
1147 }
1148 else if (XEventGetType(xevent) == LeaveNotify)
1149 {
1150 //if (local_event.xcrossingr.mode!=NotifyNormal)
1151 // return ; // Ignore grab events
1152 eventType = wxEVT_LEAVE_WINDOW;
1153 // canvas->GetEventHandler()->OnKillFocus();
1154 }
1155 else if (XEventGetType(xevent) == MotionNotify)
1156 {
1157 eventType = wxEVT_MOTION;
1158 }
1159 else if (XEventGetType(xevent) == ButtonPress)
1160 {
1161 wxevent.SetTimestamp(XButtonEventGetTime(xevent));
1162 int button = 0;
1163 if (XButtonEventLChanged(xevent))
1164 {
1165 eventType = wxEVT_LEFT_DOWN;
1166 button = 1;
1167 }
1168 else if (XButtonEventMChanged(xevent))
1169 {
1170 eventType = wxEVT_MIDDLE_DOWN;
1171 button = 2;
1172 }
1173 else if (XButtonEventRChanged(xevent))
1174 {
1175 eventType = wxEVT_RIGHT_DOWN;
1176 button = 3;
1177 }
1178
1179 // check for a double click
1180 // TODO: where can we get this value from?
1181 //long dclickTime = XtGetMultiClickTime(wxGlobalDisplay());
1182 long dclickTime = 200;
1183 long ts = wxevent.GetTimestamp();
1184
1185 int buttonLast = win->GetLastClickedButton();
1186 long lastTS = win->GetLastClickTime();
1187 if ( buttonLast && buttonLast == button && (ts - lastTS) < dclickTime )
1188 {
1189 // I have a dclick
1190 win->SetLastClick(0, ts);
1191 if ( eventType == wxEVT_LEFT_DOWN )
1192 eventType = wxEVT_LEFT_DCLICK;
1193 else if ( eventType == wxEVT_MIDDLE_DOWN )
1194 eventType = wxEVT_MIDDLE_DCLICK;
1195 else if ( eventType == wxEVT_RIGHT_DOWN )
1196 eventType = wxEVT_RIGHT_DCLICK;
1197 }
1198 else
1199 {
1200 // not fast enough or different button
1201 win->SetLastClick(button, ts);
1202 }
1203 }
1204 else if (XEventGetType(xevent) == ButtonRelease)
1205 {
1206 if (XButtonEventLChanged(xevent))
1207 {
1208 eventType = wxEVT_LEFT_UP;
1209 }
1210 else if (XButtonEventMChanged(xevent))
1211 {
1212 eventType = wxEVT_MIDDLE_UP;
1213 }
1214 else if (XButtonEventRChanged(xevent))
1215 {
1216 eventType = wxEVT_RIGHT_UP;
1217 }
1218 else return FALSE;
1219 }
1220 else
1221 {
1222 return FALSE;
1223 }
1224
1225 wxevent.SetEventType(eventType);
1226
1227 wxevent.m_x = XButtonEventGetX(xevent);
1228 wxevent.m_y = XButtonEventGetY(xevent);
1229
1230 wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN)
1231 || (XButtonEventLIsDown(xevent)
1232 && (eventType != wxEVT_LEFT_UP)));
1233 wxevent.m_middleDown = ((eventType == wxEVT_MIDDLE_DOWN)
1234 || (XButtonEventMIsDown(xevent)
1235 && (eventType != wxEVT_MIDDLE_UP)));
1236 wxevent.m_rightDown = ((eventType == wxEVT_RIGHT_DOWN)
1237 || (XButtonEventRIsDown (xevent)
1238 && (eventType != wxEVT_RIGHT_UP)));
1239
1240 wxevent.m_shiftDown = XButtonEventShiftIsDown(xevent);
1241 wxevent.m_controlDown = XButtonEventCtrlIsDown(xevent);
1242 wxevent.m_altDown = XButtonEventAltIsDown(xevent);
1243 wxevent.m_metaDown = XButtonEventMetaIsDown(xevent);
1244
1245 wxevent.SetId(win->GetId());
1246 wxevent.SetEventObject(win);
1247
1248 return TRUE;
1249 }
1250 }
1251 return FALSE;
1252 }
1253
1254 bool wxTranslateKeyEvent(wxKeyEvent& wxevent, wxWindow *win, Window WXUNUSED(win), XEvent *xevent)
1255 {
1256 switch (XEventGetType(xevent))
1257 {
1258 case KeyPress:
1259 case KeyRelease:
1260 {
1261 char buf[20];
1262
1263 KeySym keySym;
1264 (void) XLookupString ((XKeyEvent *) xevent, buf, 20, &keySym, NULL);
1265 int id = wxCharCodeXToWX (keySym);
1266
1267 wxevent.m_shiftDown = XKeyEventShiftIsDown(xevent);
1268 wxevent.m_controlDown = XKeyEventCtrlIsDown(xevent);
1269 wxevent.m_altDown = XKeyEventAltIsDown(xevent);
1270 wxevent.m_metaDown = XKeyEventMetaIsDown(xevent);
1271 wxevent.SetEventObject(win);
1272 wxevent.m_keyCode = id;
1273 wxevent.SetTimestamp(XKeyEventGetTime(xevent));
1274
1275 wxevent.m_x = XKeyEventGetX(xevent);
1276 wxevent.m_y = XKeyEventGetY(xevent);
1277
1278 if (id > -1)
1279 return TRUE;
1280 else
1281 return FALSE;
1282 break;
1283 }
1284 default:
1285 break;
1286 }
1287 return FALSE;
1288 }
1289
1290 // ----------------------------------------------------------------------------
1291 // Colour stuff
1292 // ----------------------------------------------------------------------------
1293
1294 bool wxWindowX11::SetBackgroundColour(const wxColour& col)
1295 {
1296 wxWindowBase::SetBackgroundColour(col);
1297
1298 Display *xdisplay = (Display*) wxGlobalDisplay();
1299 int xscreen = DefaultScreen( xdisplay );
1300 Colormap cm = DefaultColormap( xdisplay, xscreen );
1301
1302 m_backgroundColour.CalcPixel( (WXColormap) cm );
1303
1304 if (!GetMainWindow())
1305 return FALSE;
1306
1307 /*
1308 XSetWindowAttributes attrib;
1309 attrib.background_pixel = colour.GetPixel();
1310
1311 XChangeWindowAttributes(wxGlobalDisplay(),
1312 (Window) GetMainWindow(),
1313 CWBackPixel,
1314 & attrib);
1315 */
1316
1317 return TRUE;
1318 }
1319
1320 bool wxWindowX11::SetForegroundColour(const wxColour& col)
1321 {
1322 if ( !wxWindowBase::SetForegroundColour(col) )
1323 return FALSE;
1324
1325 return TRUE;
1326 }
1327
1328 // ----------------------------------------------------------------------------
1329 // global functions
1330 // ----------------------------------------------------------------------------
1331
1332 wxWindow *wxGetActiveWindow()
1333 {
1334 // TODO
1335 wxFAIL_MSG("Not implemented");
1336 return NULL;
1337 }
1338
1339 /* static */
1340 wxWindow *wxWindowBase::GetCapture()
1341 {
1342 return (wxWindow *)g_captureWindow;
1343 }
1344
1345
1346 // Find the wxWindow at the current mouse position, returning the mouse
1347 // position.
1348 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
1349 {
1350 return wxFindWindowAtPoint(wxGetMousePosition());
1351 }
1352
1353 // Get the current mouse position.
1354 wxPoint wxGetMousePosition()
1355 {
1356 #if wxUSE_NANOX
1357 /* TODO */
1358 return wxPoint(0, 0);
1359 #else
1360 Display *display = wxGlobalDisplay();
1361 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
1362 Window rootReturn, childReturn;
1363 int rootX, rootY, winX, winY;
1364 unsigned int maskReturn;
1365
1366 XQueryPointer (display,
1367 rootWindow,
1368 &rootReturn,
1369 &childReturn,
1370 &rootX, &rootY, &winX, &winY, &maskReturn);
1371 return wxPoint(rootX, rootY);
1372 #endif
1373 }
1374
1375
1376 // ----------------------------------------------------------------------------
1377 // wxNoOptimize: switch off size optimization
1378 // ----------------------------------------------------------------------------
1379
1380 int wxNoOptimize::ms_count = 0;
1381