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