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/dialog.h" 
  26     #include "wx/memory.h" 
  27     #include "wx/gdicmn.h" 
  30 #include "wx/module.h" 
  31 #include "wx/evtloop.h" 
  32 #include "wx/filename.h" 
  34 #include "wx/univ/theme.h" 
  35 #include "wx/univ/renderer.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 //------------------------------------------------------------------------ 
  67 typedef int (*XErrorHandlerFunc
)(Display 
*, XErrorEvent 
*); 
  69 XErrorHandlerFunc gs_pfnXErrorHandler 
= 0; 
  71 static int wxXErrorHandler(Display 
*dpy
, XErrorEvent 
*xevent
) 
  73     // just forward to the default handler for now 
  74     if (gs_pfnXErrorHandler
) 
  75         return gs_pfnXErrorHandler(dpy
, xevent
); 
  81 //------------------------------------------------------------------------ 
  83 //------------------------------------------------------------------------ 
  85 long wxApp::sm_lastMessageTime 
= 0; 
  86 WXDisplay 
*wxApp::ms_display 
= NULL
; 
  88 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
) 
  90 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
  91     EVT_IDLE(wxAppBase::OnIdle
) 
  94 bool wxApp::Initialize(int& argC
, wxChar 
**argV
) 
  96 #if defined(__WXDEBUG__) && !wxUSE_NANOX 
  97     // install the X error handler 
  98     gs_pfnXErrorHandler 
= XSetErrorHandler( wxXErrorHandler 
); 
 101     wxString displayName
; 
 102     bool syncDisplay 
= false; 
 105     for ( int i 
= 0; i 
< argCOrig
; i
++ ) 
 107         if (wxStrcmp( argV
[i
], _T("-display") ) == 0) 
 113                 displayName 
= argV
[i
]; 
 119         else if (wxStrcmp( argV
[i
], _T("-geometry") ) == 0) 
 126                 if (wxSscanf(argV
[i
], _T("%dx%d"), &w
, &h
) != 2) 
 128                     wxLogError( _("Invalid geometry specification '%s'"), 
 129                                 wxString(argV
[i
]).c_str() ); 
 133                     g_initialSize 
= wxSize(w
, h
); 
 140         else if (wxStrcmp( argV
[i
], _T("-sync") ) == 0) 
 147         else if (wxStrcmp( argV
[i
], _T("-iconic") ) == 0) 
 156     if ( argC 
!= argCOrig 
) 
 158         // remove the argumens we consumed 
 159         for ( int i 
= 0; i 
< argC
; i
++ ) 
 163                 memmove(argV 
+ i
, argV 
+ i 
+ 1, argCOrig 
- i
); 
 170     if ( displayName
.empty() ) 
 171         xdisplay 
= XOpenDisplay( NULL 
); 
 173         xdisplay 
= XOpenDisplay( displayName
.ToAscii() ); 
 176         wxLogError( _("wxWidgets could not open display. Exiting.") ); 
 181         XSynchronize(xdisplay
, True
); 
 183     ms_display 
= (WXDisplay
*) xdisplay
; 
 185     XSelectInput( xdisplay
, XDefaultRootWindow(xdisplay
), PropertyChangeMask
); 
 188     wxSetDetectableAutoRepeat( true ); 
 190     if ( !wxAppBase::Initialize(argC
, argV
) ) 
 192         XCloseDisplay(xdisplay
); 
 198     // Glib's type system required by Pango 
 203     wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding()); 
 206     wxWidgetHashTable 
= new wxWindowHash
; 
 207     wxClientWidgetHashTable 
= new wxWindowHash
; 
 212 void wxApp::CleanUp() 
 214     delete wxWidgetHashTable
; 
 215     wxWidgetHashTable 
= NULL
; 
 216     delete wxClientWidgetHashTable
; 
 217     wxClientWidgetHashTable 
= NULL
; 
 219     wxAppBase::CleanUp(); 
 224     // TODO: parse the command line 
 228     m_mainColormap 
= (WXColormap
) NULL
; 
 229     m_topLevelWidget 
