[pygtk] Embedding a Win32 window or ActiveX control in a pygtk application

Richie Hindle richie at entrian.com
Thu Jun 9 07:23:41 WST 2005

> I don't remember all details but I did embed a Flash file into a GTK 
> window some time ago:
> [...]
> axcontainer=gtk.DrawingArea()

Aha!  Parenting the control to a DrawingArea was the step I was missing.

I've now got this working, and an example application (a poor man's webbrowser,
embedding IE in pygtk via AtlAxWin and ctypes) is below.  There are a few things
I couldn't make work:

 o My keyboard accelerator (Alt+A to focus the address box) doesn't work
   when IE has the focus.  Any ideas?  How do pygtk accelerators work under the

 o Clicking a Gtk control when the IE control has the focus doesn't focus
   the Gtk control.  I worked around this by putting an event handler on the
   Gtk controls for "button-press-event", but it would need to be done for
   every Gtk control - is there a better solution?

 o IE's accelerator keys (eg. Tab and Alt+Left) don't work.  In a pure Win32
   app, I'd fix this by calling IOleInPlaceActiveObject::TranslateAccelerator()
   in the message pump, but can I get access to the message pump in pygtk?

 o Pressing Enter in the address box should have the same effect as pressing
   the Go button - I've done this, but it's a hack.  Is there a better way?

 o I'm using 65293 as the code for the Enter key - does pygtk have a constant
   for this?

This is my first pygtk program, so any criticism or suggestions will be
gratefully received!

-------------------------------- snip snip --------------------------------

"""A poor man's webbrowser, embedding IE in pygtk via AtlAxWin and ctypes."""

import win32con

from ctypes import *
from ctypes.wintypes import *
from ctypes.com import IUnknown
from ctypes.com.automation import IDispatch, VARIANT
from ie6_gen import IWebBrowser2  # Copy ie6_gen from ctypes\win32\com\samples
kernel32 = windll.kernel32
user32 = windll.user32
atl = windll.atl                  # If this fails, you need atl.dll

import pygtk
import gtk

class GUI:
    def __init__(self):
        # Create the main GTK window.
        self.main = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.main.set_title("Poor man's browser [TM]")
        self.main.connect("destroy", gtk.main_quit)
        self.main.set_size_request(750, 550)
        # Create a VBox to house the address bar and the IE control.
        self.mainVBox = gtk.VBox()
        # Create the address bar.
        self.addressEntry = gtk.Entry()
        self.addressEntry.connect("key-press-event", self.on_addressEntry_key)
        self.addressLabel = gtk.Label()
        self.addressLabel.set_text_with_mnemonic("_Address: ")
        self.goButton = gtk.Button("  Go  ")
        self.goButton.connect("clicked", self.on_goButton_clicked)
        self.addressHbox = gtk.HBox()
                                           False, True, 2, gtk.PACK_START)
                                           False, True, 0, gtk.PACK_END)
                                        False, True, 0, gtk.PACK_START)
        # Create a DrawingArea to host IE and add it to the hbox.
        self.container = gtk.DrawingArea()
        # Make the container accept the focus and pass it to the control;
        # this makes the Tab key pass focus to IE correctly.
        self.container.set_property("can-focus", True)
        self.container.connect("focus", self.on_container_focus)
        # Resize the AtlAxWin window with its container.
        self.container.connect("size-allocate", self.on_container_size)
        # Create an instance of IE via AtlAxWin.
        hInstance = kernel32.GetModuleHandleA(None)
        parentHwnd = self.container.window.handle
        self.atlAxWinHwnd = \
            user32.CreateWindowExA(0, "AtlAxWin", "http://www.pygtk.org",
                            win32con.WS_VISIBLE | win32con.WS_CHILD |
                            win32con.WS_HSCROLL | win32con.WS_VSCROLL,
                            0, 0, 100, 100, parentHwnd, None, hInstance, 0)
        # Get the IWebBrowser2 interface for the IE control.
        pBrowserUnk = POINTER(IUnknown)()
        atl.AtlAxGetControl(self.atlAxWinHwnd, byref(pBrowserUnk))
        self.pBrowser = POINTER(IWebBrowser2)()
        # Create a Gtk window that refers to the native AtlAxWin window.
        self.gtkAtlAxWin = gtk.gdk.window_foreign_new(long(self.atlAxWinHwnd))

        # By default, clicking a GTK widget doesn't grab the focus away from
        # a native Win32 control.
        self.addressEntry.connect("button-press-event", self.on_widget_click)
    def on_goButton_clicked(self, widget):
        v = byref(VARIANT())
        self.pBrowser.Navigate(self.addressEntry.get_text(), v, v, v, v)
    def on_addressEntry_key(self, widget, event):
        if event.keyval == 65293:   # "Enter"; is there a constant for this?
    def on_widget_click(self, widget, data):
    def on_container_size(self, widget, sizeAlloc):
        self.gtkAtlAxWin.move_resize(0, 0, sizeAlloc.width, sizeAlloc.height)

    def on_container_focus(self, widget, data):
        # Pass the focus to IE.  First get the HWND of the IE control; this
        # is a bit of a hack but I couldn't make IWebBrowser2._get_HWND work.
        rect = RECT()
        user32.GetWindowRect(self.atlAxWinHwnd, byref(rect))
        ieHwnd = user32.WindowFromPoint(POINT(rect.left, rect.top))

# Show the main window and run the message loop.
gui = GUI()

-------------------------------- snip snip --------------------------------

Richie Hindle
richie at entrian.com

More information about the pygtk mailing list