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" 
  25     #include "wx/memory.h" 
  26     #include "wx/gdicmn.h" 
  27     #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" 
  36 #include "wx/generic/private/timer.h" 
  39     #include "wx/thread.h" 
  42 #include "wx/x11/private.h" 
  46 //------------------------------------------------------------------------ 
  48 //------------------------------------------------------------------------ 
  50 wxWindowHash 
*wxWidgetHashTable 
= NULL
; 
  51 wxWindowHash 
*wxClientWidgetHashTable 
= NULL
; 
  53 static bool g_showIconic 
= false; 
  54 static wxSize g_initialSize 
= wxDefaultSize
; 
  56 // This is required for wxFocusEvent::SetWindow(). It will only 
  57 // work for focus events which we provoke ourselves (by calling 
  58 // SetFocus()). It will not work for those events, which X11 
  60 static wxWindow 
*g_nextFocus 
= NULL
; 
  61 static wxWindow 
*g_prevFocus 
= NULL
; 
  63 //------------------------------------------------------------------------ 
  65 //------------------------------------------------------------------------ 
  68 typedef int (*XErrorHandlerFunc
)(Display 
*, XErrorEvent 
*); 
  70 XErrorHandlerFunc gs_pfnXErrorHandler 
= 0; 
  72 static int wxXErrorHandler(Display 
*dpy
, XErrorEvent 
*xevent
) 
  74     // just forward to the default handler for now 
  75     if (gs_pfnXErrorHandler
) 
  76         return gs_pfnXErrorHandler(dpy
, xevent
); 
  82 //------------------------------------------------------------------------ 
  84 //------------------------------------------------------------------------ 
  86 long wxApp::sm_lastMessageTime 
= 0; 
  88 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
) 
  90 bool wxApp::Initialize(int& argC
, wxChar 
**argV
) 
  92 #if defined(__WXDEBUG__) && !wxUSE_NANOX 
  93     // install the X error handler 
  94     gs_pfnXErrorHandler 
= XSetErrorHandler( wxXErrorHandler 
); 
  98     bool syncDisplay 
= false; 
 101     for ( int i 
= 0; i 
< argCOrig
; i
++ ) 
 103         if (wxStrcmp( argV
[i
], _T("-display") ) == 0) 
 109                 displayName 
= argV
[i
]; 
 115         else if (wxStrcmp( argV
[i
], _T("-geometry") ) == 0) 
 122                 if (wxSscanf(argV
[i
], _T("%dx%d"), &w
, &h
) != 2) 
 124                     wxLogError( _("Invalid geometry specification '%s'"), 
 125                                 wxString(argV
[i
]).c_str() ); 
 129                     g_initialSize 
= wxSize(w
, h
); 
 136         else if (wxStrcmp( argV
[i
], _T("-sync") ) == 0) 
 143         else if (wxStrcmp( argV
[i
], _T("-iconic") ) == 0) 
 152     if ( argC 
!= argCOrig 
) 
 154         // remove the argumens we consumed 
 155         for ( int i 
= 0; i 
< argC
; i
++ ) 
 159                 memmove(argV 
+ i
, argV 
+ i 
+ 1, argCOrig 
- i
); 
 164     // open and set up the X11 display 
 165     if ( !wxSetDisplay(displayName
) ) 
 167         wxLogError(_("wxWidgets could not open display. Exiting.")); 
 171     Display 
*dpy 
= wxGlobalDisplay(); 
 173         XSynchronize(dpy
, True
); 
 175     XSelectInput(dpy
, XDefaultRootWindow(dpy
), PropertyChangeMask
); 
 177     wxSetDetectableAutoRepeat( true ); 
 180     if ( !wxAppBase::Initialize(argC
, argV
) ) 
 184     // Glib's type system required by Pango 
 189     wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding()); 
 192     wxWidgetHashTable 
= new wxWindowHash
; 
 193     wxClientWidgetHashTable 
= new wxWindowHash
; 
 198 void wxApp::CleanUp() 
 200     delete wxWidgetHashTable
; 
 201     wxWidgetHashTable 