= (WXWindow
) NULL
; 
 230     m_maxRequestSize 
= 0; 
 231     m_showIconic 
= false; 
 232     m_initialSize 
= wxDefaultSize
; 
 248 //----------------------------------------------------------------------- 
 249 // X11 predicate function for exposure compression 
 250 //----------------------------------------------------------------------- 
 255     Bool found_non_matching
; 
 259 Bool 
wxX11ExposePredicate (Display 
*display
, XEvent 
*xevent
, XPointer arg
) 
 261     wxExposeInfo 
*info 
= (wxExposeInfo
*) arg
; 
 263     if (info
->found_non_matching
) 
 266     if (xevent
->xany
.type 
!= Expose
) 
 268         info
->found_non_matching 
= true; 
 272     if (xevent
->xexpose
.window 
!= info
->window
) 
 274         info
->found_non_matching 
= true; 
 281 #endif // wxUSE_NANOX 
 283 //----------------------------------------------------------------------- 
 284 // Processes an X event, returning true if the event was processed. 
 285 //----------------------------------------------------------------------- 
 287 bool wxApp::ProcessXEvent(WXEvent
* _event
) 
 289     XEvent
* event 
= (XEvent
*) _event
; 
 291     wxWindow
* win 
= NULL
; 
 292     Window window 
= XEventGetWindow(event
); 
 294     Window actualWindow 
= window
; 
 297     // Find the first wxWindow that corresponds to this event window 
 298     // Because we're receiving events after a window 
 299     // has been destroyed, assume a 1:1 match between 
 300     // Window and wxWindow, so if it's not in the table, 
 301     // it must have been destroyed. 
 303     win 
= wxGetWindowFromTable(window
); 
 306 #if wxUSE_TWO_WINDOWS 
 307         win 
= wxGetClientWindowFromTable(window
); 
 314     wxString windowClass 
= win
->GetClassInfo()->GetClassName(); 
 321 #if wxUSE_TWO_WINDOWS && !wxUSE_NANOX 
 322             if (event
->xexpose
.window 
!= (Window
)win
->GetClientAreaWindow()) 
 326                 info
.window 
= event
->xexpose
.window
; 
 327                 info
.found_non_matching 
= false; 
 328                 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, wxX11ExposePredicate
, (XPointer
) &info 
)) 
 330                     // Don't worry about optimizing redrawing the border etc. 
 332                 win
->NeedUpdateNcAreaInIdle(); 
 337                 win
->GetUpdateRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
), 
 338                                               XExposeEventGetWidth(event
), XExposeEventGetHeight(event
)); 
 339                 win
->GetClearRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
), 
 340                                          XExposeEventGetWidth(event
), XExposeEventGetHeight(event
)); 
 345                 info
.window 
= event
->xexpose
.window
; 
 346                 info
.found_non_matching 
= false; 
 347                 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, wxX11ExposePredicate
, (XPointer
) &info 
)) 
 349                     win
->GetUpdateRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
, 
 350                                                   tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height 
); 
 352                     win
->GetClearRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
, 
 353                                                  tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height 
); 
 357                 // This simplifies the expose and clear areas to simple 
 359                 win
->GetUpdateRegion() = win
->GetUpdateRegion().GetBox(); 
 360                 win
->GetClearRegion() = win
->GetClearRegion().GetBox(); 
 362                 // If we only have one X11 window, always indicate 
 363                 // that borders might have to be redrawn. 
 364                 if (win
->GetMainWindow() == win
->GetClientAreaWindow()) 
 365                     win
->NeedUpdateNcAreaInIdle(); 
 367                 // Only erase background, paint in idle time. 
 368                 win
->SendEraseEvents(); 
 380             wxLogTrace( _T("expose"), _T("GraphicsExpose from %s"), win
->GetName().c_str()); 
 382             win
->GetUpdateRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
, 
 383                                           event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
); 
 385             win
->GetClearRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
, 
 386                                          event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
); 
 388             if (event
->xgraphicsexpose
.count 
== 0) 
 390                 // Only erase background, paint in idle time. 
 391                 win
