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