1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/x11/app.cpp
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // for compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
24 #include "wx/gdicmn.h"
26 #include "wx/dialog.h"
28 #include "wx/module.h"
29 #include "wx/memory.h"
31 #include "wx/evtloop.h"
33 #include "wx/filename.h"
35 #include "wx/univ/theme.h"
36 #include "wx/univ/renderer.h"
39 #include "wx/thread.h"
42 #include "wx/x11/private.h"
46 //------------------------------------------------------------------------
48 //------------------------------------------------------------------------
50 extern wxList wxPendingDelete
;
52 wxWindowHash
*wxWidgetHashTable
= NULL
;
53 wxWindowHash
*wxClientWidgetHashTable
= NULL
;
55 static bool g_showIconic
= false;
56 static wxSize g_initialSize
= wxDefaultSize
;
58 // This is required for wxFocusEvent::SetWindow(). It will only
59 // work for focus events which we provoke ourselves (by calling
60 // SetFocus()). It will not work for those events, which X11
62 static wxWindow
*g_nextFocus
= NULL
;
63 static wxWindow
*g_prevFocus
= NULL
;
65 //------------------------------------------------------------------------
67 //------------------------------------------------------------------------
70 typedef int (*XErrorHandlerFunc
)(Display
*, XErrorEvent
*);
72 XErrorHandlerFunc gs_pfnXErrorHandler
= 0;
74 static int wxXErrorHandler(Display
*dpy
, XErrorEvent
*xevent
)
76 // just forward to the default handler for now
77 if (gs_pfnXErrorHandler
)
78 return gs_pfnXErrorHandler(dpy
, xevent
);
84 //------------------------------------------------------------------------
86 //------------------------------------------------------------------------
88 long wxApp::sm_lastMessageTime
= 0;
89 WXDisplay
*wxApp::ms_display
= NULL
;
91 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
93 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
94 EVT_IDLE(wxAppBase::OnIdle
)
97 bool wxApp::Initialize(int& argC
, wxChar
**argV
)
99 #if defined(__WXDEBUG__) && !wxUSE_NANOX
100 // install the X error handler
101 gs_pfnXErrorHandler
= XSetErrorHandler( wxXErrorHandler
);
102 #endif // __WXDEBUG__
104 wxString displayName
;
105 bool syncDisplay
= false;
108 for ( int i
= 0; i
< argCOrig
; i
++ )
110 if (wxStrcmp( argV
[i
], _T("-display") ) == 0)
116 displayName
= argV
[i
];
122 else if (wxStrcmp( argV
[i
], _T("-geometry") ) == 0)
129 if (wxSscanf(argV
[i
], _T("%dx%d"), &w
, &h
) != 2)
131 wxLogError( _("Invalid geometry specification '%s'"),
132 wxString(argV
[i
]).c_str() );
136 g_initialSize
= wxSize(w
, h
);
143 else if (wxStrcmp( argV
[i
], _T("-sync") ) == 0)
150 else if (wxStrcmp( argV
[i
], _T("-iconic") ) == 0)
159 if ( argC
!= argCOrig
)
161 // remove the argumens we consumed
162 for ( int i
= 0; i
< argC
; i
++ )
166 memmove(argV
+ i
, argV
+ i
+ 1, argCOrig
- i
);
173 if ( displayName
.empty() )
174 xdisplay
= XOpenDisplay( NULL
);
176 xdisplay
= XOpenDisplay( displayName
.ToAscii() );
179 wxLogError( _("wxWidgets could not open display. Exiting.") );
184 XSynchronize(xdisplay
, True
);
186 ms_display
= (WXDisplay
*) xdisplay
;
188 XSelectInput( xdisplay
, XDefaultRootWindow(xdisplay
), PropertyChangeMask
);
191 wxSetDetectableAutoRepeat( true );
193 if ( !wxAppBase::Initialize(argC
, argV
) )
195 XCloseDisplay(xdisplay
);
201 // Glib's type system required by Pango
206 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
209 wxWidgetHashTable
= new wxWindowHash
;
210 wxClientWidgetHashTable
= new wxWindowHash
;
215 void wxApp::CleanUp()
217 delete wxWidgetHashTable
;
218 wxWidgetHashTable
= NULL
;
219 delete wxClientWidgetHashTable
;
220 wxClientWidgetHashTable
= NULL
;
222 wxAppBase::CleanUp();
227 // TODO: parse the command line
231 m_mainColormap
= (WXColormap
) NULL
;
232 m_topLevelWidget
= (WXWindow
) NULL
;
233 m_maxRequestSize
= 0;
234 m_showIconic
= false;
235 m_initialSize
= wxDefaultSize
;
251 //-----------------------------------------------------------------------
252 // X11 predicate function for exposure compression
253 //-----------------------------------------------------------------------
258 Bool found_non_matching
;
262 Bool
wxX11ExposePredicate (Display
*display
, XEvent
*xevent
, XPointer arg
)
264 wxExposeInfo
*info
= (wxExposeInfo
*) arg
;
266 if (info
->found_non_matching
)
269 if (xevent
->xany
.type
!= Expose
)
271 info
->found_non_matching
= true;
275 if (xevent
->xexpose
.window
!= info
->window
)
277 info
->found_non_matching
= true;
284 #endif // wxUSE_NANOX
286 //-----------------------------------------------------------------------
287 // Processes an X event, returning true if the event was processed.
288 //-----------------------------------------------------------------------
290 bool wxApp::ProcessXEvent(WXEvent
* _event
)
292 XEvent
* event
= (XEvent
*) _event
;
294 wxWindow
* win
= NULL
;
295 Window window
= XEventGetWindow(event
);
297 Window actualWindow
= window
;
300 // Find the first wxWindow that corresponds to this event window
301 // Because we're receiving events after a window
302 // has been destroyed, assume a 1:1 match between
303 // Window and wxWindow, so if it's not in the table,
304 // it must have been destroyed.
306 win
= wxGetWindowFromTable(window
);
309 #if wxUSE_TWO_WINDOWS
310 win
= wxGetClientWindowFromTable(window
);
317 wxString windowClass
= win
->GetClassInfo()->GetClassName();
324 #if wxUSE_TWO_WINDOWS && !wxUSE_NANOX
325 if (event
->xexpose
.window
!= (Window
)win
->GetClientAreaWindow())
329 info
.window
= event
->xexpose
.window
;
330 info
.found_non_matching
= false;
331 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, wxX11ExposePredicate
, (XPointer
) &info
))
333 // Don't worry about optimizing redrawing the border etc.
335 win
->NeedUpdateNcAreaInIdle();
340 win
->GetUpdateRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
),
341 XExposeEventGetWidth(event
), XExposeEventGetHeight(event
));
342 win
->GetClearRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
),
343 XExposeEventGetWidth(event
), XExposeEventGetHeight(event
));
348 info
.window
= event
->xexpose
.window
;
349 info
.found_non_matching
= false;
350 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, wxX11ExposePredicate
, (XPointer
) &info
))
352 win
->GetUpdateRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
,
353 tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height
);
355 win
->GetClearRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
,
356 tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height
);
360 // This simplifies the expose and clear areas to simple
362 win
->GetUpdateRegion() = win
->GetUpdateRegion().GetBox();
363 win
->GetClearRegion() = win
->GetClearRegion().GetBox();
365 // If we only have one X11 window, always indicate
366 // that borders might have to be redrawn.
367 if (win
->GetMainWindow() == win
->GetClientAreaWindow())
368 win
->NeedUpdateNcAreaInIdle();
370 // Only erase background, paint in idle time.
371 win
->SendEraseEvents();
383 wxLogTrace( _T("expose"), _T("GraphicsExpose from %s"), win
->GetName().c_str());
385 win
->GetUpdateRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
,
386 event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
);
388 win
->GetClearRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
,
389 event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
);
391 if (event
->xgraphicsexpose
.count
== 0)
393 // Only erase background, paint in idle time.
394 win
->SendEraseEvents();
404 if (!win
->IsEnabled())
407 wxKeyEvent
keyEvent(wxEVT_KEY_DOWN
);
408 wxTranslateKeyEvent(keyEvent
, win
, window
, event
);
410 // wxLogDebug( "OnKey from %s", win->GetName().c_str() );
412 // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR
413 if (win
->GetEventHandler()->ProcessEvent( keyEvent
))
416 keyEvent
.SetEventType(wxEVT_CHAR
);
417 // Do the translation again, retaining the ASCII
419 wxTranslateKeyEvent(keyEvent
, win
, window
, event
, true);
420 if (win
->GetEventHandler()->ProcessEvent( keyEvent
))
423 if ( (keyEvent
.m_keyCode
== WXK_TAB
) &&
424 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
426 wxNavigationKeyEvent new_event
;
427 new_event
.SetEventObject( win
->GetParent() );
428 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
429 new_event
.SetDirection( (keyEvent
.m_keyCode
== WXK_TAB
) );
430 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
431 new_event
.SetWindowChange( keyEvent
.ControlDown() );
432 new_event
.SetCurrentFocus( win
);
433 return win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
440 if (!win
->IsEnabled())
443 wxKeyEvent
keyEvent(wxEVT_KEY_UP
);
444 wxTranslateKeyEvent(keyEvent
, win
, window
, event
);
446 return win
->GetEventHandler()->ProcessEvent( keyEvent
);
448 case ConfigureNotify
:
451 if (event
->update
.utype
== GR_UPDATE_SIZE
)
454 wxTopLevelWindow
*tlw
= wxDynamicCast(win
, wxTopLevelWindow
);
457 tlw
->SetConfigureGeometry( XConfigureEventGetX(event
), XConfigureEventGetY(event
),
458 XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
) );
461 if ( tlw
&& tlw
->IsShown() )
463 tlw
->SetNeedResizeInIdle();
467 wxSizeEvent
sizeEvent( wxSize(XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
)), win
->GetId() );
468 sizeEvent
.SetEventObject( win
);
470 return win
->GetEventHandler()->ProcessEvent( sizeEvent
);
478 //wxLogDebug("PropertyNotify: %s", windowClass.c_str());
479 return HandlePropertyChange(_event
);
483 if (!win
->IsEnabled())
486 Atom wm_delete_window
= XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True
);
487 Atom wm_protocols
= XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True
);
489 if (event
->xclient
.message_type
== wm_protocols
)
491 if ((Atom
) (event
->xclient
.data
.l
[0]) == wm_delete_window
)
502 printf( "destroy from %s\n", win
->GetName().c_str() );
507 printf( "create from %s\n", win
->GetName().c_str() );
512 printf( "map request from %s\n", win
->GetName().c_str() );
517 printf( "resize request from %s\n", win
->GetName().c_str() );
519 Display
*disp
= (Display
*) wxGetDisplay();
524 while( XCheckTypedWindowEvent (disp
, actualWindow
, ResizeRequest
, &report
));
526 wxSize sz
= win
->GetSize();
527 wxSizeEvent
sizeEvent(sz
, win
->GetId());
528 sizeEvent
.SetEventObject(win
);
530 return win
->GetEventHandler()->ProcessEvent( sizeEvent
);
535 case GR_EVENT_TYPE_CLOSE_REQ
:
552 if (!win
->IsEnabled())
555 // Here we check if the top level window is
556 // disabled, which is one aspect of modality.
558 while (tlw
&& !tlw
->IsTopLevel())
559 tlw
= tlw
->GetParent();
560 if (tlw
&& !tlw
->IsEnabled())
563 if (event
->type
== ButtonPress
)
565 if ((win
!= wxWindow::FindFocus()) && win
->AcceptsFocus())
567 // This might actually be done in wxWindow::SetFocus()
568 // and not here. TODO.
569 g_prevFocus
= wxWindow::FindFocus();
572 wxLogTrace( _T("focus"), _T("About to call SetFocus on %s of type %s due to button press"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
574 // Record the fact that this window is
575 // getting the focus, because we'll need to
576 // check if its parent is getting a bogus
577 // focus and duly ignore it.
578 // TODO: may need to have this code in SetFocus, too.
579 extern wxWindow
* g_GettingFocus
;
580 g_GettingFocus
= win
;
586 if (event
->type
== LeaveNotify
|| event
->type
== EnterNotify
)
588 // Throw out NotifyGrab and NotifyUngrab
589 if (event
->xcrossing
.mode
!= NotifyNormal
)
593 wxMouseEvent wxevent
;
594 wxTranslateMouseEvent(wxevent
, win
, window
, event
);
595 return win
->GetEventHandler()->ProcessEvent( wxevent
);
599 if ((event
->xfocus
.detail
!= NotifyPointer
) &&
600 (event
->xfocus
.mode
== NotifyNormal
))
603 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
605 extern wxWindow
* g_GettingFocus
;
606 if (g_GettingFocus
&& g_GettingFocus
->GetParent() == win
)
608 // Ignore this, this can be a spurious FocusIn
609 // caused by a child having its focus set.
610 g_GettingFocus
= NULL
;
611 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s being deliberately ignored"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
616 wxFocusEvent
focusEvent(wxEVT_SET_FOCUS
, win
->GetId());
617 focusEvent
.SetEventObject(win
);
618 focusEvent
.SetWindow( g_prevFocus
);
621 return win
->GetEventHandler()->ProcessEvent(focusEvent
);
628 if ((event
->xfocus
.detail
!= NotifyPointer
) &&
629 (event
->xfocus
.mode
== NotifyNormal
))
632 wxLogTrace( _T("focus"), _T("FocusOut from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
634 wxFocusEvent
focusEvent(wxEVT_KILL_FOCUS
, win
->GetId());
635 focusEvent
.SetEventObject(win
);
636 focusEvent
.SetWindow( g_nextFocus
);
638 return win
->GetEventHandler()->ProcessEvent(focusEvent
);
644 //wxString eventName = wxGetXEventName(XEvent& event);
645 //wxLogDebug(wxT("Event %s not handled"), eventName.c_str());
647 #endif // __WXDEBUG__
653 // This should be redefined in a derived class for
654 // handling property change events for XAtom IPC.
655 bool wxApp::HandlePropertyChange(WXEvent
*event
)
657 // by default do nothing special
658 // TODO: what to do for X11
659 // XtDispatchEvent((XEvent*) event);
663 void wxApp::WakeUpIdle()
665 // TODO: use wxMotif implementation?
667 // Wake up the idle handler processor, even if it is in another thread...
671 // Create display, and other initialization
672 bool wxApp::OnInitGui()
674 // Eventually this line will be removed, but for
675 // now we don't want to try popping up a dialog
676 // for error messages.
677 delete wxLog::SetActiveTarget(new wxLogStderr
);
679 if (!wxAppBase::OnInitGui())
682 GetMainColormap( wxApp::GetDisplay() );
684 m_maxRequestSize
= XMaxRequestSize( (Display
*) wxApp::GetDisplay() );
687 m_visualInfo
= new wxXVisualInfo
;
688 wxFillXVisualInfo( m_visualInfo
, (Display
*) wxApp::GetDisplay() );
696 #include <pango/pango.h>
697 #include <pango/pangox.h>
698 #ifdef HAVE_PANGO_XFT
699 #include <pango/pangoxft.h>
702 PangoContext
* wxApp::GetPangoContext()
704 static PangoContext
*ret
= NULL
;
708 Display
*xdisplay
= (Display
*) wxApp::GetDisplay();
710 #ifdef HAVE_PANGO_XFT
711 int xscreen
= DefaultScreen(xdisplay
);
712 static int use_xft
= -1;
715 wxString val
= wxGetenv( L
"GDK_USE_XFT" );
716 use_xft
= (val
== L
"1");
720 ret
= pango_xft_get_context( xdisplay
, xscreen
);
723 ret
= pango_x_get_context( xdisplay
);
725 if (!PANGO_IS_CONTEXT(ret
))
726 wxLogError( wxT("No pango context.") );
732 WXColormap
wxApp::GetMainColormap(WXDisplay
* display
)
734 if (!display
) /* Must be called first with non-NULL display */
735 return m_mainColormap
;
737 int defaultScreen
= DefaultScreen((Display
*) display
);
738 Screen
* screen
= XScreenOfDisplay((Display
*) display
, defaultScreen
);
740 Colormap c
= DefaultColormapOfScreen(screen
);
743 m_mainColormap
= (WXColormap
) c
;
745 return (WXColormap
) c
;
748 Window
wxGetWindowParent(Window window
)
750 wxASSERT_MSG( window
, _T("invalid window") );
755 // VMS chokes on unreacheable code
756 Window parent
, root
= 0;
760 unsigned int noChildren
= 0;
762 Window
* children
= NULL
;
764 // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc)
769 XQueryTree((Display
*) wxGetDisplay(), window
, & root
, & parent
,
770 & children
, & noChildren
);
784 wxAppConsole::Exit();
787 // Yield to other processes
789 bool wxApp::Yield(bool onlyIfNeeded
)
791 // Sometimes only 2 yields seem
792 // to do the trick, e.g. in the
795 for (i
= 0; i
< 2; i
++)
797 static bool s_inYield
= false;
803 wxFAIL_MSG( wxT("wxYield called recursively" ) );
811 // Make sure we have an event loop object,
812 // or Pending/Dispatch will fail
813 wxEventLoop
* eventLoop
= wxEventLoop::GetActive();
814 wxEventLoop
* newEventLoop
= NULL
;
817 newEventLoop
= new wxEventLoop
;
818 wxEventLoop::SetActive(newEventLoop
);
821 // Call dispatch at least once so that sockets
823 wxTheApp
->Dispatch();
825 while (wxTheApp
&& wxTheApp
->Pending())
826 wxTheApp
->Dispatch();
829 wxTimer::NotifyTimers();
835 wxEventLoop::SetActive(NULL
);
847 void wxApp::OnAssert(const wxChar
*file
, int line
, const wxChar
* cond
, const wxChar
*msg
)
849 // While the GUI isn't working that well, just print out the
852 wxAppBase::OnAssert(file
, line
, cond
, msg
);
855 msg2
.Printf("At file %s:%d: %s", file
, line
, msg
);
860 #endif // __WXDEBUG__