From c978d36124197b5612a2cabefed7591ad0eea6e2 Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Sat, 9 Mar 2002 21:51:10 +0000 Subject: [PATCH] Added reparenting helper classes to help apps to grab the windows 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 | 2 + include/wx/x11/reparent.h | 71 ++++++++ src/x11/app.cpp | 2 +- src/x11/bitmap.cpp | 1 + src/x11/dcclient.cpp | 122 +++++++++++++ src/x11/files.lst | 3 + src/x11/reparent.cpp | 322 +++++++++++++++++++++++++++++++++ 7 files changed, 522 insertions(+), 1 deletion(-) create mode 100644 include/wx/x11/reparent.h create mode 100644 src/x11/reparent.cpp diff --git a/distrib/msw/tmake/filelist.txt b/distrib/msw/tmake/filelist.txt index cc00e84a98..d880f8316b 100644 --- a/distrib/msw/tmake/filelist.txt +++ b/distrib/msw/tmake/filelist.txt @@ -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 index 0000000000..8170084a19 --- /dev/null +++ b/include/wx/x11/reparent.h @@ -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_ diff --git a/src/x11/app.cpp b/src/x11/app.cpp index 8f64f5a3ac..34416b4f9b 100644 --- a/src/x11/app.cpp +++ b/src/x11/app.cpp @@ -403,7 +403,7 @@ bool wxApp::Initialized() int wxApp::MainLoop() { - int rt; + int rt; m_mainLoop = new wxEventLoop; rt = m_mainLoop->Run(); diff --git a/src/x11/bitmap.cpp b/src/x11/bitmap.cpp index 07dad230d6..214d4554f7 100644 --- a/src/x11/bitmap.cpp +++ b/src/x11/bitmap.cpp @@ -1410,6 +1410,7 @@ int GrGetPixelColor(GR_SCREEN_INFO* sinfo, GR_PALETTE* palette, GR_PIXELVAL pixe return 1; } #endif + #endif // wxUSE_NANOX diff --git a/src/x11/dcclient.cpp b/src/x11/dcclient.cpp index aee60a0bfc..04c54e565e 100644 --- a/src/x11/dcclient.cpp +++ b/src/x11/dcclient.cpp @@ -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, diff --git a/src/x11/files.lst b/src/x11/files.lst index 691edda06e..528caf7182 100644 --- a/src/x11/files.lst +++ b/src/x11/files.lst @@ -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 index 0000000000..349aea15e8 --- /dev/null +++ b/src/x11/reparent.cpp @@ -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; eachGetXDisplay(), + 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; +} + -- 2.45.2