1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/x11/toplevel.cpp 
   3 // Purpose:     implements wxTopLevelWindow for X11 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) 2002 Julian Smart 
   9 // License:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #include "wx/toplevel.h" 
  31     #include "wx/string.h" 
  36     #include "wx/statusbr.h" 
  37     #include "wx/settings.h" 
  40 #include "wx/x11/private.h" 
  41 #include "X11/Xutil.h" 
  43 #include "wx/unix/utilsx11.h" 
  45 bool wxMWMIsRunning(Window w
); 
  47 // ---------------------------------------------------------------------------- 
  48 // wxTopLevelWindowX11 creation 
  49 // ---------------------------------------------------------------------------- 
  51 void wxTopLevelWindowX11::Init() 
  54     m_maximizeOnShow 
= false; 
  56     // unlike (almost?) all other windows, frames are created hidden 
  59     // Data to save/restore when calling ShowFullScreen 
  61     m_fsIsMaximized 
= false; 
  62     m_fsIsShowing 
= false; 
  64     m_needResizeInIdle 
= false; 
  72 bool wxTopLevelWindowX11::Create(wxWindow 
*parent
, 
  74                                  const wxString
& title
, 
  83     m_windowStyle 
= style
; 
  88     m_windowId 
= id 
== wxID_ANY 
? NewControlId() : id
; 
  91         parent
->AddChild(this); 
  93     wxTopLevelWindows
.Append(this); 
  95     Display 
*xdisplay 
= wxGlobalDisplay(); 
  96     int xscreen 
= DefaultScreen( xdisplay 
); 
  97     Visual 
*xvisual 
= DefaultVisual( xdisplay
, xscreen 
); 
  98     Window xparent 
= RootWindow( xdisplay
, xscreen 
); 
  99     Colormap cm 
= DefaultColormap( xdisplay
, xscreen 
); 
 101     if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
) 
 102         m_backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
); 
 104         m_backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
); 
 105     m_backgroundColour
.CalcPixel( (WXColormap
) cm 
); 
 125     XSetWindowAttributes xattributes
; 
 127     long xattributes_mask 
= 
 128         CWBorderPixel 
| CWBackPixel
; 
 130     xattributes
.background_pixel 
= m_backgroundColour
.GetPixel(); 
 131     xattributes
.border_pixel 
= BlackPixel( xdisplay
, xscreen 
); 
 133     if (HasFlag( wxNO_BORDER 
)) 
 135         xattributes_mask 
|= CWOverrideRedirect
; 
 136         xattributes
.override_redirect 
= True
; 
 139     if (!HasFlag( wxFULL_REPAINT_ON_RESIZE 
)) 
 141         xattributes_mask 
|= CWBitGravity
; 
 142         xattributes
.bit_gravity 
= NorthWestGravity
; 
 145     xattributes_mask 
|= CWEventMask
; 
 146     xattributes
.event_mask 
= 
 147         ExposureMask 
| KeyPressMask 
| KeyReleaseMask 
| ButtonPressMask 
| ButtonReleaseMask 
| 
 148         ButtonMotionMask 
| EnterWindowMask 
| LeaveWindowMask 
| PointerMotionMask 
| 
 149         KeymapStateMask 
| FocusChangeMask 
| ColormapChangeMask 
| StructureNotifyMask 
| 
 152     Window xwindow 
= XCreateWindow( xdisplay
, xparent
, m_x
, m_y
, m_width
, m_height
, 
 153                                     0, DefaultDepth(xdisplay
,xscreen
), InputOutput
, xvisual
, xattributes_mask
, &xattributes 
); 
 155     long backColor
, foreColor
; 
 156     backColor 
= GR_RGB(m_backgroundColour
.Red(), m_backgroundColour
.Green(), m_backgroundColour
.Blue()); 
 157     foreColor 
= GR_RGB(m_foregroundColour
.Red(), m_foregroundColour
.Green(), m_foregroundColour
.Blue()); 
 159     Window xwindow 
