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