->SendEraseEvents(); 
 401             if (!win
->IsEnabled()) 
 404             wxKeyEvent 
keyEvent(wxEVT_KEY_DOWN
); 
 405             wxTranslateKeyEvent(keyEvent
, win
, window
, event
); 
 407             // wxLogDebug( "OnKey from %s", win->GetName().c_str() ); 
 409             // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR 
 410             if (win
->GetEventHandler()->ProcessEvent( keyEvent 
)) 
 413             keyEvent
.SetEventType(wxEVT_CHAR
); 
 414             // Do the translation again, retaining the ASCII 
 416             wxTranslateKeyEvent(keyEvent
, win
, window
, event
, true); 
 417             if (win
->GetEventHandler()->ProcessEvent( keyEvent 
)) 
 420             if ( (keyEvent
.m_keyCode 
== WXK_TAB
) && 
 421                  win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) ) 
 423                 wxNavigationKeyEvent new_event
; 
 424                 new_event
.SetEventObject( win
->GetParent() ); 
 425                 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */ 
 426                 new_event
.SetDirection( (keyEvent
.m_keyCode 
== WXK_TAB
) ); 
 427                 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ 
 428                 new_event
.SetWindowChange( keyEvent
.ControlDown() ); 
 429                 new_event
.SetCurrentFocus( win 
); 
 430                 return win
->GetParent()->GetEventHandler()->ProcessEvent( new_event 
); 
 437             if (!win
->IsEnabled()) 
 440             wxKeyEvent 
keyEvent(wxEVT_KEY_UP
); 
 441             wxTranslateKeyEvent(keyEvent
, win
, window
, event
); 
 443             return win
->GetEventHandler()->ProcessEvent( keyEvent 
); 
 445         case ConfigureNotify
: 
 448             if (event
->update
.utype 
== GR_UPDATE_SIZE
) 
 451                 wxTopLevelWindow 
*tlw 
= wxDynamicCast(win
, wxTopLevelWindow
); 
 454                     tlw
->SetConfigureGeometry( XConfigureEventGetX(event
), XConfigureEventGetY(event
), 
 455                         XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
) ); 
 458                 if ( tlw 
&& tlw
->IsShown() ) 
 460                     tlw
->SetNeedResizeInIdle(); 
 464                     wxSizeEvent 
sizeEvent( wxSize(XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
)), win
->GetId() ); 
 465                     sizeEvent
.SetEventObject( win 
); 
 467                     return win
->GetEventHandler()->ProcessEvent( sizeEvent 
); 
 475             //wxLogDebug("PropertyNotify: %s", windowClass.c_str()); 
 476             return HandlePropertyChange(_event
); 
 480             if (!win
->IsEnabled()) 
 483             Atom wm_delete_window 
= XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True
); 
 484             Atom wm_protocols 
= XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True
); 
 486             if (event
->xclient
.message_type 
== wm_protocols
) 
 488                 if ((Atom
) (event
->xclient
.data
.l
[0]) == wm_delete_window
) 
 499             printf( "destroy from %s\n", win
->GetName().c_str() ); 
 504             printf( "create from %s\n", win
->GetName().c_str() ); 
 509             printf( "map request from %s\n", win
->GetName().c_str() ); 
 514             printf( "resize request from %s\n", win
->GetName().c_str() ); 
 516             Display 
*disp 
= (Display
*) wxGetDisplay(); 
 521             while( XCheckTypedWindowEvent (disp
, actualWindow
, ResizeRequest
, &report
)); 
 523             wxSize sz 
= win
->GetSize(); 
 524             wxSizeEvent 
sizeEvent(sz
, win
->GetId()); 
 525             sizeEvent
.SetEventObject(win
); 
 527             return win
->GetEventHandler()->ProcessEvent( sizeEvent 
); 
 532         case GR_EVENT_TYPE_CLOSE_REQ
