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