]> git.saurik.com Git - wxWidgets.git/commitdiff
Added reparenting helper classes to help apps to grab the windows
authorJulian Smart <julian@anthemion.co.uk>
Sat, 9 Mar 2002 21:51:10 +0000 (21:51 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Sat, 9 Mar 2002 21:51:10 +0000 (21:51 +0000)
of other applications.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@14524 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

distrib/msw/tmake/filelist.txt
include/wx/x11/reparent.h [new file with mode: 0644]
src/x11/app.cpp
src/x11/bitmap.cpp
src/x11/dcclient.cpp
src/x11/files.lst
src/x11/reparent.cpp [new file with mode: 0644]

index cc00e84a984039aacf0d94e57d10a78ca3b53967..d880f8316b1fc4e28b3963d8fce760299b33c2c6 100644 (file)
@@ -631,6 +631,7 @@ palette.cpp X11
 pen.cpp        X11
 popupwin.cpp   X11
 region.cpp     X11
+reparent.cpp   X11
 settings.cpp   X11
 toplevel.cpp   X11
 utils.cpp      X11
@@ -1206,6 +1207,7 @@ pen.h     X11H
 print.h        X11H
 private.h      X11H
 region.h       X11H
+reparent.h     X11H
 settings.h     X11H
 toolbar.h      X11H
 toplevel.h     X11H
diff --git a/include/wx/x11/reparent.h b/include/wx/x11/reparent.h
new file mode 100644 (file)
index 0000000..8170084
--- /dev/null
@@ -0,0 +1,71 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        reparent.h
+// Purpose:     Reparenting classes
+// Author:      Julian Smart
+// Modified by:
+// Created:     2002-03-09
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_REPARENT_H_
+#define _WX_REPARENT_H_
+
+#ifdef __GNUG__
+#pragma interface "reparent.h"
+#endif
+
+#include "wx/window.h"
+
+/*
+ * This class helps to reparent a specific window
+ */
+
+class wxAdoptedWindow;
+class wxReparenter: public wxObject
+{
+public:
+    wxReparenter() {}
+
+    // We assume that toReparent has had its X window set
+    // appropriately. toReparent is typically a wxAdoptedWindow.
+    bool Reparent(wxWindow* newParent, wxAdoptedWindow* toReparent);
+
+    // Wait for an appropriate window to be created.
+    // If exactMatch is FALSE, a substring match is OK.
+    // If windowName is empty, then wait for the next overrideRedirect window.
+    bool WaitAndReparent(wxWindow* newParent, wxAdoptedWindow* toReparent,
+                         const wxString& windowName = wxEmptyString,
+                         bool exactMatch = TRUE);
+
+protected:
+
+    bool ProcessXEvent(WXEvent* event);
+    WXWindow FindAClientWindow(WXWindow window, const wxString& name);
+    
+    static bool sm_done;
+    static wxAdoptedWindow* sm_toReparent;
+    static wxWindow* sm_newParent;
+    static wxString  sm_name;
+    static bool      sm_exactMatch;
+};
+
+/*
+ * A window that adopts its handle from the native
+ * toolkit. It has no parent until reparented.
+ */
+
+class wxAdoptedWindow: public wxWindow
+{
+  public:
+    wxAdoptedWindow();
+    wxAdoptedWindow(WXWindow window);
+    ~wxAdoptedWindow();
+
+    void SetHandle(WXWindow window) { m_mainWidget = window; }
+    WXWindow GetHandle() const { return GetXWindow(); }
+};
+
+#endif
+// _WX_REPARENT_H_
index 8f64f5a3acd211d883a3b5152d6ad12d7384b7a6..34416b4f9b6f1861d9ab7339a3c3288af5da3774 100644 (file)
@@ -403,7 +403,7 @@ bool wxApp::Initialized()
 
 int wxApp::MainLoop()
 {
-     int rt;
+    int rt;
     m_mainLoop = new wxEventLoop;
 
     rt = m_mainLoop->Run();
index 07dad230d60b3752ab203af73f690fad8213193f..214d4554f7c20f5a31786a995ec1b8e07564ec12 100644 (file)
@@ -1410,6 +1410,7 @@ int GrGetPixelColor(GR_SCREEN_INFO* sinfo, GR_PALETTE* palette, GR_PIXELVAL pixe
     return 1;
 }
 #endif
+
 #endif
   // wxUSE_NANOX
 
index aee60a0bfc5c50342e0f850564b5c3c6cceb6629..04c54e565e5b9766d221c8e8339750515f8c51f6 100644 (file)
@@ -840,6 +840,126 @@ void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y)
 {
 }
 
+#if wxUSE_NANOX
+void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
+                               wxCoord x, wxCoord y,
+                               bool useMask )
+{
+    wxCHECK_RET( Ok(), wxT("invalid window dc") );
+
+    wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") );
+    
+    bool is_mono = (bitmap.GetBitmap() != NULL);
+
+    /* scale/translate size and position */
+    int xx = XLOG2DEV(x);
+    int yy = YLOG2DEV(y);
+
+    int w = bitmap.GetWidth();
+    int h = bitmap.GetHeight();
+
+    CalcBoundingBox( x, y );
+    CalcBoundingBox( x + w, y + h );
+
+    if (!m_window) return;
+
+    int ww = XLOG2DEVREL(w);
+    int hh = YLOG2DEVREL(h);
+
+    /* compare to current clipping region */
+    if (!m_currentClippingRegion.IsNull())
+    {
+        wxRegion tmp( xx,yy,ww,hh );
+        tmp.Intersect( m_currentClippingRegion );
+        if (tmp.IsEmpty())
+            return;
+    }
+
+    /* scale bitmap if required */
+    wxBitmap use_bitmap;
+    if ((w != ww) || (h != hh))
+    {
+        wxImage image( bitmap );
+        image.Rescale( ww, hh );
+#if 0
+        if (is_mono)
+            use_bitmap = image.ConvertToMonoBitmap(255,255,255);
+        else
+#endif
+            use_bitmap = image.ConvertToBitmap();
+    }
+    else
+    {
+        use_bitmap = bitmap;
+    }
+
+    /* apply mask if any */
+    WXPixmap mask = NULL;
+    if (use_bitmap.GetMask())
+        mask = use_bitmap.GetMask()->GetBitmap();
+
+    if (useMask && mask)
+    {
+        Pixmap pixmap = (Pixmap) use_bitmap.GetPixmap() ;
+        Pixmap maskPixmap = (Pixmap) use_bitmap.GetMask()->GetBitmap() ;
+        Pixmap bufPixmap = GrNewPixmap(w, h, 0);
+        GC gc = GrNewGC();
+        GrSetGCUseBackground(gc, FALSE);
+        GrSetGCMode(gc, GR_MODE_COPY);
+
+        // This code assumes that background and foreground
+        // colours are used in ROPs, like in MSW.
+        // Not sure if this is true.
+
+        // Copy destination to buffer.
+        // In DoBlit, we need this step because Blit has
+        // a ROP argument. Here, we don't need it.
+        // In DoBlit, we may be able to eliminate this step
+        // if we check if the rop = copy
+#if 0
+        GrCopyArea(bufPixmap, gc, 0, 0, w, h, (Window) m_window,
+                  0, 0, GR_MODE_COPY);
+#endif
+            
+        // Copy src to buffer using selected raster op (none selected
+        // in DrawBitmap, so just use Gxcopy)
+        GrCopyArea(bufPixmap, gc, 0, 0, w, h, pixmap,
+                   0, 0, GR_MODE_COPY);
+
+        // Set masked area in buffer to BLACK (pixel value 0)
+        GrSetGCBackground(gc, WHITE);
+        GrSetGCForeground(gc, BLACK);
+        GrCopyArea(bufPixmap, gc, 0, 0, w, h, maskPixmap,
+                    0, 0, GR_MODE_AND);
+                       
+        // set unmasked area in dest to BLACK
+        GrSetGCBackground(gc, BLACK);
+        GrSetGCForeground(gc, WHITE);
+        GrCopyArea((Window) m_window, gc, xx, yy, w, h, maskPixmap,
+                   0, 0, GR_MODE_AND);
+
+        // OR buffer to dest
+        GrCopyArea((Window) m_window, gc, xx, yy, w, h, bufPixmap,
+                   0, 0, GR_MODE_OR);
+
+        GrDestroyGC(gc);
+        GrDestroyWindow(bufPixmap);
+    }
+    else
+      XCopyArea( (Display*) m_display, (Pixmap) use_bitmap.GetPixmap(), (Window) m_window,
+            (GC) m_penGC, 0, 0, w, h, xx, yy );
+
+    /* remove mask again if any */
+    if (useMask && mask)
+    {
+        if (!m_currentClippingRegion.IsNull())
+                XSetRegion( (Display*) m_display, (GC) m_penGC, (Region) m_currentClippingRegion.GetX11Region() );
+    }
+}
+
+#else
+
+// Normal X11
 void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
                                wxCoord x, wxCoord y,
                                bool useMask )
