[gtk+/xi2: 981/981] Merge branch 'master' into xi2



commit 90e0b05a4e5dea237f73276d2008aed2f95001dd
Merge: affc7e6 5098f34
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue May 4 11:25:33 2010 +0200

    Merge branch 'master' into xi2
    
    Conflicts:
    	gdk/gdk.symbols
    	gdk/x11/gdkprivate-x11.h
    	gtk/gtkmain.c
    	gtk/gtkmenu.c
    	gtk/gtkprivate.h
    	gtk/gtktextview.c
    	gtk/gtktreeview.c
    	gtk/gtkwidget.c
    	gtk/gtkwindow.c

 INSTALL.in                                         |    4 +-
 Makefile.am                                        |    2 +-
 NEWS                                               |  128 +
 README.in                                          |   15 +-
 build/Makefile.am                                  |    4 +
 build/win32/Makefile.am                            |    4 +
 build/win32/vs9/Makefile.am                        |   16 +
 build/win32/vs9/README.txt                         |   22 +
 build/win32/vs9/gdk-pixbuf-csource.vcproj          |  166 +
 build/win32/vs9/gdk-pixbuf-query-loaders.vcproj    |  166 +
 build/win32/vs9/gdk-pixbuf.vcproj                  |  258 +
 build/win32/vs9/gdk-win32.vcproj                   |  153 +
 build/win32/vs9/gdk.vcprojin                       |  220 +
 build/win32/vs9/gtk+.sln                           |  122 +
 build/win32/vs9/gtk+.vsprops                       |  390 +
 build/win32/vs9/gtk-demo.vcproj                    |  209 +
 build/win32/vs9/gtk.vcprojin                       |  235 +
 build/win32/vs9/install.vcproj                     |   78 +
 config.h.win32.in                                  |   24 +-
 configure.in                                       |   17 +-
 demos/gtk-demo/appwindow.c                         |    2 +-
 demos/gtk-demo/assistant.c                         |    2 +-
 demos/gtk-demo/builder.c                           |    2 +-
 demos/gtk-demo/button_box.c                        |    2 +-
 demos/gtk-demo/clipboard.c                         |    2 +-
 demos/gtk-demo/colorsel.c                          |    2 +-
 demos/gtk-demo/combobox.c                          |    2 +-
 demos/gtk-demo/dialog.c                            |    2 +-
 demos/gtk-demo/drawingarea.c                       |    4 +-
 demos/gtk-demo/editable_cells.c                    |    2 +-
 demos/gtk-demo/entry_buffer.c                      |    2 +-
 demos/gtk-demo/entry_completion.c                  |    2 +-
 demos/gtk-demo/expander.c                          |    2 +-
 demos/gtk-demo/hypertext.c                         |    2 +-
 demos/gtk-demo/iconview.c                          |    2 +-
 demos/gtk-demo/iconview_edit.c                     |    2 +-
 demos/gtk-demo/images.c                            |   23 +-
 demos/gtk-demo/infobar.c                           |    2 +-
 demos/gtk-demo/links.c                             |    2 +-
 demos/gtk-demo/list_store.c                        |   32 +-
 demos/gtk-demo/menus.c                             |    4 +-
 demos/gtk-demo/offscreen_window.c                  |   26 +-
 demos/gtk-demo/offscreen_window2.c                 |   26 +-
 demos/gtk-demo/panes.c                             |    2 +-
 demos/gtk-demo/pickers.c                           |    2 +-
 demos/gtk-demo/pixbufs.c                           |    2 +-
 demos/gtk-demo/rotated_text.c                      |    2 +-
 demos/gtk-demo/search_entry.c                      |  224 +-
 demos/gtk-demo/sizegroup.c                         |    2 +-
 demos/gtk-demo/spinner.c                           |    2 +-
 demos/gtk-demo/stock_browser.c                     |    2 +-
 demos/gtk-demo/textscroll.c                        |    2 +-
 demos/gtk-demo/textview.c                          |    2 +-
 demos/gtk-demo/toolpalette.c                       |    2 +-
 demos/gtk-demo/tree_store.c                        |    2 +-
 demos/gtk-demo/ui_manager.c                        |    2 +-
 docs/RELEASE-HOWTO                                 |    5 +-
 docs/reference/gdk/gdk-docs.sgml                   |    4 +
 docs/reference/gdk/tmpl/windows.sgml               |    1 -
 docs/reference/gtk/building.sgml                   |   20 +-
 docs/reference/gtk/drawing-model.xml               |    2 +-
 docs/reference/gtk/gtk-docs.sgml                   |    9 +
 docs/reference/gtk/gtk-sections.txt                |   58 +-
 docs/reference/gtk/gtk.types                       |    1 +
 docs/reference/gtk/tmpl/.gitignore                 |    6 +
 docs/reference/gtk/tmpl/gtkaction.sgml             |  560 --
 docs/reference/gtk/tmpl/gtkalignment.sgml          |  141 -
 docs/reference/gtk/tmpl/gtkarrow.sgml              |   82 -
 docs/reference/gtk/tmpl/gtkaspectframe.sgml        |   88 -
 docs/reference/gtk/tmpl/gtkassistant.sgml          |  344 -
 docs/reference/gtk/tmpl/gtkbbox.sgml               |  210 -
 docs/reference/gtk/tmpl/gtkbin.sgml                |   54 -
 docs/reference/gtk/tmpl/gtkbox.sgml                |  291 -
 docs/reference/gtk/tmpl/gtkbuildable.sgml          |  193 -
 docs/reference/gtk/tmpl/gtkbuilder.sgml            |  456 --
 docs/reference/gtk/tmpl/gtkcontainer.sgml          |  295 +-
 docs/reference/gtk/tmpl/gtkdnd.sgml                |   15 +-
 docs/reference/gtk/tmpl/gtkdrawingarea.sgml        |    2 +-
 docs/reference/gtk/tmpl/gtkhbox.sgml               |   49 -
 docs/reference/gtk/tmpl/gtklabel.sgml              |   20 +-
 docs/reference/gtk/tmpl/gtkmessagedialog.sgml      |  213 -
 docs/reference/gtk/tmpl/gtkplug.sgml               |  126 -
 docs/reference/gtk/tmpl/gtksocket.sgml             |  170 -
 docs/reference/gtk/tmpl/gtktesting.sgml            |  177 -
 docs/reference/gtk/tmpl/gtkvbbox.sgml              |   98 -
 docs/reference/gtk/tmpl/gtkvbox.sgml               |   49 -
 docs/reference/gtk/tmpl/gtkviewport.sgml           |  134 -
 docs/reference/gtk/tmpl/gtkvolumebutton.sgml       |   35 -
 docs/reference/gtk/tmpl/gtkvpaned.sgml             |   35 -
 docs/reference/gtk/tmpl/gtkvruler.sgml             |   50 -
 docs/reference/gtk/tmpl/gtkvscale.sgml             |   51 -
 docs/reference/gtk/tmpl/gtkvscrollbar.sgml         |   40 -
 docs/reference/gtk/tmpl/gtkvseparator.sgml         |   41 -
 docs/reference/libgail-util/tmpl/gailmisc.sgml     |  125 -
 docs/reference/libgail-util/tmpl/gailtextutil.sgml |   95 -
 docs/tutorial/gtk-tut.sgml                         |  398 +-
 examples/calendar/calendar.c                       |    4 +-
 examples/entry/entry.c                             |    2 +-
 examples/gtkdial/gtkdial.c                         |    4 +-
 examples/progressbar/progressbar.c                 |    2 +-
 examples/radiobuttons/radiobuttons.c               |    2 +-
 examples/rangewidgets/rangewidgets.c               |    2 +-
 examples/scribble-simple/scribble-simple.c         |    2 +-
 examples/scribble-xinput/Makefile                  |    5 +-
 examples/scribble-xinput/scribble-xinput.c         |    8 +-
 examples/scrolledwin/scrolledwin.c                 |    2 +-
 examples/text/text.c                               |    2 +-
 gdk-pixbuf/Makefile.am                             |    1 +
 gdk-pixbuf/gdk-pixbuf-io.c                         |   14 +-
 gdk-pixbuf/gdk-pixbuf-loader.c                     |    6 +-
 gdk-pixbuf/io-png.c                                |    4 +-
 gdk-pixbuf/io-qtif.c                               |    2 +-
 gdk-pixbuf/io-tga.c                                |    8 +-
 gdk/Makefile.am                                    |   16 +-
 gdk/directfb/gdkcolor-directfb.c                   |   12 +-
 gdk/directfb/gdkdisplay-directfb.c                 |   23 +-
 gdk/directfb/gdkkeys-directfb.c                    |   15 +
 gdk/directfb/gdkwindow-directfb.c                  |   15 +-
 gdk/gdk.c                                          |    6 +-
 gdk/gdk.symbols                                    |    6 +
 gdk/gdkapplaunchcontext.c                          |    4 +-
 gdk/gdkdisplay.c                                   |    6 +-
 gdk/gdkdraw.c                                      |   12 +-
 gdk/gdkevents.c                                    |    2 +-
 gdk/gdkpango.c                                     |   14 +-
 gdk/gdkpixbuf-drawable.c                           |    6 +-
 gdk/gdkpixmap.c                                    |   34 +-
 gdk/gdkrectangle.c                                 |    2 +-
 gdk/gdkrgb.c                                       |    8 +-
 gdk/gdkscreen.c                                    |    2 +-
 gdk/gdkselection.c                                 |    2 +-
 gdk/gdkvisual.c                                    |    4 +-
 gdk/gdkwindow.c                                    |  288 +-
 gdk/gdkwindow.h                                    |   13 +
 gdk/x11/gdkapplaunchcontext-x11.c                  |    7 +
 gdk/x11/gdkcolor-x11.c                             |    2 +-
 gdk/x11/gdkdnd-x11.c                               |   16 +-
 gdk/x11/gdkkeys-x11.c                              |   16 +-
 gdk/x11/gdkprivate-x11.h                           |    2 -
 gdk/x11/gdkscreen-x11.c                            |   61 +-
 gdk/x11/gdkvisual-x11.c                            |   13 +-
 gdk/x11/gdkwindow-x11.c                            |   34 +-
 gtk/Makefile.am                                    |   20 +-
 gtk/compose-parse.py                               |   53 +-
 gtk/gen-paper-names.c                              |  103 +-
 gtk/gtk-compose-lookaside.txt                      |   18 -
 gtk/gtk.h                                          |    1 +
 gtk/gtk.symbols                                    |   19 +
 gtk/gtkaboutdialog.c                               |    6 +-
 gtk/gtkaccelgroup.c                                |   11 +-
 gtk/gtkaccellabel.c                                |    4 +-
 gtk/gtkaccessible.c                                |   20 +
 gtk/gtkaccessible.h                                |    3 +-
 gtk/gtkaction.c                                    |   45 +-
 gtk/gtkactivatable.c                               |    2 +-
 gtk/gtkalignment.c                                 |  218 +-
 gtk/gtkarrow.c                                     |   48 +-
 gtk/gtkaspectframe.c                               |   48 +-
 gtk/gtkassistant.c                                 |   99 +-
 gtk/gtkassistant.h                                 |   30 +
 gtk/gtkbbox.c                                      |  103 +-
 gtk/gtkbbox.h                                      |   19 +
 gtk/gtkbin.c                                       |  140 +-
 gtk/gtkbox.c                                       | 1078 ++-
 gtk/gtkbox.h                                       |   22 +
 gtk/gtkbuildable.c                                 |   40 +-
 gtk/gtkbuildable.h                                 |   49 +
 gtk/gtkbuilder.c                                   |  271 +-
 gtk/gtkbuilder.h                                   |   31 +
 gtk/gtkbutton.c                                    |  192 +-
 gtk/gtkcalendar.c                                  |   64 +-
 gtk/gtkcelleditable.c                              |  157 +-
 gtk/gtkcellrenderer.c                              |   22 +-
 gtk/gtkcellrendererpixbuf.c                        |  161 +-
 gtk/gtkcellrendererspinner.c                       |    4 +-
 gtk/gtkcellrenderertext.c                          |    8 +-
 gtk/gtkcellrenderertoggle.c                        |    4 +-
 gtk/gtkcellview.c                                  |   10 +-
 gtk/gtkcheckbutton.c                               |   35 +-
 gtk/gtkcheckmenuitem.c                             |   14 +-
 gtk/gtkclipboard.c                                 |    4 +-
 gtk/gtkclist.c                                     |  106 +-
 gtk/gtkcolorbutton.c                               |    4 +-
 gtk/gtkcolorsel.c                                  |    8 +-
 gtk/gtkcombo.c                                     |   16 +-
 gtk/gtkcombobox.c                                  |   55 +-
 gtk/gtkcontainer.c                                 |   36 +-
 gtk/gtkctree.c                                     |   30 +-
 gtk/gtkcurve.c                                     |    2 +-
 gtk/gtkcustompaperunixdialog.c                     |    4 +-
 gtk/gtkdebug.h                                     |   25 +-
 gtk/gtkdialog.c                                    |   11 +-
 gtk/gtkdnd-quartz.c                                |   10 +-
 gtk/gtkdnd.c                                       |   57 +-
 gtk/gtkdrawingarea.c                               |    4 +-
 gtk/gtkentry.c                                     |  249 +-
 gtk/gtkentrybuffer.c                               |    2 +-
 gtk/gtkentrycompletion.c                           |   20 +-
 gtk/gtkenums.h                                     |   10 +
 gtk/gtkeventbox.c                                  |   20 +-
 gtk/gtkexpander.c                                  |   42 +-
 gtk/gtkextendedlayout.c                            |  535 ++
 gtk/gtkextendedlayout.h                            |   89 +
 gtk/gtkfilechooser.c                               |   25 +-
 gtk/gtkfilechooserbutton.c                         |   23 +-
 gtk/gtkfilechooserdefault.c                        |   67 +-
 gtk/gtkfilechooserdialog.c                         |   18 +-
 gtk/gtkfilechooserentry.c                          |    2 +-
 gtk/gtkfilefilter.c                                |    2 +-
 gtk/gtkfilesel.c                                   |    4 +-
 gtk/gtkfilesystem.c                                |   24 +-
 gtk/gtkfilesystem.h                                |    3 +-
 gtk/gtkfilesystemmodel.c                           |   13 +-
 gtk/gtkfixed.c                                     |   21 +-
 gtk/gtkfontbutton.c                                |    2 +-
 gtk/gtkfontsel.c                                   |    2 +-
 gtk/gtkframe.c                                     |  185 +-
 gtk/gtkgamma.c                                     |    2 +-
 gtk/gtkhandlebox.c                                 |   44 +-
 gtk/gtkhbox.c                                      |   25 +
 gtk/gtkhscrollbar.c                                |    2 +-
 gtk/gtkhsv.c                                       |   20 +-
 gtk/gtkiconfactory.c                               |    4 +-
 gtk/gtkicontheme.c                                 |  149 +-
 gtk/gtkicontheme.h                                 |    7 +
 gtk/gtkiconview.c                                  |   83 +-
 gtk/gtkimage.c                                     |  161 +-
 gtk/gtkimagemenuitem.c                             |   11 +-
 gtk/gtkimcontext.c                                 |    2 +-
 gtk/gtkimcontextsimpleseqs.h                       |  114 +-
 gtk/gtkinfobar.c                                   |    7 +-
 gtk/gtkinputdialog.c                               |    4 +-
 gtk/gtkinvisible.c                                 |    8 +-
 gtk/gtkitem.c                                      |    4 +-
 gtk/gtkitemfactory.c                               |   12 +-
 gtk/gtklabel.c                                     |  792 ++-
 gtk/gtklayout.c                                    |   31 +-
 gtk/gtklinkbutton.c                                |   12 +-
 gtk/gtklist.c                                      |   38 +-
 gtk/gtklistitem.c                                  |   28 +-
 gtk/gtkliststore.c                                 |    8 +-
 gtk/gtkmain.c                                      |   39 +-
 gtk/gtkmenu.c                                      |   75 +-
 gtk/gtkmenubar.c                                   |   18 +-
 gtk/gtkmenuitem.c                                  |   59 +-
 gtk/gtkmenushell.c                                 |   78 +-
 gtk/gtkmenutoolbutton.c                            |   10 +-
 gtk/gtkmessagedialog.c                             |   53 +-
 gtk/gtkmessagedialog.h                             |   37 +-
 gtk/gtkmisc.c                                      |   24 +-
 gtk/gtkmnemonichash.c                              |    4 +-
 gtk/gtkmountoperation.c                            |    4 +-
 gtk/gtknotebook.c                                  |  199 +-
 gtk/gtkoffscreenwindow.c                           |   12 +-
 gtk/gtkoldeditable.c                               |   12 +-
 gtk/gtkoptionmenu.c                                |   38 +-
 gtk/gtkorientable.c                                |   35 +-
 gtk/gtkpagesetup.c                                 |   14 +-
 gtk/gtkpagesetupunixdialog.c                       |    4 +-
 gtk/gtkpaned.c                                     |   63 +-
 gtk/gtkpapersize.c                                 |    2 +-
 gtk/gtkpathbar.c                                   |   45 +-
 gtk/gtkpixmap.c                                    |    8 +-
 gtk/gtkplug.c                                      |   54 +-
 gtk/gtkpreview.c                                   |    4 +-
 gtk/gtkprinteroptionset.c                          |    3 +-
 gtk/gtkprinteroptionwidget.c                       |    2 +-
 gtk/gtkprintjob.c                                  |    2 +-
 gtk/gtkprintoperation-unix.c                       |    4 +-
 gtk/gtkprintoperation-win32.c                      |    2 +-
 gtk/gtkprintoperation.c                            |    6 +-
 gtk/gtkprintsettings.c                             |   20 +-
 gtk/gtkprintunixdialog.c                           |   24 +-
 gtk/gtkprivate.h                                   |   57 +-
 gtk/gtkprogress.c                                  |   10 +-
 gtk/gtkprogressbar.c                               |   10 +-
 gtk/gtkradioaction.c                               |    4 +-
 gtk/gtkradiobutton.c                               |   23 +-
 gtk/gtkradiotoolbutton.c                           |    4 +-
 gtk/gtkrange.c                                     |   29 +-
 gtk/gtkrbtree.c                                    |   42 +-
 gtk/gtkrc.c                                        |   30 +-
 gtk/gtkrc.h                                        |    4 +
 gtk/gtkrecentaction.c                              |   10 +-
 gtk/gtkrecentchooser.c                             |   10 +-
 gtk/gtkrecentchooserdefault.c                      |    4 +-
 gtk/gtkrecentchooserdialog.c                       |   14 +-
 gtk/gtkrecentchooserutils.c                        |    4 +-
 gtk/gtkrecentmanager.c                             |   10 +-
 gtk/gtkruler.c                                     |   25 +-
 gtk/gtkscale.c                                     |   17 +-
 gtk/gtkscalebutton.c                               |    2 +-
 gtk/gtkscrollbar.c                                 |    2 +-
 gtk/gtkscrolledwindow.c                            |  330 +-
 gtk/gtksearchenginetracker.c                       |  297 +-
 gtk/gtkselection.c                                 |    8 +-
 gtk/gtkseparator.c                                 |   12 +-
 gtk/gtkshow.c                                      |    2 +-
 gtk/gtksizegroup.c                                 |  218 +-
 gtk/gtksizegroup.h                                 |   11 +-
 gtk/gtksocket-win32.c                              |    2 +-
 gtk/gtksocket.c                                    |   93 +-
 gtk/gtkspinbutton.c                                |   30 +-
 gtk/gtkspinner.c                                   |    6 +-
 gtk/gtkstatusbar.c                                 |   16 +-
 gtk/gtkstatusicon.c                                |   66 +-
 gtk/gtkstyle.c                                     |   86 +-
 gtk/gtktable.c                                     |   34 +-
 gtk/gtktearoffmenuitem.c                           |    2 +-
 gtk/gtktestutils.c                                 |    9 +-
 gtk/gtktext.c                                      |   50 +-
 gtk/gtktextbuffer.c                                |    8 +-
 gtk/gtktextdisplay.c                               |   12 +-
 gtk/gtktextiter.c                                  |    6 +-
 gtk/gtktextlayout.c                                |    4 +-
 gtk/gtktextmark.c                                  |    2 +-
 gtk/gtktexttag.c                                   |    2 +-
 gtk/gtktexttagtable.c                              |    2 +-
 gtk/gtktextutil.c                                  |    8 +-
 gtk/gtktextview.c                                  |  157 +-
 gtk/gtktextview.h                                  |    3 +
 gtk/gtktipsquery.c                                 |    2 +-
 gtk/gtktoggleaction.c                              |    4 +-
 gtk/gtktogglebutton.c                              |    6 +-
 gtk/gtktoolbar.c                                   |   52 +-
 gtk/gtktoolbutton.c                                |    6 +-
 gtk/gtktoolitem.c                                  |   17 +-
 gtk/gtktoolitemgroup.c                             |   45 +-
 gtk/gtktoolpalette.c                               |    9 +-
 gtk/gtktooltip.c                                   |  104 +-
 gtk/gtktrayicon-x11.c                              |  190 +-
 gtk/gtktrayicon.h                                  |    2 +-
 gtk/gtktree.c                                      |   28 +-
 gtk/gtktreeitem.c                                  |   58 +-
 gtk/gtktreemodel.c                                 |    4 +-
 gtk/gtktreemodelfilter.c                           |    8 +-
 gtk/gtktreemodelsort.c                             |    2 +-
 gtk/gtktreesortable.c                              |    8 +-
 gtk/gtktreestore.c                                 |   28 +-
 gtk/gtktreeview.c                                  |  255 +-
 gtk/gtktreeviewcolumn.c                            |   36 +-
 gtk/gtkuimanager.c                                 |    6 +-
 gtk/gtkvbbox.c                                     |   80 +-
 gtk/gtkvbox.c                                      |   23 +
 gtk/gtkviewport.c                                  |  165 +-
 gtk/gtkvolumebutton.c                              |   10 +
 gtk/gtkvolumebutton.h                              |    2 +-
 gtk/gtkvpaned.c                                    |   18 +
 gtk/gtkvruler.c                                    |   29 +
 gtk/gtkvscale.c                                    |   20 +-
 gtk/gtkvscale.h                                    |    6 +
 gtk/gtkvscrollbar.c                                |   16 +-
 gtk/gtkvscrollbar.h                                |    6 +
 gtk/gtkvseparator.c                                |   18 +
 gtk/gtkvseparator.h                                |    6 +
 gtk/gtkwidget.c                                    |  751 ++-
 gtk/gtkwidget.h                                    |   77 +-
 gtk/gtkwin32embedwidget.c                          |   18 +-
 gtk/gtkwindow.c                                    |  339 +-
 gtk/gtkxembed.c                                    |    4 +-
 gtk/paper_names_offsets.c                          |  165 -
 gtk/tests/Makefile.am                              |    4 +
 gtk/tests/action.c                                 |   91 +
 gtk/tests/builder.c                                |    2 +-
 gtk/tests/filechooser.c                            |   48 +-
 gtk/tests/testing.c                                |    2 +-
 modules/engines/ms-windows/msw_style.c             |    4 +-
 modules/other/gail/gail.c                          |    6 +-
 modules/other/gail/gailbooleancell.c               |   22 +-
 modules/other/gail/gailbooleancell.h               |    1 +
 modules/other/gail/gailbutton.c                    |   10 +-
 modules/other/gail/gailcell.c                      |   13 +-
 modules/other/gail/gailcheckmenuitem.c             |   14 +-
 modules/other/gail/gailchecksubmenuitem.c          |   14 +-
 modules/other/gail/gailcombo.c                     |    6 +-
 modules/other/gail/gailcombobox.c                  |    6 +-
 modules/other/gail/gailentry.c                     |    4 +-
 modules/other/gail/gailexpander.c                  |    6 +-
 modules/other/gail/gailitem.c                      |    2 +-
 modules/other/gail/gaillabel.c                     |    2 +-
 modules/other/gail/gailmenuitem.c                  |   10 +-
 modules/other/gail/gailnotebookpage.c              |    2 +-
 modules/other/gail/gailoptionmenu.c                |    4 +-
 modules/other/gail/gailrange.c                     |    4 +-
 modules/other/gail/gailscalebutton.c               |    2 +-
 modules/other/gail/gailtogglebutton.c              |   14 +-
 modules/other/gail/gailtoplevel.c                  |    2 +-
 modules/other/gail/gailtreeview.c                  |   16 +-
 modules/other/gail/gailwidget.c                    |   21 +-
 modules/other/gail/gailwindow.c                    |    6 +-
 modules/other/gail/libgail-util/gailmisc.c         |   12 +
 modules/other/gail/libgail-util/gailtextutil.c     |   15 +
 modules/other/gail/tests/ferret.c                  |    2 +-
 modules/printbackends/cups/gtkprintbackendcups.c   |   34 +
 perf/gtkwidgetprofiler.c                           |    2 +-
 po-properties/af.po                                |  150 +-
 po-properties/am.po                                |  150 +-
 po-properties/ang.po                               |  150 +-
 po-properties/ar.po                                |  150 +-
 po-properties/as.po                                |  150 +-
 po-properties/ast.po                               |  150 +-
 po-properties/az.po                                |  150 +-
 po-properties/az_IR.po                             |  150 +-
 po-properties/be.po                                |  150 +-
 po-properties/be latin po                          |  150 +-
 po-properties/bg.po                                |  234 +-
 po-properties/bn.po                                | 3848 +++++-----
 po-properties/bn_IN.po                             | 3892 +++++-----
 po-properties/br.po                                |  150 +-
 po-properties/bs.po                                |  150 +-
 po-properties/ca.po                                | 3805 +++++-----
 po-properties/ca valencia po                       | 3959 +++++-----
 po-properties/crh.po                               |  378 +-
 po-properties/cs.po                                |  150 +-
 po-properties/cy.po                                |  150 +-
 po-properties/da.po                                |  282 +-
 po-properties/de.po                                |  432 +-
 po-properties/dz.po                                |  150 +-
 po-properties/el.po                                |  384 +-
 po-properties/en_CA.po                             |  150 +-
 po-properties/en_GB.po                             |  268 +-
 po-properties/eo.po                                |  150 +-
 po-properties/es.po                                | 3592 +++++----
 po-properties/et.po                                |  150 +-
 po-properties/eu.po                                |  670 +-
 po-properties/fa.po                                |  150 +-
 po-properties/fi.po                                |  259 +-
 po-properties/fr.po                                |  150 +-
 po-properties/ga.po                                |  150 +-
 po-properties/gl.po                                | 3721 +++++-----
 po-properties/gu.po                                |  150 +-
 po-properties/he.po                                |  150 +-
 po-properties/hi.po                                |  150 +-
 po-properties/hr.po                                |  150 +-
 po-properties/hu.po                                |  278 +-
 po-properties/hy.po                                |  150 +-
 po-properties/ia.po                                |  150 +-
 po-properties/id.po                                |  150 +-
 po-properties/io.po                                |  150 +-
 po-properties/is.po                                |  150 +-
 po-properties/it.po                                |  479 +-
 po-properties/ja.po                                |  150 +-
 po-properties/ka.po                                |  150 +-
 po-properties/kk.po                                | 8603 ++++++++++++++++++++
 po-properties/kn.po                                | 3796 +++++-----
 po-properties/ko.po                                |  311 +-
 po-properties/ku.po                                |  150 +-
 po-properties/li.po                                |  150 +-
 po-properties/lt.po                                |  326 +-
 po-properties/lv.po                                |  150 +-
 po-properties/mai.po                               |  150 +-
 po-properties/mi.po                                |  150 +-
 po-properties/mk.po                                |  150 +-
 po-properties/ml.po                                |  150 +-
 po-properties/mn.po                                |  150 +-
 po-properties/mr.po                                | 3857 +++++-----
 po-properties/ms.po                                |  150 +-
 po-properties/my.po                                |  150 +-
 po-properties/nb.po                                |  150 +-
 po-properties/nds.po                               | 4617 +++++++----
 po-properties/ne.po                                |  150 +-
 po-properties/nl.po                                |  150 +-
 po-properties/nn.po                                |  150 +-
 po-properties/nso.po                               |  150 +-
 po-properties/oc.po                                |  150 +-
 po-properties/or.po                                |  150 +-
 po-properties/pa.po                                |  259 +-
 po-properties/pl.po                                |  359 +-
 po-properties/ps.po                                |  150 +-
 po-properties/pt.po                                |  267 +-
 po-properties/pt_BR.po                             |  150 +-
 po-properties/ro.po                                |  269 +-
 po-properties/ru.po                                |  276 +-
 po-properties/rw.po                                |  150 +-
 po-properties/si.po                                |  150 +-
 po-properties/sk.po                                |  150 +-
 po-properties/sl.po                                |  295 +-
 po-properties/sq.po                                |  150 +-
 po-properties/sr.po                                |  311 +-
 po-properties/sr ije po                            |  150 +-
 po-properties/sr latin po                          |  311 +-
 po-properties/sv.po                                |  235 +-
 po-properties/ta.po                                |  150 +-
 po-properties/te.po                                |  150 +-
 po-properties/th.po                                |  150 +-
 po-properties/tk.po                                |  150 +-
 po-properties/tr.po                                |  150 +-
 po-properties/tt.po                                |  150 +-
 po-properties/uk.po                                | 3658 +++++-----
 po-properties/ur.po                                |  150 +-
 po-properties/uz.po                                |  150 +-
 po-properties/uz cyrillic po                       |  150 +-
 po-properties/vi.po                                |  386 +-
 po-properties/wa.po                                |  150 +-
 po-properties/xh.po                                |  150 +-
 po-properties/yi.po                                |  150 +-
 po-properties/zh_CN.po                             |  150 +-
 po-properties/zh_HK.po                             |  251 +-
 po-properties/zh_TW.po                             |  253 +-
 po/LINGUAS                                         |    1 +
 po/af.po                                           | 2250 ++----
 po/am.po                                           |  824 +--
 po/ang.po                                          |  824 +--
 po/ar.po                                           |  857 +--
 po/as.po                                           |  828 +--
 po/ast.po                                          |  828 +--
 po/az.po                                           |  828 +--
 po/az_IR.po                                        |  824 +--
 po/be.po                                           |  828 +--
 po/be latin po                                     |  828 +--
 po/bg.po                                           |  858 +--
 po/bn.po                                           | 3559 ++++-----
 po/bn_IN.po                                        | 2522 +++---
 po/br.po                                           |  824 +--
 po/bs.po                                           |  828 +--
 po/ca.po                                           |  984 +--
 po/ca valencia po                                  | 3469 +++++----
 po/crh.po                                          |  994 +--
 po/cs.po                                           | 2401 +++---
 po/cy.po                                           |  828 +--
 po/da.po                                           | 2476 +++---
 po/de.po                                           |  893 +--
 po/dz.po                                           |  828 +--
 po/el.po                                           | 2453 +++---
 po/en_CA.po                                        |  828 +--
 po/en_GB.po                                        |  900 +--
 po/eo.po                                           |  828 +--
 po/es.po                                           |  868 +--
 po/et.po                                           |  874 +--
 po/eu.po                                           | 1684 ++---
 po/fa.po                                           |  828 +--
 po/fi.po                                           | 1059 +--
 po/fr.po                                           |  827 +--
 po/ga.po                                           |  828 +--
 po/gl.po                                           | 2713 +++----
 po/gu.po                                           |  896 +--
 po/he.po                                           |  828 +--
 po/hi.po                                           |  828 +--
 po/hr.po                                           |  828 +--
 po/hu.po                                           |  921 +--
 po/hy.po                                           |  828 +--
 po/ia.po                                           |  824 +--
 po/id.po                                           | 4668 ++++-------
 po/io.po                                           |  827 +--
 po/is.po                                           |  828 +--
 po/it.po                                           |  992 +--
 po/ja.po                                           |  837 +--
 po/ka.po                                           |  828 +--
 po/kk.po                                           | 5336 ++++++++++++
 po/kn.po                                           | 2461 +++---
 po/ko.po                                           |  950 +--
 po/ku.po                                           |  828 +--
 po/li.po                                           |  828 +--
 po/lt.po                                           |  980 +--
 po/lv.po                                           | 3310 ++++----
 po/mai.po                                          |  828 +--
 po/mi.po                                           |  828 +--
 po/mk.po                                           |  828 +--
 po/ml.po                                           |  828 +--
 po/mn.po                                           |  830 +--
 po/mr.po                                           | 2534 +++----
 po/ms.po                                           |  828 +--
 po/my.po                                           |  828 +--
 po/nb.po                                           |  872 +--
 po/nds.po                                          | 1307 ++--
 po/ne.po                                           |  828 +--
 po/nl.po                                           |  903 +--
 po/nn.po                                           |  828 +--
 po/nso.po                                          |  828 +--
 po/oc.po                                           |  825 +--
 po/or.po                                           |  847 +--
 po/pa.po                                           |  881 +--
 po/pl.po                                           | 1261 ++--
 po/ps.po                                           |  824 +--
 po/pt.po                                           |  902 +--
 po/pt_BR.po                                        |  889 +--
 po/ro.po                                           |  920 +--
 po/ru.po                                           |  957 +--
 po/rw.po                                           |  828 +--
 po/si.po                                           |  828 +--
 po/sk.po                                           |  828 +--
 po/sl.po                                           |  898 +--
 po/sq.po                                           |  828 +--
 po/sr.po                                           |  882 +--
 po/sr ije po                                       |  828 +--
 po/sr latin po                                     |  882 +--
 po/sv.po                                           |  857 +--
 po/ta.po                                           |  828 +--
 po/te.po                                           |  828 +--
 po/th.po                                           |  833 +--
 po/tk.po                                           |  824 +--
 po/tr.po                                           |  830 +--
 po/tt.po                                           |  824 +--
 po/uk.po                                           | 3117 +++-----
 po/ur.po                                           |  824 +--
 po/uz.po                                           |  824 +--
 po/uz cyrillic po                                  |  824 +--
 po/vi.po                                           |  887 +--
 po/wa.po                                           |  828 +--
 po/xh.po                                           |  828 +--
 po/yi.po                                           |  828 +--
 po/zh_CN.po                                        |  828 +--
 po/zh_HK.po                                        |  916 +--
 po/zh_TW.po                                        |  918 +--
 sanitize-la.sh                                     |    5 +-
 tests/Makefile.am                                  |    3 +
 tests/extendedlayoutexample.c                      |  620 ++
 tests/gtkoffscreenbox.c                            |   42 +-
 tests/multidevice/testphotoalbumwidget.c           |    4 +-
 tests/testassistant.c                              |   10 +-
 tests/testcalendar.c                               |    2 +-
 tests/testellipsise.c                              |  121 +-
 tests/testgtk.c                                    |  238 +-
 tests/testinput.c                                  |   12 +-
 tests/testmenubars.c                               |   12 +-
 tests/testmenus.c                                  |    4 +-
 tests/testoffscreenwindow.c                        |    2 +-
 tests/testrecentchoosermenu.c                      |    2 +-
 tests/testsocket_common.c                          |    2 +-
 tests/testtext.c                                   |   10 +-
 620 files changed, 104620 insertions(+), 104213 deletions(-)