: 
 549             if (!win
->IsEnabled()) 
 552             // Here we check if the top level window is 
 553             // disabled, which is one aspect of modality. 
 555             while (tlw 
&& !tlw
->IsTopLevel()) 
 556                 tlw 
= tlw
->GetParent(); 
 557             if (tlw 
&& !tlw
->IsEnabled()) 
 560             if (event
->type 
== ButtonPress
) 
 562                 if ((win 
!= wxWindow::FindFocus()) && win
->AcceptsFocus()) 
 564                     // This might actually be done in wxWindow::SetFocus() 
 565                     // and not here. TODO. 
 566                     g_prevFocus 
= wxWindow::FindFocus(); 
 569                     wxLogTrace( _T("focus"), _T("About to call SetFocus on %s of type %s due to button press"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() ); 
 571                     // Record the fact that this window is 
 572                     // getting the focus, because we'll need to 
 573                     // check if its parent is getting a bogus 
 574                     // focus and duly ignore it. 
 575                     // TODO: may need to have this code in SetFocus, too. 
 576                     extern wxWindow
* g_GettingFocus
; 
 577                     g_GettingFocus 
= win
; 
 583             if (event
->type 
== LeaveNotify 
|| event
->type 
== EnterNotify
) 
 585                 // Throw out NotifyGrab and NotifyUngrab 
 586                 if (event
->xcrossing
.mode 
!= NotifyNormal
) 
 590             wxMouseEvent wxevent
; 
 591             wxTranslateMouseEvent(wxevent
, win
, window
, event
); 
 592             return win
->GetEventHandler()->ProcessEvent( wxevent 
); 
 596             if ((event
->xfocus
.detail 
!= NotifyPointer
) && 
 597                 (event
->xfocus
.mode 
== NotifyNormal
)) 
 600                 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() ); 
 602                 extern wxWindow
* g_GettingFocus
; 
 603                 if (g_GettingFocus 
&& g_GettingFocus
->GetParent() == win
) 
 605                     // Ignore this, this can be a spurious FocusIn 
 606                     // caused by a child having its focus set. 
 607                     g_GettingFocus 
= NULL
; 
 608                     wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s being deliberately ignored"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() ); 
 613                     wxFocusEvent 
focusEvent(wxEVT_SET_FOCUS
, win
->GetId()); 
 614                     focusEvent
.SetEventObject(win
); 
 615                     focusEvent
.SetWindow( g_prevFocus 
); 
 618                     return win
