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