---
diff --cc gdk/gdk.symbols
index f073d0a,bb6e2b2..039ac35
--- a/gdk/gdk.symbols
+++ b/gdk/gdk.symbols
@@@ -717,9 -696,8 +719,10 @@@ gdk_window_freeze_update
  gdk_window_get_children
  gdk_window_get_internal_paint_info
  gdk_window_get_parent
+ gdk_window_get_effective_parent
 +#ifndef GDK_MULTIDEVICE_SAFE
  gdk_window_get_pointer
 +#endif
  gdk_window_get_position
  gdk_window_get_state
  gdk_window_get_toplevel
diff --cc gdk/gdkwindow.c
index 8979de0,e264feb..43f7e74
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@@ -9256,45 -9179,11 +9471,12 @@@ update_cursor (GdkDisplay *display
  
    /* Set all cursors on toplevel, otherwise its tricky to keep track of
     * which native window has what cursor set. */
 -  toplevel = (GdkWindowObject *)get_event_toplevel (pointer_window);
 +  toplevel = (GdkWindowObject *) get_event_toplevel (pointer_window);
    impl_iface = GDK_WINDOW_IMPL_GET_IFACE (toplevel->impl);
 -  impl_iface->set_cursor ((GdkWindow *)toplevel, cursor_window->cursor);
 +  impl_iface->set_device_cursor ((GdkWindow *) toplevel, device,
 +                                 cursor_window->cursor);
  }
  
