Mostrando un gtk.Calendar en un menú?

calendar-menu-screenshot

Quiero construir un menú contextual con un elemento de menú para seleccionar una fecha. (El caso de uso es seleccionar un grupo de elementos en una vista de árbol y luego establecer una nueva fecha de vencimiento para todos los artículos).

Dado que un artículo es un Gtk.Bin, puedo especificar cualquier widget en lugar de una etiqueta. Sin embargo, parece que no puedo interactuar con el widget. Si hago clic en cualquier parte del menú, el menuitem obtiene el clic. Por lo tanto, no puedo seleccionar una fecha en particular, ni navegar meses o años. ¿Cómo puedo hacer que el calendario obtenga la actividad del ratón?

Además, hay un relleno extraño alrededor de la parte exterior del calendario, y cuando se coloca sobre él se vuelve naranja. ¿Cómo puedo eliminar el relleno y / o no hacer el resaltado naranja?

#!/usr/bin/env python import gobject import pygtk pygtk.require('2.0') import gtk import time class ContextMenu(gtk.Menu): def __init__(self): gtk.Menu.__init__(self) def add_calendar_submenu_item(self, text, callback, uuids, data=None): calendar = gtk.Calendar() calendar.show() calendar_item = gtk.MenuItem() calendar_item.add(calendar) calendar_item.show() submenu = gtk.Menu() submenu.append(calendar_item) submenu_item = gtk.MenuItem("%s..." %(text)) submenu_item.set_submenu(submenu) submenu_item.show() submenu_item.connect("activate", self.on_calendar_activate) self.append(submenu_item) def on_calendar_activate(self, widget): print "activate" if __name__ == "__main__": class CalendarExample: def __init__(self): window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.set_title("Calendar Example") window.set_border_width(5) window.set_size_request(200, 100) window.set_resizable(False) window.stick() window.connect("destroy", lambda x: gtk.main_quit()) menu = ContextMenu() menu.add_calendar_submenu_item("date", self.on_date, ['123']) root_menu = gtk.MenuItem("Calendar Menu") root_menu.show() root_menu.set_submenu(menu) vbox = gtk.VBox(False, 10) window.add(vbox) vbox.show() menu_bar = gtk.MenuBar() vbox.pack_start(menu_bar, False, False, 2) menu_bar.append (root_menu) menu_bar.show() button = gtk.Button("Push Me") button.connect("clicked", self.on_menu_push, menu) vbox.pack_start(button, False, True, 10) button.show() window.show() def on_menu_push(self, widget, menu): menu.popup(None, None, None, 0, 0) def on_action(self, widget, uuids, text): print "Item %s pressed" %(text) def on_date(self, widget, uuids, text): print "Calendar activated with %s" %(text) CalendarExample() gtk.main() 

[Actualizar]

Lo que busco es algo parecido al calendario de fecha / hora del menú del indicador de Ubuntu.

Calendario de Ubuntu

Como ya lo mencionó ilius en los comentarios, el menú no está diseñado para contener un widget arbitrario. También se ha discutido en esta publicación SO . Tendrá que ir con la opción de ventana emergente.
El applet de reloj en Ubuntu que está intentando emular utiliza una ventana emergente. Puedes verificar esto usando xwininfo . Si tiene el calendario visualizado, selecciónelo (para la utilidad xwininfo ) puede ver que es una ventana separada y no es lo mismo que el panel.
Además, esto puede confirmarse mirando la fuente . El applet de reloj que se muestra es un botón de alternancia que, al alternar, muestra u oculta la ventana emergente con el calendario (más preciso es un widget personalizado CalendarWindow que extiende GtkWindow y agrega GtkCalendar adecuadamente cuando se crea). Una implementación burda de la misma idea basada en su código es la siguiente (perdone mi conocimiento limitado de Python):

 #!/usr/bin/env python import gobject import pygtk pygtk.require('2.0') import gtk import time class CalendarExample: def __init__(self): window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.set_title("Calendar Example") window.set_border_width(5) window.set_size_request(200, 100) window.set_resizable(False) window.stick() window.connect("destroy", lambda x: gtk.main_quit()) vbox = gtk.VBox(False, 10) window.add(vbox) # Could have used WINDOW_POPUP to create below window, but trying to emulate the same properties as the window # in applet. cal_window = gtk.Window(gtk.WINDOW_TOPLEVEL) cal_window.set_decorated(False) cal_window.set_resizable(False) cal_window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK) cal_window.stick() cal_vbox = gtk.VBox(False, 10) cal_window.add(cal_vbox) cal_vbox.pack_start(gtk.Calendar(), True, False, 0) cal_vbox.pack_start(gtk.Button("Dummy locations"), True, False, 0) toggle_button = gtk.ToggleButton("Show Calendar") vbox.pack_start(toggle_button, False, True, 10) toggle_button.connect("toggled", self.on_toggle, cal_window) # Track movements of the window to move calendar window as well window.connect("configure-event", self.on_window_config, toggle_button, cal_window) window.show_all() # Calendar window co ordinates without off-screen correction: # Window origin (x, y) # | # V # --------------------------------- # | Main Window | # | | # | | # |Toggle button's (x, y) | # |(relative to parent window) | # | | | # | V | # | ......................... | # Calendar | | Toggle Button | | # window's | | | | # (x, y)---+> ......................... | # |(Calendar window will be here) | # | | # | | # --------------------------------- # Calendar Window's screen coordinates: # x = Window's origin x + Toggle Button's relative x # y = Window's origin y + Toggle Button's relative y + Toggle Button's height # "toggle" callback which shows & hides calendar window. def on_toggle(self, toggle_button, cal_window): if toggle_button.get_active(): rect = toggle_button.get_allocation() main_window = toggle_button.get_toplevel() [win_x, win_y] = main_window.get_window().get_origin() cal_x = win_x + rect.x cal_y = win_y + rect.y + rect.height [x, y] = self.apply_screen_coord_correction(cal_x, cal_y, cal_window, toggle_button) cal_window.move(x, y) cal_window.show_all() toggle_button.set_label("Hide Calendar") else: cal_window.hide_all() toggle_button.set_label("Show Calendar") # "configure-event" callback of main window, try to move calendar window along with main window. def on_window_config(self, widget, event, toggle_button, cal_window): # Maybe better way to find the visiblilty if cal_window.get_mapped(): rect = toggle_button.get_allocation() cal_x = event.x + rect.x cal_y = event.y + rect.y + rect.height [x, y] = self.apply_screen_coord_correction(cal_x, cal_y, cal_window, toggle_button) cal_window.move(x, y) # This function "tries" to correct calendar window position so that it is not obscured when # a portion of main window is off-screen. # Known bug: If the main window is partially off-screen before Calendar window # has been realized then get_allocation() will return rect of 1x1 in which case # the calculations will fail & correction will not be applied def apply_screen_coord_correction(self, x, y, widget, relative_widget): corrected_y = y corrected_x = x rect = widget.get_allocation() screen_w = gtk.gdk.screen_width() screen_h = gtk.gdk.screen_height() delta_x = screen_w - (x + rect.width) delta_y = screen_h - (y + rect.height) if delta_x < 0: corrected_x += delta_x if corrected_x < 0: corrected_x = 0 if delta_y < 0: corrected_y = y - rect.height - relative_widget.get_allocation().height if corrected_y < 0: corrected_y = 0 return [corrected_x, corrected_y] if __name__ == "__main__": CalendarExample() gtk.main() 

¡Espero que esto ayude!