@@ -970,6 +1090,8 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap,
         }
     }
 }
+#endif
+  // wxUSE_NANOX/!wxUSE_NANOX
 
 bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
                          wxDC *source, wxCoord xsrc, wxCoord ysrc, int rop, bool useMask,
index 691edda06e686e2a6926fe6bd560d51a2d109edb..528caf718215647ab1e798cfe27ff6584018eee3 100644 (file)
@@ -27,6 +27,7 @@ ALL_SOURCES = \
                x11/pen.cpp \
                x11/popupwin.cpp \
                x11/region.cpp \
+               x11/reparent.cpp \
                x11/settings.cpp \
                x11/toplevel.cpp \
                x11/utils.cpp \
@@ -492,6 +493,7 @@ ALL_HEADERS = \
                x11/print.h \
                x11/private.h \
                x11/region.h \
+               x11/reparent.h \
                x11/settings.h \
                x11/toolbar.h \
                x11/toplevel.h \
@@ -622,6 +624,7 @@ GUI_LOWLEVEL_OBJS = \
                pen.o \
                popupwin.o \
                region.o \
+               reparent.o \
                settings.o \
                toplevel.o \
                utils.o \
diff --git a/src/x11/reparent.cpp b/src/x11/reparent.cpp
new file mode 100644 (file)
index 0000000..349aea1
--- /dev/null
@@ -0,0 +1,322 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        reparent.cpp
+// Purpose:     wxWindow
+// Author:      Julian Smart
+// Modified by:
+// Created:     2002-03-09
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+    #pragma implementation "reparent.h"
+#endif
+
+#include "wx/x11/reparent.h"
+#include "wx/evtloop.h"
+#include "wx/log.h"
+#include "wx/app.h"
+#include "wx/timer.h"
+
+#include "wx/x11/private.h"
+#include "X11/Xatom.h"
+
+/*
+
+  Adapted from code by Mike Yang, as follows.
+
+From: Mike Yang (mikey@eukanuba.wpd.sgi.com)
+Subject: Re: Wrapping new widget around existing windows 
+Newsgroups: comp.windows.x
+View: Complete Thread (17 articles) | Original Format 
+Date: 1991-08-09 09:45:48 PST 
+
+Enough people asked, so here's my test program which reparents another
+window.  It's a single file (reparent.c), and will work with Motif or
+Xaw.  Xaw users should comment out the "#define MOTIF" line.
+
+The reparent program first prompts for the application name of the
+client that it will reparent.  If you're going to start the
+application override_redirect (e.g. -xrm "*overrideRedirect: true"),
+then this name is ignored and the first override_redirect window is
+assumed to be the one.
+
+Input focus is supposed to be correctly handled, as is resizing with
+window manager hints.  If you have input focus problems, try launching
+your application override_redirect instead.  This method is preferred
+anyway, since you can map it off-screen and then avoid the "window
+flash" effect as the application's top-level window is reparented.
+
+-----------------------------------------------------------------------
+                 Mike Yang        Silicon Graphics, Inc.
+               mikey@sgi.com           415/335-1786
+
+
+------------------------------- cut here ------------------------------
+*/
+
+/*
+
+Copyright 1991 by Mike Yang, mikey@sgi.com, Silicon Graphics, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of SGI not be used in advertising or
+publicity pertaining to distribution of the software without specific,
+written prior permission.  SGI makes no representations about the
+suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+*/
+
+/*
+ * wxAdoptedWindow
+ */
+
+wxAdoptedWindow::wxAdoptedWindow()
+{
+}
+
+wxAdoptedWindow::wxAdoptedWindow(WXWindow window)
+{
+    m_mainWidget = window;
+}
+
+wxAdoptedWindow::~wxAdoptedWindow()
+{
+}
+/*
+ * wxReparenter
+ */
+
+static bool Xerror;
+static Atom WM_STATE = 0;
+bool wxReparenter::sm_done = FALSE;
+wxAdoptedWindow* wxReparenter::sm_toReparent = NULL;
+wxWindow* wxReparenter::sm_newParent = NULL;
+wxString wxReparenter::sm_name;
+bool wxReparenter::sm_exactMatch = FALSE;
+
+static int
+ErrorHandler(Display* dpy, XErrorEvent* event)
+{
+  Xerror = True;
+  return False;
+}
+
+// We assume that toReparent has had its X window set
+// appropriately.
+bool wxReparenter::Reparent(wxWindow* newParent, wxAdoptedWindow* toReparent)
+{
+    XWindowAttributes xwa;
+    Window *children;
+    unsigned int numchildren, each;
+    Window returnroot, returnparent;
+    XErrorHandler old;
+    int parentOffset = 0;
+
+    old = XSetErrorHandler(ErrorHandler);
+    XReparentWindow((Display*) newParent->GetXDisplay(),
+                    (Window) toReparent->GetXWindow(),
+                    (Window) newParent->GetXWindow(),
+                    0, 0);
+
+    if (!XQueryTree((Display*) newParent->GetXDisplay(),
+                    (Window) toReparent->GetXWindow(),
+                    &returnroot, &returnparent,
+                    &children, &numchildren) || Xerror)
+    {
+        XSetErrorHandler(old);
+        return TRUE;
+    }
+
+    if (numchildren > 0)
+    {
+        fprintf(stderr, "Reparenting %d children.\n", numchildren);
+        /* Stacking order is preserved since XQueryTree returns its children in
+           bottommost to topmost order
+         */
+        for (each=0; each<numchildren; each++)
+        {
+            XGetWindowAttributes((Display*) newParent->GetXDisplay(),
+                                 children[each], &xwa);
+            fprintf(stderr,
+              "Reparenting child at offset %d and position %d, %d.\n",
+               parentOffset, parentOffset+xwa.x, parentOffset+xwa.y);
+            XReparentWindow((Display*) newParent->GetXDisplay(),
+                            children[each], (Window) newParent->GetXWindow(),
+              xwa.x, xwa.y);
+        }
+    }
+
+    XSetErrorHandler(old);
+    return TRUE;
+}
+
+// Wait for an appropriate window to be created.
+// If exactMatch is FALSE, a substring match is OK.
+// If windowName is empty, then wait for the next overrideRedirect window.
+bool wxReparenter::WaitAndReparent(wxWindow* newParent, wxAdoptedWindow* toReparent,
+                                   const wxString& windowName,
+                                   bool exactMatch)
+{
+    sm_newParent = newParent;
+    sm_toReparent = toReparent;
+    sm_exactMatch = exactMatch;
+    sm_name = windowName;
+    
+    Display* display = (Display*) newParent->GetXDisplay() ;
+    XSelectInput(display,
+        RootWindowOfScreen(DefaultScreenOfDisplay(display)),
+        SubstructureNotifyMask);
+
+    if (!WM_STATE)
+        WM_STATE = XInternAtom(display, "WM_STATE", False);
+
+#ifdef __WXDEBUG__
+    if (!windowName.IsEmpty())
+        wxLogDebug(_T("Waiting for window %s"), windowName.c_str());
+#endif
+    
+    sm_done = FALSE;
+
+    wxEventLoop eventLoop;
+    while (!sm_done)
+    {
+        if (eventLoop.Pending())
+        {
+            XEvent xevent;
+            XNextEvent(display, & xevent);
+            if (!wxTheApp->ProcessXEvent((WXEvent*) & xevent))
+            {
+                // Do the local event processing
+                ProcessXEvent((WXEvent*) & xevent);
+            }
+        }
+        else
+        {
+#if wxUSE_TIMER
+            wxTimer::NotifyTimers();
+            wxTheApp->SendIdleEvents();
+#endif
+        }
+    }
+    return TRUE;
+}
+
+bool wxReparenter::ProcessXEvent(WXEvent* event)
+{
+    XEvent* xevent = (XEvent*) event;
+    Window client;
+
+    if (!sm_done)
+    {
+        if (xevent->type == MapNotify)
+        {
+            wxLogDebug(_T("Window was mapped"));
+        }
+        
+        if (xevent->type == MapNotify && !xevent->xmap.override_redirect &&
+            (client = (Window) FindAClientWindow((WXWindow) xevent->xmap.window, sm_name)))
+        {
+            wxLogDebug(_T("Found a client window, about to reparent"));
+            wxASSERT(sm_toReparent->GetParent() == NULL);
+            
+            sm_toReparent->SetHandle((WXWindow) client);
+            sm_newParent->AddChild(sm_toReparent);
+            sm_done = Reparent(sm_newParent, sm_toReparent);
+            return sm_done;
+        } else if (xevent->type == MapNotify &&
+                   xevent->xmap.override_redirect &&
+                   xevent->xmap.window)
+        {
+            wxLogDebug(_T("Found an override redirect window, about to reparent"));
+            sm_toReparent->SetHandle((WXWindow) xevent->xmap.window);
+            sm_newParent->AddChild(sm_toReparent);
+            wxASSERT(sm_toReparent->GetParent() == NULL);
+            
+            sm_done = Reparent(sm_newParent, sm_toReparent);
+            return sm_done;
+        }
+    }
+    return FALSE;
+}
+
+WXWindow wxReparenter::FindAClientWindow(WXWindow window, const wxString& name)
+{
+  int rvalue, i;
+  Atom actualtype;
+  int actualformat;
+  unsigned long nitems, bytesafter;
+  unsigned char *propreturn;
+  Window *children;
+  unsigned int numchildren;
+  Window returnroot, returnparent;
+  Window result = 0;
+  XErrorHandler old;
+  char *clientName;
+
+  Xerror = False;
+  old = XSetErrorHandler(ErrorHandler);
+  rvalue = XGetWindowProperty((Display*) wxGetDisplay(),
+                              (Window) window, WM_STATE,
+                              0, 1, False,
+                              AnyPropertyType, &actualtype, &actualformat,
+                              &nitems, &bytesafter, &propreturn);
+  XSetErrorHandler(old);
+  if (!Xerror && rvalue == Success && actualtype != None)
+  {
+      if (rvalue == Success)
+      {
+          XFree((char *) propreturn);
+      }
+      XFetchName((Display*) wxGetDisplay(), (Window) window, &clientName);
+
+      wxString str1(name);
+      wxString str2(clientName);
+      str1.Lower();
+      str2.Lower();
+
+      bool matches;
+      if (sm_exactMatch)
+          matches = (name == clientName);
+      else
+          matches = (str1.Contains(str2) || str2.Contains(str1));
+      
+      XFree(clientName);
+
+      if (matches)
+          return (WXWindow) window;
+      else
+          return NULL;
+  }
+
+  old = XSetErrorHandler(ErrorHandler);
+  if (!XQueryTree((Display*) wxGetDisplay(), (Window) window, &returnroot, &returnparent,
+    &children, &numchildren) || Xerror) {
+    XSetErrorHandler(old);
+    return NULL;
+  }
+  XSetErrorHandler(old);
+
+  result = 0;
+  for (i=0; i<(int)numchildren && !result ;i++) {
+    result = (Window) FindAClientWindow((WXWindow) children[i], name);
+  }
+  if (numchildren) {
+    XFree((char *) children);
+  } return (WXWindow) result;
+}
+