Problems Sending Input/Focus to Plug Window



Dear list members,

I'm trying to create an unmanaged Gtk window containing one or more embedded
windows (for example terminals). I'm having Problems focussing and sending input
to these embedded windows. I already tried to embed an xterm and a urxvt window.
At least the urxvt works correctly, if no other elements are in the window.
However putting a button into the window leads to the terminal loosing its focus
with no apparent way to let it regain it. It is however possible to send an
XEMBED_FOCUS_IN message to the urxvt window. Whe the urxvt recieves the message,
it will at least change the cursor correctly, but yet, no input is send to it.
Using an xterm doesn't work, even with normal toplevel windows. Can You help me
in solving this problem? Here is a gist containing a more or less minimal
example (I'm using the gtkmm C++ interface):
https://gist.github.com/anonymous/f179ff891f7c8029faf8
or clone it via:
git clone https://gist.github.com/f179ff891f7c8029faf8.git

  Benjamin

For reference, here is the code from the gist:

Makefile:
sockfoc: sockfoc.cc window_ext.h
  g++ -ggdb sockfoc.cc -o sockfoc `pkg-config gtkmm-3.0 --cflags --libs` -lX11

sockfoc.cc
#include <gtkmm.h>
#include <gtkmm/socket.h>

#include "window_ext.h"

#define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_CURRENT 0

class TheWindow : public WindowExt
{
  Gtk::Box* box;
  Gtk::Socket* socket;
  Gtk::Button* button_close;

  public:
    TheWindow() : WindowExt(Gtk::WINDOW_POPUP)
    {
      signal_realize().connect( sigc::mem_fun(*this,&TheWindow::add_term) ); 

      button_close = Gtk::manage( new Gtk::Button("Close Window.") );
      box = Gtk::manage( new Gtk::Box(Gtk::ORIENTATION_VERTICAL) );
      box->pack_start( *button_close );
      add(*box);

      button_close->signal_clicked().connect(
        sigc::mem_fun(*this,&Window::hide)
      );

      show_all();
      grab_keyboard(this->get_window());
    }

    void add_term()
    {
      socket = Gtk::manage( new Gtk::Socket );
      box->pack_start( *socket );
      int xid = socket->get_id();
      char buffer[50];
      //sprintf(buffer, "xterm -into %d &", xid);
      sprintf(buffer, "urxvt -embed %d &", xid);
      system(buffer);
      box->show_all();

      socket->signal_plug_added().connect(
          sigc::mem_fun(*this, &TheWindow::send_focus_in)
      );

      socket->signal_plug_removed().connect(
          sigc::mem_fun(*this, &TheWindow::on_plug_removed)
      );

    }

    bool on_plug_removed()
    { 
      hide();
      return false;
    }

    void send_focus_in()
    {
      GdkWindow* plug = socket->get_plug_window()->gobj();
      GdkDisplay *display = gdk_window_get_display(plug);

      XClientMessageEvent xclient;
      memset(&xclient, 0, sizeof (xclient));

      xclient.window = GDK_WINDOW_XID(plug);
      xclient.type = ClientMessage;
      xclient.message_type =
          gdk_x11_get_xatom_by_name_for_display(display, "_XEMBED");
      xclient.format = 32;
      xclient.data.l[0] = gtk_get_current_event_time();
      xclient.data.l[1] = XEMBED_FOCUS_IN;
      xclient.data.l[2] = XEMBED_FOCUS_CURRENT;
      xclient.data.l[3] = 0;
      xclient.data.l[4] = 0;

      XSendEvent(
          GDK_WINDOW_XDISPLAY(plug),
          GDK_WINDOW_XID(plug), False, NoEventMask, (XEvent *)&xclient
      );
    }
};

int main(int argc, char** argv)
{
  Glib::RefPtr<Gtk::Application> app;
  app = Gtk::Application::create(argc, argv, "socket.focustest");

  TheWindow win;
  return app->run(win);
}

window_ext.h:
#ifndef WINDOW_EXT_H
#define WINDOW_EXT_H

#include <gtkmm.h>
#include <iostream>

class Overlay;

class WindowExt : public Gtk::Window
{
  private:
    Cairo::RefPtr<Cairo::Region> shape;

  public:
    void grab_keyboard(Glib::RefPtr<Gdk::Window> dest)
    {
      Glib::RefPtr<Gdk::Display> display = get_display();
      Glib::RefPtr<Gdk::DeviceManager> deviceM = display->get_device_manager();

      std::vector< Glib::RefPtr<Gdk::Device> >devices =
        deviceM->list_devices( Gdk::DEVICE_TYPE_MASTER );

      std::vector< Glib::RefPtr<Gdk::Device> >::iterator it;

      for(it = devices.begin(); it != devices.end(); ++it)
      {
        for(int grab = Gdk::GRAB_NOT_VIEWABLE; grab == Gdk::GRAB_NOT_VIEWABLE;)
        {
          grab = (*it)->grab(
            dest, Gdk::OWNERSHIP_NONE, true,
            Gdk::ALL_EVENTS_MASK, GDK_CURRENT_TIME
          );
        }
      }
    }

    WindowExt(Gtk::WindowType type=Gtk::WINDOW_TOPLEVEL) : Window(type) {}

    virtual ~WindowExt(){}
};

#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]