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