Add basic support for XEMBED.

This commit is contained in:
Jonathan Moore Liles 2013-03-23 15:10:58 -07:00
parent 1a548d8e0e
commit ef299488fc
5 changed files with 437 additions and 3 deletions

50
FL/Fl_Socket_Window.H Normal file
View File

@ -0,0 +1,50 @@
/*******************************************************************************/
/* Copyright (C) 2013 Jonathan Moore Liles */
/* */
/* This program is free software; you can redistribute it and/or modify it */
/* under the terms of the GNU Library General Public License as published */
/* by the Free Software Foundation; either version 2 of the License, or (at */
/* your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
/* more details. */
/* */
/* You should have received a copy of the GNU General Public License along */
/* with This program; see the file COPYING. If not,write to the Free Software */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*******************************************************************************/
#ifndef FL_SOCKET_WINDOW_H
#define FL_SOCKET_WINDOW_H
#include <FL/Fl_Window.H>
#include <FL/x.H>
class Fl_Socket_Window : public Fl_Window
{
static const char * class_name ( void ) { return "Fl_Socket_Window"; }
Window _plug_xid;
public:
Fl_Socket_Window ( int X, int Y, int W, int H, const char *L=0 ) : Fl_Window(X,Y,W,H,L)
{
user_data( (void*)class_name() );
}
~Fl_Socket_Window ( )
{
}
static bool is_socket ( Fl_Window *w ) { return class_name() == w->user_data(); }
virtual Window plug_xid ( void ) const { return _plug_xid; }
virtual void plug_xid ( Window w ) { _plug_xid = w; }
};
#endif

3
FL/x.H
View File

@ -185,6 +185,7 @@ public:
extern FL_EXPORT char fl_override_redirect; // hack into Fl_X::make_xid()
extern FL_EXPORT int fl_background_pixel; // hack into Fl_X::make_xid()
extern FL_EXPORT Window fl_parent_window; // hack into Fl_X::make_xid()
inline Window fl_xid(const Fl_Window* w) { Fl_X *temp = Fl_X::i(w); return temp ? temp->xid : 0; }
@ -196,7 +197,7 @@ extern Window fl_xid_(const Fl_Window* w);
#endif // FL_LIBRARY || FL_INTERNALS
FL_EXPORT Fl_Window* fl_find(Window xid);
FL_EXPORT void fl_embed ( Fl_Window *w, Window parent );
// Dummy function to register a function for opening files via the window manager...
inline void fl_open_callback(void (*)(const char *)) {}

View File