= NULL
; 
 202     delete wxClientWidgetHashTable
; 
 203     wxClientWidgetHashTable 
= NULL
; 
 205     wxAppBase::CleanUp(); 
 210     m_mainColormap 
= NULL
; 
 211     m_topLevelWidget 
= NULL
; 
 212     m_maxRequestSize 
= 0; 
 213     m_showIconic 
= false; 
 214     m_initialSize 
= wxDefaultSize
; 
 230 //----------------------------------------------------------------------- 
 231 // X11 predicate function for exposure compression 
 232 //----------------------------------------------------------------------- 
 237     Bool found_non_matching
; 
 241 Bool 
wxX11ExposePredicate (Display 
*WXUNUSED(display
), XEvent 
*xevent
, XPointer arg
) 
 243     wxExposeInfo 
*info 
= (wxExposeInfo
*) arg
; 
 245     if (info
->found_non_matching
) 
 248     if (xevent
->xany
.type 
!= Expose
) 
 250         info
->found_non_matching 
= true; 
 254     if (xevent
->xexpose
.window 
!= info
->window
) 
 256         info
->found_non_matching 
= true; 
 263 #endif // wxUSE_NANOX 
 265 //----------------------------------------------------------------------- 
 266 // Processes an X event, returning true if the event was processed. 
 267 //----------------------------------------------------------------------- 
 269 bool wxApp::ProcessXEvent(WXEvent
* _event
) 
 271     XEvent
* event 
= (XEvent
*) _event
; 
 273     wxWindow
* win 
= NULL
; 
 274     Window window 
= XEventGetWindow(event
); 
 276     Window actualWindow 
= window
; 
 279     // Find the first wxWindow that corresponds to this event window 
 280     // Because we're receiving events after a window 
 281     // has been destroyed, assume a 1:1 match between 
 282     // Window and wxWindow, so if it's not in the table, 
 283     // it must have been destroyed. 
 285     win 
= wxGetWindowFromTable(window
); 
 288 #if wxUSE_TWO_WINDOWS 
 289         win 
= wxGetClientWindowFromTable(window
); 
 296     wxString windowClass 
= win
->GetClassInfo()->GetClassName(); 
 303 #if wxUSE_TWO_WINDOWS && !wxUSE_NANOX 
 304             if (event
->xexpose
.window 
!= (Window
)win
->GetClientAreaWindow()) 
 308                 info
.window 
= event
->xexpose
.window
; 
 309                 info
.found_non_matching 
= false; 
 310                 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, wxX11ExposePredicate
, (XPointer
) &info 
)) 
 312                     // Don't worry about optimizing redrawing the border etc. 
 314                 win
->NeedUpdateNcAreaInIdle(); 
 319                 win
->GetUpdateRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
), 
 320                                               XExposeEventGetWidth(event
), XExposeEventGetHeight(event
)); 
 321                 win
->GetClearRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
), 
 322                                          XExposeEventGetWidth(event
), XExposeEventGetHeight(event
)); 
 327                 info
.window 
= event
->xexpose
.window
; 
 328                 info
.found_non_matching 
= false; 
 329                 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, wxX11ExposePredicate
, (XPointer
) &info 
)) 
 331                     win
->GetUpdateRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
, 
 332                                                   tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height 
); 
 334                     win
->GetClearRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
, 
 335                                                  tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height 
); 
 339                 // This simplifies the expose and clear areas to simple 
 341                 win
->GetUpdateRegion() = win
->GetUpdateRegion().GetBox(); 
 342                 win
->GetClearRegion() = win
->GetClearRegion().GetBox(); 
 344                 // If we only have one X11 window, always indicate 
 345                 // that borders might have to be redrawn. 
 346                 if (win
->GetMainWindow() == win
->GetClientAreaWindow()) 
 347                     win
->NeedUpdateNcAreaInIdle(); 
 349                 // Only erase background, paint in idle time. 
 350                 win
->SendEraseEvents(); 
 362             wxLogTrace( _T("expose"), _T("GraphicsExpose from %s"), win
->GetName().c_str()); 
 364             win
->GetUpdateRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
, 
 365                                           event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
); 
 367             win
->GetClearRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
, 
 368                                          event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
); 
 370             if (event
->xgraphicsexpose
.count 
== 0) 
 372                 // Only erase background, paint in idle time. 
 373                 win
->SendEraseEvents(); 
 383             if (!win
->IsEnabled()) 
 386             wxKeyEvent 
keyEvent(wxEVT_KEY_DOWN
); 
 387             wxTranslateKeyEvent(keyEvent
, win
, window
, event
); 
 389             // wxLogDebug( "OnKey from %s", win->GetName().c_str() ); 
 391             // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR 
 392             if (win
->HandleWindowEvent( keyEvent 
)) 
 395             keyEvent
.SetEventType(wxEVT_CHAR
); 
 396             // Do the translation again, retaining the ASCII 
 398             if (wxTranslateKeyEvent(keyEvent
, win
, window
, event
, true) && 
 399                 win
->HandleWindowEvent( keyEvent 
)) 
 402             if ( (keyEvent
.m_keyCode 
== WXK_TAB
) && 
 403                  win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) ) 
 405                 wxNavigationKeyEvent new_event
; 
 406                 new_event
.SetEventObject( win
->GetParent() ); 
 407                 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */ 
 408                 new_event
.SetDirection( (keyEvent
.m_keyCode 
== WXK_TAB
) ); 
 409                 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ 
 410                 new_event
.SetWindowChange( keyEvent
.ControlDown() ); 
 411                 new_event
.SetCurrentFocus( win 
); 
 412                 return win
->GetParent()->HandleWindowEvent( new_event 
); 
 419             if (!win
->IsEnabled()) 
 422             wxKeyEvent 
keyEvent(wxEVT_KEY_UP
); 
 423             wxTranslateKeyEvent(keyEvent
, win
, window
, event
); 
 425             return win
->HandleWindowEvent( keyEvent 
); 
 427         case ConfigureNotify
: 
 430             if (event
->update
.utype 
== GR_UPDATE_SIZE
) 
 433                 wxTopLevelWindow 
*tlw 
= wxDynamicCast(win
, wxTopLevelWindow
); 
 436                     tlw
->SetConfigureGeometry( XConfigureEventGetX(event
), XConfigureEventGetY(event
), 
 437                         XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
) ); 
 440                 if ( tlw 
&& tlw
->IsShown() ) 
 442                     tlw
->SetNeedResizeInIdle(); 
 446                     wxSizeEvent 
sizeEvent( wxSize(XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
)), win
->GetId() ); 
 447                     sizeEvent
.SetEventObject( win 
); 
 449                     return win
->HandleWindowEvent( sizeEvent 
); 
 457             //wxLogDebug("PropertyNotify: %s", windowClass.c_str()); 
 458             return HandlePropertyChange(_event
); 
 462             if (!win
->IsEnabled()) 
 465             Atom wm_delete_window 
= XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True
); 
 466             Atom wm_protocols 
= XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True
); 
 468             if (event
->xclient
.message_type 
== wm_protocols
) 
 470                 if ((Atom
) (event
->xclient
.data
.l
[0]) == wm_delete_window
) 
 481             printf( "destroy from %s\n", win
->GetName().c_str() ); 
 486             printf( "create from %s\n", win
->GetName().c_str() ); 
 491             printf( "map request from %s\n", win
->GetName().c_str() ); 
 496             printf( "resize request from %s\n", win
->GetName().c_str() ); 
 498             Display 
*disp 
= (Display
*) wxGetDisplay(); 
 503             while( XCheckTypedWindowEvent (disp
, actualWindow
, ResizeRequest
, &report
)); 
 505             wxSize sz 
= win
->GetSize(); 
 506             wxSizeEvent 
sizeEvent(sz
, win
->GetId()); 
 507             sizeEvent
.SetEventObject(win
); 
 509             return win
->HandleWindowEvent( sizeEvent 
); 
 514         case GR_EVENT_TYPE_CLOSE_REQ