= XCreateWindowWithColor( xdisplay
, xparent
, m_x
, m_y
, m_width
, m_height
, 
 160                                     0, 0, InputOutput
, xvisual
, backColor
, foreColor
); 
 163     m_mainWindow 
= (WXWindow
) xwindow
; 
 164     m_clientWindow 
= (WXWindow
) xwindow
; 
 165     wxAddWindowToTable( xwindow
, (wxWindow
*) this ); 
 168     XSelectInput( xdisplay
, xwindow
, 
 169                   GR_EVENT_MASK_CLOSE_REQ 
| 
 182                   StructureNotifyMask 
| 
 187     // Set background to None which will prevent X11 from clearing the 
 188     // background completely. 
 189     XSetWindowBackgroundPixmap( xdisplay
, xwindow
, None 
); 
 192     if (HasFlag( wxSTAY_ON_TOP 
)) 
 194         Window xroot 
= RootWindow( xdisplay
, xscreen 
); 
 195         XSetTransientForHint( xdisplay
, xwindow
, xroot 
); 
 199        if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
) 
 201             if (GetParent() && GetParent()->GetMainWindow()) 
 203                 Window xparentwindow 
= (Window
) GetParent()->GetMainWindow(); 
 204                 XSetTransientForHint( xdisplay
, xwindow
, xparentwindow 
); 
 209     XSizeHints size_hints
; 
 210     size_hints
.flags 
= PSize 
| PPosition 
| PWinGravity
; 
 213     size_hints
.width 
= m_width
; 
 214     size_hints
.height 
= m_height
; 
 215     size_hints
.win_gravity 
= NorthWestGravity
; 
 216     XSetWMNormalHints( xdisplay
, xwindow
, &size_hints
); 
 219     wm_hints
.flags 
= InputHint 
| StateHint
; 
 222         wm_hints
.flags 
|= WindowGroupHint
; 
 223         wm_hints
.window_group 
= (Window
) GetParent()->GetMainWindow(); 
 225     wm_hints
.input 
= True
; 
 226     wm_hints
.initial_state 
= NormalState
; 
 227     XSetWMHints( xdisplay
, xwindow
, &wm_hints
); 
 229     Atom wm_protocols
[2]; 
 230     wm_protocols
[0] = XInternAtom( xdisplay
, "WM_DELETE_WINDOW", False 
); 
 231     wm_protocols
[1] = XInternAtom( xdisplay
, "WM_TAKE_FOCUS", False 
); 
 232     XSetWMProtocols( xdisplay
, xwindow
, wm_protocols
, 2); 
 236     wxSetWMDecorations( xwindow
, style
); 
 243 wxTopLevelWindowX11::~wxTopLevelWindowX11() 
 245     wxTopLevelWindows
.DeleteObject(this); 
 247     // If this is the last top-level window, exit. 
 248     if ( wxTheApp 
&& (wxTopLevelWindows
.GetCount() == 0) ) 
 250         wxTheApp
->SetTopWindow(NULL
); 
 252         if (wxTheApp
->GetExitOnFrameDelete()) 
 254             // Signal to the app that we're going to close 
 255             wxTheApp
->ExitMainLoop(); 
 260 void wxTopLevelWindowX11::OnInternalIdle() 
 262     wxWindow::OnInternalIdle(); 
 264     // Do this only after the last idle event so that 
 265     // all windows have been updated before a new 
 266     // round of size events is sent 
 267     if (m_needResizeInIdle 
&& !wxTheApp
->Pending()) 
 269         wxSizeEvent 
event( GetClientSize(), GetId() ); 
 270         event
.SetEventObject( this ); 
 271         HandleWindowEvent( event 
); 
 273         m_needResizeInIdle 
= false; 
 277 // ---------------------------------------------------------------------------- 
 278 // wxTopLevelWindowX11 showing 
 279 // ---------------------------------------------------------------------------- 
 281 bool wxTopLevelWindowX11::Show(bool show
) 
 285         wxSizeEvent 
