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