: 
 531             if (!win
->IsEnabled()) 
 534             // Here we check if the top level window is 
 535             // disabled, which is one aspect of modality. 
 537             while (tlw 
&& !tlw
->IsTopLevel()) 
 538                 tlw 
= tlw
->GetParent(); 
 539             if (tlw 
&& !tlw
->IsEnabled()) 
 542             if (event
->type 
== ButtonPress
) 
 544                 if ((win 
!= wxWindow::FindFocus()) && win
->CanAcceptFocus()) 
 546                     // This might actually be done in wxWindow::SetFocus() 
 547                     // and not here. TODO. 
 548                     g_prevFocus 
= wxWindow::FindFocus(); 
 551                     wxLogTrace( _T("focus"), _T("About to call SetFocus on %s of type %s due to button press"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() ); 
 553                     // Record the fact that this window is 
 554                     // getting the focus, because we'll need to 
 555                     // check if its parent is getting a bogus 
 556                     // focus and duly ignore it. 
 557                     // TODO: may need to have this code in SetFocus, too. 
 558                     extern wxWindow
* g_GettingFocus
; 
 559                     g_GettingFocus 
= win
; 
 565             if (event
->type 
== LeaveNotify 
|| event
->type 
== EnterNotify
) 
 567                 // Throw out NotifyGrab and NotifyUngrab 
 568                 if (event
->xcrossing
.mode 
!= NotifyNormal
) 
 572             wxMouseEvent wxevent
; 
 573             wxTranslateMouseEvent(wxevent
, win
, window
, event
); 
 574             return win
->HandleWindowEvent( wxevent 
); 
 578             if ((event
->xfocus
.detail 
!= NotifyPointer
) && 
 579                 (event
->xfocus
.mode 
== NotifyNormal
)) 
 582                 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() ); 
 584                 extern wxWindow
* g_GettingFocus
; 
 585                 if (g_GettingFocus 
&& g_GettingFocus
->GetParent() == win
) 
 587                     // Ignore this, this can be a spurious FocusIn 
 588                     // caused by a child having its focus set. 
 589                     g_GettingFocus 
= NULL
; 
 590                     wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s being deliberately ignored"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() ); 
 595                     wxFocusEvent 
focusEvent(wxEVT_SET_FOCUS
, win
->GetId()); 
 596                     focusEvent
.SetEventObject(win
); 
 597                     focusEvent
.SetWindow( g_prevFocus 
); 
 600                     return win