- static void
- from_embedder (GdkWindowObject *window,
- 	       gdouble          embedder_x,
-                gdouble          embedder_y,
- 	       gdouble         *offscreen_x,
-                gdouble         *offscreen_y)
- {
-   g_signal_emit (window,
- 		 signals[FROM_EMBEDDER], 0,
- 		 embedder_x, embedder_y,
- 		 offscreen_x, offscreen_y,
- 		 NULL);
- }
- 
- static void
- convert_coords_to_child (GdkWindowObject *child,
- 			 gdouble          x,
-                          gdouble          y,
- 			 gdouble         *child_x,
-                          gdouble         *child_y)
- {
-   if (gdk_window_is_offscreen (child))
-     {
-       from_embedder (child, x, y,
- 		     child_x, child_y);
-     }
-   else
-     {
-       *child_x = x - child->x;
-       *child_y = y - child->y;
-     }
- }
- 
  static gboolean
  point_in_window (GdkWindowObject *window,
  		 gdouble          x,
diff --cc gtk/gtkbutton.c
index bec7a08,37367b3..4ebe9a0
--- a/gtk/gtkbutton.c
+++ b/gtk/gtkbutton.c
@@@ -1752,21 -1718,14 +1719,21 @@@ gtk_real_button_activate (GtkButton *bu
    guint32 time;
  
    priv = GTK_BUTTON_GET_PRIVATE (button);
 +  device = gtk_get_current_event_device ();
 +
 +  g_return_if_fail (device && device->source == GDK_SOURCE_KEYBOARD);
  
-   if (GTK_WIDGET_REALIZED (button) && !button->activate_timeout)
+   if (gtk_widget_get_realized (widget) && !button->activate_timeout)
      {
        time = gtk_get_current_event_time ();
 -      if (gdk_keyboard_grab (button->event_window, TRUE, time) == 
 -	  GDK_GRAB_SUCCESS)
 -	{
 -	  priv->has_grab = TRUE;
 +
 +      if (gdk_device_grab (device, button->event_window,
 +                           GDK_OWNERSHIP_WINDOW, TRUE,
 +                           GDK_KEY_PRESS | GDK_KEY_RELEASE,
 +                           NULL, time) == GDK_GRAB_SUCCESS)
 +        {
 +          gtk_device_grab_add (widget, device, TRUE);
 +	  priv->grab_keyboard = device;
  	  priv->grab_time = time;
  	}
  
diff --cc gtk/gtkcombobox.c
index fec0d63,fd92dd0..c6b930d
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@@ -1927,34 -1910,13 +1927,34 @@@ gtk_combo_box_popup_for_device (GtkComb
    gint x, y, width, height;
    GtkTreePath *path = NULL, *ppath;
    GtkWidget *toplevel;
 +  GdkDevice *keyboard, *pointer;
 +  guint32 time;
 +
 +  g_return_if_fail (GTK_IS_COMBO_BOX (combo_box));
 +  g_return_if_fail (GDK_IS_DEVICE (device));
  
-   if (!GTK_WIDGET_REALIZED (combo_box))
+   if (!gtk_widget_get_realized (GTK_WIDGET (combo_box)))
      return;
  
-   if (GTK_WIDGET_MAPPED (priv->popup_widget))
+   if (gtk_widget_get_mapped (priv->popup_widget))
      return;
  
 +  if (priv->grab_pointer && priv->grab_keyboard)
 +    return;
 +
 +  time = gtk_get_current_event_time ();
 +
 +  if (device->source == GDK_SOURCE_KEYBOARD)
 +    {
 +      keyboard = device;
 +      pointer = gdk_device_get_associated_device (device);
 +    }
 +  else
 +    {
 +      pointer = device;
 +      keyboard = gdk_device_get_associated_device (device);
 +    }
 +
    if (GTK_IS_MENU (priv->popup_widget))
      {
        gtk_combo_box_menu_popup (combo_box, 
@@@ -2076,10 -2011,10 +2076,10 @@@ gtk_combo_box_popdown (GtkComboBox *com
        return;
      }
  
-   if (!GTK_WIDGET_REALIZED (GTK_WIDGET (combo_box)))
+   if (!gtk_widget_get_realized (GTK_WIDGET (combo_box)))
      return;
  
 -  gtk_grab_remove (priv->popup_window);
 +  gtk_device_grab_remove (priv->popup_window, priv->grab_pointer);
    gtk_widget_hide_all (priv->popup_window);
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button),
                                  FALSE);
@@@ -3958,10 -3893,10 +3961,10 @@@ gtk_combo_box_list_button_pressed (GtkW
      return FALSE;
  
    if (priv->focus_on_click && 
-       !GTK_WIDGET_HAS_FOCUS (priv->button))
+       !gtk_widget_has_focus (priv->button))
      gtk_widget_grab_focus (priv->button);
  
 -  gtk_combo_box_popup (combo_box);
 +  gtk_combo_box_popup_for_device (combo_box, event->device);
  
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE);
  
diff --cc gtk/gtkentry.c
index 7dc86f5,20653b4..70dc1d7
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@@ -9255,10 -9271,10 +9274,10 @@@ gtk_entry_completion_timeout (gpointer 
        g_object_get (completion, "popup-single-match", &popup_single, NULL);
        if ((matches > (popup_single ? 0: 1)) || actions > 0)
  	{ 
- 	  if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
+ 	  if (gtk_widget_get_visible (completion->priv->popup_window))
  	    _gtk_entry_completion_resize_popup (completion);
            else
 -	    _gtk_entry_completion_popup (completion);
 +	    _gtk_entry_completion_popup (completion, priv->completion_device);
  	}
        else 
  	_gtk_entry_completion_popdown (completion);
diff --cc gtk/gtkentrycompletion.c
index a76cf56,68b758a..e9475fb
--- a/gtk/gtkentrycompletion.c
+++ b/gtk/gtkentrycompletion.c
@@@ -1475,18 -1474,15 +1475,18 @@@ _gtk_entry_completion_popup (GtkEntryCo
    GList *renderers;
    GtkWidget *toplevel;
  
-   if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
+   if (gtk_widget_get_mapped (completion->priv->popup_window))
      return;
  
-   if (!GTK_WIDGET_MAPPED (completion->priv->entry))
+   if (!gtk_widget_get_mapped (completion->priv->entry))
      return;
  
-   if (!GTK_WIDGET_HAS_FOCUS (completion->priv->entry))
+   if (!gtk_widget_has_focus (completion->priv->entry))
      return;
  
 +  if (completion->priv->grab_device)
 +    return;
 +
    completion->priv->ignore_enter = TRUE;
      
    column = gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0);
diff --cc gtk/gtkmain.c
index 5e5eaaf,082eb0f..4f5cc87
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@@ -1514,36 -1524,11 +1515,34 @@@ gtk_main_do_event (GdkEvent *event
  	  gtk_widget_is_ancestor (event_widget, grab_widget))
  	grab_widget = event_widget;
      }
 -  else
 +  else if (device)
 +    {
 +      grab_widget = gtk_window_group_get_current_device_grab (window_group, device);
 +
-       if (grab_widget)
-         {
-           if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
-               gtk_widget_is_ancestor (event_widget, grab_widget))
-             grab_widget = event_widget;
-         }
++      if (grab_widget &&
++          gtk_widget_get_sensitive (event_widget) &&
++          gtk_widget_is_ancestor (event_widget, grab_widget))
++        grab_widget = event_widget;
 +    }
 +
 +  if (!grab_widget)
 +    grab_widget = event_widget;
 +
 +  /* If the widget receiving events is actually blocked by another device GTK+ grab */
 +  if (device &&
 +      _gtk_window_group_widget_is_blocked_for_device (window_group, grab_widget, device))
      {
 -      grab_widget = event_widget;
 +      if (rewritten_event)
 +        gdk_event_free (rewritten_event);
 +
 +      return;
      }
  
 +  /* Push the event onto a stack of current events for
 +   * gtk_current_event_get().
 +   */
 +  current_events = g_list_prepend (current_events, event);
 +
    /* Not all events get sent to the grabbing widget.
     * The delete, destroy, expose, focus change and resize
     *  events still get sent to the event widget because
@@@ -1664,18 -1649,15 +1663,18 @@@
        break;
        
      case GDK_ENTER_NOTIFY:
 -      GTK_PRIVATE_SET_FLAG (event_widget, GTK_HAS_POINTER);
 -      _gtk_widget_set_pointer_window (event_widget, event->any.window);
 +      _gtk_widget_set_device_window (event_widget,
 +                                     gdk_event_get_device (event),
 +                                     event->any.window);
-       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
+       if (gtk_widget_is_sensitive (grab_widget))
  	gtk_widget_event (grab_widget, event);
        break;
        
      case GDK_LEAVE_NOTIFY:
 -      GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_HAS_POINTER);
 +      _gtk_widget_set_device_window (event_widget,
 +                                     gdk_event_get_device (event),
 +                                     NULL);
-       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
+       if (gtk_widget_is_sensitive (grab_widget))
  	gtk_widget_event (grab_widget, event);
        break;
        
@@@ -1843,21 -1759,19 +1842,21 @@@ gtk_grab_notify_foreach (GtkWidget *chi
    if (is_shadowed)
      {
        GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
 -      if (!was_shadowed && GTK_WIDGET_HAS_POINTER (child)
 -	  && gtk_widget_is_sensitive (child))
 -	_gtk_widget_synthesize_crossing (child, info->new_grab_widget,
 -					 GDK_CROSSING_GTK_GRAB);
 +      if (!was_shadowed && devices &&
- 	  GTK_WIDGET_IS_SENSITIVE (child))
++	  gtk_widget_is_sensitive (child))
 +        synth_crossing_for_grab_notify (child, info->new_grab_widget,
 +                                        info, devices,
 +                                        GDK_CROSSING_GTK_GRAB);
      }
    else
      {
        GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
 -      if (was_shadowed && GTK_WIDGET_HAS_POINTER (child)
 -	  && gtk_widget_is_sensitive (child))
 -	_gtk_widget_synthesize_crossing (info->old_grab_widget, child,
 -					 info->from_grab ? GDK_CROSSING_GTK_GRAB
 -					 : GDK_CROSSING_GTK_UNGRAB);
 +      if (was_shadowed && devices &&
- 	  GTK_WIDGET_IS_SENSITIVE (child))
++          gtk_widget_is_sensitive (child))
 +        synth_crossing_for_grab_notify (info->old_grab_widget, child,
 +                                        info, devices,
 +                                        info->from_grab ? GDK_CROSSING_GTK_GRAB :
 +                                        GDK_CROSSING_GTK_UNGRAB);
      }
  
    if (was_shadowed != is_shadowed)
diff --cc gtk/gtkmenu.c
index eed2feb,b5b9820..995d257
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@@ -1406,13 -1395,12 +1406,13 @@@ popup_grab_on_window (GdkWindow *window
  }
  
  /**
 - * gtk_menu_popup:
 + * gtk_menu_popup_for_device:
   * @menu: a #GtkMenu.
-  * @device: a #GdkDevice
-  * @parent_menu_shell: the menu shell containing the triggering menu item, or %NULL
-  * @parent_menu_item: the menu item whose activation triggered the popup, or %NULL
-  * @func: a user supplied function used to position the menu, or %NULL
-  * @data: user supplied data to be passed to @func.
++ * @device: (allow-none): a #GdkDevice
+  * @parent_menu_shell: (allow-none): the menu shell containing the triggering menu item, or %NULL
+  * @parent_menu_item: (allow-none): the menu item whose activation triggered the popup, or %NULL
+  * @func: (allow-none): a user supplied function used to position the menu, or %NULL
+  * @data: (allow-none): user supplied data to be passed to @func.
   * @button: the mouse button which was pressed to initiate the event.
   * @activate_time: the time at which the activation event occurred.
   *
@@@ -1667,71 -1630,6 +1667,71 @@@ gtk_menu_popup_for_device (GtkMen
    _gtk_menu_shell_update_mnemonics (menu_shell);
  }
  
 +/**
 + * gtk_menu_popup:
 + * @menu: a #GtkMenu.
-  * @parent_menu_shell: the menu shell containing the triggering menu item, or %NULL
-  * @parent_menu_item: the menu item whose activation triggered the popup, or %NULL
-  * @func: a user supplied function used to position the menu, or %NULL
-  * @data: user supplied data to be passed to @func.
++ * @parent_menu_shell: (allow-none): the menu shell containing the triggering menu item, or %NULL
++ * @parent_menu_item: (allow-none): the menu item whose activation triggered the popup, or %NULL
++ * @func: (allow-none): a user supplied function used to position the menu, or %NULL
++ * @data: (allow-none): user supplied data to be passed to @func.
 + * @button: the mouse button which was pressed to initiate the event.
 + * @activate_time: the time at which the activation event occurred.
 + *
 + * Displays a menu and makes it available for selection.  Applications can use
 + * this function to display context-sensitive menus, and will typically supply
 + * %NULL for the @parent_menu_shell, @parent_menu_item, @func and @data 
 + * parameters. The default menu positioning function will position the menu
 + * at the current mouse cursor position.
 + *
 + * The @button parameter should be the mouse button pressed to initiate
 + * the menu popup. If the menu popup was initiated by something other than
 + * a mouse button press, such as a mouse button release or a keypress,
 + * @button should be 0.
 + *
 + * The @activate_time parameter is used to conflict-resolve initiation of
 + * concurrent requests for mouse/keyboard grab requests. To function
 + * properly, this needs to be the time stamp of the user event (such as
 + * a mouse click or key press) that caused the initiation of the popup.
 + * Only if no such event is available, gtk_get_current_event_time() can
 + * be used instead.
 + */
 +void
 +gtk_menu_popup (GtkMenu		    *menu,
 +		GtkWidget	    *parent_menu_shell,
 +		GtkWidget	    *parent_menu_item,
 +		GtkMenuPositionFunc  func,
 +		gpointer	     data,
 +		guint		     button,
 +		guint32		     activate_time)
 +{
 +  GdkDevice *device;
 +
 +  g_return_if_fail (GTK_IS_MENU (menu));
 +
 +  device = gtk_get_current_event_device ();
 +
 +  if (!device)
 +    {
 +      GdkDisplay *display;
 +      GdkDeviceManager *device_manager;
 +      GList *devices;
 +
 +      display = gtk_widget_get_display (GTK_WIDGET (menu));
 +      device_manager = gdk_display_get_device_manager (display);
 +      devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 +
 +      device = devices->data;
 +
 +      g_list_free (devices);
 +    }
 +
 +  gtk_menu_popup_for_device (menu, device,
 +                             parent_menu_shell,
 +                             parent_menu_item,
 +                             func, data,
 +                             button, activate_time);
 +}
 +
  void
  gtk_menu_popdown (GtkMenu *menu)
  {
@@@ -4081,11 -3972,9 +4084,11 @@@ gtk_menu_stop_navigating_submenu_cb (gp
  
    gtk_menu_stop_navigating_submenu (menu);
    
-   if (GTK_WIDGET_REALIZED (menu))
+   if (gtk_widget_get_realized (GTK_WIDGET (menu)))
      {
 -      child_window = gdk_window_get_pointer (menu->bin_window, NULL, NULL, NULL);
 +      child_window = gdk_window_get_device_position (menu->bin_window,
 +                                                     popdown_data->device,
 +                                                     NULL, NULL, NULL);
  
        if (child_window)
  	{
diff --cc gtk/gtkmenushell.c
index da94b60,c3e107f..615f9a4
--- a/gtk/gtkmenushell.c
+++ b/gtk/gtkmenushell.c
@@@ -135,11 -135,12 +135,15 @@@ struct _GtkMenuShellPrivat
    GtkMnemonicHash *mnemonic_hash;
    GtkKeyHash *key_hash;
  
 +  GdkDevice *grab_keyboard;
 +  GdkDevice *grab_pointer;
 +
    guint take_focus : 1;
    guint activated_submenu : 1;
+   /* This flag is a crutch to keep mnemonics in the same menu
+    * if the user moves the mouse over an unselectable menuitem.
+    */
+   guint in_unselectable_item : 1;
  };
  
  static void gtk_menu_shell_set_property      (GObject           *object,
diff --cc gtk/gtkprivate.h
index ded69e0,4c5efb3..8db5c48
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@@ -35,18 -35,22 +35,21 @@@ G_BEGIN_DECL
   */
  typedef enum
  {
-   PRIVATE_GTK_USER_STYLE	= 1 <<  0,
-   PRIVATE_GTK_RESIZE_PENDING	= 1 <<  2,
-   PRIVATE_GTK_SHADOWED		= 1 <<  4,   /* If there is a grab in effect shadowing the widget */
-   PRIVATE_GTK_HAS_SHAPE_MASK	= 1 <<  5,
-   PRIVATE_GTK_IN_REPARENT       = 1 <<  6,
-   PRIVATE_GTK_DIRECTION_SET     = 1 <<  7,   /* If the reading direction is not DIR_NONE */
-   PRIVATE_GTK_DIRECTION_LTR     = 1 <<  8,   /* If the reading direction is DIR_LTR */
-   PRIVATE_GTK_ANCHORED          = 1 <<  9,   /* If widget has a GtkWindow ancestor */
-   PRIVATE_GTK_CHILD_VISIBLE     = 1 <<  10,  /* If widget should be mapped when parent is mapped */
-   PRIVATE_GTK_REDRAW_ON_ALLOC   = 1 <<  11,  /* If we should queue a draw on the entire widget when it is reallocated */
-   PRIVATE_GTK_ALLOC_NEEDED      = 1 <<  12,  /* If we we should allocate even if the allocation is the same */
-   PRIVATE_GTK_REQUEST_NEEDED    = 1 <<  13   /* Whether we need to call gtk_widget_size_request */
+   PRIVATE_GTK_USER_STYLE            = 1 <<  0,
+   PRIVATE_GTK_RESIZE_PENDING        = 1 <<  2,
+   PRIVATE_GTK_HAS_POINTER           = 1 <<  3,   /* If the pointer is above a window belonging to the widget */
+   PRIVATE_GTK_SHADOWED		    = 1 <<  4,   /* If there is a grab in effect shadowing the widget */
+   PRIVATE_GTK_HAS_SHAPE_MASK	    = 1 <<  5,
+   PRIVATE_GTK_IN_REPARENT           = 1 <<  6,
+   PRIVATE_GTK_DIRECTION_SET         = 1 <<  7,   /* If the reading direction is not DIR_NONE */
+   PRIVATE_GTK_DIRECTION_LTR         = 1 <<  8,   /* If the reading direction is DIR_LTR */
+   PRIVATE_GTK_ANCHORED              = 1 <<  9,   /* If widget has a GtkWindow ancestor */
+   PRIVATE_GTK_CHILD_VISIBLE         = 1 <<  10,  /* If widget should be mapped when parent is mapped */
+   PRIVATE_GTK_REDRAW_ON_ALLOC       = 1 <<  11,  /* If we should queue a draw on the entire widget when it is reallocated */
+   PRIVATE_GTK_ALLOC_NEEDED          = 1 <<  12,  /* If we we should allocate even if the allocation is the same */
+   PRIVATE_GTK_REQUEST_NEEDED        = 1 <<  13,  /* Whether we need to call gtk_widget_size_request */
+   PRIVATE_GTK_WIDTH_REQUEST_NEEDED  = 1 <<  14,  /* Whether we need to call gtk_extended_layout_get_desired_width */
+   PRIVATE_GTK_HEIGHT_REQUEST_NEEDED = 1 <<  15   /* Whether we need to call gtk_extended_layout_get_desired_height */
 -
  } GtkPrivateFlags;
  
  /* Macros for extracting a widgets private_flags from GtkWidget.
diff --cc gtk/gtkrange.c
index 6d0875b,552eac7..ffbefe8
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@@ -2207,9 -2180,8 +2206,9 @@@ gtk_range_button_press (GtkWidget      
  			GdkEventButton *event)
  {
    GtkRange *range = GTK_RANGE (widget);
 +  GdkDevice *device;
    
-   if (!GTK_WIDGET_HAS_FOCUS (widget))
+   if (!gtk_widget_has_focus (widget))
      gtk_widget_grab_focus (widget);
  
    /* ignore presses when we're already doing something else. */
diff --cc gtk/gtktextview.c
index e6b830c,e286101..b4aa731
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@@ -109,7 -109,7 +109,8 @@@ struct _GtkTextViewPrivat
    guint blink_time;  /* time in msec the cursor has blinked since last user event */
    guint im_spot_idle;
    gchar *im_module;
 +  GdkDevice *grab_device;
+   guint scroll_after_paste : 1;
  };
  
  
diff --cc gtk/gtktreeview.c
index 2d5064b,f464ec4..6b517bc
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@@ -10267,54 -10264,17 +10271,43 @@@ gtk_tree_view_search_entry_flush_timeou
  /* Cut and paste from gtkwindow.c */
  static void
  send_focus_change (GtkWidget *widget,
 +                   GdkDevice *device,
  		   gboolean   in)
  {
 -  GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
 +  GdkDeviceManager *device_manager;
 +  GList *devices, *d;
  
-   g_object_ref (widget);
- 
-   if (in)
-     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
-   else
-     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
- 
 -  fevent->focus_change.type = GDK_FOCUS_CHANGE;
 -  fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget));
 -  fevent->focus_change.in = in;
 +  device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
 +  devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 +  devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
 +  devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
  
 -  gtk_widget_send_focus_change (widget, fevent);
 +  for (d = devices; d; d = d->next)
 +    {
 +      GdkDevice *dev = d->data;
 +      GdkEvent *fevent;
  
 -  gdk_event_free (fevent);
 +      if (dev->source != GDK_SOURCE_KEYBOARD)
 +        continue;
 +
 +      /* Skip non-master keyboards that haven't
 +       * selected for events from this window
 +       */
 +      if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
 +          !gdk_window_get_device_events (widget->window, dev))
 +        continue;
 +
 +      fevent = gdk_event_new (GDK_FOCUS_CHANGE);
 +
 +      fevent->focus_change.type = GDK_FOCUS_CHANGE;
 +      fevent->focus_change.window = g_object_ref (widget->window);
 +      fevent->focus_change.in = in;
 +      gdk_event_set_device (fevent, device);
 +
-       gtk_widget_event (widget, fevent);
++      gtk_widget_send_focus_change (widget, fevent);
 +
 +      gdk_event_free (fevent);
 +    }
- 
-   g_object_notify (G_OBJECT (widget), "has-focus");
- 
-   g_object_unref (widget);
  }
  
  static void
@@@ -14207,13 -14163,13 +14200,13 @@@ gtk_tree_view_search_dialog_hide (GtkWi
        tree_view->priv->typeselect_flush_timeout = 0;
      }
  	
-   if (GTK_WIDGET_VISIBLE (search_dialog))
+   if (gtk_widget_get_visible (search_dialog))
      {
        /* send focus-in event */
 -      send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
 +      send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
        gtk_widget_hide (search_dialog);
        gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
 -      send_focus_change (GTK_WIDGET (tree_view), TRUE);
 +      send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
      }
  }
  
diff --cc gtk/gtkwidget.c
index 6125eb6,b27207c..d862aaf
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@@ -5826,60 -5758,6 +5882,60 @@@ _gtk_widget_set_has_grab (GtkWidget *wi
  }
  
  /**
 + * gtk_widget_device_is_shadowed:
 + * @widget: a #GtkWidget
 + * @device: a #GdkDevice
 + *
 + * Returns %TRUE if @device has been shadowed by a GTK+
 + * device grab on another widget, so it would stop sending
 + * events to @widget. This may be used in the
 + * #GtkWidget::grab-notify signal to check for specific
 + * devices. See gtk_device_grab_add().
 + *
 + * Returns: %TRUE if there is an ongoing grab on @device
 + *          by another #GtkWidget than @widget.
 + **/
 +gboolean
 +gtk_widget_device_is_shadowed (GtkWidget *widget,
 +                               GdkDevice *device)
 +{
 +  GtkWindowGroup *group;
 +  GtkWidget *grab_widget, *toplevel;
 +
 +  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), FALSE);
 +
-   if (!GTK_WIDGET_REALIZED (widget))
++  if (!gtk_widget_get_realized (widget))
 +    return TRUE;
 +
 +  toplevel = gtk_widget_get_toplevel (widget);
 +
 +  if (GTK_IS_WINDOW (toplevel))
 +    group = gtk_window_get_group (GTK_WINDOW (toplevel));
 +  else
 +    group = gtk_window_get_group (NULL);
 +
 +  grab_widget = gtk_window_group_get_current_device_grab (group, device);
 +
 +  /* Widget not inside the hierarchy of grab_widget */
 +  if (grab_widget &&
 +      widget != grab_widget &&
 +      !gtk_widget_is_ancestor (widget, grab_widget))
 +    return TRUE;
 +
 +  if (group->grabs)
 +    {
 +      grab_widget = group->grabs->data;
 +
 +      if (widget != grab_widget &&
 +          !gtk_widget_is_ancestor (widget, grab_widget))
 +        return TRUE;
 +    }
 +
 +  return FALSE;
 +}
 +
 +/**
   * gtk_widget_set_name:
   * @widget: a #GtkWidget
   * @name: name for the widget
@@@ -9066,36 -8972,18 +9151,36 @@@ _gtk_widget_peek_colormap (void
   * Actually stores it on the #GdkScreen, but you don't need to know that.
   */
  void
 -_gtk_widget_set_pointer_window (GtkWidget *widget,
 -                                GdkWindow *pointer_window)
 +_gtk_widget_set_device_window (GtkWidget *widget,
 +                               GdkDevice *device,
 +                               GdkWindow *window)
  {
 +  GdkScreen *screen;
 +  GHashTable *device_window;
 +
    g_return_if_fail (GTK_IS_WIDGET (widget));
 +  g_return_if_fail (GDK_IS_DEVICE (device));
 +  g_return_if_fail (!window || GDK_IS_WINDOW (window));
  
-   if (!GTK_WIDGET_REALIZED (widget))
 -  if (gtk_widget_get_realized (widget))
 -    {
 -      GdkScreen *screen = gdk_drawable_get_screen (widget->window);
++  if (!gtk_widget_get_realized (widget))
 +    return;
  
 -      g_object_set_qdata (G_OBJECT (screen), quark_pointer_window,
 -                          pointer_window);
 +  screen = gdk_drawable_get_screen (widget->window);
 +  device_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
 +
 +  if (G_UNLIKELY (!device_window))
 +    {
 +      device_window = g_hash_table_new (NULL, NULL);
 +      g_object_set_qdata_full (G_OBJECT (screen),
 +                               quark_pointer_window,
 +                               device_window,
 +                               (GDestroyNotify) g_hash_table_destroy);
      }
 +
 +  if (window)
 +    g_hash_table_insert (device_window, device, window);
 +  else
 +    g_hash_table_remove (device_window, device);
  }
  
  /*
@@@ -9107,85 -8994,18 +9192,85 @@@
   * to, or %NULL.
   */
  GdkWindow *
 -_gtk_widget_get_pointer_window (GtkWidget *widget)
 +_gtk_widget_get_device_window (GtkWidget *widget,
 +                               GdkDevice *device)
  {
 +  GdkScreen *screen;
 +  GHashTable *device_window;
 +  GdkWindow *window;
 +  GtkWidget *w;
 +
    g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
  
-   if (!GTK_WIDGET_REALIZED (widget))
 -  if (gtk_widget_get_realized (widget))
++  if (!gtk_widget_get_realized (widget))
 +    return NULL;
 +
 +  screen = gdk_drawable_get_screen (widget->window);
 +  device_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
 +
 +  if (G_UNLIKELY (!device_window))
 +    return NULL;
 +
 +  window = g_hash_table_lookup (device_window, device);
 +
 +  if (!window)
 +    return NULL;
 +
 +  gdk_window_get_user_data (window, (gpointer *) &w);
 +
 +  if (widget != w)
 +    return NULL;
 +
 +  return window;
 +}
 +
 +/*
 + * _gtk_widget_list_devices:
 + * @widget: a #GtkWidget.
 + *
 + * Returns the list of #GdkDevices that is currently on top of any widget #GdkWindow.
 + * Free the list with g_list_free(), the elements are owned by GTK+ and must not
 + * be freed.
 + */
 +GList *
 +_gtk_widget_list_devices (GtkWidget *widget)
 +{
 +  GdkScreen *screen;
 +  GHashTableIter iter;
 +  GHashTable *device_window;
 +  GList *devices = NULL;
 +  gpointer key, value;
 +
 +  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
 +
-   if (!GTK_WIDGET_REALIZED (widget))
++  if (!gtk_widget_get_realized (widget))
 +    return NULL;
 +
 +  screen = gdk_drawable_get_screen (widget->window);
 +  device_window = g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
 +
 +  if (G_UNLIKELY (!device_window))
 +    return NULL;
 +
 +  g_hash_table_iter_init (&iter, device_window);
 +
 +  while (g_hash_table_iter_next (&iter, &key, &value))
      {
 -      GdkScreen *screen = gdk_drawable_get_screen (widget->window);
 +      GdkDevice *device = key;
 +      GdkWindow *window = value;
 +      GtkWidget *w;
  
 -      return g_object_get_qdata (G_OBJECT (screen), quark_pointer_window);
 +      if (window)
 +        {
 +          gdk_window_get_user_data (window, (gpointer *) &w);
 +
 +          if (widget == w)
 +            devices = g_list_prepend (devices, device);
 +        }
      }
  
 -  return NULL;
 +  return devices;
  }
  
  static void
@@@ -9466,41 -9300,15 +9551,41 @@@ gtk_widget_propagate_state (GtkWidge
  
        g_signal_emit (widget, widget_signals[STATE_CHANGED], 0, old_state);
  
 -      if (GTK_WIDGET_HAS_POINTER (widget) && !GTK_WIDGET_SHADOWED (widget))
 -	{
 -	  if (!gtk_widget_is_sensitive (widget))
 -	    _gtk_widget_synthesize_crossing (widget, NULL, 
 -					     GDK_CROSSING_STATE_CHANGED);
 -	  else if (old_state == GTK_STATE_INSENSITIVE)
 -	    _gtk_widget_synthesize_crossing (NULL, widget, 
 -					     GDK_CROSSING_STATE_CHANGED);
 -	}
 +      if (!GTK_WIDGET_SHADOWED (widget))
 +        {
 +          GList *event_windows = NULL;
 +          GList *devices, *d;
 +
 +          devices = _gtk_widget_list_devices (widget);
 +
 +          for (d = devices; d; d = d->next)
 +            {
 +              GdkWindow *window;
 +              GdkDevice *device;
 +
 +              device = d->data;
 +              window = _gtk_widget_get_device_window (widget, device);
 +
 +              /* Do not propagate more than once to the
 +               * same window if non-multidevice aware.
 +               */
 +              if (!gdk_window_get_support_multidevice (window) &&
 +                  g_list_find (event_windows, window))
 +                continue;
 +
-               if (!GTK_WIDGET_IS_SENSITIVE (widget))
++              if (!gtk_widget_is_sensitive (widget))
 +                _gtk_widget_synthesize_crossing (widget, NULL, d->data,
 +                                                 GDK_CROSSING_STATE_CHANGED);
 +              else if (old_state == GTK_STATE_INSENSITIVE)
 +                _gtk_widget_synthesize_crossing (NULL, widget, d->data,
 +                                                 GDK_CROSSING_STATE_CHANGED);
 +
 +              event_windows = g_list_prepend (event_windows, window);
 +            }
 +
 +          g_list_free (event_windows);
 +          g_list_free (devices);
 +        }
  
        if (GTK_IS_CONTAINER (widget))
  	{
@@@ -11529,304 -11421,71 +11698,370 @@@ gtk_widget_get_window (GtkWidget *widge
    return widget->window;
  }
  
 +/**
 + * gtk_widget_get_support_multidevice:
 + * @widget: a #GtkWidget
 + *
 + * Returns %TRUE if @widget is multiple pointer aware. See
 + * gtk_widget_set_support_multidevice() for more information.
 + *
 + * Returns: %TRUE is @widget is multidevice aware.
 + **/
 +gboolean
 +gtk_widget_get_support_multidevice (GtkWidget *widget)
 +{
 +  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
 +
 +  return GTK_WIDGET_FLAGS (widget) & GTK_MULTIDEVICE;
 +}
 +
 +/**
 + * gtk_widget_set_support_multidevice:
 + * @widget: a #GtkWidget
 + * @support_multidevice: %TRUE to support input from multiple devices.
 + *
 + * Enables or disables multiple pointer awareness. If this setting is %TRUE,
 + * @widget will start receiving multiple, per device enter/leave events. Note
 + * that if custom #GdkWindow<!-- -->s are created in #GtkWidget::realize,
 + * gdk_window_set_support_multidevice() will have to be called manually on them.
 + **/
 +void
 +gtk_widget_set_support_multidevice (GtkWidget *widget,
 +                                    gboolean   support_multidevice)
 +{
 +  g_return_if_fail (GTK_IS_WIDGET (widget));
 +
 +  if (support_multidevice)
 +    {
 +      GTK_WIDGET_SET_FLAGS (widget, GTK_MULTIDEVICE);
 +      gtk_widget_set_extension_events (widget, GDK_EXTENSION_EVENTS_ALL);
 +    }
 +  else
 +    {
 +      GTK_WIDGET_UNSET_FLAGS (widget, GTK_MULTIDEVICE);
 +      gtk_widget_set_extension_events (widget, GDK_EXTENSION_EVENTS_NONE);
 +    }
 +
-   if (GTK_WIDGET_REALIZED (widget))
++  if (gtk_widget_get_realized (widget))
 +    gdk_window_set_support_multidevice (widget->window, support_multidevice);
 +}
 +
 +static GdkEventMotion *
 +convert_event_to_motion (GdkEvent *event)
 +{
 +  GdkEventMotion *new_event;
 +
 +  new_event = (GdkEventMotion *) gdk_event_new (GDK_MOTION_NOTIFY);
 +
 +  switch (event->type)
 +    {
 +    case GDK_BUTTON_PRESS:
 +    case GDK_2BUTTON_PRESS:
 +    case GDK_3BUTTON_PRESS:
 +    case GDK_BUTTON_RELEASE:
 +      new_event->window = g_object_ref (event->button.window);
 +      new_event->send_event = TRUE;
 +      new_event->time = event->button.time;
 +      new_event->x = event->button.x;
 +      new_event->y = event->button.y;
 +
 +      if (event->button.axes)
 +	new_event->axes = g_memdup (event->button.axes,
 +                                    sizeof (gdouble) * event->button.device->num_axes);
 +
 +      new_event->state = 0; /* FIXME */
 +      new_event->is_hint = FALSE;
 +      new_event->device = event->button.device;
 +      new_event->x_root = event->button.x_root;
 +      new_event->y_root = event->button.y_root;
 +      break;
 +    case GDK_ENTER_NOTIFY:
 +    case GDK_LEAVE_NOTIFY:
 +      new_event->window = g_object_ref (event->crossing.window);
 +      new_event->send_event = TRUE;
 +      new_event->time = event->crossing.time;
 +      new_event->x = event->crossing.x;
 +      new_event->y = event->crossing.y;
 +      new_event->axes = NULL; /* FIXME: not ideal for non-mice */
 +      new_event->state = 0; /* FIXME */
 +      new_event->is_hint = FALSE;
 +      new_event->x_root = event->crossing.x_root;
 +      new_event->y_root = event->crossing.y_root;
 +      gdk_event_set_device ((GdkEvent *) new_event, gdk_event_get_device ((GdkEvent *) event));
 +      break;
 +    default:
 +      g_warning ("Event with type %d can not be transformed to GdkEventMotion", event->type);
 +      gdk_event_free ((GdkEvent *) new_event);
 +      new_event = NULL;
 +    }
 +
 +  return new_event;
 +}
 +
 +static void
 +device_group_device_added (GtkDeviceGroup *group,
 +                           GdkDevice      *device,
 +                           GtkWidget      *widget)
 +{
 +  GtkMultiDeviceData *data;
 +  GtkDeviceGroup *old_group;
 +  GdkEventMotion *new_event = NULL;
 +  GtkWidget *event_widget;
 +  GdkEvent *event;
 +
 +  data = g_object_get_qdata (G_OBJECT (widget), quark_multidevice_data);
 +
 +  if (G_UNLIKELY (!data))
 +    return;
 +
 +  /* Remove device from old group, if any */
 +  old_group = g_hash_table_lookup (data->by_dev, device);
 +
 +  if (old_group)
 +    gtk_device_group_remove_device (old_group, device);
 +
 +  g_hash_table_insert (data->by_dev,
 +                       g_object_ref (device),
 +                       g_object_ref (group));
 +
 +  event = gtk_get_current_event ();
 +
 +  if (!event)
 +    return;
 +
 +  if (event->type == GDK_MOTION_NOTIFY)
 +    new_event = (GdkEventMotion *) event;
 +  else
 +    {
 +      event_widget = gtk_get_event_widget (event);
 +
 +      if (widget == event_widget)
 +        new_event = convert_event_to_motion (event);
 +
 +      gdk_event_free (event);
 +    }
 +
 +  if (new_event)
 +    {
 +      gtk_widget_event_internal (widget, (GdkEvent *) new_event);
 +      gdk_event_free ((GdkEvent *) new_event);
 +    }
 +}
 +
 +static void
 +device_group_device_removed (GtkDeviceGroup *group,
 +                             GdkDevice      *device,
 +                             GtkWidget      *widget)
 +{
 +  GtkMultiDeviceData *data;
 +
 +  data = g_object_get_qdata (G_OBJECT (widget), quark_multidevice_data);
 +
 +  g_assert (data != NULL);
 +
 +  compose_multidevice_event (widget, device, NULL);
 +  g_hash_table_remove (data->by_dev, device);
 +}
 +
 +static void
 +free_multidevice_data (GtkMultiDeviceData *data)
 +{
 +  g_list_foreach (data->groups, (GFunc) g_object_unref, NULL);
 +  g_list_free (data->groups);
 +
 +  g_hash_table_destroy (data->by_dev);
 +
 +  g_slice_free (GtkMultiDeviceData, data);
 +}
 +
 +/**
 + * gtk_widget_create_device_group:
 + * @widget: a #GtkWidget
 + *
 + * Creates a new #GtkDeviceGroup for @widget. devices can be added
 + * later through gtk_device_group_add_device(). Note that
 + * #GdkDevice<!-- -->s can only pertain to one #GtkDeviceGroup for a
 + * given #GtkWidget, so adding it to a new group will remove it from
 + * its previous one.
 + *
 + * Returns: a newly created #GtkDeviceGroup. This object is owned by
 + *          @widget and must be destroyed through
 + *          gtk_widget_remove_device_group().
 + **/
 +GtkDeviceGroup *
 +gtk_widget_create_device_group (GtkWidget *widget)
 +{
 +  GtkMultiDeviceData *data;
 +  GtkDeviceGroup *group;
 +
 +  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
 +
 +  group = g_object_new (GTK_TYPE_DEVICE_GROUP, NULL);
 +
 +  g_signal_connect (group, "device-added",
 +                    G_CALLBACK (device_group_device_added), widget);
 +  g_signal_connect (group, "device-removed",
 +                    G_CALLBACK (device_group_device_removed), widget);
 +
 +  data = g_object_get_qdata (G_OBJECT (widget), quark_multidevice_data);
 +
 +  if (G_UNLIKELY (!data))
 +    {
 +      data = g_slice_new0 (GtkMultiDeviceData);
 +      data->by_dev = g_hash_table_new_full (g_direct_hash,
 +                                            g_direct_equal,
 +                                            (GDestroyNotify) g_object_unref,
 +                                            (GDestroyNotify) g_object_unref);
 +
 +      g_object_set_qdata_full (G_OBJECT (widget),
 +                               quark_multidevice_data,
 +                               data,
 +                               (GDestroyNotify) free_multidevice_data);
 +    }
 +
 +  data->groups = g_list_prepend (data->groups, group);
 +
 +  return group;
 +}
 +
 +/**
 + * gtk_widget_remove_device_group:
 + * @widget: a #GtkWidget
 + * @group: a #GtkDeviceGroup
 + *
 + * If @group pertains to @widget, @group will be destroyed so no further
 + * #GtkWidget::multidevice-event<!-- -->s are emitted for it.
 + **/
 +void
 +gtk_widget_remove_device_group (GtkWidget      *widget,
 +                                GtkDeviceGroup *group)
 +{
 +  GtkMultiDeviceData *data;
 +  GList *devices, *g;
 +
 +  g_return_if_fail (GTK_IS_WIDGET (widget));
 +  g_return_if_fail (GTK_IS_DEVICE_GROUP (group));
 +
 +  data = g_object_get_qdata (G_OBJECT (widget), quark_multidevice_data);
 +
 +  if (G_UNLIKELY (!data))
 +    return;
 +
 +  g = g_list_find (data->groups, group);
 +
 +  if (G_UNLIKELY (!g))
 +    return;
 +
 +  devices = gtk_device_group_get_devices (group);
 +
 +  /* Free per-device data */
 +  while (devices)
 +    {
 +      g_hash_table_remove (data->by_dev, devices->data);
 +      devices = devices->next;
 +    }
 +
 +  /* Free group */
 +  data->groups = g_list_remove_link (data->groups, g);
 +  g_object_unref (g->data);
 +  g_list_free_1 (g);
 +}
 +
 +/**
 + * gtk_widget_get_group_for_device:
 + * @widget: a #GtkWidget
 + * @device: a #GdkDevice
 + *
 + * Returns the #GtkDeviceGroup containing the #GdkDevice, or %NULL if
 + * there is none.
 + *
 + * Returns: a #GtkDeviceGroup, or %NULL.
 + **/
 +GtkDeviceGroup *
 +gtk_widget_get_group_for_device (GtkWidget *widget,
 +                                 GdkDevice *device)
 +{
 +  GtkMultiDeviceData *data;
 +  GtkDeviceGroup *group = NULL;
 +
 +  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
 +  g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
 +
 +  data = g_object_get_qdata (G_OBJECT (widget), quark_multidevice_data);
 +
 +  if (!data)
 +    return NULL;
 +
 +  group = g_hash_table_lookup (data->by_dev, device);
 +
 +  return group;
 +}
 +
+ static void
+ _gtk_widget_set_has_focus (GtkWidget *widget,
+                            gboolean   has_focus)
+ {
+   if (has_focus)
+     GTK_OBJECT_FLAGS (widget) |= GTK_HAS_FOCUS;
+   else
+     GTK_OBJECT_FLAGS (widget) &= ~(GTK_HAS_FOCUS);
+ }
+ 
+ /**
+  * gtk_widget_send_focus_change:
+  * @widget: a #GtkWidget
+  * @event: a #GdkEvent of type GDK_FOCUS_CHANGE
+  *
+  * Sends the focus change @event to @widget
+  *
+  * This function is not meant to be used by applications. The only time it
+  * should be used is when it is necessary for a #GtkWidget to assign focus
+  * to a widget that is semantically owned by the first widget even though
+  * it's not a direct child - for instance, a search entry in a floating
+  * window similar to the quick search in #GtkTreeView.
+  *
+  * An example of its usage is:
+  *
+  * |[
+  *   GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
+  *
+  *   fevent->focus_change.type = GDK_FOCUS_CHANGE;
+  *   fevent->focus_change.in = TRUE;
+  *   fevent->focus_change.window = gtk_widget_get_window (widget);
+  *   if (fevent->focus_change.window != NULL)
+  *     g_object_ref (fevent->focus_change.window);
+  *
+  *   gtk_widget_send_focus_change (widget, fevent);
+  *
+  *   gdk_event_free (event);
+  * ]|
+  *
+  * Return value: the return value from the event signal emission: %TRUE
+  *   if the event was handled, and %FALSE otherwise
+  *
+  * Since: 2.20
+  */
+ gboolean
+ gtk_widget_send_focus_change (GtkWidget *widget,
+                               GdkEvent  *event)
+ {
+   gboolean res;
+ 
+   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+   g_return_val_if_fail (event != NULL && event->type == GDK_FOCUS_CHANGE, FALSE);
+ 
+   g_object_ref (widget);
+ 
+   _gtk_widget_set_has_focus (widget, event->focus_change.in);
+ 
+   res = gtk_widget_event (widget, event);
+ 
+   g_object_notify (G_OBJECT (widget), "has-focus");
+ 
+   g_object_unref (widget);
+ 
+   return res;
+ }
+ 
  #define __GTK_WIDGET_C__
  #include "gtkaliasdef.c"
diff --cc gtk/gtkwidget.h
index 94be39a,760d7ce..7ffa394
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@@ -429,8 -481,8 +483,9 @@@ typedef struct _GtkWidgetShapeInfo GtkW
  typedef struct _GtkClipboard	   GtkClipboard;
  typedef struct _GtkTooltip         GtkTooltip;
  typedef struct _GtkWindow          GtkWindow;
 +typedef struct _GtkMultiDeviceEvent GtkMultiDeviceEvent;
  
+ 
  /**
   * GtkAllocation:
   * @x: the X position of the widget's area relative to its parents allocation.
diff --cc gtk/gtkwindow.c
index fcc100f,1af7d02..307ffbc
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@@ -5287,53 -5262,17 +5278,42 @@@ static voi
  do_focus_change (GtkWidget *widget,
  		 gboolean   in)
  {
 -  GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
 -  
 -  fevent->focus_change.type = GDK_FOCUS_CHANGE;
 -  fevent->focus_change.window = widget->window;
 -  fevent->focus_change.in = in;
 -  if (widget->window)
 -    g_object_ref (widget->window);
 +  GdkDeviceManager *device_manager;
 +  GList *devices, *d;
 +
-   g_object_ref (widget);
- 
-   if (in)
-     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
-   else
-     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
- 
 +  device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
 +  devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
 +  devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
 +  devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
 +
 +  for (d = devices; d; d = d->next)
 +    {
 +      GdkDevice *dev = d->data;
 +      GdkEvent *fevent;
  
 -  gtk_widget_send_focus_change (widget, fevent);
 +      if (dev->source != GDK_SOURCE_KEYBOARD)
 +        continue;
  
 -  gdk_event_free (fevent);
 +      /* Skip non-master keyboards that haven't
 +       * selected for events from this window
 +       */
 +      if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
 +          !gdk_window_get_device_events (widget->window, dev))
 +        continue;
 +
 +      fevent = gdk_event_new (GDK_FOCUS_CHANGE);
 +
 +      fevent->focus_change.type = GDK_FOCUS_CHANGE;
 +      fevent->focus_change.window = widget->window;
 +      if (widget->window)
 +        g_object_ref (widget->window);
 +      fevent->focus_change.in = in;
 +      gdk_event_set_device (fevent, dev);
 +
-       gtk_widget_event (widget, fevent);
++      gtk_widget_send_focus_change (widget, fevent);
 +
 +      gdk_event_free (fevent);
 +    }
- 
-   g_object_notify (G_OBJECT (widget), "has-focus");
- 
-   g_object_unref (widget);
  }
  
  static gint
