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