->HandleWindowEvent(focusEvent
); 
 607             if ((event
->xfocus
.detail 
!= NotifyPointer
) && 
 608                 (event
->xfocus
.mode 
== NotifyNormal
)) 
 611                 wxLogTrace( _T("focus"), _T("FocusOut from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() ); 
 613                 wxFocusEvent 
focusEvent(wxEVT_KILL_FOCUS
, win
->GetId()); 
 614                 focusEvent
.SetEventObject(win
); 
 615                 focusEvent
.SetWindow( g_nextFocus 
); 
 617                 return win
->HandleWindowEvent(focusEvent
); 
 623             //wxString eventName = wxGetXEventName(XEvent& event); 
 624             //wxLogDebug(wxT("Event %s not handled"), eventName.c_str()); 
 626 #endif // __WXDEBUG__ 
 632 // This should be redefined in a derived class for 
 633 // handling property change events for XAtom IPC. 
 634 bool wxApp::HandlePropertyChange(WXEvent 
*WXUNUSED(event
)) 
 636     // by default do nothing special 
 637     // TODO: what to do for X11 
 638     // XtDispatchEvent((XEvent*) event); 
 642 void wxApp::WakeUpIdle() 
 644     // TODO: use wxMotif implementation? 
 646     // Wake up the idle handler processor, even if it is in another thread... 
 650 // Create display, and other initialization 
 651 bool wxApp::OnInitGui() 
 654     // Eventually this line will be removed, but for 
 655     // now we don't want to try popping up a dialog 
 656     // for error messages. 
 657     delete wxLog::SetActiveTarget(new wxLogStderr
); 
 660     if (!wxAppBase::OnInitGui()) 
 663     Display 
*dpy 
= wxGlobalDisplay(); 
 664     GetMainColormap(dpy
); 
 666     m_maxRequestSize 
= XMaxRequestSize(dpy
); 
 669     m_visualInfo 
= new wxXVisualInfo
; 
 670     wxFillXVisualInfo(m_visualInfo
, dpy
); 
 678 #include <pango/pango.h> 
 679 #include <pango/pangox.h> 
 680 #ifdef HAVE_PANGO_XFT 
 681     #include <pango/pangoxft.h> 
 684 PangoContext
* wxApp::GetPangoContext() 
 686     static PangoContext 
*s_pangoContext 
= NULL
; 
 687     if ( !s_pangoContext 
) 
 689         Display 
*dpy 
= wxGlobalDisplay(); 
 691 #ifdef HAVE_PANGO_XFT 
 692         int xscreen 
= DefaultScreen(dpy
); 
 693         static int use_xft 
= -1; 
 696             wxString val 
= wxGetenv( L
"GDK_USE_XFT" ); 
 697             use_xft 
= val 
== L
"1"; 
 701             s_pangoContext 
= pango_xft_get_context(dpy
, xscreen
); 
 703 #endif // HAVE_PANGO_XFT 
 704             s_pangoContext 
= pango_x_get_context(dpy
); 
 706         if (!PANGO_IS_CONTEXT(s_pangoContext
)) 
 707             wxLogError( wxT("No pango context.") ); 
 710     return s_pangoContext
; 
 713 #endif // wxUSE_UNICODE 
 715 WXColormap 
wxApp::GetMainColormap(WXDisplay
* display
) 
 717     if (!display
) /* Must be called first with non-NULL display */ 
 718         return m_mainColormap
; 
 720     int defaultScreen 
= DefaultScreen((Display
*) display
); 
 721     Screen
* screen 
= XScreenOfDisplay((Display
*) display
, defaultScreen
); 
 723     Colormap c 
= DefaultColormapOfScreen(screen
); 
 726         m_mainColormap 
= (WXColormap
) c
; 
 728     return (WXColormap
) c
; 
 731 Window 
wxGetWindowParent(Window window
) 
 733     wxASSERT_MSG( window
, _T("invalid window") ); 
 738    // VMS chokes on unreacheable code 
 739    Window parent
, root 
= 0; 
 743     unsigned int noChildren 
= 0; 
 745     Window
* children 
= NULL
; 
 747     // #define XQueryTree(d,w,r,p,c,nc)     GrQueryTree(w,p,c,nc) 
 752         XQueryTree((Display
*) wxGetDisplay(), window
, & root
, & parent
, 
 753              & children
, & noChildren
); 
 767     wxAppConsole::Exit(); 
 770 // Yield to other processes 
 772 bool wxApp::Yield(bool onlyIfNeeded
) 
 774     // Sometimes only 2 yields seem 
 775     // to do the trick, e.g. in the 
 778     for (i 
= 0; i 
< 2; i
++) 
 780         if ( m_isInsideYield 
) 
 784                 wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 790         m_isInsideYield 
= true; 
 792         // Make sure we have an event loop object, 
 793         // or Pending/Dispatch will fail 
 794         wxEventLoopGuarantor dummyLoopIfNeeded
; 
 796         // Call dispatch at least once so that sockets 
 798         wxTheApp
->Dispatch(); 
 800         while (wxTheApp 
&& wxTheApp
->Pending()) 
 801             wxTheApp
->Dispatch(); 
 804         wxGenericTimerImpl::NotifyTimers(); 
 808         m_isInsideYield 
= false; 
 816 void wxApp::OnAssert(const wxChar 
*file
, int line
, const wxChar
* cond
, const wxChar 
*msg
) 
 818     // While the GUI isn't working that well, just print out the 
 821     wxAppBase::OnAssert(file
, line
, cond
, msg
); 
 824     msg2
.Printf("At file %s:%d: %s", file
, line
, msg
); 
 829 #endif // __WXDEBUG__