diff --cc tests/multidevice/testphotoalbumwidget.c
index dbd6eb4,0000000..b530069
mode 100644,000000..100644
--- a/tests/multidevice/testphotoalbumwidget.c
+++ b/tests/multidevice/testphotoalbumwidget.c
@@@ -1,508 -1,0 +1,508 @@@
 +/*
 + * Copyright (C) 2009 Carlos Garnacho  <carlosg gnome org>
 + *
 + * This work is provided "as is"; redistribution and modification
 + * in whole or in part, in any medium, physical or electronic is
 + * permitted without restriction.
 + *
 + * This work 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.
 + *
 + * In no event shall the authors or contributors be liable for any
 + * direct, indirect, incidental, special, exemplary, or consequential
 + * damages (including, but not limited to, procurement of substitute
 + * goods or services; loss of use, data, or profits; or business
 + * interruption) however caused and on any theory of liability, whether
 + * in contract, strict liability, or tort (including negligence or
 + * otherwise) arising in any way out of the use of this software, even
 + * if advised of the possibility of such damage.
 + */
 +
 +#include "testphotoalbumwidget.h"
 +#include <math.h>
 +
 +#define TEST_PHOTO_ALBUM_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TEST_TYPE_PHOTO_ALBUM_WIDGET, TestPhotoAlbumWidgetPrivate))
 +
 +typedef struct TestPhotoAlbumWidgetPrivate TestPhotoAlbumWidgetPrivate;
 +typedef struct TestPhoto TestPhoto;
 +
 +struct TestPhoto
 +{
 +  GdkPixbuf *pixbuf;
 +  GtkDeviceGroup *group;
 +  gdouble center_x;
 +  gdouble center_y;
 +  gdouble x;
 +  gdouble y;
 +  gdouble angle;
 +  gdouble zoom;
 +
 +  GdkRegion *region;
 +
 +  gdouble base_zoom;
 +  gdouble base_angle;
 +  gdouble initial_distance;
 +  gdouble initial_angle;
 +};
 +
 +struct TestPhotoAlbumWidgetPrivate
 +{
 +  GPtrArray *photos;
 +};
 +
 +static GQuark quark_group_photo = 0;
 +
 +
 +static void test_photo_album_widget_class_init (TestPhotoAlbumWidgetClass *klass);
 +static void test_photo_album_widget_init       (TestPhotoAlbumWidget      *album);
 +
 +static void test_photo_album_widget_destroy    (GtkObject          *object);
 +
 +static gboolean test_photo_album_widget_button_press      (GtkWidget           *widget,
 +                                                           GdkEventButton      *event);
 +static gboolean test_photo_album_widget_button_release    (GtkWidget           *widget,
 +                                                           GdkEventButton      *event);
 +static void     test_photo_album_widget_multidevice_event (GtkWidget           *widget,
 +                                                           GtkDeviceGroup      *group,
 +                                                           GtkMultiDeviceEvent *event);
 +static gboolean test_photo_album_widget_expose            (GtkWidget           *widget,
 +                                                           GdkEventExpose      *event);
 +
 +G_DEFINE_TYPE (TestPhotoAlbumWidget, test_photo_album_widget, GTK_TYPE_DRAWING_AREA)
 +
 +
 +static void
 +test_photo_album_widget_class_init (TestPhotoAlbumWidgetClass *klass)
 +{
 +  GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
 +  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 +
 +  object_class->destroy = test_photo_album_widget_destroy;
 +
 +  widget_class->button_press_event = test_photo_album_widget_button_press;
 +  widget_class->button_release_event = test_photo_album_widget_button_release;
 +  widget_class->expose_event = test_photo_album_widget_expose;
 +
 +  g_type_class_add_private (klass, sizeof (TestPhotoAlbumWidgetPrivate));
 +
 +  quark_group_photo = g_quark_from_static_string ("group-photo");
 +}
 +
 +static void
 +test_photo_album_widget_init (TestPhotoAlbumWidget *album)
 +{
 +  TestPhotoAlbumWidgetPrivate *priv;
 +  GtkWidget *widget;
 +
 +  priv = TEST_PHOTO_ALBUM_WIDGET_GET_PRIVATE (album);
 +  widget = GTK_WIDGET (album);
 +
 +  priv->photos = g_ptr_array_new ();
 +
 +  gtk_widget_add_events (widget,
 +                         (GDK_POINTER_MOTION_MASK |
 +                          GDK_BUTTON_MOTION_MASK |
 +                          GDK_BUTTON_PRESS_MASK |
 +                          GDK_BUTTON_RELEASE_MASK));
 +
 +  gtk_widget_set_support_multidevice (widget, TRUE);
 +
 +  /* Multidevice events are not exposed through GtkWidgetClass */
 +  g_signal_connect (album, "multidevice-event",
 +                    G_CALLBACK (test_photo_album_widget_multidevice_event), NULL);
 +}
 +
 +static void
 +calculate_rotated_point (gdouble  angle,
 +                         gdouble  zoom,
 +                         gdouble  center_x,
 +                         gdouble  center_y,
 +                         gdouble  point_x,
 +                         gdouble  point_y,
 +                         gdouble *ret_x,
 +                         gdouble *ret_y)
 +{
 +  gdouble distance, xd, yd, ang;
 +
 +  xd = center_x - point_x;
 +  yd = center_y - point_y;
 +
 +  if (xd == 0 && yd == 0)
 +    {
 +      *ret_x = center_x;
 +      *ret_y = center_y;
 +      return;
 +    }
 +
 +  distance = sqrt ((xd * xd) + (yd * yd));
 +  distance *= zoom;
 +
 +  ang = atan2 (xd, yd);
 +
 +  /* Invert angle */
 +  ang = (2 * G_PI) - ang;
 +
 +  /* Shift it 270° */
 +  ang += 3 * (G_PI / 2);
 +
 +  /* And constraint it to 0°-360° */
 +  ang = fmod (ang, 2 * G_PI);
 +  ang += angle;
 +
 +  *ret_x = center_x + (distance * cos (ang));
 +  *ret_y = center_y + (distance * sin (ang));
 +}
 +
 +static void
 +allocate_photo_region (TestPhoto *photo)
 +{
 +  GdkPoint points[4];
 +  gint width, height, i;
 +
 +  width = gdk_pixbuf_get_width (photo->pixbuf);
 +  height = gdk_pixbuf_get_height (photo->pixbuf);
 +
 +  /* Top/left */
 +  points[0].x = photo->x - photo->center_x;
 +  points[0].y = photo->y - photo->center_y;
 +
 +  /* Top/right */
 +  points[1].x = photo->x - photo->center_x + width;
 +  points[1].y = photo->y - photo->center_y;
 +
 +  /* Bottom/right */
 +  points[2].x = photo->x - photo->center_x + width;
 +  points[2].y = photo->y - photo->center_y + height;
 +
 +  /* Bottom/left */
 +  points[3].x = photo->x - photo->center_x;
 +  points[3].y = photo->y - photo->center_y + height;
 +
 +  for (i = 0; i < 4; i++)
 +    {
 +      gdouble ret_x, ret_y;
 +
 +      calculate_rotated_point (photo->angle,
 +                               photo->zoom,
 +                               photo->x,
 +                               photo->y,
 +                               (gdouble) points[i].x,
 +                               (gdouble) points[i].y,
 +                               &ret_x,
 +                               &ret_y);
 +
 +      points[i].x = (gint) ret_x;
 +      points[i].y = (gint) ret_y;
 +    }
 +
 +  if (photo->region)
 +    gdk_region_destroy (photo->region);
 +
 +  photo->region = gdk_region_polygon (points, 4, GDK_WINDING_RULE);
 +}
 +
 +static TestPhoto *
 +test_photo_new (TestPhotoAlbumWidget *album,
 +                GdkPixbuf            *pixbuf)
 +{
 +  TestPhoto *photo;
 +  static gdouble angle = 0;
 +
 +  photo = g_slice_new0 (TestPhoto);
 +  photo->pixbuf = g_object_ref (pixbuf);
 +  photo->group = gtk_widget_create_device_group (GTK_WIDGET (album));
 +  g_object_set_qdata (G_OBJECT (photo->group), quark_group_photo, photo);
 +
 +  photo->center_x = 0;
 +  photo->center_y = 0;
 +  photo->x = 0;
 +  photo->y = 0;
 +  photo->angle = angle;
 +  photo->zoom = 1.0;
 +
 +  angle += 0.1;
 +
 +  allocate_photo_region (photo);
 +
 +  return photo;
 +}
 +
 +static void
 +test_photo_free (TestPhoto            *photo,
 +                 TestPhotoAlbumWidget *album)
 +{
 +  g_object_unref (photo->pixbuf);
 +  gtk_widget_remove_device_group (GTK_WIDGET (album), photo->group);
 +
 +  g_slice_free (TestPhoto, photo);
 +}
 +
 +static void
 +test_photo_raise (TestPhoto            *photo,
 +                  TestPhotoAlbumWidget *album)
 +{
 +  TestPhotoAlbumWidgetPrivate *priv;
 +
 +  priv = TEST_PHOTO_ALBUM_WIDGET_GET_PRIVATE (album);
 +  g_ptr_array_remove (priv->photos, photo);
 +  g_ptr_array_add (priv->photos, photo);
 +}
 +
 +static void
 +test_photo_album_widget_destroy (GtkObject *object)
 +{
 +  TestPhotoAlbumWidgetPrivate *priv;
 +
 +  priv = TEST_PHOTO_ALBUM_WIDGET_GET_PRIVATE (object);
 +
 +  if (priv->photos)
 +    {
 +      g_ptr_array_foreach (priv->photos, (GFunc) test_photo_free, object);
 +      g_ptr_array_free (priv->photos, TRUE);
 +      priv->photos = NULL;
 +    }
 +
 +  GTK_OBJECT_CLASS (test_photo_album_widget_parent_class)->destroy (object);
 +}
 +
 +static TestPhoto *
 +find_photo_at_position (TestPhotoAlbumWidget *album,
 +                        gdouble               x,
 +                        gdouble               y)
 +{
 +  TestPhotoAlbumWidgetPrivate *priv;
 +  TestPhoto *photo;
 +  gint i;
 +
 +  priv = TEST_PHOTO_ALBUM_WIDGET_GET_PRIVATE (album);
 +
 +  for (i = priv->photos->len - 1; i >= 0; i--)
 +    {
 +      photo = g_ptr_array_index (priv->photos, i);
 +
 +      if (gdk_region_point_in (photo->region, (gint) x, (gint) y))
 +        return photo;
 +    }
 +
 +  return NULL;
 +}
 +
 +static gboolean
 +test_photo_album_widget_button_press (GtkWidget      *widget,
 +                                      GdkEventButton *event)
 +{
 +  TestPhoto *photo;
 +
 +  photo = find_photo_at_position (TEST_PHOTO_ALBUM_WIDGET (widget), event->x, event->y);
 +
 +  if (!photo)
 +    return FALSE;
 +
 +  test_photo_raise (photo, TEST_PHOTO_ALBUM_WIDGET (widget));
 +  gtk_device_group_add_device (photo->group, event->device);
 +
 +  return TRUE;
 +}
 +
 +static gboolean
 +test_photo_album_widget_button_release (GtkWidget      *widget,
 +                                        GdkEventButton *event)
 +{
 +  GtkDeviceGroup *group;
 +
 +  group = gtk_widget_get_group_for_device (widget, event->device);
 +
 +  if (group)
 +    gtk_device_group_remove_device (group, event->device);
 +
 +  return TRUE;
 +}
 +
 +static void
 +test_photo_album_widget_multidevice_event (GtkWidget           *widget,
 +                                           GtkDeviceGroup      *group,
 +                                           GtkMultiDeviceEvent *event)
 +{
 +  TestPhotoAlbumWidgetPrivate *priv;
 +  GdkRegion *region;
 +  TestPhoto *photo;
 +  gboolean new_center = FALSE;
 +  gboolean new_position = FALSE;
 +  gdouble event_x, event_y;
 +
 +  priv = TEST_PHOTO_ALBUM_WIDGET_GET_PRIVATE (widget);
 +  photo = g_object_get_qdata (G_OBJECT (group), quark_group_photo);
 +
 +  region = gdk_region_copy (photo->region);
 +
 +  if (event->n_events == 1)
 +    {
 +      if (event->type == GTK_EVENT_DEVICE_REMOVED)
 +        {
 +          /* Device was just removed, unset zoom/angle info */
 +          photo->base_zoom = 0;
 +          photo->base_angle = 0;
 +          photo->initial_angle = 0;
 +          photo->initial_distance = 0;
 +          new_center = TRUE;
 +        }
 +      else if (event->type == GTK_EVENT_DEVICE_ADDED)
 +        new_center = TRUE;
 +
 +      event_x = event->events[0]->x;
 +      event_y = event->events[0]->y;
 +      new_position = TRUE;
 +    }
 +  else if (event->n_events == 2)
 +    {
 +      gdouble distance, angle;
 +
 +      gdk_events_get_center ((GdkEvent *) event->events[0],
 +                             (GdkEvent *) event->events[1],
 +                             &event_x, &event_y);
 +
 +      gdk_events_get_distance ((GdkEvent *) event->events[0],
 +                               (GdkEvent *) event->events[1],
 +                               &distance);
 +
 +      gdk_events_get_angle ((GdkEvent *) event->events[0],
 +                            (GdkEvent *) event->events[1],
 +                            &angle);
 +
 +      if (event->type == GTK_EVENT_DEVICE_ADDED)
 +        {
 +          photo->base_zoom = photo->zoom;
 +          photo->base_angle = photo->angle;
 +          photo->initial_angle = angle;
 +          photo->initial_distance = distance;
 +          new_center = TRUE;
 +        }
 +
 +      photo->zoom = photo->base_zoom * (distance / photo->initial_distance);
 +      photo->angle = photo->base_angle + (angle - photo->initial_angle);
 +      new_position = TRUE;
 +    }
 +
 +  if (new_center)
 +    {
 +      gdouble origin_x, origin_y;
 +
 +      origin_x = photo->x - photo->center_x;
 +      origin_y = photo->y - photo->center_y;
 +
 +      calculate_rotated_point (- photo->angle,
 +                               1 / photo->zoom,
 +                               photo->x - origin_x,
 +                               photo->y - origin_y,
 +                               event_x - origin_x,
 +                               event_y - origin_y,
 +                               &photo->center_x,
 +                               &photo->center_y);
 +    }
 +
 +  if (new_position)
 +    {
 +      photo->x = event_x;
 +      photo->y = event_y;
 +    }
 +
 +  allocate_photo_region (photo);
 +
 +  gdk_region_union (region, photo->region);
 +  gdk_region_shrink (region, -4, -4);
 +
 +  gdk_window_invalidate_region (widget->window, region, FALSE);
 +}
 +
 +static gboolean
 +test_photo_album_widget_expose (GtkWidget      *widget,
 +                                GdkEventExpose *event)
 +{
 +  TestPhotoAlbumWidgetPrivate *priv;
 +  cairo_t *cr;
 +  gint i;
 +
 +  priv = TEST_PHOTO_ALBUM_WIDGET_GET_PRIVATE (widget);
 +  cr = gdk_cairo_create (widget->window);
 +
 +  for (i = 0; i < priv->photos->len; i++)
 +    {
 +      TestPhoto *photo = g_ptr_array_index (priv->photos, i);
 +      GdkRegion *region;
 +      gint width, height;
 +
 +      region = gdk_region_copy (photo->region);
 +      gdk_region_shrink (region, -4, -4);
 +
 +      gdk_region_intersect (region, event->region);
 +
 +      if (gdk_region_empty (region))
 +        {
 +          gdk_region_destroy (region);
 +          continue;
 +        }
 +
 +      width = gdk_pixbuf_get_width (photo->pixbuf);
 +      height = gdk_pixbuf_get_height (photo->pixbuf);
 +
 +      cairo_save (cr);
 +
 +      gdk_cairo_region (cr, region);
 +      cairo_clip (cr);
 +
 +      cairo_translate (cr, photo->x, photo->y);
 +
 +      cairo_scale (cr, photo->zoom, photo->zoom);
 +      cairo_rotate (cr, photo->angle);
 +      gdk_cairo_set_source_pixbuf (cr,
 +                                   photo->pixbuf,
 +                                   - photo->center_x,
 +                                   - photo->center_y);
 +
 +      cairo_rectangle (cr,
 +                       - photo->center_x,
 +                       - photo->center_y,
 +                       width, height);
 +      cairo_fill_preserve (cr);
 +
 +      cairo_set_source_rgb (cr, 0., 0., 0.);
 +      cairo_stroke (cr);
 +
 +      cairo_restore (cr);
 +
 +      gdk_region_destroy (region);
 +    }
 +
 +  cairo_destroy (cr);
 +
 +  return TRUE;
 +}
 +
 +GtkWidget *
 +test_photo_album_widget_new (void)
 +{
 +  return g_object_new (TEST_TYPE_PHOTO_ALBUM_WIDGET, NULL);
 +}
 +
 +void
 +test_photo_album_widget_add_image (TestPhotoAlbumWidget *album,
 +                                   GdkPixbuf            *pixbuf)
 +{
 +  TestPhotoAlbumWidgetPrivate *priv;
 +  TestPhoto *photo;
 +
 +  g_return_if_fail (TEST_IS_PHOTO_ALBUM_WIDGET (album));
 +  g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
 +
 +  priv = TEST_PHOTO_ALBUM_WIDGET_GET_PRIVATE (album);
 +
 +  photo = test_photo_new (album, pixbuf);
 +  g_ptr_array_add (priv->photos, photo);
 +
-   if (GTK_WIDGET_REALIZED (album) &&
-       GTK_WIDGET_DRAWABLE (album))
++  if (gtk_widget_get_realized (album) &&
++      gtk_widget_is_drawable (album))
 +    gdk_window_invalidate_region (GTK_WIDGET (album)->window,
 +                                  photo->region,
 +                                  FALSE);
 +}



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