->GetEventHandler()->ProcessEvent(focusEvent
); 
 625             if ((event
->xfocus
.detail 
!= NotifyPointer
) && 
 626                 (event
->xfocus
.mode 
== NotifyNormal
)) 
 629                 wxLogTrace( _T("focus"), _T("FocusOut from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() ); 
 631                 wxFocusEvent 
focusEvent(wxEVT_KILL_FOCUS
, win
->GetId()); 
 632                 focusEvent
.SetEventObject(win
); 
 633                 focusEvent
.SetWindow( g_nextFocus 
); 
 635                 return win
->GetEventHandler()->ProcessEvent(focusEvent
); 
 641             //wxString eventName = wxGetXEventName(XEvent& event); 
 642             //wxLogDebug(wxT("Event %s not handled"), eventName.c_str()); 
 644 #endif // __WXDEBUG__ 
 650 // This should be redefined in a derived class for 
 651 // handling property change events for XAtom IPC. 
 652 bool wxApp::HandlePropertyChange(WXEvent 
*event
) 
 654     // by default do nothing special 
 655     // TODO: what to do for X11 
 656     // XtDispatchEvent((XEvent*) event); 
 660 void wxApp::WakeUpIdle() 
 662     // TODO: use wxMotif implementation? 
 664     // Wake up the idle handler processor, even if it is in another thread... 
 668 // Create display, and other initialization 
 669 bool wxApp::OnInitGui() 
 671     // Eventually this line will be removed, but for 
 672     // now we don't want to try popping up a dialog 
 673     // for error messages. 
 674     delete wxLog::SetActiveTarget(new wxLogStderr
); 
 676     if (!wxAppBase::OnInitGui()) 
 679     GetMainColormap( wxApp::GetDisplay() ); 
 681     m_maxRequestSize 
= XMaxRequestSize( (Display
*) wxApp::GetDisplay() ); 
 684     m_visualInfo 
= new wxXVisualInfo
; 
 685     wxFillXVisualInfo( m_visualInfo
, (Display
*) wxApp::GetDisplay() ); 
 693 #include <pango/pango.h> 
 694 #include <pango/pangox.h> 
 695 #ifdef HAVE_PANGO_XFT 
 696     #include <pango/pangoxft.h> 
 699 PangoContext
* wxApp::GetPangoContext() 
 701     static PangoContext 
*ret 
= NULL
; 
 705     Display 
*xdisplay 
= (Display
*) wxApp::GetDisplay(); 
 707 #ifdef HAVE_PANGO_XFT 
 708     int xscreen 
= DefaultScreen(xdisplay
); 
 709     static int use_xft 
= -1; 
 712         wxString val 
= wxGetenv( L
"GDK_USE_XFT" ); 
 713         use_xft 
= (val 
== L
"1"); 
 717         ret 
= pango_xft_get_context( xdisplay
, xscreen 
); 
 720         ret 
= pango_x_get_context( xdisplay 
); 
 722     if (!PANGO_IS_CONTEXT(ret
)) 
 723         wxLogError( wxT("No pango context.") ); 
 729 WXColormap 
wxApp::GetMainColormap(WXDisplay
* display
) 
 731     if (!display
) /* Must be called first with non-NULL display */ 
 732         return m_mainColormap
; 
 734     int defaultScreen 
= DefaultScreen((Display
*) display
); 
 735     Screen
* screen 
= XScreenOfDisplay((Display
*) display
, defaultScreen
); 
 737     Colormap c 
= DefaultColormapOfScreen(screen
); 
 740         m_mainColormap 
= (WXColormap
) c
; 
 742     return (WXColormap
) c
; 
 745 Window 
wxGetWindowParent(Window window
) 
 747     wxASSERT_MSG( window
, _T("invalid window") ); 
 752    // VMS chokes on unreacheable code 
 753    Window parent
, root 
= 0; 
 757     unsigned int noChildren 
= 0; 
 759     Window
* children 
= NULL
; 
 761     // #define XQueryTree(d,w,r,p,c,nc)     GrQueryTree(w,p,c,nc) 
 766         XQueryTree((Display
*) wxGetDisplay(), window
, & root
, & parent
, 
 767              & children
, & noChildren
); 
 781     wxAppConsole::Exit(); 
 784 // Yield to other processes 
 786 bool wxApp::Yield(bool onlyIfNeeded
) 
 788     // Sometimes only 2 yields seem 
 789     // to do the trick, e.g. in the 
 792     for (i 
= 0; i 
< 2; i
++) 
 794         static bool s_inYield 
= false; 
 800                 wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 808         // Make sure we have an event loop object, 
 809         // or Pending/Dispatch will fail 
 810         wxEventLoop
* eventLoop 
= wxEventLoop::GetActive(); 
 811         wxEventLoop
* newEventLoop 
= NULL
; 
 814             newEventLoop 
= new wxEventLoop
; 
 815             wxEventLoop::SetActive(newEventLoop
); 
 818         // Call dispatch at least once so that sockets 
 820         wxTheApp
->Dispatch(); 
 822         while (wxTheApp 
&& wxTheApp
->Pending()) 
 823             wxTheApp
->Dispatch(); 
 826         wxTimer::NotifyTimers(); 
 832             wxEventLoop::SetActive(NULL
); 
 844 void wxApp::OnAssert(const wxChar 
*file
, int line
, const wxChar
* cond
, const wxChar 
*msg
) 
 846     // While the GUI isn't working that well, just print out the 
 849     wxAppBase::OnAssert(file
, line
, cond
, msg
); 
 852     msg2
.Printf("At file %s:%d: %s", file
, line
, msg
); 
 857 #endif // __WXDEBUG__