event(GetSize(), GetId()); 
 287         event
.SetEventObject(this); 
 288         HandleWindowEvent(event
); 
 290         m_needResizeInIdle 
= false; 
 293     bool ret 
= wxWindowX11::Show(show
); 
 298 // ---------------------------------------------------------------------------- 
 299 // wxTopLevelWindowX11 maximize/minimize 
 300 // ---------------------------------------------------------------------------- 
 302 void wxTopLevelWindowX11::Maximize(bool WXUNUSED(maximize
)) 
 307 bool wxTopLevelWindowX11::IsMaximized() const 
 313 void wxTopLevelWindowX11::Iconize(bool iconize
) 
 321     if (!m_iconized 
&& GetMainWindow()) 
 323         if (XIconifyWindow(wxGlobalDisplay(), 
 324             (Window
) GetMainWindow(), DefaultScreen(wxGlobalDisplay())) != 0) 
 329 bool wxTopLevelWindowX11::IsIconized() const 
 334 void wxTopLevelWindowX11::Restore() 
 336     // This is the way to deiconify the window, according to the X FAQ 
 337     if (m_iconized 
&& GetMainWindow()) 
 339         XMapWindow(wxGlobalDisplay(), (Window
) GetMainWindow()); 
 344 // ---------------------------------------------------------------------------- 
 345 // wxTopLevelWindowX11 fullscreen 
 346 // ---------------------------------------------------------------------------- 
 348 bool wxTopLevelWindowX11::ShowFullScreen(bool show
, long style
) 
 355         m_fsIsShowing 
= true; 
 367         m_fsIsShowing 
= false; 
 374 // ---------------------------------------------------------------------------- 
 375 // wxTopLevelWindowX11 misc 
 376 // ---------------------------------------------------------------------------- 
 378 void wxTopLevelWindowX11::DoSetIcon(const wxIcon
& icon
) 
 380     if (icon
.Ok() && GetMainWindow()) 
 383         XWMHints 
*wmHints 
= XAllocWMHints(); 
 384         wmHints
->icon_pixmap 
= (Pixmap
) icon
.GetPixmap(); 
 386         wmHints
->flags 
= IconPixmapHint
; 
 390             wmHints
->flags 
|= IconMaskHint
; 
 391             wmHints
