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