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