->icon_mask 
= (Pixmap
) icon
.GetMask()->GetBitmap(); 
 394         XSetWMHints(wxGlobalDisplay(), (Window
) GetMainWindow(), wmHints
); 
 400 void wxTopLevelWindowX11::SetIcons(const wxIconBundle
& icons 
) 
 403     wxTopLevelWindowBase::SetIcons( icons 
); 
 405     DoSetIcon( icons
.GetIcon( -1 ) ); 
 406     wxSetIconsX11( wxGlobalDisplay(), GetMainWindow(), icons 
); 
 409 bool wxTopLevelWindowX11::SetShape(const wxRegion
& region
) 
 411     return wxDoSetShape( wxGlobalDisplay(), 
 412                          (Window
)GetMainWindow(), 
 416 void wxTopLevelWindowX11::SetTitle(const wxString
& title
) 
 423         //  I wonder of e.g. Metacity takes UTF-8 here 
 424         XStoreName(wxGlobalDisplay(), (Window
) GetMainWindow(), 
 425             (const char*) title
.ToAscii() ); 
 426         XSetIconName(wxGlobalDisplay(), (Window
) GetMainWindow(), 
 427             (const char*) title
.ToAscii() ); 
 429         XStoreName(wxGlobalDisplay(), (Window
) GetMainWindow(), 
 430             (const char*) title
); 
 431         XSetIconName(wxGlobalDisplay(), (Window
) GetMainWindow(), 
 432             (const char*) title
); 
 437 wxString 
wxTopLevelWindowX11::GetTitle() const 
 442 // For implementation purposes - sometimes decorations make the client area 
 444 wxPoint 
wxTopLevelWindowX11::GetClientAreaOrigin() const 
 446     // wxFrame::GetClientAreaOrigin 
 447     // does the required calculation already. 
 448     return wxPoint(0, 0); 
 451 void wxTopLevelWindowX11::DoGetClientSize( int *width
, int *height 
) const 
 459 void wxTopLevelWindowX11::DoGetSize( int *width
, int *height 
) const 
 461     // TODO add non-client size 
 469 void wxTopLevelWindowX11::DoSetClientSize(int width
, int height
) 
 471     int old_width 
= m_width
; 
 472     int old_height 
= m_height
; 
 477     if (m_width 
== old_width 
&& m_height 
== old_height
) 
 480     // wxLogDebug("DoSetClientSize: %s (%ld) %dx%d", GetClassInfo()->GetClassName(), GetId(), width, height); 
 483     XSizeHints size_hints
; 
 484     size_hints
.flags 
= PSize
; 
 485     size_hints
.width 
= width
; 
 486     size_hints
.height 
= height
; 
 487     XSetWMNormalHints( wxGlobalDisplay(), (Window
) GetMainWindow(), &size_hints 
); 
 490     wxWindowX11::DoSetClientSize(width
, height
); 
 493 void wxTopLevelWindowX11::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
 497     int old_width 
= m_width
; 
 498     int old_height 
= m_height
; 
 500     if (x 
!= wxDefaultCoord 
|| (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 503     if (y 
!= wxDefaultCoord 
|| (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 506     if (width 
!= wxDefaultCoord 
|| (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 509     if (height 
!= wxDefaultCoord 
|| (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 512     if (m_x 
== old_x 
&& m_y 
== old_y 
&& m_width 
== old_width 
&& m_height 
== old_height
) 
 515     // wxLogDebug("DoSetSize: %s (%ld) %d, %d %dx%d", GetClassInfo()->GetClassName(), GetId(), x, y, width, height); 
 518     XSizeHints size_hints
; 
 519     size_hints
.flags 
= 0; 
 520     size_hints
.flags 
|= PPosition
; 
 521     size_hints
.flags 
|= PSize
; 
 524     size_hints
.width 
= m_width
; 
 525     size_hints
.height 
= m_height
; 
 526     XSetWMNormalHints( wxGlobalDisplay(), (Window
) GetMainWindow(), &size_hints
); 
 529     wxWindowX11::DoSetSize(x
, y
, width
, height
, sizeFlags
); 
 532     Display 
*display 
= wxGlobalDisplay(); 
 533     Window root 
= RootWindowOfScreen(DefaultScreenOfDisplay(display
)); 
 534     Window parent_window 
= window
, 
 535         next_parent   
= window
; 
 537     // search for the parent that is child of ROOT, because the WM may 
 538     // reparent twice and notify only the next parent (like FVWM) 
 539     while (next_parent 
!= root
) { 
 546         parent_window 
= next_parent
; 
 547         XQueryTree(display
, parent_window
, &root
, 
 548             &next_parent
, &theChildren
, &n
); 
 549         XFree(theChildren
); // not needed 
 552     XWindowChanges windowChanges
; 
 555     windowChanges
.width 
= width
; 
 556     windowChanges
.height 
= height
; 
 557     windowChanges
.stack_mode 
= 0; 
 558     int valueMask 
= CWX 
| CWY 
| CWWidth 
| CWHeight
; 
 560     if (x 
!= wxDefaultCoord 
|| (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 564     if (y 
!= wxDefaultCoord 
|| (sizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 568     if (width 
!= wxDefaultCoord
) 
 570         windowChanges
.width 
= wxMax(1, width
); 
 571         valueMask 
|= CWWidth
; 
 573     if (height 
!= wxDefaultCoord
) 
 575         windowChanges
.height 
= wxMax(1, height
); 
 576         valueMask 
|= CWHeight
; 
 579     XConfigureWindow( display
, parent_window
, valueMask
, &windowChanges 
); 
 583 void wxTopLevelWindowX11::DoGetPosition(int *x
, int *y
) const 
 585     XSync(wxGlobalDisplay(), False
); 
 586     Window window 
= (Window
) m_mainWindow
; 
 590     Display 
*display 
= wxGlobalDisplay(); 
 591     Window root 
= RootWindowOfScreen(DefaultScreenOfDisplay(display
)); 
 592     Window parent_window 
= window
, 
 593         next_parent   
= window
; 
 595     // search for the parent that is child of ROOT, because the WM may 
 596     // reparent twice and notify only the next parent (like FVWM) 
 597     while (next_parent 
!= root
) { 
 604         parent_window 
= next_parent
; 
 605         XQueryTree(display
, parent_window
, &root
, 
 606             &next_parent
, &theChildren
, &n
); 
 607         XFree(theChildren
); // not needed 
 610     int xx
, yy
; unsigned int dummy
; 
 611     XGetGeometry(display
, parent_window
, &root
, 
 612                  &xx
, &yy
, &dummy
, &dummy
, &dummy
, &dummy
); 
 616     XWindowAttributes attr
; 
 617     Status status 
= XGetWindowAttributes( wxGlobalDisplay(), parent_window
, & attr
); 
 632 #ifndef MWM_DECOR_BORDER 
 634 #define MWM_HINTS_FUNCTIONS     (1L << 0) 
 635 #define MWM_HINTS_DECORATIONS   (1L << 1) 
 636 #define MWM_HINTS_INPUT_MODE    (1L << 2) 
 637 #define MWM_HINTS_STATUS        (1L << 3) 
 639 #define MWM_DECOR_ALL           (1L << 0) 
 640 #define MWM_DECOR_BORDER        (1L << 1) 
 641 #define MWM_DECOR_RESIZEH       (1L << 2) 
 642 #define MWM_DECOR_TITLE         (1L << 3) 
 643 #define MWM_DECOR_MENU          (1L << 4) 
 644 #define MWM_DECOR_MINIMIZE      (1L << 5) 
 645 #define MWM_DECOR_MAXIMIZE      (1L << 6) 
 647 #define MWM_FUNC_ALL            (1L << 0) 
 648 #define MWM_FUNC_RESIZE         (1L << 1) 
 649 #define MWM_FUNC_MOVE           (1L << 2) 
 650 #define MWM_FUNC_MINIMIZE       (1L << 3) 
 651 #define MWM_FUNC_MAXIMIZE       (1L << 4) 
 652 #define MWM_FUNC_CLOSE          (1L << 5) 
 654 #define MWM_INPUT_MODELESS 0 
 655 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 
 656 #define MWM_INPUT_SYSTEM_MODAL 2 
 657 #define MWM_INPUT_FULL_APPLICATION_MODAL 3 
 658 #define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL 
 660 #define MWM_TEAROFF_WINDOW (1L<<0) 
 671 #define PROP_MOTIF_WM_HINTS_ELEMENTS 5 
 673 // Set the window manager decorations according to the 
 674 // given wxWidgets style 
 675 bool wxSetWMDecorations(Window w
, long style
) 
 678     GR_WM_PROPERTIES wmProp
; 
 683     if (style 
& wxRESIZE_BORDER
) 
 685         wmProp
.props 
|= GR_WM_PROPS_APPFRAME 
; 
 686         wmProp
.flags 
|= GR_WM_FLAGS_PROPS 
; 
 689     if (style 
& wxCLOSE_BOX
) 
 691         wmProp
.props 
|= GR_WM_PROPS_CLOSEBOX 
; 
 692         wmProp
.flags 
|= GR_WM_FLAGS_PROPS 
; 
 695     if ((style 
& wxCAPTION
) || 
 696         (style 
& wxTINY_CAPTION_HORIZ
) || 
 697         (style 
& wxTINY_CAPTION_VERT
)) 
 699         wmProp
.props 
|= GR_WM_PROPS_CAPTION 
; 
 700         wmProp
.flags 
|= GR_WM_FLAGS_PROPS 
; 
 702         // The default dialog style doesn't include any kind 
 703         // of border, which is a bit odd. Anyway, inclusion 
 704         // of a caption surely implies a border. 
 705         style 
|= wxRESIZE_BORDER
; 
 708     if (style 
& wxRESIZE_BORDER
) 
 710         wmProp
.props 
|= GR_WM_PROPS_APPFRAME 
; 
 711         wmProp
.flags 
|= GR_WM_FLAGS_PROPS 
; 
 714     if (style 
& wxSIMPLE_BORDER
) 
 716         wmProp
.props 
|= GR_WM_PROPS_BORDER 
; 
 717         wmProp
.flags 
|= GR_WM_FLAGS_PROPS 
; 
 720     if (style 
& wxMINIMIZE_BOX
) 
 724     if (style 
& wxMAXIMIZE_BOX
) 
 726         wmProp
.props 
|= GR_WM_PROPS_MAXIMIZE 
; 
 727         wmProp
.flags 
|= GR_WM_FLAGS_PROPS 
; 
 730     if (((style 
& wxBORDER
) != wxBORDER
) && ((style 
& wxRESIZE_BORDER
) != wxRESIZE_BORDER
) 
 731         && ((style 
& wxRESIZE_BORDER
) != wxRESIZE_BORDER
)) 
 733         wmProp
.props 
|= GR_WM_PROPS_NODECORATE 
; 
 734         wmProp
.flags 
|= GR_WM_FLAGS_PROPS 
; 
 737     GrSetWMProperties(w
, & wmProp
); 
 741     Atom mwm_wm_hints 
= XInternAtom(wxGlobalDisplay(),"_MOTIF_WM_HINTS", False
); 
 742     if (mwm_wm_hints 
== 0) 
 746     hints
.flags 
= MWM_HINTS_DECORATIONS 
| MWM_HINTS_FUNCTIONS
; 
 747     hints
.decorations 
= 0; 
 750     if ((style 
& wxSIMPLE_BORDER
) || (style 
& wxNO_BORDER
)) 
 756         hints
.decorations 
= MWM_DECOR_BORDER
; 
 757         hints
.functions 
= MWM_FUNC_MOVE
; 
 759         if ((style 
& wxCAPTION
) != 0) 
 760             hints
.decorations 
|= MWM_DECOR_TITLE
; 
 762         if ((style 
& wxSYSTEM_MENU
) != 0) 
 763             hints
.decorations 
|= MWM_DECOR_MENU
; 
 765         if ((style 
& wxCLOSE_BOX
) != 0) 
 766             hints
.functions 
|= MWM_FUNC_CLOSE
; 
 768         if ((style 
& wxMINIMIZE_BOX
) != 0) 
 770             hints
.functions 
|= MWM_FUNC_MINIMIZE
; 
 771             hints
.decorations 
|= MWM_DECOR_MINIMIZE
; 
 774         if ((style 
& wxMAXIMIZE_BOX
) != 0) 
 776             hints
.functions 
|= MWM_FUNC_MAXIMIZE
; 
 777             hints
.decorations 
|= MWM_DECOR_MAXIMIZE
; 
 780         if ((style 
& wxRESIZE_BORDER
) != 0) 
 782             hints
.functions 
|= MWM_FUNC_RESIZE
; 
 783             hints
.decorations 
|= MWM_DECOR_RESIZEH
; 
 787     XChangeProperty(wxGlobalDisplay(), 
 789                     mwm_wm_hints
, mwm_wm_hints
, 
 791                     (unsigned char *) &hints
, PROP_MOTIF_WM_HINTS_ELEMENTS
);