@ -52,6 +52,7 @@
# include <X11/Xlocale.h>
# include <X11/Xlib.h>
# include <X11/keysym.h>
#include <FL/Fl_Socket_Window.H>
#include <FL/themes.H>
@ -111,6 +112,31 @@ struct FD {
static FD *fd = 0;
/* XEMBED messages */
#define XEMBED_EMBEDDED_NOTIFY 0
#define XEMBED_WINDOW_ACTIVATE 1
#define XEMBED_WINDOW_DEACTIVATE 2
#define XEMBED_REQUEST_FOCUS 3
#define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_OUT 5
#define XEMBED_FOCUS_NEXT 6
#define XEMBED_FOCUS_PREV 7
/* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */
#define XEMBED_MODALITY_ON 10
#define XEMBED_MODALITY_OFF 11
#define XEMBED_REGISTER_ACCELERATOR 12
#define XEMBED_UNREGISTER_ACCELERATOR 13
#define XEMBED_ACTIVATE_ACCELERATOR 14
/* Details for XEMBED_FOCUS_IN: */
#define XEMBED_FOCUS_CURRENT 0
#define XEMBED_FOCUS_FIRST 1
#define XEMBED_FOCUS_LAST 2
#define XEMBED_MAPPED (1<<0)
Window fl_parent_window = 0; /* hack into Fl_X::make_xid() */
void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) {
remove_fd(n,events);
int i = nfds++;
@ -343,6 +369,8 @@ Atom fl_XaUtf8String;
Atom fl_XaTextUriList;
Atom fl_NET_WM_NAME; // utf8 aware window label
Atom fl_NET_WM_ICON_NAME; // utf8 aware window icon name
Atom fl_XEMBED;
Atom fl_XEMBED_INFO;
/*
X defines 32-bit-entities to have a format value of max. 32,
@ -640,6 +668,8 @@ void fl_open_display(Display* d) {
fl_XaTextUriList = XInternAtom(d, "text/uri-list", 0);
fl_NET_WM_NAME = XInternAtom(d, "_NET_WM_NAME", 0);
fl_NET_WM_ICON_NAME = XInternAtom(d, "_NET_WM_ICON_NAME", 0);
fl_XEMBED = XInternAtom(d, "_XEMBED", 0);
fl_XEMBED_INFO = XInternAtom(d, "_XEMBED_INFO", 0);
if (sizeof(Atom) < 4)
atom_bits = sizeof(Atom) * 8;
@ -879,6 +909,242 @@ static int wasXExceptionRaised() {
}
void fl_embed ( Fl_Window *w, Window parent )
{
/* this destroys the existing window */
w->hide();
/* embedded windows don't need borders */
w->border(0);
fl_parent_window = parent;
Fl_X::make_xid( w, fl_visual, fl_colormap );
fl_parent_window = 0;
/* mark this window as wanting to be embedded */
unsigned long buffer[2];
buffer[0] = 1; /* protocol version */
buffer[1] = 0;
/* XEMBED_MAPPED; */
XChangeProperty (fl_display,
fl_xid( w ),
fl_XEMBED_INFO, fl_XEMBED_INFO, 32,
PropModeReplace,
(unsigned char *)buffer, 2);
XSync(fl_display, False );
}
static void
xembed_send_configure_event ( Fl_Socket_Window *w )
{
/* printf( "NTK: Sending synthetic configure event to embedded window\n" ); */
XConfigureEvent xc;
memset( &xc, 0, sizeof( xc ) );
xc.type = ConfigureNotify;
xc.event = w->plug_xid();
xc.window = w->plug_xid();
/* xc.x = w->x(); */
/* xc.y = w->y(); */
xc.x = 0;
xc.y = 0;
xc.width = w->w();
xc.height = w->h();
xc.border_width = 0;
xc.above = None;
xc.override_redirect = False;
XSendEvent( fl_display, w->plug_xid(), False, NoEventMask, (XEvent*)&xc );
}
static int
xembed_get_info ( Window window, unsigned long *version, unsigned long *flags )
{
int r;
Atom type;
int format;
unsigned long nitems, bytes_after;
unsigned char *data;
unsigned long *data_long;
r = XGetWindowProperty( fl_display, window, fl_XEMBED_INFO, 0, 2, False, fl_XEMBED_INFO, &type, &format, &nitems, &bytes_after, &data );
if ( r != Success || type != fl_XEMBED_INFO )
return 0;
if ( nitems < 2 )
{
XFree(data);
return 0;
}
data_long = (unsigned long*)data;
if ( version )
*version = data_long[0];
if ( flags )
*flags = data_long[1] & XEMBED_MAPPED;
XFree(data);
return 1;
}
static int
xembed_maybe_embed_window ( Window parent, Window window )
{
if ( parent != window )
{
Fl_Socket_Window *p = (Fl_Socket_Window*)fl_find( parent );
if ( p )
{
if ( Fl_Socket_Window::is_socket( p ) )
{
if ( p->plug_xid() )
{
// error, already embedded.
}
else
{
/* printf( "NTK: Got embed request... Replying with XEMBED_EMBEDDED_NOTIFY\n" ); */
fl_sendClientMessage(window, fl_XEMBED, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0, window, 0 );
fl_sendClientMessage(window, fl_XEMBED, CurrentTime, XEMBED_WINDOW_ACTIVATE );
p->plug_xid( window );
XMapWindow( fl_display, window );
xembed_send_configure_event( p );
return 1;
}
}
}
}
return 0;
}
static int fl_handle_xembed ( const XEvent &xevent )
{
switch (xevent.type) {
case DestroyNotify:
{
/* printf( "Got destroy notify\n" ); */
Fl_Socket_Window *p = (Fl_Socket_Window*)fl_find( xevent.xdestroywindow.event );
if ( p && Fl_Socket_Window::is_socket( p ) )
{
/* printf( "Ending embedding\n" ); */
p->plug_xid( 0 );
return 1;
}
return 0;
break;
}
case MapRequest:
{
/* printf( "Got map request\n" ); */
return xembed_maybe_embed_window( xevent.xmaprequest.parent, xevent.xmaprequest.window );
break;
}
case CreateNotify:
{
/* printf( "Got create notify\n" ); */
const XCreateWindowEvent *cw = &fl_xevent->xcreatewindow;
return xembed_maybe_embed_window( cw->parent, cw->window );
break;
}
case ReparentNotify:
/* printf( "Got reparent notify\n" ); */
return xembed_maybe_embed_window( xevent.xreparent.parent, xevent.xreparent.window );
break;
case ConfigureRequest:
{
/* printf( "Got configure request\n" ); */
XConfigureRequestEvent *xe = (XConfigureRequestEvent*)&fl_xevent->xconfigurerequest;
xembed_maybe_embed_window( xe->parent, xe->window );
printf( "Got configure request for %ix%i... Not gonna happen.\n", xe->width, xe->height );
Fl_Socket_Window *p = (Fl_Socket_Window*)fl_find( xe->parent );
if ( p && Fl_Socket_Window::is_socket( p ) )
{
xembed_send_configure_event( p );
return 1;
}
return 0;
break;
}
case PropertyNotify:
{
/* printf( "Got property notify.\n" ); */
if ( xevent.xproperty.atom == fl_XEMBED_INFO )
{
unsigned long version, flags;
xembed_get_info( xevent.xproperty.window, &version, &flags );
if ( (flags & XEMBED_MAPPED) )
{
XMapWindow( fl_display, xevent.xproperty.window );
}
return 1;
}
return 0;
break;
}
case ClientMessage: {
Fl_Window* window = fl_find(fl_xevent->xclient.window);
Atom message = fl_xevent->xclient.message_type;
const long* data = fl_xevent->xclient.data.l;
if ( message == fl_XEMBED )
{
switch ( data[1] )
{
case XEMBED_EMBEDDED_NOTIFY:
/* printf( "NTK: Got XEMBED_EMBEDDED_NOTIFY\n" ); */
window->resize( 0, 0, window->w(), window->h() );
break;
case XEMBED_WINDOW_ACTIVATE:
/* printf( "NTK: Got XEMBED_WINDOW_ACTIVATE\n" ); */
/* window->resize( 0, 0, window->w(), window->h() ); */
break;
case XEMBED_WINDOW_DEACTIVATE:
/* printf( "NTK: Got XEMBED_WINDOW_DEACTIVATE\n" ); */
break;
default:
/* unsupported message */
break;
}
return 1;
}
return 0;
break;
}
default:
return 0;
}
return 0;
}
int fl_handle(const XEvent& thisevent)
{
@ -945,7 +1211,10 @@ int fl_handle(const XEvent& thisevent)
if ( XFilterEvent((XEvent *)&xevent, 0) )
return(1);
if ( fl_handle_xembed( xevent ) )
return 1;
switch (xevent.type) {
case KeymapNotify:
@ -1667,7 +1936,12 @@ ExposureMask|StructureNotifyMask
|KeyPressMask|KeyReleaseMask|KeymapStateMask|FocusChangeMask
|ButtonPressMask|ButtonReleaseMask
|EnterWindowMask|LeaveWindowMask
|PointerMotionMask;
|PointerMotionMask;
static const int XEmbedEventMask = XEventMask |
SubstructureRedirectMask |
SubstructureNotifyMask |
PropertyChangeMask;
void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
{
@ -1723,9 +1997,16 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
ulong root = win->parent() ?
fl_xid(win->window()) : RootWindow(fl_display, fl_screen);
if ( fl_parent_window )
root = fl_parent_window;
XSetWindowAttributes attr;
int mask = CWBorderPixel|CWColormap|CWEventMask|CWBitGravity;
attr.event_mask = win->parent() ? childEventMask : XEventMask;
if ( Fl_Socket_Window::is_socket( win ) )
attr.event_mask = XEmbedEventMask;
attr.colormap = colormap;
attr.border_pixel = 0;
attr.bit_gravity = 0; // StaticGravity;

101
test/embed.cxx Normal file
View File

@ -0,0 +1,101 @@
/*******************************************************************************/
/* Copyright (C) 2013 Jonathan Moore Liles */
/* */
/* This program is free software; you can redistribute it and/or modify it */
/* under the terms of the GNU General Public License as published by the */
/* Free Software Foundation; either version 2 of the License, or (at your */
/* option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
/* more details. */
/* */
/* You should have received a copy of the GNU General Public License along */
/* with This program; see the file COPYING. If not,write to the Free Software */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*******************************************************************************/
#include <FL/x.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Socket_Window.H>
#include <stdlib.h>
int main ( int argc, char **argv )
{
Window into = 0;
int wait_for_client = 0;
if ( argc > 1 )
{
if ( !strcmp( argv[1], "--wait" ) )
wait_for_client = 1;
else
sscanf( argv[1], "%lx", &into );
}
fl_open_display();
Fl_Double_Window *plug = NULL;
if ( ! wait_for_client )
{
{ Fl_Double_Window *o = plug = new Fl_Double_Window( 300,300, "Plug");
o->color( FL_GRAY );
{
Fl_Box *o = new Fl_Box( 0, 0, 300, 300,
"You should see a gray box in the upper left hand corner on green field if embedding worked.");
o->align( FL_ALIGN_WRAP );
o->box(FL_UP_BOX);
Fl_Group::current()->resizable(o);
}
o->end();
/* NOTE: window to be embedded is never show()'n */
}
}
Fl_Socket_Window *socket = NULL;
if ( ! into )
{
{ Fl_Double_Window *o = new Fl_Double_Window( 500, 600, "Top-Level" );
{ Fl_Box *o = new Fl_Box( 0, 0, 500, 100, "This is the top-level window, the window for embedding should be nested below" );
o->align( FL_ALIGN_WRAP );
o->box( FL_BORDER_BOX );
}
{ Fl_Socket_Window *o = socket = new Fl_Socket_Window( 0, 100, 500,500, "Socket");
o->color(FL_GREEN);
o->end();
o->show();
}
o->end();
o->show();
}
}
if ( ! wait_for_client )
{
if ( ! into )
{
fl_embed( plug, fl_xid( socket ));
}
else
{
fl_embed( plug, into );
}
}
else
{
printf( "Waiting for client... win_id = 0x%lx %ld\n", fl_xid( socket ), fl_xid( socket ) );
}
Fl::run();
return 0;
}

View File

@ -24,6 +24,7 @@ def example(bld,*k,**kw):
def build(bld):
if bld.env.ENABLE_TEST:
bld.example(source='embed.cxx', target='embed')
bld.example(source='glpuzzle.cxx', target='glpuzzle', use=['ntk_gl_static'])
bld.example(source='fractals.cxx fracviewer.cxx', target='fractals', use=['ntk_gl_static'])
bld.example(source='gl_overlay.cxx', target='gl_overlay', use=['ntk_gl_static'])