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
This commit is contained in:
Julian Smart
2002-03-09 21:51:10 +00:00
parent 39578f9cfc
commit c978d36124
7 changed files with 522 additions and 1 deletions

View 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

71
include/wx/x11/reparent.h Normal file
View File

@@ -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_

View File

@@ -403,7 +403,7 @@ bool wxApp::Initialized()
int wxApp::MainLoop()
{
int rt;
int rt;
m_mainLoop = new wxEventLoop;
rt = m_mainLoop->Run();

View File

@@ -1410,6 +1410,7 @@ int GrGetPixelColor(GR_SCREEN_INFO* sinfo, GR_PALETTE* palette, GR_PIXELVAL pixe
return 1;
}
#endif
#endif
// wxUSE_NANOX

View 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,

View 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 \

322
src/x11/reparent.cpp Normal file
View File

@@ -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;
}