1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/x11/app.cpp
4 // Author: Julian Smart
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // for compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
23 #include "wx/dialog.h"
24 #include "wx/memory.h"
25 #include "wx/gdicmn.h"
26 #include "wx/module.h"
30 #include "wx/evtloop.h"
31 #include "wx/filename.h"
33 #include "wx/univ/theme.h"
34 #include "wx/univ/renderer.h"
35 #include "wx/generic/private/timer.h"
38 #include "wx/thread.h"
41 #include "wx/x11/private.h"
45 //------------------------------------------------------------------------
47 //------------------------------------------------------------------------
49 wxWindowHash
*wxWidgetHashTable
= NULL
;
50 wxWindowHash
*wxClientWidgetHashTable
= NULL
;
52 static bool g_showIconic
= false;
53 static wxSize g_initialSize
= wxDefaultSize
;
55 // This is required for wxFocusEvent::SetWindow(). It will only
56 // work for focus events which we provoke ourselves (by calling
57 // SetFocus()). It will not work for those events, which X11
59 static wxWindow
*g_nextFocus
= NULL
;
60 static wxWindow
*g_prevFocus
= NULL
;
62 //------------------------------------------------------------------------
64 //------------------------------------------------------------------------
66 typedef int (*XErrorHandlerFunc
)(Display
*, XErrorEvent
*);
68 XErrorHandlerFunc gs_pfnXErrorHandler
= 0;
70 static int wxXErrorHandler(Display
*dpy
, XErrorEvent
*xevent
)
72 // just forward to the default handler for now
73 if (gs_pfnXErrorHandler
)
74 return gs_pfnXErrorHandler(dpy
, xevent
);
79 //------------------------------------------------------------------------
81 //------------------------------------------------------------------------
83 long wxApp::sm_lastMessageTime
= 0;
85 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
87 bool wxApp::Initialize(int& argC
, wxChar
**argV
)
90 // install the X error handler
91 gs_pfnXErrorHandler
= XSetErrorHandler( wxXErrorHandler
);
95 bool syncDisplay
= false;
98 for ( int i
= 0; i
< argCOrig
; i
++ )
100 if (wxStrcmp( argV
[i
], wxT("-display") ) == 0)
102 if (i
< (argCOrig
- 1))
106 displayName
= argV
[i
];
112 else if (wxStrcmp( argV
[i
], wxT("-geometry") ) == 0)
114 if (i
< (argCOrig
- 1))
119 if (wxSscanf(argV
[i
], wxT("%dx%d"), &w
, &h
) != 2)
121 wxLogError( _("Invalid geometry specification '%s'"),
122 wxString(argV
[i
]).c_str() );
126 g_initialSize
= wxSize(w
, h
);
133 else if (wxStrcmp( argV
[i
], wxT("-sync") ) == 0)
140 else if (wxStrcmp( argV
[i
], wxT("-iconic") ) == 0)
149 if ( argC
!= argCOrig
)
151 // remove the arguments we consumed
152 for ( int i
= 0; i
< argC
; i
++ )
156 memmove(argV
+ i
, argV
+ i
+ 1, (argCOrig
- i
)*sizeof(wxChar
*));
161 // open and set up the X11 display
162 if ( !wxSetDisplay(displayName
) )
164 wxLogError(_("wxWidgets could not open display. Exiting."));
168 Display
*dpy
= wxGlobalDisplay();
170 XSynchronize(dpy
, True
);
172 XSelectInput(dpy
, XDefaultRootWindow(dpy
), PropertyChangeMask
);
174 wxSetDetectableAutoRepeat( true );
177 if ( !wxAppBase::Initialize(argC
, argV
) )
181 // Glib's type system required by Pango
186 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
189 wxWidgetHashTable
= new wxWindowHash
;
190 wxClientWidgetHashTable
= new wxWindowHash
;
195 void wxApp::CleanUp()
197 wxDELETE(wxWidgetHashTable
);
198 wxDELETE(wxClientWidgetHashTable
);
200 wxAppBase::CleanUp();
205 m_mainColormap
= NULL
;
206 m_topLevelWidget
= NULL
;
207 m_maxRequestSize
= 0;
208 m_showIconic
= false;
209 m_initialSize
= wxDefaultSize
;
225 //-----------------------------------------------------------------------
226 // X11 predicate function for exposure compression
227 //-----------------------------------------------------------------------
232 Bool found_non_matching
;
236 Bool
wxX11ExposePredicate (Display
*WXUNUSED(display
), XEvent
*xevent
, XPointer arg
)
238 wxExposeInfo
*info
= (wxExposeInfo
*) arg
;
240 if (info
->found_non_matching
)
243 if (xevent
->xany
.type
!= Expose
)
245 info
->found_non_matching
= true;
249 if (xevent
->xexpose
.window
!= info
->window
)
251 info
->found_non_matching
= true;
258 #endif // wxUSE_NANOX
260 //-----------------------------------------------------------------------
261 // Processes an X event, returning true if the event was processed.
262 //-----------------------------------------------------------------------
264 bool wxApp::ProcessXEvent(WXEvent
* _event
)
266 XEvent
* event
= (XEvent
*) _event
;
268 wxWindow
* win
= NULL
;
269 Window window
= XEventGetWindow(event
);
271 Window actualWindow
= window
;
274 // Find the first wxWindow that corresponds to this event window
275 // Because we're receiving events after a window
276 // has been destroyed, assume a 1:1 match between
277 // Window and wxWindow, so if it's not in the table,
278 // it must have been destroyed.
280 win
= wxGetWindowFromTable(window
);
283 #if wxUSE_TWO_WINDOWS
284 win
= wxGetClientWindowFromTable(window
);
295 #if wxUSE_TWO_WINDOWS && !wxUSE_NANOX
296 if (event
->xexpose
.window
!= (Window
)win
->GetClientAreaWindow())
300 info
.window
= event
->xexpose
.window
;
301 info
.found_non_matching
= false;
302 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, wxX11ExposePredicate
, (XPointer
) &info
))
304 // Don't worry about optimizing redrawing the border etc.
306 win
->NeedUpdateNcAreaInIdle();
311 win
->GetUpdateRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
),
312 XExposeEventGetWidth(event
), XExposeEventGetHeight(event
));
313 win
->GetClearRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
),
314 XExposeEventGetWidth(event
), XExposeEventGetHeight(event
));
319 info
.window
= event
->xexpose
.window
;
320 info
.found_non_matching
= false;
321 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, wxX11ExposePredicate
, (XPointer
) &info
))
323 win
->GetUpdateRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
,
324 tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height
);
326 win
->GetClearRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
,
327 tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height
);
331 // This simplifies the expose and clear areas to simple
333 win
->GetUpdateRegion() = win
->GetUpdateRegion().GetBox();
334 win
->GetClearRegion() = win
->GetClearRegion().GetBox();
336 // If we only have one X11 window, always indicate
337 // that borders might have to be redrawn.
338 if (win
->X11GetMainWindow() == win
->GetClientAreaWindow())
339 win
->NeedUpdateNcAreaInIdle();
341 // Only erase background, paint in idle time.
342 win
->SendEraseEvents();
354 wxLogTrace( wxT("expose"), wxT("GraphicsExpose from %s"), win
->GetName().c_str());
356 win
->GetUpdateRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
,
357 event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
);
359 win
->GetClearRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
,
360 event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
);
362 if (event
->xgraphicsexpose
.count
== 0)
364 // Only erase background, paint in idle time.
365 win
->SendEraseEvents();
375 if (!win
->IsEnabled())
378 wxKeyEvent
keyEvent(wxEVT_KEY_DOWN
);
379 wxTranslateKeyEvent(keyEvent
, win
, window
, event
);
381 // wxLogDebug( "OnKey from %s", win->GetName().c_str() );
383 // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR
384 if (win
->HandleWindowEvent( keyEvent
))
387 keyEvent
.SetEventType(wxEVT_CHAR
);
388 // Do the translation again, retaining the ASCII
390 if (wxTranslateKeyEvent(keyEvent
, win
, window
, event
, true) &&
391 win
->HandleWindowEvent( keyEvent
))
394 if ( (keyEvent
.m_keyCode
== WXK_TAB
) &&
395 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
397 wxNavigationKeyEvent new_event
;
398 new_event
.SetEventObject( win
->GetParent() );
399 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
400 new_event
.SetDirection( (keyEvent
.m_keyCode
== WXK_TAB
) );
401 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
402 new_event
.SetWindowChange( keyEvent
.ControlDown() );
403 new_event
.SetCurrentFocus( win
);
404 return win
->GetParent()->HandleWindowEvent( new_event
);
411 if (!win
->IsEnabled())
414 wxKeyEvent
keyEvent(wxEVT_KEY_UP
);
415 wxTranslateKeyEvent(keyEvent
, win
, window
, event
);
417 return win
->HandleWindowEvent( keyEvent
);
419 case ConfigureNotify
:
422 if (event
->update
.utype
== GR_UPDATE_SIZE
)
425 wxTopLevelWindow
*tlw
= wxDynamicCast(win
, wxTopLevelWindow
);
428 tlw
->SetConfigureGeometry( XConfigureEventGetX(event
), XConfigureEventGetY(event
),
429 XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
) );
432 if ( tlw
&& tlw
->IsShown() )
434 tlw
->SetNeedResizeInIdle();
438 wxSizeEvent
sizeEvent( wxSize(XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
)), win
->GetId() );
439 sizeEvent
.SetEventObject( win
);
441 return win
->HandleWindowEvent( sizeEvent
);
448 return HandlePropertyChange(_event
);
452 if (!win
->IsEnabled())
455 Atom wm_delete_window
= XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True
);
456 Atom wm_protocols
= XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True
);
458 if (event
->xclient
.message_type
== wm_protocols
)
460 if ((Atom
) (event
->xclient
.data
.l
[0]) == wm_delete_window
)
471 printf( "destroy from %s\n", win
->GetName().c_str() );
476 printf( "create from %s\n", win
->GetName().c_str() );
481 printf( "map request from %s\n", win
->GetName().c_str() );
486 printf( "resize request from %s\n", win
->GetName().c_str() );
488 Display
*disp
= (Display
*) wxGetDisplay();
493 while( XCheckTypedWindowEvent (disp
, actualWindow
, ResizeRequest
, &report
));
495 wxSize sz
= win
->GetSize();
496 wxSizeEvent
sizeEvent(sz
, win
->GetId());
497 sizeEvent
.SetEventObject(win
);
499 return win
->HandleWindowEvent( sizeEvent
);
504 case GR_EVENT_TYPE_CLOSE_REQ
:
521 if (!win
->IsEnabled())
524 // Here we check if the top level window is
525 // disabled, which is one aspect of modality.
527 while (tlw
&& !tlw
->IsTopLevel())
528 tlw
= tlw
->GetParent();
529 if (tlw
&& !tlw
->IsEnabled())
532 if (event
->type
== ButtonPress
)
534 if ((win
!= wxWindow::FindFocus()) && win
->CanAcceptFocus())
536 // This might actually be done in wxWindow::SetFocus()
537 // and not here. TODO.
538 g_prevFocus
= wxWindow::FindFocus();
541 wxLogTrace( wxT("focus"), wxT("About to call SetFocus on %s of type %s due to button press"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
543 // Record the fact that this window is
544 // getting the focus, because we'll need to
545 // check if its parent is getting a bogus
546 // focus and duly ignore it.
547 // TODO: may need to have this code in SetFocus, too.
548 extern wxWindow
* g_GettingFocus
;
549 g_GettingFocus
= win
;
555 if (event
->type
== LeaveNotify
|| event
->type
== EnterNotify
)
557 // Throw out NotifyGrab and NotifyUngrab
558 if (event
->xcrossing
.mode
!= NotifyNormal
)
562 wxMouseEvent wxevent
;
563 wxTranslateMouseEvent(wxevent
, win
, window
, event
);
564 return win
->HandleWindowEvent( wxevent
);
568 if ((event
->xfocus
.detail
!= NotifyPointer
) &&
569 (event
->xfocus
.mode
== NotifyNormal
))
572 wxLogTrace( wxT("focus"), wxT("FocusIn from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
574 extern wxWindow
* g_GettingFocus
;
575 if (g_GettingFocus
&& g_GettingFocus
->GetParent() == win
)
577 // Ignore this, this can be a spurious FocusIn
578 // caused by a child having its focus set.
579 g_GettingFocus
= NULL
;
580 wxLogTrace( wxT("focus"), wxT("FocusIn from %s of type %s being deliberately ignored"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
585 wxFocusEvent
focusEvent(wxEVT_SET_FOCUS
, win
->GetId());
586 focusEvent
.SetEventObject(win
);
587 focusEvent
.SetWindow( g_prevFocus
);
590 return win
->HandleWindowEvent(focusEvent
);
597 if ((event
->xfocus
.detail
!= NotifyPointer
) &&
598 (event
->xfocus
.mode
== NotifyNormal
))
601 wxLogTrace( wxT("focus"), wxT("FocusOut from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
603 wxFocusEvent
focusEvent(wxEVT_KILL_FOCUS
, win
->GetId());
604 focusEvent
.SetEventObject(win
);
605 focusEvent
.SetWindow( g_nextFocus
);
607 return win
->HandleWindowEvent(focusEvent
);
615 // This should be redefined in a derived class for
616 // handling property change events for XAtom IPC.
617 bool wxApp::HandlePropertyChange(WXEvent
*WXUNUSED(event
))
619 // by default do nothing special
620 // TODO: what to do for X11
621 // XtDispatchEvent((XEvent*) event);
625 void wxApp::WakeUpIdle()
627 // TODO: use wxMotif implementation?
629 // Wake up the idle handler processor, even if it is in another thread...
633 // Create display, and other initialization
634 bool wxApp::OnInitGui()
637 // Eventually this line will be removed, but for
638 // now we don't want to try popping up a dialog
639 // for error messages.
640 delete wxLog::SetActiveTarget(new wxLogStderr
);
643 if (!wxAppBase::OnInitGui())
646 Display
*dpy
= wxGlobalDisplay();
647 GetMainColormap(dpy
);
649 m_maxRequestSize
= XMaxRequestSize(dpy
);
652 m_visualInfo
= new wxXVisualInfo
;
653 wxFillXVisualInfo(m_visualInfo
, dpy
);
661 #include <pango/pango.h>
662 #include <pango/pangox.h>
663 #ifdef HAVE_PANGO_XFT
664 #include <pango/pangoxft.h>
667 PangoContext
* wxApp::GetPangoContext()
669 static PangoContext
*s_pangoContext
= NULL
;
670 if ( !s_pangoContext
)
672 Display
*dpy
= wxGlobalDisplay();
674 #ifdef HAVE_PANGO_XFT
675 int xscreen
= DefaultScreen(dpy
);
676 static int use_xft
= -1;
679 wxString val
= wxGetenv( L
"GDK_USE_XFT" );
680 use_xft
= val
== L
"1";
684 s_pangoContext
= pango_xft_get_context(dpy
, xscreen
);
686 #endif // HAVE_PANGO_XFT
687 s_pangoContext
= pango_x_get_context(dpy
);
689 if (!PANGO_IS_CONTEXT(s_pangoContext
))
691 wxLogError( wxT("No pango context.") );
695 return s_pangoContext
;
698 #endif // wxUSE_UNICODE
700 WXColormap
wxApp::GetMainColormap(WXDisplay
* display
)
702 if (!display
) /* Must be called first with non-NULL display */
703 return m_mainColormap
;
705 int defaultScreen
= DefaultScreen((Display
*) display
);
706 Screen
* screen
= XScreenOfDisplay((Display
*) display
, defaultScreen
);
708 Colormap c
= DefaultColormapOfScreen(screen
);
711 m_mainColormap
= (WXColormap
) c
;
713 return (WXColormap
) c
;
716 Window
wxGetWindowParent(Window window
)
718 wxASSERT_MSG( window
, wxT("invalid window") );
723 // VMS chokes on unreacheable code
724 Window parent
, root
= 0;
728 unsigned int noChildren
= 0;
730 Window
* children
= NULL
;
732 // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc)
737 XQueryTree((Display
*) wxGetDisplay(), window
, & root
, & parent
,
738 & children
, & noChildren
);
752 wxAppConsole::Exit();