]> git.saurik.com Git - wxWidgets.git/blob - src/motif/toplevel.cpp
minor tab height bug fix
[wxWidgets.git] / src / motif / toplevel.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/toplevel.cpp
3 // Purpose: wxTopLevelWindow Motif implementation
4 // Author: Mattia Barbon
5 // Modified by:
6 // Created: 12/10/2002
7 // RCS-ID: $Id$
8 // Copyright: (c) Mattia Barbon
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #include "wx/toplevel.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/app.h"
27 #endif
28
29 #ifdef __VMS__
30 #define XtDisplay XTDISPLAY
31 #define XtParent XTPARENT
32 #define XtScreen XTSCREEN
33 #define XtWindow XTWINDOW
34 #pragma message disable nosimpint
35 #endif
36
37 #include <Xm/Xm.h>
38 #include <X11/Shell.h>
39 #include <X11/Core.h>
40 #if XmVersion >= 1002
41 #include <Xm/XmAll.h>
42 #else
43 #include <Xm/Frame.h>
44 #endif
45
46 #ifdef __VMS__
47 #pragma message enable nosimpint
48 #endif
49
50 #include "wx/motif/private.h"
51
52 wxList wxModelessWindows; // Frames and modeless dialogs
53
54 // ---------------------------------------------------------------------------
55 // Callbacks
56 // ---------------------------------------------------------------------------
57
58 static void wxCloseTLWCallback( Widget widget, XtPointer client_data,
59 XmAnyCallbackStruct *cbs );
60 static void wxTLWEventHandler( Widget wid,
61 XtPointer client_data,
62 XEvent* event,
63 Boolean *continueToDispatch );
64
65 // ===========================================================================
66 // wxTopLevelWindowMotif implementation
67 // ===========================================================================
68
69 void wxTopLevelWindowMotif::PreDestroy()
70 {
71 wxModelessWindows.DeleteObject(this);
72
73 m_icons.m_icons.Empty();
74
75 DestroyChildren();
76
77 // MessageDialog and FileDialog do not have a client widget
78 if( GetClientWidget() )
79 {
80 XtRemoveEventHandler( (Widget)GetClientWidget(),
81 ButtonPressMask | ButtonReleaseMask |
82 PointerMotionMask | KeyPressMask,
83 False,
84 wxTLWEventHandler,
85 (XtPointer)this );
86 }
87 }
88
89 wxTopLevelWindowMotif::~wxTopLevelWindowMotif()
90 {
91 SetMainWidget( (WXWidget)0 );
92 }
93
94 void wxTopLevelWindowMotif::Init()
95 {
96 m_isShown = false;
97 }
98
99 bool wxTopLevelWindowMotif::Create( wxWindow *parent, wxWindowID id,
100 const wxString& title,
101 const wxPoint& pos,
102 const wxSize& size,
103 long style,
104 const wxString& name )
105 {
106 SetName(name);
107 m_windowStyle = style;
108
109 if ( parent )
110 parent->AddChild(this);
111
112 wxTopLevelWindows.Append(this);
113
114 m_windowId = ( id > -1 ) ? id : NewControlId();
115
116 bool retval = XmDoCreateTLW( parent, id, title, pos, size, style, name );
117
118 if( !retval ) return false;
119
120 // Intercept CLOSE messages from the window manager
121 Widget shell = (Widget)GetShellWidget();
122 Atom WM_DELETE_WINDOW = XmInternAtom( XtDisplay( shell ),
123 "WM_DELETE_WINDOW", False );
124
125 // Remove and add WM_DELETE_WINDOW so ours is only handler
126 // This only appears to be necessary for wxDialog, but does not hurt
127 // for wxFrame
128 XmRemoveWMProtocols( shell, &WM_DELETE_WINDOW, 1 );
129 XmAddWMProtocols( shell, &WM_DELETE_WINDOW, 1 );
130 XmActivateWMProtocol( shell, WM_DELETE_WINDOW );
131
132 // Modified Steve Hammes for Motif 2.0
133 #if (XmREVISION > 1 || XmVERSION > 1)
134 XmAddWMProtocolCallback( shell, WM_DELETE_WINDOW,
135 (XtCallbackProc)wxCloseTLWCallback,
136 (XtPointer)this );
137 #elif XmREVISION == 1
138 XmAddWMProtocolCallback( shell, WM_DELETE_WINDOW,
139 (XtCallbackProc)wxCloseTLWCallback,
140 (caddr_t)this );
141 #else
142 XmAddWMProtocolCallback( shell, WM_DELETE_WINDOW,
143 (void (*)())wxCloseTLWCallback, (caddr_t)this );
144 #endif
145
146 // This patch come from Torsten Liermann lier@lier1.muc.de
147 if( XmIsMotifWMRunning( shell ) )
148 {
149 int decor = 0 ;
150 if( !(m_windowStyle & wxNO_BORDER) )
151 decor |= MWM_DECOR_BORDER;
152 if( m_windowStyle & wxRESIZE_BORDER )
153 decor |= MWM_DECOR_RESIZEH;
154 if( m_windowStyle & wxSYSTEM_MENU )
155 decor |= MWM_DECOR_MENU;
156 if( ( m_windowStyle & wxCAPTION ) ||
157 ( m_windowStyle & wxTINY_CAPTION_HORIZ ) ||
158 ( m_windowStyle & wxTINY_CAPTION_VERT ) )
159 decor |= MWM_DECOR_TITLE;
160 if( m_windowStyle & wxRESIZE_BORDER )
161 decor |= MWM_DECOR_BORDER;
162 if( m_windowStyle & wxMINIMIZE_BOX )
163 decor |= MWM_DECOR_MINIMIZE;
164 if( m_windowStyle & wxMAXIMIZE_BOX )
165 decor |= MWM_DECOR_MAXIMIZE;
166
167 XtVaSetValues( shell,
168 XmNmwmDecorations, decor,
169 NULL );
170 }
171 else
172 {
173 // This allows non-Motif window managers to support at least the
174 // no-decorations case.
175 if( ( m_windowStyle & wxCAPTION ) != wxCAPTION )
176 XtVaSetValues( shell,
177 XmNoverrideRedirect, True,
178 NULL );
179 }
180
181 XtAddEventHandler( (Widget)GetClientWidget(),
182 ButtonPressMask | ButtonReleaseMask |
183 PointerMotionMask | KeyPressMask,
184 False,
185 wxTLWEventHandler,
186 (XtPointer)this );
187
188 return retval;
189 }
190
191 void wxTopLevelWindowMotif::DoGetPosition(int *x, int *y) const
192 {
193 Widget top = (Widget) GetTopWidget();
194 Window parent_window = XtWindow((Widget) top),
195 next_parent = XtWindow((Widget) top),
196 root = RootWindowOfScreen(XtScreen((Widget) top));
197
198 // search for the parent that is child of ROOT, because the WM may
199 // reparent twice and notify only the next parent (like FVWM)
200 while (next_parent != root) {
201 Window *theChildren; unsigned int n;
202 parent_window = next_parent;
203 XQueryTree(XtDisplay((Widget) top), parent_window, &root,
204 &next_parent, &theChildren, &n);
205 XFree(theChildren); // not needed
206 }
207 int xx, yy; unsigned int dummy;
208 XGetGeometry(XtDisplay((Widget) top), parent_window, &root,
209 &xx, &yy, &dummy, &dummy, &dummy, &dummy);
210 if (x) *x = xx;
211 if (y) *y = yy;
212 }
213
214 void wxTopLevelWindowMotif::Raise()
215 {
216 Widget top = (Widget) GetTopWidget();
217 Window parent_window = XtWindow( top ),
218 next_parent = XtWindow( top ),
219 root = RootWindowOfScreen( XtScreen( top ) );
220 // search for the parent that is child of ROOT, because the WM may
221 // reparent twice and notify only the next parent (like FVWM)
222 while( next_parent != root )
223 {
224 Window *theChildren;
225 unsigned int n;
226
227 parent_window = next_parent;
228 XQueryTree( XtDisplay( top ), parent_window, &root,
229 &next_parent, &theChildren, &n );
230 XFree( theChildren ); // not needed
231 }
232 XRaiseWindow( XtDisplay( top ), parent_window );
233 }
234
235 void wxTopLevelWindowMotif::Lower()
236 {
237 Widget top = (Widget) GetTopWidget();
238 Window parent_window = XtWindow( top ),
239 next_parent = XtWindow( top ),
240 root = RootWindowOfScreen( XtScreen( top ) );
241 // search for the parent that is child of ROOT, because the WM may
242 // reparent twice and notify only the next parent (like FVWM)
243 while( next_parent != root )
244 {
245 Window *theChildren;
246 unsigned int n;
247
248 parent_window = next_parent;
249 XQueryTree( XtDisplay( top ), parent_window, &root,
250 &next_parent, &theChildren, &n );
251 XFree( theChildren ); // not needed
252 }
253 XLowerWindow( XtDisplay( top ), parent_window );
254 }
255
256 static inline Widget GetShell( const wxTopLevelWindowMotif* tlw )
257 {
258 Widget main = (Widget) tlw->GetMainWidget();
259 if( !main ) return (Widget) NULL;
260
261 return XtParent( main );
262 }
263
264 WXWidget wxTopLevelWindowMotif::GetShellWidget() const
265 {
266 return (WXWidget) GetShell( this );
267 }
268
269 bool wxTopLevelWindowMotif::ShowFullScreen( bool WXUNUSED(show),
270 long WXUNUSED(style) )
271 {
272 // TODO, see wxGTK
273 return false;
274 }
275
276 bool wxTopLevelWindowMotif::IsFullScreen() const
277 {
278 // TODO, see wxGTK
279 return false;
280 }
281
282 void wxTopLevelWindowMotif::Restore()
283 {
284 Widget shell = GetShell( this );
285
286 if( shell )
287 XtVaSetValues( shell,
288 XmNiconic, False,
289 NULL );
290 }
291
292 void wxTopLevelWindowMotif::Iconize( bool iconize )
293 {
294 Widget shell = GetShell( this );
295 if( !shell ) return;
296
297 if( !iconize )
298 Show( true );
299
300 XtVaSetValues( shell,
301 XmNiconic, (Boolean)iconize,
302 NULL );
303 }
304
305 bool wxTopLevelWindowMotif::IsIconized() const
306 {
307 Widget shell = GetShell( this );
308
309 if( !shell )
310 return false;
311
312 Boolean iconic;
313 XtVaGetValues( shell,
314 XmNiconic, &iconic,
315 NULL );
316
317 return (iconic == True);
318 }
319
320 void wxTopLevelWindowMotif::Maximize( bool maximize )
321 {
322 Show( true );
323
324 if( maximize )
325 Restore();
326 }
327
328 bool wxTopLevelWindowMotif::IsMaximized() const
329 {
330 return false;
331 }
332
333 void wxTopLevelWindowMotif::DoSetSizeHints( int minW, int minH,
334 int maxW, int maxH,
335 int incW, int incH )
336 {
337 wxTopLevelWindowBase::DoSetSizeHints( minW, minH, maxW, maxH, incW, incH );
338
339 int count = 0;
340 Arg args[6];
341
342 if( minW > -1 ) { XtSetArg( args[count], XmNminWidth, minW ); ++count; }
343 if( minH > -1 ) { XtSetArg( args[count], XmNminHeight, minH ); ++count; }
344 if( maxW > -1 ) { XtSetArg( args[count], XmNmaxWidth, maxW ); ++count; }
345 if( maxH > -1 ) { XtSetArg( args[count], XmNmaxHeight, maxH ); ++count; }
346 if( incW > -1 ) { XtSetArg( args[count], XmNwidthInc, incW ); ++count; }
347 if( incH > -1 ) { XtSetArg( args[count], XmNheightInc, incH ); ++count; }
348
349 XtSetValues( (Widget)GetShellWidget(), args, count );
350 }
351
352 bool wxTopLevelWindowMotif::SetShape( const wxRegion& region )
353 {
354 return wxDoSetShape( (Display*)GetXDisplay(),
355 XtWindow( (Widget)GetShellWidget() ),
356 region );
357 }
358
359 // ---------------------------------------------------------------------------
360 // Callback definition
361 // ---------------------------------------------------------------------------
362
363 // Handle a close event from the window manager
364 static void wxCloseTLWCallback( Widget WXUNUSED(widget), XtPointer client_data,
365 XmAnyCallbackStruct *WXUNUSED(cbs) )
366 {
367 wxTopLevelWindowMotif* tlw = (wxTopLevelWindowMotif*)client_data;
368 wxCloseEvent closeEvent( wxEVT_CLOSE_WINDOW, tlw->GetId() );
369 closeEvent.SetEventObject( tlw );
370
371 // May delete the dialog (with delayed deletion)
372 tlw->GetEventHandler()->ProcessEvent(closeEvent);
373 }
374
375 void wxTLWEventHandler( Widget wid,
376 XtPointer WXUNUSED(client_data),
377 XEvent* event,
378 Boolean* continueToDispatch)
379 {
380 wxTopLevelWindowMotif* tlw =
381 (wxTopLevelWindowMotif*)wxGetWindowFromTable( wid );
382
383 if( tlw )
384 {
385 wxMouseEvent wxevent( wxEVT_NULL );
386
387 if( wxTranslateMouseEvent( wxevent, tlw, wid, event ) )
388 {
389 wxevent.SetEventObject( tlw );
390 wxevent.SetId( tlw->GetId() );
391 tlw->GetEventHandler()->ProcessEvent( wxevent );
392 }
393 else
394 {
395 // An attempt to implement OnCharHook by calling OnCharHook first;
396 // if this returns true, set continueToDispatch to False
397 // (don't continue processing).
398 // Otherwise set it to True and call OnChar.
399 wxKeyEvent keyEvent( wxEVT_CHAR );
400 if( wxTranslateKeyEvent( keyEvent, tlw, wid, event ))
401 {
402 keyEvent.SetEventObject( tlw );
403 keyEvent.SetId( tlw->GetId() );
404 keyEvent.SetEventType( wxEVT_CHAR_HOOK );
405 if( tlw->GetEventHandler()->ProcessEvent( keyEvent ) )
406 {
407 *continueToDispatch = False;
408 return;
409 }
410 else
411 {
412 // For simplicity, OnKeyDown is the same as OnChar
413 // TODO: filter modifier key presses from OnChar
414 keyEvent.SetEventType( wxEVT_KEY_DOWN );
415
416 // Only process OnChar if OnKeyDown didn't swallow it
417 if( !tlw->GetEventHandler()->ProcessEvent( keyEvent ) )
418 {
419 keyEvent.SetEventType( wxEVT_CHAR );
420 tlw->GetEventHandler()->ProcessEvent( keyEvent );
421 }
422 }
423 }
424 }
425 }
426
427 *continueToDispatch = True;
428 }