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