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