XEmbed with Ruby and Gtk::Socket
I recently discovered a Python IDE called PIDA that provides support for embedded Vim. I'm not a big fan of Python IDEs, but being able to use Vim as the editing component is definitely a killer feature. I haven't seen Vim embedded in a GNOME program since the unfortunate demise of the GVim Bonobo component and I had no idea it was even possible with current versions of Vim. A quick inspection of PIDA's source code revealed that it launches a new instance of GVim and then uses XEmbed to incorporate it into the user interface.
I had never heard of XEmbed before, but seeing it used in PIDA compelled me to pursue further investigation. Apparently, XEmbed makes it possible to embed virtually any X11 window inside of another application. GTK provides support for this with the Plug and Socket widgets, which are available in GTK's Python and Ruby bindings. XEmbed client support is also available in Qt with the QtXEmbedContainer object.
For the sake of experimentation, I wrote a simple Ruby script that uses my window management library and the Gtk::Socket object to facilitate window embedding. It provides two combo boxes which each contain a complete list of windows. The user selects a window in each one, and then clicks the Grab button to grab those windows and reparent them in Socket objects separated by a resizeable splitter. The source code for this experiment is relatively simple:
#!/usr/bin/env ruby require "wmlib" require "gtk2" win = Gtk::Window.new("Embed Test") win.signal_connect("destroy") {|w| Gtk.main_quit} win.add vb = Gtk::VBox.new vb.pack_start(hb = Gtk::HBox.new, false, false) lst = Gtk::ListStore.new String, Integer hb.pack_start(combo1 = Gtk::ComboBox.new) hb.pack_start(combo2 = Gtk::ComboBox.new) hb.pack_start(btnGrab = Gtk::Button.new("Grab"), false) combo1.model = lst combo2.model = lst for w in WM::Window i = lst.append i[0], i[1] = w.title[0..30], w.id if w.title end vb.pack_start(pane = Gtk::HPaned.new) pane.pack1 socket = Gtk::Socket.new, true, false pane.pack2 socket2 = Gtk::Socket.new, true, false ## Use tabs instead of panes #vb.pack_start(tabs = Gtk::Notebook.new) #tabs.append_page(socket = Gtk::Socket.new) #tabs.append_page(socket2 = Gtk::Socket.new) win.show_all() btnGrab.signal_connect("clicked") {|*a| socket.add_id combo1.active_iter[1] socket2.add_id combo2.active_iter[1] } Gtk.main
While experimenting with panes and XEmbed, one is reminded of tiling window managers like Ion. The ability to place arbitrary windows into tabs or panes is very compelling, and I'm certain I'll find some uses for the feature in the future.
Tags: programming, gnome, ruby
Posted on 2007-01-060 comments
