From 9508b76bd2401b6b9e289b5c8ec9fc0e08909283 Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Mon, 24 Nov 1997 22:37:52 +0000 Subject: [PATCH] Initial revision --- .cvsignore | 10 + AUTHORS | 3 + COPYING | 481 ++++ ChangeLog | 1140 +++++++++ ChangeLog.pre-2-0 | 1140 +++++++++ ChangeLog.pre-2-10 | 1140 +++++++++ ChangeLog.pre-2-2 | 1140 +++++++++ ChangeLog.pre-2-4 | 1140 +++++++++ ChangeLog.pre-2-6 | 1140 +++++++++ ChangeLog.pre-2-8 | 1140 +++++++++ INSTALL | 0 Makefile.am | 30 + NEWS | 0 README | 17 + TODO | 36 + acconfig.h | 47 + aclocal.m4 | 395 +++ config.guess | 883 +++++++ config.h.in | 36 + config.sub | 954 ++++++++ configure.in | 214 ++ docs/.cvsignore | 1 + docs/Makefile.am | 10 + docs/gdk.texi | 326 +++ docs/gtk.texi | 3285 +++++++++++++++++++++++++ docs/macros.texi | 18 + docs/texinfo.tex | 4692 ++++++++++++++++++++++++++++++++++++ gdk/.cvsignore | 6 + gdk/Makefile.am | 75 + gdk/gdk.c | 2897 ++++++++++++++++++++++ gdk/gdk.h | 614 +++++ gdk/gdkcolor.c | 718 ++++++ gdk/gdkcursor.c | 52 + gdk/gdkdraw.c | 383 +++ gdk/gdkfont.c | 379 +++ gdk/gdkgc.c | 636 +++++ gdk/gdkglobals.c | 47 + gdk/gdkimage.c | 492 ++++ gdk/gdkinput.c | 324 +++ gdk/gdkinput.h | 143 ++ gdk/gdkinputcommon.h | 687 ++++++ gdk/gdkinputgxi.h | 628 +++++ gdk/gdkinputnone.h | 72 + gdk/gdkinputxfree.h | 368 +++ gdk/gdkpixmap.c | 657 +++++ gdk/gdkprivate.h | 197 ++ gdk/gdkproperty.c | 194 ++ gdk/gdkrectangle.c | 83 + gdk/gdkselection.c | 168 ++ gdk/gdktypes.h | 967 ++++++++ gdk/gdkvisual.c | 431 ++++ gdk/gdkwindow.c | 1358 +++++++++++ gdk/gdkx.h | 48 + gdk/gdkxid.c | 74 + gdk/gxid.c | 844 +++++++ gdk/gxid_lib.c | 116 + gdk/gxid_lib.h | 6 + gdk/gxid_proto.h | 39 + gdk/makecursors | 5 + gdk/makecursors.sed | 3 + gdk/makekeysyms | 5 + gdk/makekeysyms.sed | 3 + gdk/x11/gdkcolor-x11.c | 718 ++++++ gdk/x11/gdkcursor-x11.c | 52 + gdk/x11/gdkfont-x11.c | 379 +++ gdk/x11/gdkglobals-x11.c | 47 + gdk/x11/gdkimage-x11.c | 492 ++++ gdk/x11/gdkinput-gxi.c | 628 +++++ gdk/x11/gdkinput-none.c | 72 + gdk/x11/gdkinput-x11.c | 687 ++++++ gdk/x11/gdkinput-xfree.c | 368 +++ gdk/x11/gdkinput.c | 324 +++ gdk/x11/gdkmain-x11.c | 2897 ++++++++++++++++++++++ gdk/x11/gdkpixmap-x11.c | 657 +++++ gdk/x11/gdkproperty-x11.c | 194 ++ gdk/x11/gdkselection-x11.c | 168 ++ gdk/x11/gdkvisual-x11.c | 431 ++++ gdk/x11/gdkwindow-x11.c | 1358 +++++++++++ gdk/x11/gdkx.h | 48 + gdk/x11/gdkxid.c | 74 + gdk/x11/gxid.c | 844 +++++++ gdk/x11/gxid_lib.c | 116 + gdk/x11/gxid_lib.h | 6 + gdk/x11/gxid_proto.h | 39 + glib/.cvsignore | 11 + glib/AUTHORS | 1 + glib/COPYING | 0 glib/ChangeLog | 10 + glib/INSTALL | 0 glib/Makefile.am | 38 + glib/NEWS | 0 glib/README | 0 glib/acconfig.h | 62 + glib/aclocal.m4 | 395 +++ glib/config.guess | 883 +++++++ glib/config.sub | 954 ++++++++ glib/configure | 2921 ++++++++++++++++++++++ glib/configure.in | 116 + glib/garray.c | 142 ++ glib/gcache.c | 211 ++ glib/gerror.c | 256 ++ glib/ghash.c | 418 ++++ glib/glib.h | 674 ++++++ glib/glibconfig.h.in | 67 + glib/glist.c | 349 +++ glib/gmem.c | 824 +++++++ glib/gprimes.c | 61 + glib/gslist.c | 324 +++ glib/gstring.c | 487 ++++ glib/gtimer.c | 119 + glib/gtree.c | 718 ++++++ glib/gutils.c | 732 ++++++ glib/install-sh | 238 ++ glib/ltconfig | 1415 +++++++++++ glib/ltmain.sh | 2372 ++++++++++++++++++ glib/missing | 134 + glib/mkinstalldirs | 36 + glib/stamp-h.in | 1 + glib/testglib.c | 296 +++ gtk+.prj | 334 +++ gtk+.xconfig.in | 3 + gtk/.cvsignore | 9 + gtk/3DRings.xpm | 116 + gtk/FilesQueue.xpm | 98 + gtk/Makefile.am | 248 ++ gtk/Modeller.xpm | 117 + gtk/fnmatch.c | 200 ++ gtk/fnmatch.h | 67 + gtk/gentypeinfo.el | 137 ++ gtk/gtk.defs | 810 +++++++ gtk/gtk.h | 106 + gtk/gtkaccelerator.c | 352 +++ gtk/gtkaccelerator.h | 73 + gtk/gtkadjustment.c | 118 + gtk/gtkadjustment.h | 74 + gtk/gtkalignment.c | 193 ++ gtk/gtkalignment.h | 72 + gtk/gtkarrow.c | 165 ++ gtk/gtkarrow.h | 66 + gtk/gtkaspectframe.c | 336 +++ gtk/gtkaspectframe.h | 75 + gtk/gtkbbox.c | 228 ++ gtk/gtkbbox.h | 93 + gtk/gtkbin.c | 286 +++ gtk/gtkbin.h | 60 + gtk/gtkbox.c | 453 ++++ gtk/gtkbox.h | 90 + gtk/gtkbutton.c | 915 +++++++ gtk/gtkbutton.h | 76 + gtk/gtkcheckbutton.c | 362 +++ gtk/gtkcheckbutton.h | 66 + gtk/gtkcheckmenuitem.c | 250 ++ gtk/gtkcheckmenuitem.h | 69 + gtk/gtkcolorsel.c | 1463 +++++++++++ gtk/gtkcolorsel.h | 152 ++ gtk/gtkcontainer.c | 844 +++++++ gtk/gtkcontainer.h | 95 + gtk/gtkcurve.c | 860 +++++++ gtk/gtkcurve.h | 96 + gtk/gtkdata.c | 73 + gtk/gtkdata.h | 60 + gtk/gtkdialog.c | 80 + gtk/gtkdialog.h | 64 + gtk/gtkdrawingarea.c | 146 ++ gtk/gtkdrawingarea.h | 62 + gtk/gtkentry.c | 1678 +++++++++++++ gtk/gtkentry.h | 94 + gtk/gtkenums.h | 191 ++ gtk/gtkeventbox.c | 226 ++ gtk/gtkeventbox.h | 57 + gtk/gtkfilesel.c | 2161 +++++++++++++++++ gtk/gtkfilesel.h | 73 + gtk/gtkfixed.c | 525 ++++ gtk/gtkfixed.h | 76 + gtk/gtkframe.c | 419 ++++ gtk/gtkframe.h | 73 + gtk/gtkgamma.c | 464 ++++ gtk/gtkgamma.h | 71 + gtk/gtkgc.c | 382 +++ gtk/gtkgc.h | 42 + gtk/gtkhbbox.c | 269 +++ gtk/gtkhbbox.h | 66 + gtk/gtkhbox.c | 306 +++ gtk/gtkhbox.h | 60 + gtk/gtkhpaned.c | 355 +++ gtk/gtkhpaned.h | 59 + gtk/gtkhruler.c | 277 +++ gtk/gtkhruler.h | 59 + gtk/gtkhscale.c | 436 ++++ gtk/gtkhscale.h | 59 + gtk/gtkhscrollbar.c | 383 +++ gtk/gtkhscrollbar.h | 59 + gtk/gtkhseparator.c | 90 + gtk/gtkhseparator.h | 59 + gtk/gtkimage.c | 181 ++ gtk/gtkimage.h | 69 + gtk/gtkinputdialog.c | 546 +++++ gtk/gtkinputdialog.h | 76 + gtk/gtkitem.c | 191 ++ gtk/gtkitem.h | 65 + gtk/gtklabel.c | 329 +++ gtk/gtklabel.h | 69 + gtk/gtklist.c | 1007 ++++++++ gtk/gtklist.h | 107 + gtk/gtklistitem.c | 394 +++ gtk/gtklistitem.h | 62 + gtk/gtkmain.c | 1129 +++++++++ gtk/gtkmain.h | 76 + gtk/gtkmenu.c | 732 ++++++ gtk/gtkmenu.h | 94 + gtk/gtkmenubar.c | 310 +++ gtk/gtkmenubar.h | 66 + gtk/gtkmenufactory.c | 541 +++++ gtk/gtkmenufactory.h | 88 + gtk/gtkmenuitem.c | 746 ++++++ gtk/gtkmenuitem.h | 98 + gtk/gtkmenushell.c | 633 +++++ gtk/gtkmenushell.h | 83 + gtk/gtkmisc.c | 181 ++ gtk/gtkmisc.h | 70 + gtk/gtknotebook.c | 1303 ++++++++++ gtk/gtknotebook.h | 98 + gtk/gtkobject.c | 994 ++++++++ gtk/gtkobject.h | 250 ++ gtk/gtkoptionmenu.c | 584 +++++ gtk/gtkoptionmenu.h | 71 + gtk/gtkpaned.c | 452 ++++ gtk/gtkpaned.h | 78 + gtk/gtkpixmap.c | 176 ++ gtk/gtkpixmap.h | 69 + gtk/gtkpreview.c | 1571 ++++++++++++ gtk/gtkpreview.h | 144 ++ gtk/gtkprogressbar.c | 259 ++ gtk/gtkprogressbar.h | 64 + gtk/gtkradiobutton.c | 321 +++ gtk/gtkradiobutton.h | 69 + gtk/gtkradiomenuitem.c | 240 ++ gtk/gtkradiomenuitem.h | 64 + gtk/gtkrange.c | 1369 +++++++++++ gtk/gtkrange.h | 144 ++ gtk/gtkrc.c | 1489 ++++++++++++ gtk/gtkrc.h | 45 + gtk/gtkruler.c | 305 +++ gtk/gtkruler.h | 91 + gtk/gtkscale.c | 229 ++ gtk/gtkscale.h | 75 + gtk/gtkscrollbar.c | 54 + gtk/gtkscrollbar.h | 58 + gtk/gtkscrolledwindow.c | 510 ++++ gtk/gtkscrolledwindow.h | 74 + gtk/gtkselection.c | 1388 +++++++++++ gtk/gtkselection.h | 91 + gtk/gtkseparator.c | 57 + gtk/gtkseparator.h | 58 + gtk/gtksignal.c | 1322 ++++++++++ gtk/gtksignal.h | 124 + gtk/gtkstyle.c | 1795 ++++++++++++++ gtk/gtkstyle.h | 217 ++ gtk/gtktable.c | 1178 +++++++++ gtk/gtktable.h | 126 + gtk/gtktext.c | 3522 +++++++++++++++++++++++++++ gtk/gtktext.h | 204 ++ gtk/gtktogglebutton.c | 372 +++ gtk/gtktogglebutton.h | 70 + gtk/gtktooltips.c | 632 +++++ gtk/gtktooltips.h | 88 + gtk/gtktree.c | 81 + gtk/gtktree.h | 68 + gtk/gtktreeitem.c | 108 + gtk/gtktreeitem.h | 72 + gtk/gtktypebuiltins.c | 53 + gtk/gtktypebuiltins.h | 54 + gtk/gtktypeutils.c | 459 ++++ gtk/gtktypeutils.h | 196 ++ gtk/gtkvbbox.c | 272 +++ gtk/gtkvbbox.h | 66 + gtk/gtkvbox.c | 306 +++ gtk/gtkvbox.h | 60 + gtk/gtkviewport.c | 616 +++++ gtk/gtkviewport.h | 75 + gtk/gtkvpaned.c | 356 +++ gtk/gtkvpaned.h | 59 + gtk/gtkvruler.c | 282 +++ gtk/gtkvruler.h | 59 + gtk/gtkvscale.c | 441 ++++ gtk/gtkvscale.h | 59 + gtk/gtkvscrollbar.c | 387 +++ gtk/gtkvscrollbar.h | 59 + gtk/gtkvseparator.c | 90 + gtk/gtkvseparator.h | 59 + gtk/gtkwidget.c | 3390 ++++++++++++++++++++++++++ gtk/gtkwidget.h | 505 ++++ gtk/gtkwindow.c | 1195 +++++++++ gtk/gtkwindow.h | 105 + gtk/line-arrow.xbm | 4 + gtk/line-wrap.xbm | 4 + gtk/marble.xpm | 408 ++++ gtk/parent | 10 + gtk/runelisp | 6 + gtk/simple.c | 39 + gtk/test.xpm | 92 + gtk/testgtk.c | 3110 ++++++++++++++++++++++++ gtk/testgtkrc | 69 + gtk/testinput.c | 379 +++ gtk/testselection.c | 466 ++++ install-sh | 238 ++ ltconfig | 1415 +++++++++++ ltmain.sh | 2372 ++++++++++++++++++ makecopyright | 124 + missing | 134 + mkinstalldirs | 36 + stamp-h.in | 1 + tests/3DRings.xpm | 116 + tests/FilesQueue.xpm | 98 + tests/Modeller.xpm | 117 + tests/marble.xpm | 408 ++++ tests/simple.c | 39 + tests/test.xpm | 92 + tests/testgtk.c | 3110 ++++++++++++++++++++++++ tests/testgtkrc | 69 + tests/testinput.c | 379 +++ tests/testselection.c | 466 ++++ 322 files changed, 132552 insertions(+) create mode 100644 .cvsignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 ChangeLog.pre-2-0 create mode 100644 ChangeLog.pre-2-10 create mode 100644 ChangeLog.pre-2-2 create mode 100644 ChangeLog.pre-2-4 create mode 100644 ChangeLog.pre-2-6 create mode 100644 ChangeLog.pre-2-8 create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 TODO create mode 100644 acconfig.h create mode 100644 aclocal.m4 create mode 100755 config.guess create mode 100644 config.h.in create mode 100755 config.sub create mode 100644 configure.in create mode 100644 docs/.cvsignore create mode 100644 docs/Makefile.am create mode 100644 docs/gdk.texi create mode 100644 docs/gtk.texi create mode 100644 docs/macros.texi create mode 100644 docs/texinfo.tex create mode 100644 gdk/.cvsignore create mode 100644 gdk/Makefile.am create mode 100644 gdk/gdk.c create mode 100644 gdk/gdk.h create mode 100644 gdk/gdkcolor.c create mode 100644 gdk/gdkcursor.c create mode 100644 gdk/gdkdraw.c create mode 100644 gdk/gdkfont.c create mode 100644 gdk/gdkgc.c create mode 100644 gdk/gdkglobals.c create mode 100644 gdk/gdkimage.c create mode 100644 gdk/gdkinput.c create mode 100644 gdk/gdkinput.h create mode 100644 gdk/gdkinputcommon.h create mode 100644 gdk/gdkinputgxi.h create mode 100644 gdk/gdkinputnone.h create mode 100644 gdk/gdkinputxfree.h create mode 100644 gdk/gdkpixmap.c create mode 100644 gdk/gdkprivate.h create mode 100644 gdk/gdkproperty.c create mode 100644 gdk/gdkrectangle.c create mode 100644 gdk/gdkselection.c create mode 100644 gdk/gdktypes.h create mode 100644 gdk/gdkvisual.c create mode 100644 gdk/gdkwindow.c create mode 100644 gdk/gdkx.h create mode 100644 gdk/gdkxid.c create mode 100644 gdk/gxid.c create mode 100644 gdk/gxid_lib.c create mode 100644 gdk/gxid_lib.h create mode 100644 gdk/gxid_proto.h create mode 100755 gdk/makecursors create mode 100644 gdk/makecursors.sed create mode 100755 gdk/makekeysyms create mode 100644 gdk/makekeysyms.sed create mode 100644 gdk/x11/gdkcolor-x11.c create mode 100644 gdk/x11/gdkcursor-x11.c create mode 100644 gdk/x11/gdkfont-x11.c create mode 100644 gdk/x11/gdkglobals-x11.c create mode 100644 gdk/x11/gdkimage-x11.c create mode 100644 gdk/x11/gdkinput-gxi.c create mode 100644 gdk/x11/gdkinput-none.c create mode 100644 gdk/x11/gdkinput-x11.c create mode 100644 gdk/x11/gdkinput-xfree.c create mode 100644 gdk/x11/gdkinput.c create mode 100644 gdk/x11/gdkmain-x11.c create mode 100644 gdk/x11/gdkpixmap-x11.c create mode 100644 gdk/x11/gdkproperty-x11.c create mode 100644 gdk/x11/gdkselection-x11.c create mode 100644 gdk/x11/gdkvisual-x11.c create mode 100644 gdk/x11/gdkwindow-x11.c create mode 100644 gdk/x11/gdkx.h create mode 100644 gdk/x11/gdkxid.c create mode 100644 gdk/x11/gxid.c create mode 100644 gdk/x11/gxid_lib.c create mode 100644 gdk/x11/gxid_lib.h create mode 100644 gdk/x11/gxid_proto.h create mode 100644 glib/.cvsignore create mode 100644 glib/AUTHORS create mode 100644 glib/COPYING create mode 100644 glib/ChangeLog create mode 100644 glib/INSTALL create mode 100644 glib/Makefile.am create mode 100644 glib/NEWS create mode 100644 glib/README create mode 100644 glib/acconfig.h create mode 100644 glib/aclocal.m4 create mode 100755 glib/config.guess create mode 100755 glib/config.sub create mode 100755 glib/configure create mode 100644 glib/configure.in create mode 100644 glib/garray.c create mode 100644 glib/gcache.c create mode 100644 glib/gerror.c create mode 100644 glib/ghash.c create mode 100644 glib/glib.h create mode 100644 glib/glibconfig.h.in create mode 100644 glib/glist.c create mode 100644 glib/gmem.c create mode 100644 glib/gprimes.c create mode 100644 glib/gslist.c create mode 100644 glib/gstring.c create mode 100644 glib/gtimer.c create mode 100644 glib/gtree.c create mode 100644 glib/gutils.c create mode 100755 glib/install-sh create mode 100755 glib/ltconfig create mode 100644 glib/ltmain.sh create mode 100755 glib/missing create mode 100755 glib/mkinstalldirs create mode 100644 glib/stamp-h.in create mode 100644 glib/testglib.c create mode 100644 gtk+.prj create mode 100644 gtk+.xconfig.in create mode 100644 gtk/.cvsignore create mode 100644 gtk/3DRings.xpm create mode 100644 gtk/FilesQueue.xpm create mode 100644 gtk/Makefile.am create mode 100644 gtk/Modeller.xpm create mode 100644 gtk/fnmatch.c create mode 100644 gtk/fnmatch.h create mode 100644 gtk/gentypeinfo.el create mode 100644 gtk/gtk.defs create mode 100644 gtk/gtk.h create mode 100644 gtk/gtkaccelerator.c create mode 100644 gtk/gtkaccelerator.h create mode 100644 gtk/gtkadjustment.c create mode 100644 gtk/gtkadjustment.h create mode 100644 gtk/gtkalignment.c create mode 100644 gtk/gtkalignment.h create mode 100644 gtk/gtkarrow.c create mode 100644 gtk/gtkarrow.h create mode 100644 gtk/gtkaspectframe.c create mode 100644 gtk/gtkaspectframe.h create mode 100644 gtk/gtkbbox.c create mode 100644 gtk/gtkbbox.h create mode 100644 gtk/gtkbin.c create mode 100644 gtk/gtkbin.h create mode 100644 gtk/gtkbox.c create mode 100644 gtk/gtkbox.h create mode 100644 gtk/gtkbutton.c create mode 100644 gtk/gtkbutton.h create mode 100644 gtk/gtkcheckbutton.c create mode 100644 gtk/gtkcheckbutton.h create mode 100644 gtk/gtkcheckmenuitem.c create mode 100644 gtk/gtkcheckmenuitem.h create mode 100644 gtk/gtkcolorsel.c create mode 100644 gtk/gtkcolorsel.h create mode 100644 gtk/gtkcontainer.c create mode 100644 gtk/gtkcontainer.h create mode 100644 gtk/gtkcurve.c create mode 100644 gtk/gtkcurve.h create mode 100644 gtk/gtkdata.c create mode 100644 gtk/gtkdata.h create mode 100644 gtk/gtkdialog.c create mode 100644 gtk/gtkdialog.h create mode 100644 gtk/gtkdrawingarea.c create mode 100644 gtk/gtkdrawingarea.h create mode 100644 gtk/gtkentry.c create mode 100644 gtk/gtkentry.h create mode 100644 gtk/gtkenums.h create mode 100644 gtk/gtkeventbox.c create mode 100644 gtk/gtkeventbox.h create mode 100644 gtk/gtkfilesel.c create mode 100644 gtk/gtkfilesel.h create mode 100644 gtk/gtkfixed.c create mode 100644 gtk/gtkfixed.h create mode 100644 gtk/gtkframe.c create mode 100644 gtk/gtkframe.h create mode 100644 gtk/gtkgamma.c create mode 100644 gtk/gtkgamma.h create mode 100644 gtk/gtkgc.c create mode 100644 gtk/gtkgc.h create mode 100644 gtk/gtkhbbox.c create mode 100644 gtk/gtkhbbox.h create mode 100644 gtk/gtkhbox.c create mode 100644 gtk/gtkhbox.h create mode 100644 gtk/gtkhpaned.c create mode 100644 gtk/gtkhpaned.h create mode 100644 gtk/gtkhruler.c create mode 100644 gtk/gtkhruler.h create mode 100644 gtk/gtkhscale.c create mode 100644 gtk/gtkhscale.h create mode 100644 gtk/gtkhscrollbar.c create mode 100644 gtk/gtkhscrollbar.h create mode 100644 gtk/gtkhseparator.c create mode 100644 gtk/gtkhseparator.h create mode 100644 gtk/gtkimage.c create mode 100644 gtk/gtkimage.h create mode 100644 gtk/gtkinputdialog.c create mode 100644 gtk/gtkinputdialog.h create mode 100644 gtk/gtkitem.c create mode 100644 gtk/gtkitem.h create mode 100644 gtk/gtklabel.c create mode 100644 gtk/gtklabel.h create mode 100644 gtk/gtklist.c create mode 100644 gtk/gtklist.h create mode 100644 gtk/gtklistitem.c create mode 100644 gtk/gtklistitem.h create mode 100644 gtk/gtkmain.c create mode 100644 gtk/gtkmain.h create mode 100644 gtk/gtkmenu.c create mode 100644 gtk/gtkmenu.h create mode 100644 gtk/gtkmenubar.c create mode 100644 gtk/gtkmenubar.h create mode 100644 gtk/gtkmenufactory.c create mode 100644 gtk/gtkmenufactory.h create mode 100644 gtk/gtkmenuitem.c create mode 100644 gtk/gtkmenuitem.h create mode 100644 gtk/gtkmenushell.c create mode 100644 gtk/gtkmenushell.h create mode 100644 gtk/gtkmisc.c create mode 100644 gtk/gtkmisc.h create mode 100644 gtk/gtknotebook.c create mode 100644 gtk/gtknotebook.h create mode 100644 gtk/gtkobject.c create mode 100644 gtk/gtkobject.h create mode 100644 gtk/gtkoptionmenu.c create mode 100644 gtk/gtkoptionmenu.h create mode 100644 gtk/gtkpaned.c create mode 100644 gtk/gtkpaned.h create mode 100644 gtk/gtkpixmap.c create mode 100644 gtk/gtkpixmap.h create mode 100644 gtk/gtkpreview.c create mode 100644 gtk/gtkpreview.h create mode 100644 gtk/gtkprogressbar.c create mode 100644 gtk/gtkprogressbar.h create mode 100644 gtk/gtkradiobutton.c create mode 100644 gtk/gtkradiobutton.h create mode 100644 gtk/gtkradiomenuitem.c create mode 100644 gtk/gtkradiomenuitem.h create mode 100644 gtk/gtkrange.c create mode 100644 gtk/gtkrange.h create mode 100644 gtk/gtkrc.c create mode 100644 gtk/gtkrc.h create mode 100644 gtk/gtkruler.c create mode 100644 gtk/gtkruler.h create mode 100644 gtk/gtkscale.c create mode 100644 gtk/gtkscale.h create mode 100644 gtk/gtkscrollbar.c create mode 100644 gtk/gtkscrollbar.h create mode 100644 gtk/gtkscrolledwindow.c create mode 100644 gtk/gtkscrolledwindow.h create mode 100644 gtk/gtkselection.c create mode 100644 gtk/gtkselection.h create mode 100644 gtk/gtkseparator.c create mode 100644 gtk/gtkseparator.h create mode 100644 gtk/gtksignal.c create mode 100644 gtk/gtksignal.h create mode 100644 gtk/gtkstyle.c create mode 100644 gtk/gtkstyle.h create mode 100644 gtk/gtktable.c create mode 100644 gtk/gtktable.h create mode 100644 gtk/gtktext.c create mode 100644 gtk/gtktext.h create mode 100644 gtk/gtktogglebutton.c create mode 100644 gtk/gtktogglebutton.h create mode 100644 gtk/gtktooltips.c create mode 100644 gtk/gtktooltips.h create mode 100644 gtk/gtktree.c create mode 100644 gtk/gtktree.h create mode 100644 gtk/gtktreeitem.c create mode 100644 gtk/gtktreeitem.h create mode 100644 gtk/gtktypebuiltins.c create mode 100644 gtk/gtktypebuiltins.h create mode 100644 gtk/gtktypeutils.c create mode 100644 gtk/gtktypeutils.h create mode 100644 gtk/gtkvbbox.c create mode 100644 gtk/gtkvbbox.h create mode 100644 gtk/gtkvbox.c create mode 100644 gtk/gtkvbox.h create mode 100644 gtk/gtkviewport.c create mode 100644 gtk/gtkviewport.h create mode 100644 gtk/gtkvpaned.c create mode 100644 gtk/gtkvpaned.h create mode 100644 gtk/gtkvruler.c create mode 100644 gtk/gtkvruler.h create mode 100644 gtk/gtkvscale.c create mode 100644 gtk/gtkvscale.h create mode 100644 gtk/gtkvscrollbar.c create mode 100644 gtk/gtkvscrollbar.h create mode 100644 gtk/gtkvseparator.c create mode 100644 gtk/gtkvseparator.h create mode 100644 gtk/gtkwidget.c create mode 100644 gtk/gtkwidget.h create mode 100644 gtk/gtkwindow.c create mode 100644 gtk/gtkwindow.h create mode 100644 gtk/line-arrow.xbm create mode 100644 gtk/line-wrap.xbm create mode 100644 gtk/marble.xpm create mode 100644 gtk/parent create mode 100644 gtk/runelisp create mode 100644 gtk/simple.c create mode 100644 gtk/test.xpm create mode 100644 gtk/testgtk.c create mode 100644 gtk/testgtkrc create mode 100644 gtk/testinput.c create mode 100644 gtk/testselection.c create mode 100755 install-sh create mode 100755 ltconfig create mode 100644 ltmain.sh create mode 100755 makecopyright create mode 100755 missing create mode 100755 mkinstalldirs create mode 100644 stamp-h.in create mode 100644 tests/3DRings.xpm create mode 100644 tests/FilesQueue.xpm create mode 100644 tests/Modeller.xpm create mode 100644 tests/marble.xpm create mode 100644 tests/simple.c create mode 100644 tests/test.xpm create mode 100644 tests/testgtk.c create mode 100644 tests/testgtkrc create mode 100644 tests/testinput.c create mode 100644 tests/testselection.c diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 000000000..0858b3946 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,10 @@ +*.lo +config.log +config.h +libtool +config.status +stamp-h +Makefile +gtk+.xconfig +config.cache + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..f1adbf18a --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +Peter Mattis (petm@xcf.berkeley.edu) +Spencer Kimball (spencer@xcf.berkeley.edu) +Josh MacDonald (jmacd@xcf.berkeley.edu) diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..eb685a5ec --- /dev/null +++ b/COPYING @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..a065ebef5 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis + + * gtkmenufactory.c: A path which ends in "" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis + + * gtkcolorsel.c: Add "#include " to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis + + * Started ChangeLog diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 new file mode 100644 index 000000000..a065ebef5 --- /dev/null +++ b/ChangeLog.pre-2-0 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis + + * gtkmenufactory.c: A path which ends in "" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis + + * gtkcolorsel.c: Add "#include " to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis + + * Started ChangeLog diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 new file mode 100644 index 000000000..a065ebef5 --- /dev/null +++ b/ChangeLog.pre-2-10 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis + + * gtkmenufactory.c: A path which ends in "" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis + + * gtkcolorsel.c: Add "#include " to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis + + * Started ChangeLog diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 new file mode 100644 index 000000000..a065ebef5 --- /dev/null +++ b/ChangeLog.pre-2-2 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis + + * gtkmenufactory.c: A path which ends in "" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis + + * gtkcolorsel.c: Add "#include " to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis + + * Started ChangeLog diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 new file mode 100644 index 000000000..a065ebef5 --- /dev/null +++ b/ChangeLog.pre-2-4 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis + + * gtkmenufactory.c: A path which ends in "" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis + + * gtkcolorsel.c: Add "#include " to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis + + * Started ChangeLog diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 new file mode 100644 index 000000000..a065ebef5 --- /dev/null +++ b/ChangeLog.pre-2-6 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis + + * gtkmenufactory.c: A path which ends in "" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis + + * gtkcolorsel.c: Add "#include " to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis + + * Started ChangeLog diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 new file mode 100644 index 000000000..a065ebef5 --- /dev/null +++ b/ChangeLog.pre-2-8 @@ -0,0 +1,1140 @@ +Mon Nov 17 1997 Jay Painter + * gtkviewport.c: Raph's Mon, 10 Nov 1997 patch to gtk-list + to fix some viewport bugs + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwidget.c: gtk-ajaborsk-971016-2 + A little patch again to prevent user to use gtk_widget_set_events() + when a widget is already realized. + In this case, the gtk_widget_set_events() doesn't work. + +Mon Nov 17 1997 Jay Painter + * gtk/gtkwindow.c: gtk-ajaborsk-971016-1 + This small patch correct position for GTK_WIN_POS_CENTER and + GTK_WIN_POS_MOUSE GtkWindow positions. + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Sat Nov 15 1997 Jay Painter + * gdk/gdkgc.c: added function gdk_gc_set_clip_rectangle + * gdk/gdk.h: header for above + +Wed Nov 12 1997 Jay Painter + * gdk/gdkpixmap.c: Patrice Fortier's patch for transparent pixmaps. + * gdk/gdk.h: + gdk/gdkdraw.c: Patrice Fortier's patch to add pixel draw function. + +Sun Nov 9 1997 Jay Painter + * Fixed problems with makefiles relating to the bug + which required glib to be installed. + * Fixed makefiles to incluce the xpm's in gtk+/gtk needed + for testgtk. + * Updated gtk+ and gtk+/glib to libtool-1.0f + +Fri Nov 7 1997 Jay Painter + * gtk/gtktext.c: return char_widths[ch & 0xff]; in line 2152 + +Thr Nov 5 1997 Jay Painter + * gtk/testgtk.c: added drag and drop test, removed the test hack + from the button test + +Tue Nov 4 08:28:57 1997 Federico Mena + + * gtk/gtkmain.c (gtk_handle_idle): Patch from David Mosberger to + avoid crashes when handling idle function (this manifested itself + in the Umax and Microtek backends in SANE. + +Sun Nov 2 07:34:56 1997 Tim Janik + + * gtk/gtkfilesel.c: Small fixes about a segmentation viaolation + cause by a double click in the directoy list (introduced by my + previous changes). + + * gtk/gtklist.c: Small fixes to gtk_list_add() and gtk_list_remove(). + + * gtk/testgtk.c (list_add): Applied Stefan Wille's patch to make this + function do something ;). + +Fri Oct 31 Jay Painter + *gdk/gdk.c: reformatted DND code for GTK coding standards + *gdk/gdkwindow.c: changed memory allocation for DND to q_mem stuff + +Thu Oct 30 Jay Painter + * gdk/gdkwindow.c: + * gdk/gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: Applied Stephan Willie's shaped window patch + + * gdk/gdkwindow: + * gdk/gdk.h: + * gtk/gtkwidget.h: + * gtk/gtkwidget.c: reformatted the DND code to conform to GTK + coding standards + + * gtk/testgtk: massive fixes, SW's shaped window example + +Thu Oct 30 07:33:27 1997 Tim Janik + + * gtk/gtklistitem.c (gtk_real_list_item_toggle): applied Johannes + Keukelaar's patch for keyboard support in + GtkList widgets. + + * gtk/gtkfilesel.c: adapted dir and file list selection + behaviour to deal with keyboard selections. this is a little + bit tricky: in the dir list it just changes the entrys value on a one + button press. but on a keyboard selection via gtk_widget_activate() it + does a new population (likewise on a double click) as this seems more + obvious. + +1997-10-25 Marius Vollmer + + * gdk/gdkcolor.c (gdk_colormap_get_system): Initialize + private->ref_count. + +Wed Oct 22 09:47:43 1997 Tim Janik + + * gtk/gtkwindow.c (gtk_window_key_release_event): Fixed a stupid + bug that caused the key_release_event to be propagated twice. + +Sun Oct 12 11:01:43 1997 Tim Janik + + * acconfig.h: + * configure.in: + * gdk/gdkimage.c: Added configure check for IPC_RMID_DEFERRED_RELEASE, + because shmat() fails after a shmctl(..., IPC_RMID,...) for OSF1 V3.2, + SunOS 4.1.1, 5.5, 5.5.1, 5.6, IRIX 5.2 and 6.2. + +Mon Oct 6 11:59:07 1997 Federico Mena + + * gdk/gdk.c (gdk_event_translate): In line 1693, fixed typo that + would cause motion notify events not to be delivered. + +Sun Oct 5 18:15:06 1997 Federico Mena + + * gtk/gtkrc.c (gtk_rc_parse_bg_pixmap): Changed strdup() for + g_strdup(). + +Wed Sep 24 17:16:34 1997 Peter Mattis + + * configure.in: Fixed a stupid error in the test for libXext that + would cause it to fail if X_EXTRA_LIBS was not empty. + + * gtk/gtkmain.h (gtk-timj-970919.patch): + * gtk/gtkmain.c (gtk-timj-970919.patch): new function + `gtk_idle_remove_by_data' to remove all idle callbacks that take a + specific piece of data as argument. (gtk_get_current_event): + remove idles through gtk_idle_remove_by_data. + + * gtk/gtkwidget.c (gtk-timj-970919.patch): + (gtk_widget_destroy): remove pending idles for + widgets that have GTK_REDRAW_PENDING or GTK_RESIZE_PENDING and + GTK_ANCHORED set (only anchored widgets can have a resize queue + handler pending). widgets that have GTK_RESIZE_NEEDED will be removed + from their anchored toplevels `resize_widgets' list. + + (gtk_widget_queue_draw): let the widget remember the queue handler + tag (through `redraw_handler_key') for later call to `gtk_idle_remove'. + + (gtk_widget_queue_resize): let the widget remember the queue handler + tag (through `resize_handler_key') for later call to `gtk_idle_remove'. + corrected referencing the toplevel widget for which the handler is + pending. if a widget is added to the `resize_widgets' list of a + toplevel widget, GTK_RESIZE_NEEDED is set and it's referenced. + + (gtk_real_widget_queue_resize): on the deletion of the `resize_widgets' + list, unset GTK_RESIZE_NEEDED and unreference the removed widgets. + + * gtk/gtkwindow.c (gtk-timj-970919.patch): + (gtk_real_window_move_resize): move `resize_containers = NULL' + initialization out of if-statement. + while stepping through the `resize_widgets' list, unreference the + widgets and clear GTK_RESIZE_NEEDED. if a widget realy needs are + resize, they are flagged through GTK_RESIZE_NEEDED now (instead of + GTK_RESIZE_PENDING, as this is indicative for a pending handler). + added checks to provide segfaulting if a widgets parent pointer + is NULL (e.g. on toplevel widgets that have GTK_RESIZE_NEEDED set). + +Tue Sep 23 13:23:27 1997 Federico Mena + + * gdk/gdkimage.c: Applied Tim Janik's patch to mark shm segments + as IPC_RMID so that they are automatically removed always. + + * gdk/gdkfont.c: Removed casts from lvalues. + + * gtk/gtkmain.c: Removed GTK_RETLOC_*() (which do a cast) from lvalues. + + * gtk/gtkaccelerator.c (gtk_accelerator_table_remove): Added + "const" to the accelerator_key param to be consistent with the + declaration in gtkaccelerator.h. The const is not useful in this + case, anyway. + +Tue Sep 16 13:11:06 1997 Peter Mattis + + * gtkpreview.c: Andrew Logan Kieschnick's change to eliminate + round-off error when gamma is set to 1.0. + + * gtkrange.c: + * gtkviewport.c: Jay Painter's changes to modify the way in which + viewports resize. + + * gdkinput.c: + * gdkinputgxi.h: + * gdkinputxfree.h: + * gtk/Makefile.am: + * gtk.h: + * gtkeventbox.c: + * gtkeventbox.h: Owen Taylor's event box widget and fixes for X + input support (that I had broken). + + * gdk.h: + * gdkwindow.c: + * gtksignal.h: + * gtksignal.c: Elliot Lee's changes to support Objective C. (id is + apparently a reserved word in Objective C). + +Sun Sep 14 22:33:15 1997 Peter Mattis + + * gtkwidget.c (gtk_widget_queue_resize): If the toplevel container + is invisible we simply call "gtk_container_need_resize" on + it. This fixes a bug with option menus not redrawing correctly. + + * gtkmenuitem.c (gtk_menu_item_enter): (gtk_menu_item_leave): + These functions now simply pass the event on to their parent. This + is necessary for menus to work properly due to the change in how + grabs are dealts with. + + * gtkwindow.c (gtk_real_window_move_resize): Fixed a bug that + caused the GTK_RESIZE_PENDING flag to not be unset in some cases. + +Fri Sep 5 20:49:37 1997 Marius Vollmer + + Bug fixes: + + * Makefile.am: Added PATCHES to EXTRA_DIST. + * gtk/gtkpixmap.c (gtk_pixmap_new): Move the "pixmap != NULL" test + after the allocation of the pixmap. + + To shut up the compiler: + + * gtk/gtkfilesel.c (get_pwdb): Initialize home_dir. + * gtk/gtkmain.c (gtk_init): Replace comments around calls to + g_set_*_handler with "if (0)". + * gtk/gtkrc.c (gtk_rc_get_token): Initialize hex_number and + float_number. + * gtk/gtkwindow.c (gtk_window_key_press_event): Initialize + direction. + + Changes to the type system in gtk/: + + * Makefile.am: Added gtktypebuiltins.h to gtkinclude_HEADERS. + Added gtk.defs, runelisp, gentypeinfo.el and gtktypebuiltins.c to + EXTRA_DIST. Added rules to generate gtktypebuiltins.* from + gtk.defs. + + * runelisp, gentypeinfo.el, gtk.defs: New files. + + * gtkaccelerator.c, gtkaccelerator.h (gtk_accelerator_table_ref): + Return the table so that this function can be used as the `copy' + function for GTK_TYPE_BOXED values. + * gtkstyle.c, gtkstyle.h (gtk_style_ref): Likewise. + + * gtkenums.h: Removed GtkArgType enum. + + * gtkmain.c (gtk_init): Call gtk_type_init to initialize the type + system. + + * gtkobject.c (gtk_object_init_type): New function to take over + for gtk_object_get_type. (gtk_object_get_type): Just return the + constant GTK_TYPE_OBJECT. (gtk_object_collect_args): Do the right + thing for the new GTK_TYPE_* types. + * gtksignal.c (gtk_params_get): Likewise. + + * gtktypeutils.c: (gtk_type_init_builtin_types): New + function. (gtk_type_init): Call it. Also made non-static. + (gtk_type_unique): The allocation scheme for numerical ids has + changed: The low 8 bits hold the appropriate GtkFundamentalType of + a type, the rest is a globally unique sequence number. + (gtk_type_hash): Use the sequence number of a key to hash it. + (gtk_type_register_builtin): New function. + + * gtktypeutils.h: (GtkFundamentalType): New enumeration of the + fundamental types. (GTK_TYPE_MAKE, GTK_FUNDAMENTAL_TYPE, + GTK_TYPE_SEQNO): New macros to work with the new id scheme. + (GtkArg): Added fields for new types and renamed old ones. GtkArg + should now be a mostly opaque structure, except name and type. + (GTK_VALUE_*): New macros to access the values of a GtkArg. + (GTK_RETLOC_*): New macros to access the location of a return + value that is contained in a GtkArg. * gtktypebuiltins.h: New + file to access the typeids of the builtin types. + + * gtkwidget.h (GTK_TYPE_WIDGET): New macro to access the type id + of the widget class. + + Thru out: Changed GTK_ARG_* to the appropriate GTK_TYPE_*. + Changed access to GtkArg structure to the appropriate GTK_VALUE_* + or GTK_RETLOC_* macro. Changed GtkArgType to GtkType. Changed + some guints to GtkType. + + General changes in gtk/ to support interpreters: + + * gtkradiobutton.c (gtk_radio_button_new_from_widget, + gtk_radio_button_new_with_label_from_widget): New functions. + + * gtksignal.c (gtk_signal_connect_no_marshal): New function. + (struct _GtkHandler): Added no_marshal and destroy_func fields. + (gtk_signal_handler_new): Initialize them. + (gtk_signal_connect_by_type): Added no_marshal and destroy_func + arguments. Changed all callers. + (gtk_signal_destroy): Invoke destroy_func if there is one and the + global destroy func does not apply. (gtk_handlers_run): If the + handler has no_marshal set, call its function directly without + going thru the signal's marshaller. + +Wed Sep 3 09:56:22 1997 RHS Linux User + + * gtkrange.c: Changed the way the range control focus was drawn so + that the range control is drawn correctly when it does not have + the focus. + +Tue Sep 2 17:41:17 1997 RHS Linux User + + * gtkwidget.c: 'gtk_real_widget_queue_resize' should only remove + the "resize_widgets" if another resize is not pending. + +Mon Sep 1 18:28:08 1997 Peter Mattis + + * gtkmain.c: Changed the way GDK_DELETE events are handled. Only, + if 'gtk_widget_event' returns TRUE is the widget destroyed. By + default, 'gtk_widget_event' will return FALSE causing the window + to not be destroyed. This prevents segfaults in the GIMP and other + programs that do not correctly handle GDK_DELETE events. + + * gtkmain.c: Added modal dialog support by allowing events + destined for a child of the grab widget to go to the child instead + of the grab widget. (Added 'gtk_widget_is_ancestor' to determine + the relationship between the grab widget and the event widget). + + * *.[ch]: Incorprated a whole mess of patches. (Started keeping + the ChangeLog up to date again). + +Thu Jun 5 17:22:21 1997 Peter Mattis + + * gtkmenufactory.c: + * gtkmenufactory.h: Added 'gtk_menu_factory_remove_*' + calls. Removing entries/paths causes the associated widgets to be + destroyed. + + * gtkwidget.c: + * gtkwidget.h: Calling 'gtk_widget_set_style' is used as an + indication that the programmer specifically wants that style to be + used. RC-style substitution is disabled for the widget after such + a call. + + * gtkpixmap.c: + * gtkpixmap.h: + * gtkimage.c: + * gtkimage.h: Changed to use clip mask and a single pixmap (or + image) to deal with transparent areas. + + * gdkpixmap.c: Modified xpm loading routines to optionally return + a clip mask. + + * gdkgc.c: + * gdkdraw.c: + * gdktypes.h: Modifications to allow clip masks to be used with + gc's. Clip masks are bitmaps that specify drawable regions. + +Thu May 1 03:11:51 1997 Peter Mattis + + * gtkscrolledwindow.c: Scrolled windows need to have the + GTK_NO_WINDOW flag set. Not having it set caused an obscure + redrawing bug. + +Wed Apr 30 12:38:03 1997 Peter Mattis + + * gtkhruler.c: + * gtkvruler.c: Fixed a small bug that caused the indicator to be + positioned slightly off. + +Sun Apr 27 14:28:21 1997 Peter Mattis + + * gtkmenushell.c: + * gtkmenushell.h: + * gtkmenu.c: + * gtkmenu.h: Changes so that if a menu is popped up there is a + timeout period during which a menu item will not be activated and + if the mouse button is released in that period the menu will stay + popped up. + + * gtkcurve.c: + * gtkcurve.h: Included curve widget courtesy of David + Mosberger-Tang (davidm@azstarnet.com). + + * gtkentry.c: + * gtkentry.h: Changed "insert" and "delete" signals to + "insert_text" and "delete_text" respectively. (The symbol "delete" + cannot be used since it is a C++ reserved word). + +Sat Apr 19 01:43:49 1997 Peter Mattis + + * gtkmenufactory.c: A path which ends in "" will cause an + invisible (hidden) menu entry to be created. This is useful for + setting an accelerator key for which a corresponding menu entry is + not desired. + + * gtktooltips.c: Fixed some problems with destruction of the + active tip widget not properly updating the tooltips data + structures. + +Fri Apr 18 15:09:45 1997 Peter Mattis + + * gtkcontainer.c: + * gtklist.c: + * gtkwidget.c: + * gtkwidget.h: Patch from Owen Taylor (owt1@cornell.edu) which + fixes problems with destruction of objects and with destruction of + objects which hold the focus. + +Thu Apr 17 11:29:15 1997 Peter Mattis + + * gtkmenushell.c: Incorrect logic in + 'gtk_menu_shell_button_release' for deciding when a menu should + stay popped up when the mouse button is released. + + * *.c: Miscellaneous fixes from folks on the net. + +Tue Apr 15 02:43:17 1997 Peter Mattis + + * *.c: + * gtkwidget.h: Added GTK_BASIC widget flag which when set + specifies a widget as "basic". A "basic" widget is one which + doesn't take input events. For example, labels, pixmaps, boxes, + tables, alignments, etc. + +Sat Apr 12 15:23:08 1997 Peter Mattis + + * gtkcolorsel.c: Add "#include " to define M_PI. + + * gtksignal.c: Fixed a bug in 'gtk_signal_emit' which showed up + because of the new cast checking macros. The 'object' was being + accessed after it had been destroyed. + + * gtkoptionmenu.c: Fixed bug with using 'GTK_BIN' instead of + 'GTK_BUTTON' which showed up because of the new cast checking + macros. + + * *.h: 'GTK_CHECK_CAST', 'GTK_CHECK_CLASS_CAST' and + 'GTK_CHECK_TYPE' used by standard widget macros everywhere. + +Wed Apr 9 00:54:17 1997 Peter Mattis + + * docs/gtk.texi: Started further work on documentation. Major + changes and additions are being made. + + * gtkarrow.c: + * gtkarrow.h: Removed function 'gtk_arrow_get'. + + * gtkcontainer.c: 'gtk_container_check_resize' no performs + additional checking to account for the case where the containers + allocation is no longer sufficient because its parent (or its + parents parent, etc.) needs to resize its children. + +Tue Apr 8 21:15:50 1997 Peter Mattis + + * gtkstyle.c: Fixed a bug in 'gtk_style_init' in which the font + was not ref'd (via 'gdk_font_ref'), but was free'd (via in + 'gdk_font_free') in 'gtk_style_destroy'. (David + Mosberger-Tang). Also cleaned up 'gtk_style_destroy' while I was + at it. + + * gtkmain.c: Fixed a bug in 'gtk_propogate_event' which caused + entry widgets (and probably other widgets) not to be destroyed in + some instances. + +Mon Apr 7 01:20:38 1997 Peter Mattis + + * gtkentry.c: + * gtkentry.h: Changed the "insert_text", "delete_text" and + "changed_text" signals to "insert", "delete", and "changed" + respectively. They really should have been named this way + originally except the previous signal mechanism prevented + duplicate signal names. ("changed" is also used by adjustments). + + * gtkradiomenuitem.c: + * gtkradiomenuitem.h: New widget. + + * gtkcheckmenuitem.c: + * gtkcheckmenuitem.h: New widget. + + * gtksignal.c: Modified 'gtk_signal_lookup' to require an object + type to be passed as a parameter. In addition, signals are now + only needed to be uniquely defined in their branch of the class + hierarchy. This allows the same signal name to be used in two + different branches of the class hierarchy. For instance, the + "changed" signal is used both by adjustments and entries...in + different ways! + + * gtktypeutils.c: Added 'gtk_type_parent' which returns the parent + type for a given type. + +Sun Apr 6 22:08:35 1997 Peter Mattis + + * gtkwidget.c: If a widget is set insensitive it loses the focus + if it had it. + + * gtkcontainer.c: Insensitive widgets no longer participate in tab + traversal. + + * gtkscrolledwindow.c: The "viewport" child is now destroyed and a + container class "foreach" function was written (which fixes the + sensitivity bug). + +Sat Apr 5 14:25:38 1997 Peter Mattis + + * gtkhscrollbar.c: + * gtkvscrollbar.c: Fixed trough size allocation bug. + + * gtkhscale.c: + * gtkvscale.c: Fixed trough size allocation and position bug that + showed up when scales were placed in notebooks. + +Thu Mar 27 17:45:54 1997 David Mosberger-Tang + + * gtk/gtkmain.c (gtk_handle_idle): Fix appending pending_idles to + idle_functions so it works even when idle_functions is empty. + +Sat Mar 15 14:15:59 1997 Peter Mattis + + * *.[ch]: Moved '*_class_init' and '*_init' function declarations + for widgets into the source file as those functions no longer had + to be public. + + * gtkcheckbutton.c: Fixed redrawing of check button. + + * gtkframe.c: Fixed redrawing of frame when the shadow type is + changed. + +Sat Mar 8 15:19:23 1997 Peter Mattis + + * gdkimage.c: Fixed a stupid bug with 'gdk_image_new' which + potentially added a NULL image to "image_list" and caused problems + when 'gdk_image_exit' was called. + +Wed Mar 5 00:40:08 1997 Peter Mattis + + * gtkpreview.c: Massively changed the colormap handling used by + the preview widget. Gray previews are now dithered. A single + visual and colormap is shared by the color and gray previews. A + GTK_PREVIEW_INFO property is installed on the root window in + certain cases to allow multiple GTK programs to share the system + colormap. + +Sun Mar 2 05:43:06 1997 Peter Mattis + + * gtkcheckbutton.c: 'gtk_checkbutton_size_allocate' was allocating + too much space to its children and not leaving the check button + room for the focus border. + + * gtknotebook.c: 'gtk_notebook_size_request' wasn't requesting + enough space when the notebook tabs are visible. + +Sat Mar 1 01:59:35 1997 Peter Mattis + + * gtkpreview.c: Fixed a problem with 'gtk_preview_put' when the + image byte order is GDK_MSB_FIRST. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_connect_after' and + 'gtk_signal_connect_object_after' functions. These connect signal + handlers which will run after the class function associated with + the signal. + + * gtkstyle.c: Fixed a stupid bug in 'gtk_style_new_from_key' that + was causing twice as many styles to be created as necesary. + + * gtkwidget.c: 'gtk_real_widget_size_allocate' erases the widgets + old allocation if it has the GTK_NO_WINDOW flag set. + + * gtkwidget.c: 'gtk_real_widget_unmap' now erases the widget if it + has the GTK_NO_WINDOW flag set. + + * gtklabel.c: Removed 'gtk_label_unmap' as similar functionality + was added to gtk_real_widget_unmap. + + * gtkbin.c: Modified 'gtk_bin_map' and 'gtk_bin_unmap' so that it + erases and draws the widget if it has the GTK_NO_WINDOW flag set. + + * gtkframe.c: Modified 'gtk_frame_size_allocate' so that it erases + the old allocation. + +Fri Feb 28 03:27:05 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_set_title' now changes the window title + if the window is already realized. + + * gtkentry.c: 'gtk_entry_set_text' was emitting both a + "delete_text" and a "changed_text" signal. Modified so that it + only emits a "changed_text" signal. + + * gtkpreview.c: Modified to work correctly on systems with MSB + byte order. The colormap for TRUE and DIRECT color displays is now + created if the default visual is not equal to the visual we are + using. + + * gtkstyle.c: 'gtk_style_attach' and 'gtk_style_find' weren't + working properly in the presence of multiple colormaps are + different depth visuals. + + * gtkcontainer.c: Massively improved focus traversal using tab and + arrow keys. It now uses the layout of the widgets to determine + where to move the focus to. + +Mon Feb 24 03:24:02 1997 Peter Mattis + + * gtkmenufactory.c: Set the accelerator table field for menus when + they are created. + + * gtkmenu.c: + * gtkmenu.h: Added a default accelerator table field to menus so + that runtime modification of accelerator keys in menus can work + better. + + * gtkrange.c: 'gtk_range_default_{h,v}motion' had faulty logic for + deciding what to do when the slider was at the edge of the + trough. They previously didn't update the adjustment value event + if the value wasn't what it should be when the slider was at the + edge of the trough. + + * gtkviewport.c: 'gtk_viewport_size_allocate' and + 'gtk_viewport_adjustment_value_changed' both had the potential for + performing a divide by 0. Checks are now in place to prevent this. + + * gtkmenu.c: 'gtk_menu_map' now makes sure the menu lies on screen + if the position function is NULL. + + * gtkentry.c: Modified selection handling. 'gtk_delete_selection' + actually removes the X selection now. 'gtk_entry_destroy' removes + the selection as well and relies on the change in "gdk.c" to make + sure the selection event will not be sent to a non-existant + window. + + * gdk.c: Selection events are only passed on if the selection + owner is not NULL. + + * gtkstyle.c: 'gtk_style_detach' and 'gtk_style_destroy' were not + destroying the black and white gc's. + +Sun Feb 23 19:17:56 1997 Peter Mattis + + * gtkwindow.c: 'gtk_window_size_request' was setting the window + hints. This was also being done in 'gtk_window_map', so the + instance being done in 'gtk_window_size_request' was removed. + +Fri Feb 21 01:04:01 1997 Peter Mattis + + * gtkwidget.c: 'gtk_widget_draw' has to use the widgets allocated + position for the drawing rectangle when the widget has the + GTK_NO_WINDOW flag set. + + * gtkwidget.c: In 'gtk_widget_init' the visual and colormap were + being directly compared against 'default_visual' and + 'default_colormap' instead of calling + 'gtk_widget_get_default_{visual,colormap}'. + + * gdkrectangle.c: Amazing! There was a bug in the + 'gtk_rectangle_intersect' logic. Its been there for near eternity + and I never noticed. + + * gtkpreview.c: + * gtkpreview.h: Created preview widget which allows drawing to an + rgb or grayscale buffer which is automatically displayed on the + screen. Performs dithering as necessary. + +Thu Feb 20 20:33:21 1997 Peter Mattis + + * gdkwindow.c: Modified the logic in 'gdk_window_new' which + determined when to add a window to the WM_COLORMAP_WINDOWS + property. + +Wed Feb 19 19:55:29 1997 Peter Mattis + + * gtkruler.c: 'gtk_ruler_make_pixmap' was always destroying the + old backing store and creating a new one even when it would create + a new one of exactly the same size as the old one. + +Tue Feb 18 18:32:10 1997 Peter Mattis + + * gmem.c: 'g_mem_chunk_alloc' was incorrectly modifying the mem + areas free mem field when reallocating a previously freed + atom. This caused a fairly severe memory leak. + + * gtkmenushell.c: 'gtk_menu_shell_button_release' had a bug in the + logic for deciding whether to initiate an X pointer grab or not + when the mouse button was released. It now only initiates a grab + if the mouse is released within an active menu item. + +Fri Feb 14 00:57:40 1997 Peter Mattis + + * gtknotebook.c: Changed the look of notebook tabs slightly. + + * gtkentry.c: + * gtkentry.h: Deleting an entry widget which is holding the X + selection presents some difficulties. The X selection must be + released, but the widget can't be destroyed until the + SELECTION_CLEAR event is received that the X server will send in + response to clearing the X selection. There are probably still + bugs in the current method of entry widget deletion when the X + selection is held. + + * gtkmain.c: 'gtk_propagate_event' was not properly destroying the + toplevel window when receiving a key press event. + + * gtkwidget.c: Setting a widget insensitive did not cause it to + redraw. It now does. + +Thu Feb 13 16:59:07 1997 Peter Mattis + + * gtkviewport.c: 'gtk_viewport_size_allocate' was allocating its + child widget an adjusted allocation. Since the actual scrolling + has handled by a subwindow this caused the child to be double + scrolled. Modified to always set the child allocations origin to + (0, 0). + +Wed Feb 12 01:06:48 1997 Peter Mattis + + * gtkentry.c: Text is now centered vertically. Previously it was + pushed up against the top. This problem was only evident when the + widget was allocated more vertical space than it requested. + + * gtkfilesel.c: 'gtk_file_selection_key_press' was previously only + a stub for tab completion. The actual tab completion call had been + left out. (Oops!) + +Tue Feb 11 01:43:08 1997 Peter Mattis + + * gtksignal.c: 'gtk_signal_disconnect_by_data' was going into a + loop and crashing. Bad logic. Fixed. + + * gtkmain.c: An idle function which returns FALSE will be removed + from the list of idle functions. This makes the functioning of + idle functions and timeouts more similar. + + * gtkentry.c: 'gtk_entry_get_text' now returns an empty string + when the actual text is NULL. This allows "stupid" programs to use + the value returned by 'gtk_entry_get_text' blindly (without + checking to see if its NULL). + + * gtkradiobutton.c: Modified 'gtk_radio_button_clicked' so that + 'gtk_toggle_button_toggled' is called _after_ the widget state is + changed. + + * gtksignal.c: + * gtksignal.h: Added 'gtk_signal_name' which returns the character + string name for a given signal number. + + * gtkwidget.c: 'gtk_widget_set_parent' checks to see if the widget + is now "anchored" through the parent chain to a widget which is + GTK_ANCHORED. If it is, then it changes the widgets style using + 'gtk_rc_get_style' and recursively performs the same operation on + the widgets children. This is necessary is 'gtk_rc_get_style' only + works properly on "anchored" widgets. + + * gtkwindow.c: Modified GTK_WIN_POS logic so that it is only used + immediately after the window has been shown. + + * gtkmenu.c: 'gtk_menu_key_press'. Can now change menu item + accelerator keys on the fly. Why? Why not. Cool/useless feature of + the day. + + * gtkmenuitem.c: Accelerator key drawing. Somehow that never got + finished. (Oops!) + + * gtkdrawingarea.c: 'gtk_drawing_area_size_allocate' was not + actually installed during 'gtk_drawing_area_class_init'. (Oops!) + + * gtkframe.c: 'gtk_frame_size_request' fixed size requisition + problem caused by unsigned arithmetic. + + * gtkwindow.c: Modified window widget so that it only uses the + widget uposition auxiliary information immediately after it has + been shown. This prevents the annoying bug which can cause a + uposition'ed window to jump back to its original position after + the user moves it. + + * gtkwidget.c: Need to ref and unref style in + 'gtk_widget_{push,pop}_style' to make sure that a style on the + style stack is not destroyed. + + * gtktogglebutton.c: 'gtk_toggle_button_set_state' now calls + gtk_button_clicked to actually change the state of the + button. In this way, radio buttons can now perform the appropriate + actions when the toggle button state is set. + +Mon Feb 10 00:27:39 1997 Peter Mattis + + * gtklist.c: 'gtk_list_select_item' and 'gtk_list_unselect_item' + were casting a GList* variable to a a GtkWidget* variable. Bad bad + bad. (Tim Janik). + + * gtksignal.c: Modified 'gtk_signal_connect' and + 'gtk_signal_connect_object' to warn when a signal type cannot be + found. + +Sun Feb 9 00:15:30 1997 Peter Mattis + + * gtkoptionmenu.c: + * gtkoptionmenu.h: Changed option menus back to being derived from + buttons. This fixes up some screwiness with their user + interaction. + + * gtkwindow.c: Modified key press handler to support focus + traversal. + + * gtkcontainer.c: + * gtkcontainer.h: Added default focus traversal back in. + +Sat Feb 8 10:44:38 1997 Peter Mattis + + * gtkviewport.h: + * gtkviewport.c: Massively sped up viewport scrolling. Used to be + reallocating child's size (offset) each time a scrollbar + moved. Now a subwindow is moved. All the children are moved + automatically by moving the subwindow. Much much much faster. + +Tue Feb 4 00:20:44 1997 Peter Mattis + + * gtree.c: Changed 'g_tree_node_search' to use a loop instead of + recursion. + +Mon Feb 3 11:30:03 1997 Peter Mattis + + * gtkbutton.c: Removed 'parent_destroy' global and replaced it + with 'parent_class' global to reflect style used in other + widgets. + + * gtknotebook.c: Tab labels were being allocated less than their + requested size. + + * gtkrange.c: + * gtkrange.h: Moved the "digits" field of scales into the range + type. The adjustment value for scales is truncated to the number + of visible digits instead of being left untouched. + + * gtree.c: Fixed a bug in the AVL tree implementation. Single + rotations were always being performed during insertion. It is + sometimes necessary to perform a double rotation. + + * gtklabel.c: Modified 'gtk_label_expose' to only draw the label + when the allocated space is greater than or equal to the requested + space. + + * gtklabel.c: Added call to 'gtk_widget_unmap' to + 'gtk_label_destroy' in order for the label to redraw correctly + (erase itself) when destroyed. + + * gtklabel.c: Added 'gtk_label_unmap' call which erases the labels + allocation when it gets unmapped. + + * *.h: Removed a few remaining instances of using "class" as a + parameter name. (Causes problems for C++). + +Fri Jan 31 12:26:50 1997 Peter Mattis + + * gtkcontainer.c: 'gtk_container_enable_resize' needs to call + 'gtk_container_check_resize' instead of + 'gtk_container_need_resize'. + + * gtkwidget.c: 'gtk_real_widget_show' now maps the widget if its + parent is mapped. + + * gtkscrolledwindow.c: Fixed size allocation when the scrollbar + policy's are GTK_POLICY_AUTOMATIC. Doing it correctly is harder + than I originally thought. + + * gtklist.c: Added 'gtk_list_child_position' to determine the + integer position in a list of a child. Filled in the + 'gtk_list_item_select' and 'gtk_list_item_unselect' stubs. + +Thu Jan 30 16:08:06 1997 Peter Mattis + + * gmem.c: Changed the implementation of G_ALLOC_AND_FREE mem + chunks. They used to allocate SIZEOF_VOID_P extra bytes per atom + in order to keep track of which mem area they were allocated + from. Now the mem area is determined by searching through an AVL + tree of the mem areas for a mem chunk and comparing memory + locations. A little slower, but makes G_ALLOC_AND_FREE mem chunks + much more attractive. + + * gtree.c: Added an AVL tree implementation to glib. + + * gtksignal.c: + * gstring.c: va_arg (arg_list, {char, short}) is + invalid. Arguments passed in a variable argument list are + promoted. ({char, short}->int). Seemed to work ok before under + Linux. Crashed under FreeBSD. + +Tue Jan 28 02:27:51 1997 Peter Mattis + + * gdkwindow.c: Fixed a major slowdown apparent in the file + selection dialog which was caused by calling + 'gtk_window_add_colormap_windows' way way way too often. + + * *.c: Many widgets called 'gtk_container_need_resize' when + something internal changed which would cause the widget to grow or + shrink. The assumption was made that the widget would change size + and an expose event would be generated. This happens "most" of the + time. But its possible for certain widgets to change size without + generating expose events, or for its internal geometry to change + without a change of size which would mean no expose event was + generated. So a wrapper function called + 'gtk_container_check_resize' was created and + 'gtk_container_need_resize' was modified so that it returns FALSE + if a resize was actually generated and TRUE if nothing + changed. This allows 'gtk_container_check_resize' to initiate a + 'gtk_widget_size_allocate' and 'gtk_widget_draw' to emulate the + expose event. + +Sat Jan 25 14:17:44 1997 Peter Mattis + + * gtkmain.c: Fixed a bug with propogating key press events. The + events were sent 2 times to the toplevel windows which caused the + focus widget to be activated twice when the space bar was pressed. + + * */configure.in: + * */Makefile.am: Added support for libtool and removed the old + shared library configuration craziness. + +Fri Jan 24 12:59:22 1997 Peter Mattis + + * gtktext.c: + * gtktext.h: Josh's fixes and additions to the text widget. + + * gtkfill.c: + * gtkfill.h: Filler widget useful for filling space in a + table. Can specify a minimum size. Used by the canvas widget. + + * gtknotebook.c: + * gtknotebook.h: Made outline of notebook widget. + + * gtkcanvas.c: + * gtkcanvas.h: Started canvas widget. A composite of 2 rulers (w/ + an origin), 2 scrolllbars. Guides, grids, snap to. + +Sun Jan 19 18:26:45 1997 Peter Mattis + + * gtkdialog.c: + * gtkdialog.h: Created dialog widget which creates a standard + looking dialog with buttons along the button and a separator. + + * gtkxid.c: Generalized the window table code for looking up a gdk + window based on an XID to work for any XID and a piece of + data. Can now look up gdk fonts based on their XID. + + * gtkruler.c: + * gtkruler.h: + * gtkhruler.c: + * gtkhruler.h: + * gtkvruler.c: + * gtkvruler.h: Started conversion of the ruler widget. + + * gtktext.c: + * gtktext.h: Started conversion of the text widget. Scrolling + doesn't work. + + * gtkmain.c: Fixed a fairly major bug. The event widget needs to + be in a call for the entire duration of handling an event. Not + just for when the event widget itself is handling the event. + + * gtkfilesel.c: Fixed up some bugs with resizing. + +Fri Jan 10 14:18:03 1997 Peter Mattis + + * gtkwidget.c: + * gtkwidget.h: + * gtkentry.c: + * gtkentry.h: Support for selections. + + * gdkselection.c: + * gdk.c: + * gdktypes.h: + * gdk.h: Gdk support for X selections. Currently only text + selections are supported. + + * gtksignal.c: Fixed a major bug which occurred when destroying an + object. Memory was being written to after it was freed. + + * gtkfilesel.c: + * gtkfilesel.h: Hooked up more functionality to the file selection + dialog. + +Wed Jan 8 18:13:53 1997 Peter Mattis + + * gtkfilesel.c: + * gtkfilesel.h: Mostly converted old file selection dialog + widget. The widget is derived from the GtkWindow class and is + quite a bit simpler in the widget code. + + * gtkwidget.c: Fixed 'gtk_widget_grab_focus' and + 'gtk_widget_grab_default' to check that the toplevel widget is a + type of window (which includes classes derived from windows). + +Tue Jan 7 01:12:32 1997 Peter Mattis + + * gtkwindow.c: Was calling 'gtk_window_resize' twice in a + row...why? + + * gtksignal.c: + * gtksignal.h: + * *.c: Changed 'gtk_signal_new' so that the class function that is + called when the signal is emitted can be called either before, + after or both before and after the calling of any signal + handlers. + + * gtkobject.c: + * gtkobject.h: Added 'object_data' mechanism for storing data + associated with a character string key in objects. Removed + 'user_data' field of objects and changed + 'gtk_object_{get,set}_user_data' to use the object data + mechanism. Removed 'handlers' field of objects. + + * gtkwidget.c: + * gtkwidget.h: + * gtkwindow.c: Modified aux info mechanism to use object data + mechanism. + + * gtksignal.c: Modified signal mechanism to use object data + mechanism instead of 'handlers' field. + + +Mon Jan 6 15:10:16 1997 Peter Mattis + + * gtkmenushell.c: Fixed up button press handling so as to conform + more closely to that used by Motif. + +Wed Jan 1 21:27:17 1997 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenushell.c: + * gtkmenushell.h: Reorganization of menu-ing code so that code + duplication is reduced. The menu shell now contains most of the + code for menu-ing interaction while menus and menubars simply layout + their child menu items in the appropriate place. + +Sun Dec 29 17:48:18 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenubar.c: + * gtkmenuitem.h: + * gtkmenuitem.c: Modifications so that menu item accelerators and + the submenu indicator are drawn correctly and the correct amount + of space is allocated. + +Sat Dec 28 00:32:13 1996 Peter Mattis + + * gtkmenufactory.h: + * gtkmenufactory.c: Started menu factories as an easy method to + create and manipulate menus. + +Fri Dec 27 13:17:34 1996 Peter Mattis + + * gtkmenu.c: + * gtkmenu.h: + * gtkmenubar.c: + * gtkmenubar.h: + * gtkmenuitem.c: + * gtkmenuitem.h: + * gtkmenushell.c: + * gtkmenushell.h: Implemented basic menu functionality. Menubars + and popup menus work. Submenus work. (Much left to be done). + +Wed Dec 18 15:27:05 1996 Peter Mattis + + * gtktypeutils.h: + * gtktypeutils.c: Added 'gtk_type_from_name' which returns a type + identifier given a type name. Implemented using a second hash + table keyed by type names. + + * gtkbutton.c: + * gtktogglebutton.c: Fixed very small messed-up drawing bug when a + button loses its focus. + + * gtkwidget.h: + * gtkwidget.c: + * gtkbutton.c: + * gtkwindow.c: Added default button handling. Default buttons now + draw correctly and pressing return or enter causes the default + button (if one exists) to be activated. + +Tue Dec 17 19:32:21 1996 Peter Mattis + + * gtkhscale.c: + * gtkvscale.c: Overrode 'draw_slider' method of ranges in order to + draw the slider of scales with a line in them so as to be closer + to the Motif look-and-feel. + + * gtkwindow.c: Modified 'gtk_window_focus_in_event' so that focus + in events are only handled when the window is visible. Fixes a bug + where spurious focus in events get sent when a window is being + hidden. + + * gtkwidget.h: Added 'activate_signal' field to the GtkWidgetClass + structure. Added 'gtk_widget_activate' call to emit the activate + signal for a widget if it is non-zero. + +Tue Dec 10 15:59:45 1996 Peter Mattis + + * gtkwidget.c: 'gtk_widget_set_name' oops in strdup'ing the old + "widget->name" instead of the new one we are setting. + + * gtkrc.c: 'gtk_rc_widget_path' changed to use + 'gtk_widget_get_name' instead of accessing the "widget->name" + field directly. + + * gtkwidget.c: Added 'gtk_widget_get_name' function which returns + the widgets name if it exists and the widgets type name if it does + not. + + * gtkcheckbutton.c: Added 'gtk_check_button_draw' + function. Modified 'gtk_check_button_expose' to pass an expose + event to child instead of callings its draw function. + + * gtkentry.c: 'gtk_entry_draw_text' why was "+1" being added to + the font->ascent to calculate the font position? This was wrong + and caused some characters in fonts to be clipped. (Notably "g"). + + * gtkentry.c: 'gtk_entry_realize' specify GTK_BUTTON1_MOTION_MASK + and GTK_POINTER_MOTION_HINT_MASK for _both_ windows. + + * gtkmain.c: 'gtk_propagate_event' needs to set the GTK_IN_CALL + flag for the object before calling 'gtk_widget_event' and needs to + destroy the object if necessary after 'gtk_widget_event' returns. + + * gtkradiobutton.c: 'gtk_radio_button_clicked' needs to call + 'gtk_toggle_button_toggled' when the currently active button is + toggled. + + * gtkwidget.c: 'gtk_real_widget_hide' needs to call + 'gtk_widget_unmap' if the widget is currently mapped. + + * gtkwindow.c: Prevent automatic resizing after the user has + specified a new window size. Add 'handling_resize' flag to + windows. + + * gtkscrolledwindow.c: Implement the GTK_POLICY_AUTOMATIC + scrollbar policy. Need to connect to the adjustments 'changed' + signal and notice when the scrollbars aren't in use. + + * gtkcontainer.c: 'gtk_container_init' must set 'auto_resize' and + 'need_resize' fields to TRUE and FALSE respectively. + + * gtkwidget.c: 'gtk_widget_set_parent' must all set a widgets state + to its parents state. + +Sun Dec 1 01:31:01 1996 Peter Mattis + + * Started ChangeLog diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..e69de29bb diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..8f24c51eb --- /dev/null +++ b/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in + +SRC_SUBDIRS = glib gdk gtk +SUBDIRS = $(SRC_SUBDIRS) docs + +EXTRA_DIST = gtk+.prj makecopyright TODO + +.PHONY: files populate checkin release + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done + @for subdir in $(SUBDIRS); do \ + files=`cd $$subdir; $(MAKE) files | grep -v "make\[[1-9]\]"`; \ + for file in $$files; do \ + echo $$subdir/$$file; \ + done; \ + done + +populate: + @echo "populating project" + @files=`$(MAKE) files | grep -v "make\[[1-9]\]"`; prcs populate -d gtk+.prj $$files + +checkin: populate + @echo "checking in project" + @prcs checkin + +release: + $(MAKE) dist distdir=$(PACKAGE)`date +"%y%m%d"` diff --git a/NEWS b/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/README b/README new file mode 100644 index 000000000..728cf38a5 --- /dev/null +++ b/README @@ -0,0 +1,17 @@ + +The official ftp site is: + ftp://ftp.gimp.org/pub/gtk + +Patches can be uploaded to: + ftp://ftp.gimp.org/incoming + +Anonymous CVS access for gtk+ (as well as 'gimp', 'gimp-data', and +'gnome') is available via + CVSROOT=:pserver:anonymous@cvs.gnome.org:/home/cvs +with an empty password. + +A mailing list is located at: + gtk-list@redhat.com + +To subscribe: mail -s subscribe gtk-list-request@redhat.com < /dev/null +(Send mail to gtk-list-request@redhat.com with the subject "subscribe") diff --git a/TODO b/TODO new file mode 100644 index 000000000..8c1af4d12 --- /dev/null +++ b/TODO @@ -0,0 +1,36 @@ +Now +--- + +3. Fix focus activation of list items. Does list item activation have to be + completely reorganized? + +4. Lists should scroll to center the recently selected item if it isn't + visible. + + +The Future +---------- + +-Documentation + +-Tree widget + +-Text widget (needs to be finished) + +-Widget redrawing when the window resizes sometimes messes up. + +-Make sure a widget added to a list is a list item and a widget added + to a menu is a menu item, etc... + +-More dialogs? Print, font, etc? + +-Multiple document interface (MDI)? + +-Support another widget style? Should be possible using GtkStyle's, but + there may be some work needed to remove any style dependencies in widget + code. Maybe GtkStyle's should have 'draw_push_button', 'draw_check_button', + etc, functions to draw the various widgets. + +-OffiX drag and drop support + +-Make all widget attributes configurable after the widget is created. diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 000000000..be2cb542c --- /dev/null +++ b/acconfig.h @@ -0,0 +1,47 @@ +/* acconfig.h + This file is in the public domain. + + Descriptive text for the C preprocessor macros that + the distributed Autoconf macros can define. + No software package will use all of them; autoheader copies the ones + your configure.in uses into your configuration header file templates. + + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). Although this order + can split up related entries, it makes it easier to check whether + a given entry is in the file. + + Leave the following blank line there!! Autoheader needs it. */ + + +/* Other stuff */ +#undef HAVE_IPC_H +#undef HAVE_SHM_H +#undef HAVE_XPM +#undef HAVE_XSHM_H +#undef HAVE_SYS_SELECT_H + +#undef IPC_RMID_DEFERRED_RELEASE + +#undef NO_FD_SET + +#undef RESOURCE_BASE + +#undef XINPUT_NONE +#undef XINPUT_GXI +#undef XINPUT_XFREE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Most machines will be happy with int or void. IRIX requires '...' */ +#undef SIGNAL_ARG_TYPE + +/* #undef PACKAGE */ +/* #undef VERSION */ + + +/* Leave that blank line there!! Autoheader needs it. + If you're adding to this file, keep in mind: + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). */ diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 000000000..9f99ab8e7 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,395 @@ +dnl aclocal.m4 generated automatically by aclocal 1.2 + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AM_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") +AC_DEFINE_UNQUOTED(VERSION, "$VERSION")) +AM_SANITY_CHECK +AC_ARG_PROGRAM +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_PROG_MAKE_SET]) + + +# serial 1 + +AC_DEFUN(AM_PROG_INSTALL, +[AC_REQUIRE([AC_PROG_INSTALL]) +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' +AC_SUBST(INSTALL_SCRIPT)dnl +]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$@" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +# serial 17 AM_PROG_LIBTOOL +AC_DEFUN(AM_PROG_LIBTOOL, +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_RANLIB]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AM_PROG_LD]) +AC_REQUIRE([AM_PROG_NM]) +AC_REQUIRE([AC_PROG_LN_S]) + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL) + +dnl Allow the --disable-shared flag to stop us from building shared libs. +AC_ARG_ENABLE(shared, +[ --enable-shared build shared libraries [default=yes]], +[if test "$enableval" = no; then + libtool_enable_shared=no +else + libtool_enable_shared=yes +fi]) +test -n "$libtool_enable_shared" && enable_shared="$libtool_enable_shared" +libtool_shared= +test "$enable_shared" = no && libtool_shared=" --disable-shared" + +dnl Allow the --disable-static flag to stop us from building static libs. +AC_ARG_ENABLE(static, +[ --enable-static build static libraries [default=yes]], +[if test "$enableval" = no; then + libtool_enable_static=no +else + libtool_enable_static=yes +fi]) +test -n "$libtool_enable_static" && enable_static="$libtool_enable_static" +libtool_static= +test "$enable_static" = no && libtool_static=" --disable-static" + +libtool_flags="$libtool_shared$libtool_static" +test "$silent" = yes && libtool_flags="$libtool_flags --silent" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +[case "$host" in +*-*-irix6*) + ac_save_CFLAGS="$CFLAGS" + flag_passed=no + for f in -32 -64 -n32 ABI -cckr -mips1 -mips2 -mips3 -mips4; do + case "$f" in + ABI) + test -n "$SGI_ABI" && flag_passed=yes + if test "$flag_passed" = no && test "$ac_cv_prog_gcc" = yes; then + # Choose the ABI flag according to GCC's specs. + if $CC -dumpspecs 2>&1 | sed '/^\*link:$/,/^$/!d' | egrep -e '[ ]-32' >/dev/null; then + LD="${LD-ld} -32" + else + LD="${LD-ld} -n32" + fi + fi + ;; + + *) + if echo " $CC $CFLAGS " | egrep -e "[ ]$f[ ]" > /dev/null; then + flag_passed=yes + LD="${LD-ld} $f" + fi + ;; + esac + done + CFLAGS="$ac_save_CFLAGS" + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + CFLAGS="$CFLAGS -belf" + ;; +esac] + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ +|| AC_MSG_ERROR([libtool configure failed]) +]) + +# AM_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN(AM_PROG_LD, +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC]) +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_SUBST(LD) +AM_PROG_LD_GNU +]) + +AC_DEFUN(AM_PROG_LD_GNU, +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +]) + +# AM_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN(AM_PROG_NM, +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(ac_cv_path_NM, +[case "$NM" in +/*) + ac_cv_path_NM="$NM" # Let the user override the test with a path. + ;; +*) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb $PATH /bin; do + test -z "$ac_dir" && dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + if ($ac_dir/nm -B /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + else + ac_cv_path_NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm + ;; +esac]) +NM="$ac_cv_path_NM" +AC_MSG_RESULT([$NM]) +AC_SUBST(NM) +]) + +# Add --enable-maintainer-mode option to configure. +# From Jim Meyering + +# serial 1 + +AC_DEFUN(AM_MAINTAINER_MODE, +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT($USE_MAINTAINER_MODE) + if test $USE_MAINTAINER_MODE = yes; then + MAINT= + else + MAINT='#M#' + fi + AC_SUBST(MAINT)dnl +] +) + + +# serial 1 + +# @defmac AC_PROG_CC_STDC +# @maindex PROG_CC_STDC +# @ovindex CC +# If the C compiler in not in ANSI C mode by default, try to add an option +# to output variable @code{CC} to make it so. This macro tries various +# options that select ANSI C on some system or another. It considers the +# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and +# handles function prototypes correctly. +# +# If you use this macro, you should check after calling it whether the C +# compiler has been set to accept ANSI C; if not, the shell variable +# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source +# code in ANSI C, you can make an un-ANSIfied copy of it by using the +# program @code{ansi2knr}, which comes with Ghostscript. +# @end defmac + +AC_DEFUN(AM_PROG_CC_STDC, +[AC_REQUIRE([AC_PROG_CC]) +AC_BEFORE([$0], [AC_C_INLINE]) +AC_BEFORE([$0], [AC_C_CONST]) +AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C) +AC_CACHE_VAL(am_cv_prog_cc_stdc, +[am_cv_prog_cc_stdc=no +ac_save_CC="$CC" +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + AC_TRY_COMPILE( +[#if !defined(__STDC__) || __STDC__ != 1 +choke me +#endif +/* DYNIX/ptx V4.1.3 can't compile sys/stat.h with -Xc -D__EXTENSIONS__. */ +#ifdef _SEQUENT_ +# include +# include +#endif +], [ +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);};], +[am_cv_prog_cc_stdc="$ac_arg"; break]) +done +CC="$ac_save_CC" +]) +if test -z "$am_cv_prog_cc_stdc"; then + AC_MSG_RESULT([none needed]) +else + AC_MSG_RESULT($am_cv_prog_cc_stdc) +fi +case "x$am_cv_prog_cc_stdc" in + x|xno) ;; + *) CC="$CC $am_cv_prog_cc_stdc" ;; +esac +]) + diff --git a/config.guess b/config.guess new file mode 100755 index 000000000..413ed41c0 --- /dev/null +++ b/config.guess @@ -0,0 +1,883 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[3478]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;; + 9000/8?? ) HP_ARCH=hppa1.0 ;; + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo i386-pc-cygwin32 + exit 0 ;; + i*:MINGW*:*) + echo i386-pc-mingw32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin32 + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c </dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >dummy.c < +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/config.h.in b/config.h.in new file mode 100644 index 000000000..d190ec4fe --- /dev/null +++ b/config.h.in @@ -0,0 +1,36 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + +/* Other stuff */ +#undef HAVE_IPC_H +#undef HAVE_SHM_H +#undef HAVE_XPM +#undef HAVE_XSHM_H +#undef HAVE_SYS_SELECT_H + +#undef IPC_RMID_DEFERRED_RELEASE + +#undef NO_FD_SET + +#undef RESOURCE_BASE + +#undef XINPUT_NONE +#undef XINPUT_GXI +#undef XINPUT_XFREE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* #undef PACKAGE */ +/* #undef VERSION */ diff --git a/config.sub b/config.sub new file mode 100755 index 000000000..213a6d47d --- /dev/null +++ b/config.sub @@ -0,0 +1,954 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 \ + | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[3456]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[3456]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[3456]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[3456]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[3456]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[3456]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + np1) + basic_machine=np1-gould + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5) + basic_machine=i586-intel + ;; + pentiumpro | p6) + basic_machine=i686-intel + ;; + pentium-* | p5-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + k5) + # We don't have specific support for AMD's K5 yet, so just call it a Pentium + basic_machine=i586-amd + ;; + nexen) + # We don't have specific support for Nexgen yet, so just call it a Pentium + basic_machine=i586-nexgen + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-ibm) + os=-aix + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/configure.in b/configure.in new file mode 100644 index 000000000..faa57edc8 --- /dev/null +++ b/configure.in @@ -0,0 +1,214 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT(gdk/gdktypes.h) + +# Configure glib +AC_CONFIG_SUBDIRS(glib) + +dnl Initialize automake stuff +AM_INIT_AUTOMAKE(gtk+, 971109) + +# Specify a configuration file +AM_CONFIG_HEADER(config.h) + +dnl Initialize libtool +AM_PROG_LIBTOOL + +dnl Initialize maintainer mode +AM_MAINTAINER_MODE + +AC_CANONICAL_HOST + +AC_ARG_ENABLE(shm, [ --enable-shm support shared memory if available [default=yes]], + echo $enable_shm, enable_shm="yes") +AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging [default=no]], +if eval "test x$enable_debug = xyes"; then + DEBUGFLAG="-g" +fi) +AC_ARG_ENABLE(ansi, [ --enable-ansi turn on strict ansi [default=no]], + , enable_ansi=no) + +AC_ARG_WITH(xinput, [ --with-xinput[=no/gxi/xfree] support XInput ]) + +if test -n "$DEBUGFLAG"; then + CFLAGS="$DEBUGFLAG" +else + CFLAGS="$CFLAGS -DNDEBUG" +fi + +# Build time sanity check... +AM_SANITY_CHECK + +# Checks for programs. +AC_PROG_CC +AM_PROG_CC_STDC +AC_PROG_INSTALL +AC_PROG_MAKE_SET + +if eval "test x$GCC = xyes"; then + test `echo "$CFLAGS" | grep "\-Wall" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -Wall" + fi + + if eval "test x$enable_ansi = xyes"; then + test `echo "$CFLAGS" | grep "\-ansi" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -ansi" + fi + + test `echo "$CFLAGS" | grep "\-pedantic" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -pedantic" + fi + fi +fi + +# Find the X11 include and library directories +AC_PATH_X +AC_PATH_XTRA + +if test "x$x_includes" = "x"; then + x_includes="/usr/include" +fi + +saved_cflags="$CFLAGS" +saved_ldflags="$LDFLAGS" + +CFLAGS="$X_CFLAGS" +LDFLAGS="$X_LDFLAGS $X_LIBS" + +# Checks for libraries. +# Check for the X11 library +AC_CHECK_LIB(X11, XOpenDisplay, x_libs="-lX11 $X_EXTRA_LIBS", no_x11_lib=yes, $X_EXTRA_LIBS) + +if eval "test x$enable_shm = xyes"; then + # Check for the Xext library (needed for XShm extention) + AC_CHECK_LIB(Xext, XShmAttach, x_libs="-lXext $x_libs", no_xext_lib=yes, $x_libs) +fi + +x_cflags="$X_CFLAGS" +x_ldflags="$X_LDFLAGS $X_LIBS" + +# set up things for XInput + +if eval "test x$with_xinput = xgxi -o x$with_xinput = xyes"; then + AC_DEFINE(XINPUT_GXI) + xinput_progs=gxid + x_libs="-lXi $x_libs" +elif eval "test x$with_xinput = xxfree"; then + AC_DEFINE(XINPUT_XFREE) + x_libs="-lXi $x_libs" +else + AC_DEFINE(XINPUT_NONE) +fi + + +AC_SUBST(x_cflags) +AC_SUBST(x_includes) +AC_SUBST(x_ldflags) +AC_SUBST(x_libs) +AC_SUBST(xinput_progs) + +CFLAGS="$saved_cflags" +LDFLAGS="$saved_ldflags" + +if eval "test x$enable_shm = xyes"; then + # Check for shared memory + AC_CHECK_HEADER(sys/ipc.h, AC_DEFINE(HAVE_IPC_H), no_sys_ipc=yes) + AC_CHECK_HEADER(sys/shm.h, AC_DEFINE(HAVE_SHM_H), no_sys_shm=yes) + + # Check whether shmctl IPC_RMID allowes subsequent attaches + if test "$ac_cv_header_sys_shm_h" = "yes"; then + AC_MSG_CHECKING(whether shmctl IPC_RMID allowes subsequent attaches) + AC_TRY_RUN([ + #include + #include + #include + int main() + { + int id; + char *shmaddr; + id = shmget (IPC_PRIVATE, 4, IPC_CREAT | 0777); + if (id == -1) + exit (2); + shmaddr = shmat (id, 0, 0); + shmctl (id, IPC_RMID, 0); + if ((char*) shmat (id, 0, 0) == (char*) -1) + { + shmdt (shmaddr); + exit (1); + } + shmdt (shmaddr); + shmdt (shmaddr); + exit (0); + } + ], + AC_DEFINE(IPC_RMID_DEFERRED_RELEASE) + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no), + AC_MSG_RESULT(assuming no)) + fi + + # Check for the X shared memory extension header file + AC_MSG_CHECKING(X11/extensions/XShm.h) + if eval "test x$no_ext_lib = xyes"; then + AC_MSG_RESULT(no) + no_xshm=yes + else + if eval "test -f $x_includes/X11/extensions/XShm.h"; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_XSHM_H) + else + AC_MSG_RESULT(no) + no_xshm=yes + fi + fi +fi + +# Check for private display resource base variable +AC_MSG_CHECKING(resource base field in XDisplay) +AC_CACHE_VAL(gtk_cv_display_resource_base, +[AC_TRY_RUN([ +#define XLIB_ILLEGAL_ACCESS +#include + +int +main () +{ + Display *display; + + return 0; + + display->resource_base; +}], +gtk_cv_display_resource_base="resource_base", +gtk_cv_display_resource_base="private3")]) +AC_MSG_RESULT($gtk_cv_display_resource_base) +AC_DEFINE_UNQUOTED(RESOURCE_BASE, gdk_display->$gtk_cv_display_resource_base) + +# Checks for header files. +AC_HEADER_STDC + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +# Checks for library functions. +AC_TYPE_SIGNAL + +# Check for sys/select.h + +AC_MSG_CHECKING([fd_set and sys/select]) +AC_TRY_COMPILE([#include ], + [fd_set readMask, writeMask;], gtk_ok=yes, gtk_ok=no) +if test $gtk_ok = no; then + AC_HEADER_EGREP(fd_mask, sys/select.h, gtk_ok=yes) + if test $gtk_ok = yes; then + AC_DEFINE(HAVE_SYS_SELECT_H) + fi +fi +AC_MSG_RESULT($gtk_ok) +if test $gtk_ok = no; then + AC_DEFINE(NO_FD_SET) +fi + +AC_OUTPUT(Makefile gtk+.xconfig docs/Makefile gdk/Makefile gtk/Makefile) diff --git a/docs/.cvsignore b/docs/.cvsignore new file mode 100644 index 000000000..f3c7a7c5d --- /dev/null +++ b/docs/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/docs/Makefile.am b/docs/Makefile.am new file mode 100644 index 000000000..f4df2f3e3 --- /dev/null +++ b/docs/Makefile.am @@ -0,0 +1,10 @@ +## Process this file with automake to produce Makefile.in + +info_TEXINFOS = gdk.texi gtk.texi + +EXTRA_DIST = texinfo.tex macros.texi + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done diff --git a/docs/gdk.texi b/docs/gdk.texi new file mode 100644 index 000000000..4942fe29b --- /dev/null +++ b/docs/gdk.texi @@ -0,0 +1,326 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename gdk.info +@settitle GDK +@setchapternewpage odd +@c %**end of header + +@set edition 1.0 +@set update-date 16 May 1996 +@set update-month May 1996 + +@ifinfo +This file documents GDK, the General Drawing Kit + +Copyright (C) 1996 Peter Mattis + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies + +@ignore +Permission is granted to process this file throught TeX and print the +results, provided the printed document carries copying permission notice +identical to this one except for the removal of this paragraph (this +paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by Peter Mattis. +@end ifinfo + +@titlepage +@title The General Drawing Kit +@subtitle Version 1.0 +@subtitle @value{update-month} +@author by Peter Mattis + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1996 Peter Mattis + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by Peter Mattis. +@end titlepage + +@dircategory User Interface Toolkit +@direntry +* GDK: (gdk). The General Drawing Kit +@end direntry + +@node Top, Copying, (dir), (dir) +@top The General Drawing Kit +@ifinfo +This is edition @value{edition} of the GDK documentation, +@w{@value{update-date}}. +@end ifinfo + +@menu +* Copying:: Your rights. +* Overview:: What is GDK? +* Initialization:: Initialization and exit. +* Events:: Event handling. +* Visuals:: Understanding and using visuals. +* Windows:: Creating and using windows. +* Graphics Contexts:: Creating and modifying GCs. +* Pixmaps:: Creating pixmaps. +* Images:: Creating images. +* Color:: Specifying color. +* Fonts:: Creating fonts. +* Drawing:: Drawing commands. +* XInput Support:: Using extended devices. +* Miscellany:: Other stuff. +* Examples:: Using GDK. +* Function Index:: Index of functions +* Concept Index:: Index of concepts +@end menu + +@node Copying, Overview, Top, Top +@comment node-name, next, previous, up +@chapter Copying + +GDK is @dfn{free}; this means that everyone is free to use it and free +to redestribute it on a free basis. GDK is not in the public domain; it +is copyrighted and there are restrictions on its distribution, but these +restrictions are designed to permit everything that a good cooperating +citizen would want to do. What is not allowed is to try to prevent +others from further sharing any version of GDK that they might get from +you. + +Specifically, we want to make sure that you have the right to give away +copies of GDK, that you receive source code or else can get it if you +want it, that you can change GDK or use pieces of it in new free +programs, and that you know you can do these things. + +To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute +copies of GDK, you must give the recipients all the rights that you +have. You must make sure that they, too, receive or can get the source +code. And you must tell them their rights. + +Also, for my own protection, we must make certain that everyone finds +out that there is no warranty for GDK. If GDK is modified by someone +else and passed on, we want their recipients to know that what they have +is not what we distributed, so that any problems introduced by others +will no reflect on our reputation. + +The precise conditions of the licenses for GDK are found in the General +Public Licenses that accompanies it. + + +@node Overview, Initialization, Copying, Top +@comment node-name, next, previous, up +@chapter What is GDK? +@cindex Overview + +GDK is designed as a wrapper library that lies on top of Xlib. It +performs many common and desired operations for a programmer instead +of the programmer having to explicitly ask for such functionality from +Xlib directly. For example, GDK provides a common interface to both +regular and shared memory XImage types. By doing so, an application +can nearly transparently use the fastest image type available. GDK +also provides routines for determining the best available color depth +and the best available visual which is not always the default visual +for a screen. + +@node Initialization, Events, Overview, Top +@comment node-name, next, previous, up +@chapter Initialization and exit +@cindex Initialization +@cindex Exit + +Initializing GDK is easy. Simply call @code{gdk_init} passing in the +@var{argc} and @var{argv} parameters. Exit is similarly easy. Just +call @code{gdk_exit}. + +@deftypefun void gdk_init (int *@var{argc}, char ***@var{argv}) +Initializes the GDK library. The arguments @var{argc} and @var{argv} +are scanned and any arguments that GDK recognizes are handled and +removed. The @var{argc} and @var{argv} parameters are the values +passed to @code{main} upon program invocation. +@end deftypefun + +@deftypefun void gdk_exit (int @var{errorcode}) +Exit GDK and perform any necessary cleanup. @code{gdk_exit} will call +the systems @code{exit} function passing @var{errorcode} as the +parameter. +@end deftypefun + +@example +int +main (int argc, char *argv[]) +@{ + /* Initialize GDK. */ + gdk_init (&argc, &argv); + + /* Exit from GDK...this call will never return. */ + gdk_exit (0); + + /* Keep compiler from issuing a warning */ + return 0; +@} +@end example + + +@node Events, Visuals, Initialization, Top +@comment node-name, next, previous, up +@chapter Event handling +@cindex Events + +Events are the means by which GDK lets the programmer know of user +interaction. An event is normally a button or key press or some other +indirect user action, such as a the mouse cursor entering or leaving a +window. + +There exist only a few functions for getting events and event +information. These are @code{gdk_events_pending}, +@code{gdk_event_get}, @code{gdk_events_record} and +@code{gdk_events_playback}. The latter two functions are useful for +automatic testing of a software package and should normally not be +needed in a program. + +@deftypefun gint gdk_events_pending (void) +Returns the number of events pending on the event queue. +@end deftypefun + +@deftypefun gint gdk_event_get (GdkEvent *@var{event}) +Return the next available event in the @var{event} +structure. @code{gdk_event_get} will return @code{TRUE} on success and +@code{FALSE} on failure. Success and failure is determined by whether +an event arrived before the timeout period expired. +@end deftypefun + +@deftypefun void gdk_events_record (char *@var{filename}) +Turn on recording of events. User events and certain system events will +be saved in the file named by the variable @var{filename}. This stream +of events can later be played back and ``should'' produce the same +results as when the original events were handled. However, the +programmer does need to be careful in that the state of the program must +be the same when @code{gdk_events_record} is called and when +@code{gdk_events_playback} is called. For this reason, +@code{gdk_events_record} is normally not called directly, but is instead +invoked indirectly by specifying the ``-record'' command line option. +@end deftypefun + +@deftypefun void gdk_events_playback (char *@var{filename}) +Start playback of events from a file. (See the above description of +@code{gdk_events_record}). Normally this function is not called directly +but is invoked by the ``-playback'' command line option. +@end deftypefun + +@deftypefun void gdk_events_stop (void) +Stop recording and playback of events. +@end deftypefun + +@example +void +handle_event () +@{ + GdkEvent event; + + if (gdk_event_get (&event)) + @{ + switch (event.type) + @{ + @dots{} + @} + @} +@} +@end example + + +@node Visuals, Windows, Events, Top +@comment node-name, next, previous, up +@chapter Understanding and using visuals +@cindex Visuals + +@node Windows, Graphics Contexts, Visuals, Top +@comment node-name, next, previous, up +@chapter Creating and using windows +@cindex Windows + +@node Graphics Contexts, Pixmaps, Windows, Top +@comment node-name, next, previous, up +@chapter Creating and modifying GCs +@cindex Graphics Contexts +@cindex GC + +@node Pixmaps, Images, Graphics Contexts, Top +@comment node-name, next, previous, up +@chapter Creating pixmaps +@cindex Pixmaps + +@node Images, Color, Pixmaps, Top +@comment node-name, next, previous, up +@chapter Creating images +@cindex Images + +@node Color, Fonts, Images, Top +@comment node-name, next, previous, up +@chapter Specifying color +@cindex Color + +@node Fonts, Drawing, Color, Top +@comment node-name, next, previous, up +@chapter Creating Fonts +@cindex Fonts + +@node Drawing, XInput Support, Fonts, Top +@comment node-name, next, previous, up +@chapter Drawing Commands +@cindex Drawing + +@node XInput Support, Miscellany, Drawing, Top +@comment node-name, next, previous, up +@chapter Using extended devices +@cindex Overview +@cindex Using extended device capabilities +@cindex Controlling extended devices + +@node Miscellany, Examples, XInput Support, Top +@comment node-name, next, previous, up +@chapter Other stuff +@cindex Timers +@cindex Debugging +@cindex Miscellaneous + + +@node Examples, Function Index, Miscellany, Top +@comment node-name, next, previous, up +@chapter Using GDK +@cindex Examples + + +@node Function Index, Concept Index, Examples, Top +@comment node-name, next, previous, up +@unnumbered Variable Index + +@printindex fn + +@node Concept Index, , Function Index, Top +@comment node-name, next, previous, up +@unnumbered Concept Index + +@printindex cp + +@summarycontents +@contents +@bye diff --git a/docs/gtk.texi b/docs/gtk.texi new file mode 100644 index 000000000..93daf5b83 --- /dev/null +++ b/docs/gtk.texi @@ -0,0 +1,3285 @@ +\input texinfo @c -*-texinfo-*- +@c Copyright (C) 1996 by Peter Mattis. All rights reserved. +@c +@c %**start of header +@setfilename gtk.info +@settitle GTK +@setchapternewpage odd +@include macros.texi +@c %**end of header + +@set edition 1.0 +@set update-date 9 April 1997 +@set update-month April 1997 + +@ifinfo +This file documents GTK, the General Toolkit + +Copyright (C) 1996 Peter Mattis +Copyright (C) 1997 Peter Mattis + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies + +@ignore +Permission is granted to process this file throught TeX and print the +results, provided the printed document carries copying permission notice +identical to this one except for the removal of this paragraph (this +paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by Peter Mattis. +@end ifinfo + +@titlepage +@title The General Toolkit +@subtitle Version @value{edition} +@subtitle @value{update-month} +@author by Peter Mattis + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1996 Peter Mattis +Copyright @copyright{} 1997 Peter Mattis + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by Peter Mattis. +@end titlepage + +@dircategory User Interface Toolkit +@direntry +* GTK: (gtk). The General Toolkit +@end direntry + +@node Top, Copying, (dir), (dir) +@top The General Toolkit +@ifinfo +This is edition @value{edition} of the GTK documentation, +@w{@value{update-date}}. +@end ifinfo + +@menu +* Copying:: Your rights. +* Overview:: What is GTK? +* Objects:: Object overview. +* Signals:: Signals overview. +* Widgets:: Widget overview. +* Other Objects:: Utility objects. +* Miscellaneous:: Initialization, exit and other features. +* Examples:: Using GTK. +* Object Implementation:: Object internals. +* Signal Implementation:: Signal internals. +* Widget Implementation:: Widget internals. +* Function Index:: Index of functions. +* Concept Index:: Index of concepts. +@end menu + +@node Copying, Overview, Top, Top +@comment node-name, next, previous, up +@chapter Copying + +GTK is @dfn{free}; this means that everyone is free to use it and free +to redestribute it on a free basis. GTK is not in the public domain; it +is copyrighted and there are restrictions on its distribution, but +these restrictions are designed to permit everything that a good +cooperating citizen would want to do. What is not allowed is to try to +prevent others from further sharing any version of GTK that they might +get from you. + +Specifically, we want to make sure that you have the right to give away +copies of GTK, that you receive source code or else can get it if you +want it, that you can change GTK or use pieces of it in new free +programs, and that you know you can do these things. + +To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute +copies of GTK, you must give the recipients all the rights that you +have. You must make sure that they, too, receive or can get the source +code. And you must tell them their rights. + +Also, for my own protection, we must make certain that everyone finds +out that there is no warranty for GTK. If GTK is modified by someone +else and passed on, we want their recipients to know that what they have +is not what we distributed, so that any problems introduced by others +will no reflect on our reputation. + +The precise conditions of the licenses for GTK are found in the General +Public Licenses that accompanies it. + + +@node Overview, Objects, Copying, Top +@comment node-name, next, previous, up +@chapter What is GTK? +@cindex Overview + +GTK is a library for creating graphical user interfaces similar to the +Motif ``look and feel''. It is designed to be small and efficient, but +still flexible enough to allow the programmer freedom in the interfaces +created. GTK allows the programmer to use a variety of standard user +interface widgets (@pxref{Widgets}) such as push, radio and check +buttons, menus, lists and frames. It also provides several ``container'' +widgets which can be used to control the layout of the user interface +elements. + +GTK provides some unique features. (At least, I know of no other widget +library which provides them). For example, a button does not contain a +label, it contains a child widget, which in most instances will be a +label. However, the child widget can also be a pixmap, image or any +combination possible the programmer desires. This flexibility is adhered +to throughout the library. + + +@node Objects, Signals, Overview, Top +@comment node-name, next, previous, up +@chapter Object Overview +@cindex Objects + +GTK implements a semi-simple class mechanism and an associated class +hierarchy for widgets and several other useful objects. The GtkObject +type is the root of the class hierarchy. It provides a few items needed +by all classes, the foundation for the signal (@pxref{Signals}) +mechanism and the ``destroy'' method. + +The class hierarchy is defined by a type hierarchy. This hierarchy +allows queries to be made in regards to a type. The basic query that can +be performed is asking whether a given type has an ``is a'' relation +with another type. For instance, it is common to ask whether a general +widget pointer is a type of specific widget so that runtime sanity +checks can be made. + +@section Type utility functions + +The @code{GtkTypeInfo} structure is used to communicate information to +@code{gtk_type_unique} as opposed to passing in large numbers of +parameters. + +@example +typedef struct _GtkTypeInfo GtkTypeInfo; + +struct _GtkTypeInfo +@{ + gchar *type_name; + guint object_size; + guint class_size; + GtkClassInitFunc class_init_func; + GtkObjectInitFunc object_init_func; + GtkValueInitFunc value_init_func; +@} +@end example + +@itemize @bullet +@item +The @code{type_name} field refers to the name of the type. It is +convention for the type name to be the same as the C structure type. For +example, the type name of the @code{GtkObject} structure is +``GtkObject''. + +@item +The @code{object_size} field refers to the size in bytes of the C +structure. The easiest (and portable) means of computing this size is by +using the C @code{sizeof} operator. For instance, the sizeof of the +@code{GtkObject} structure is computed by doing @code{sizeof +(GtkObject)}. + +@item +The @code{class_size} field refers to the size in bytes of the C +structure for the class. Again, the @code{sizeof} operator should be +used to compute this value. + +@item +The @code{class_init_func} field is a callback which is used by the type +mechanism to initialize class specific fields. The single argument this +function takes is a pointer to a class structure. + +@item +The @code{object_init_func} field is a callback which is used by the +type mechanism to initialize object specific fields. The single argument +this functions takes is a pointer to an object structure. + +@item +The @code{value_init_func} field is a callback which is used by the type +mechanism to initialize object stack value types. (FIXME: unfinished). +@end itemize + +@deftypefun guint gtk_type_unique (guint @var{parent_type}, GtkTypeInfo *@var{type_info}) +The @var{parent_type} is simply the value of the new types parent +type. If @var{parent_type} is 0, then the new type is the root of the +type hierarchy. @var{type_info} is a pointer to a structure which +contains necessary information for construction of the new +type. Specifically, the @code{type_name}, @code{object_size} and +@code{class_size} fields are required. The @code{class_init_func}, +@code{object_init_func} and @code{value_init_func} fields may be NULL. +@end deftypefun + +@deftypefun gchar* gtk_type_name (guint @var{type}) +The returned string is the name of @var{type} as specified to +@code{gtk_type_unique}. +@end deftypefun + +@deftypefun guint gtk_type_from_name (guchar *@var{name}) +Return the type associated with @var{name}. If there is no type +associated with @var{name}, then 0 will be returned. +@end deftypefun + +@deftypefun guint gtk_type_parent (guint @var{type}) +Returns the parent type of @var{type} or 0 if @var{type} is the root of +the type hierarchy. +@end deftypefun + +@deftypefun gpointer gtk_type_class (guint @var{type}) +Returns the initialized class structure for @var{type}. The class +structure is actually created and initialized the first time it is +needed. If creation and initialization occurs, the @code{class_size} +field of the @code{GtkTypeInfo} structure used to initialize this type +is used to determine how large the class structure is. The +@code{class_init_func} field from the @code{GtkTypeInfo} structure is +called for all the members in the types ancestry, including the +type. The order of this invocation proceeds from the root on down. For +example, the @code{GtkWidgetClass} is first initialized as an +@code{GtkObjectClass} by the object class initialization routine and +then by the widget class initialization routine. This allows the widget +class initialization routine to override values set by the object class +initialization routine. The returned structure is shared by all objects +of @var{type} and, as such, should not be modified. +@end deftypefun + +@deftypefun gpointer gtk_type_new (guint @var{type}) +Returns a new instance of an @var{type} object. The object structure is +created and initialized similarly to the class structure (as described +above). The @code{object_size} and @code{object_init_func} fields of the +@code{GtkTypeInfo} structure are used to determine the objects allocated +size and the object specific initialization routine. Similarly to the +class initialization, all the object initialization routines from the +root on down to the particular type being created are invoked. +@end deftypefun + +@deftypefun void gtk_type_describe_heritage (guint @var{type}) +Prints the type heritage for @var{type}. The heritage for a type +includes the type and all its parent types up the type tree. +@end deftypefun + +@deftypefun void gtk_type_describe_tree (guint @var{type}, gint @var{show_size}) +Prints the type tree which starts at @var{type}. @var{show_size} is a +boolean which determines whether type sizes are printed. +@end deftypefun + +@deftypefun gint gtk_type_is_a (guint @var{type}, guint @var{is_a_type}) +A predicate function which determines whether the relation @var{type} +is_a @var{is_a_type} is true. +@end deftypefun + +@section Object functions + +The GtkObject type is the root of the type hierarchy used by GTK. It +provides a minimal set of fields used to implement the actual +object, class and signal mechanisms, as well as several utility routines +which make dealing with objects easier. + +For the adventurous, see @ref{Object Implementation}. + +@deftypefun guint gtk_object_get_type (void) +Returns the @code{GtkObject} type identifier. +@end deftypefun + +@deftypefun void gtk_object_class_add_signals (GtkObjectClass *@var{class}, gint *@var{signals}, gint @var{nsignals}) +Adds @var{signals} to the @code{signals} field in the GtkObjectClass +structure @var{class}. @xref{Signals}. +@end deftypefun + +@deftypefun void gtk_object_destroy (GtkObject *@var{object}) +Performs checks to make sure it is alright to destroy @var{object} and +then emits the @code{destroy} signal. The check which is performed is to +make sure @var{object} is not already processing another signal. If this +were the case then destroying the object immediately would undoubtedly +cause problems as the other signal would not be able to tell the object +was destroyed. The solution is that if @var{object} is processing another +signal we mark @var{object} is needing to be destroyed. When we finish +processing of the other signal we check whether the object needs to be +destroyed. +@end deftypefun + +The GtkObject type provides a mechanism for associating arbitrary +amounts of data with an object. The data is associated with the object +using a character string key. The functions @code{gtk_object_set_data}, +@code{gtk_object_get_data}, and @code{gtk_object_remove_data} are the +interface to this mechanism. Two other routines, +@code{gtk_object_set_user_data} and @code{gtk_object_get_user_data}, +exist as convenience functions which simply use the same mechanism. + +@deftypefun void gtk_object_set_data (GtkObject *@var{object}, const char *@var{key}, gpointer @var{data}) +Associate @var{data} with @var{key} in the data list of @var{object}. +@end deftypefun + +@deftypefun gpointer gtk_object_get_data (GtkObject *@var{object}, const char *@var{key}) +Retrieve the data associated with @var{key} in the data list of @var{object}. +@end deftypefun + +@deftypefun void gtk_object_remove_data (GtkObject *@var{object}, const char *@var{key}) +Remove the data associated with @var{key} in the data list of @var{object}. +@end deftypefun + +@deftypefun void gtk_object_set_user_data (GtkObject *@var{object}, gpointer @var{data}) +Sets @var{data} into the @code{user_data} field of @var{object}. +@end deftypefun + +@deftypefun gpointer gtk_object_get_user_data (GtkObject *@var{object}) +Returns the @code{user_data} field of @var{object}. +@end deftypefun + +The GtkObject type also provides a mechanism for specifying +initialization values for fields. This general mechanism is called +object value stacks. The reason for using value stacks is that they can +simplify the life of the programmer. For instance, by default widgets +are non-visible when created. However, the ``visible'' value for widgets +may be specified so that widgets are made visible when created. (FIXME: +unfinished). + +@deftypefun void gtk_object_value_stack_new (guint @var{object_type}, const gchar *@var{value_id}, GtkParamType @var{value_type}) +@end deftypefun + +@deftypefun void gtk_object_push_value (guint @var{object_type}, const gchar *@var{value_id}, @dots{}) +Push a value on the value stack specified by @var{object_type} and +@var{value_id}. The type of value is implicitly given in the context of +@var{object_type} and @var{value_id}. (That is, it is not specified +explicitly in the function call). Only a single extra argument is +expected which is the data which is to be placed on the stack. +@end deftypefun + +@deftypefun void gtk_object_pop_value (guint @var{object_type}, const gchar *@var{value_id}) +Pop a value of the value stack specified by @var{object_type} and +@var{value_id}. +@end deftypefun + +@deftypefun gint gtk_object_peek_value (guint @var{object_type}, const gchar *@var{value_id}, gpointer @var{data}) +Peek at the value on the top of the value stack specified by +@var{object_type} and @var{value_id}. The @var{data} argument is +interpreted as the location of where to place the ``peeked'' data. For +instance, if the peeked data is of type @code{GTK_PARAM_POINTER}, then +@var{data} will be a pointer to a pointer. If the value stack is empty +or does not exist or an error occurs, @code{gtk_object_peek_value} will +return @code{FALSE}. On success it will return @code{TRUE}. +@end deftypefun + + +@node Signals, Widgets, Objects, Top +@comment node-name, next, previous, up +@chapter Signals Overview +@cindex Signals + +Signals are GTK's method for objects to perform callbacks. A signal is +an event which occurs upon an object. The programmer can connect to a +signal of an object which involves specifying a function to be called +when that signal is emitted in the specified object. + +When a signal is emitted, both the class function associated with the +signal (when it was defined) and all signal handlers installed for that +signal on the particular object emitting the signal are called. The +widget programmer can specify whether the class function is to be called +before after or both before and after the signal handlers installed by +the widget user. The widget user can, however, specify that their signal +handler is to be run after the class function (using the ``_after'' +signal connection routines). Any signal handling function can emit the +same signal on the same object while it is running causing that signal +emittion to either restart or to run recursively. Additionally, signal +emittion can be terminated prematurely. While both such abilities are +rarely used, they do allow for greater flexibility in regards to +signals. For instance, a programmer can attach to the key press event +signal and intercept all tab key presses from a widget. This particular +example is used in the file selection dialog to implement tab completion +of filenames and prevent the entry widget from inserting the tab into +its buffer. + +Signals are selected using either an integer identifier or a character +string name. It is convention to name the signal the same as the class +function which is associated with it. There are two versions of most of +the signal functions, one which takes an integer identifier and one +which takes a character string name for the signal. + +@deftypefun gint gtk_signal_new (gchar *@var{name}, GtkSignalRunType @var{run_type}, gint @var{object_type}, gint @var{function_offset}, GtkSignalMarsahller @var{marshaller}, GtkParamType @var{return_val}, gint @var{nparams}, @dots{}) +Create a new signal and give it the character string identifier +@var{name}. @var{name} needs to be unique in the context of +@var{object_type}'s branch of the class hierarchy. That is, +@var{object_type} cannot create a signal type with the same name as a +signal type created by one of its parent types. + +@var{run_type} specifies whether the class function should be run before +(@code{GTK_RUN_FIRST}), after (@code{GTK_RUN_LAST}) or both before and +after normal signal handlers (@code{GTK_RUN_BOTH}). Additionally, the +@code{GTK_RUN_NO_RECURSE} value can be or'ed with any of those values to +specify that the signal should not be recursive. By default, emitting +the same signal on the same widget will cause the signal to be emitted +twice. However, if the @code{GTK_RUN_NO_RECURSE} flag is specified, +emitting the same signal on the same widget will cause the current +signal emittion to be restarted. This allows the widget programmer to +specify the semantics of signal emittion on a per signal +basis. (The @code{GTK_RUN_NO_RECURSE} flag is used by the GtkAdjustment +widget). + +The @var{function_offset} is the byte offset from the start of the class +structure to the class function field within the class structure. The +easiest means to compute this offset is by using the +@code{GTK_SIGNAL_OFFSET} macro which takes the class structure type as +the first argument and the field as the second argument. For example, +@code{GTK_SIGNAL_OFFSET (GtkObjectClass, destroy)} will give the offset +of the @code{destroy} class function within the +@code{GtkObjectClass}. Note: An offset is specified instead of an +absolute location since there will be multiple instances of a class +structure being referenced. (The @code{GtkWidgetClass} structure ``is +a'' @code{GtkObjectClass} structure, etc.) + +The @var{marshaller} function is used to invoke a signal handler. Since +signal handlers may take different parameters and return values and a +general mechanism for invoking them is not apparent, the approach of +making the signal creator responsible for invoking the signal handler +was taken. (FIXME: unfinished). + +The @var{return_val} and @var{nparams} and the remaining arguments +specify the return value and the arguments to the signal handler +respectively. Note: There is an implicit first argument to every signal +handler which is the widget the signal has been emitted from. The +variable argument list (@var{@dots{}}) specifies the types of the +arguments. These can be one of @code{GTK_PARAM_CHAR}, +@code{GTK_PARAM_SHORT}, @code{GTK_PARAM_INT}, @code{GTK_PARAM_LONG}, +@code{GTK_PARAM_POINTER} or @code{GTK_PARAM_FUNCTION}. It is undefined +to specify @code{GTK_PARAM_NONE} as an argument type, however it is ok +to use @code{GTK_PARAM_NONE} for @var{return_val}. (This corresponds to +returning a @code{void}). + +@code{gtk_signal_new} returns the integer identifier of the newly +created signal. Signal identifiers start numbering at 1 and increase +upwards. A value of -1 will be returned if an error occurs. + +@strong{Note:} @code{gtk_signal_new} is only needed by widget writers. A +normal user of GTK will never needed to invoke this function. +@end deftypefun + +@deftypefun gint gtk_signal_lookup (gchar *@var{name}, gint @var{object_type}) +Returns the integer identifier for the signal referenced by @var{name} +and @var{object_type}. If @var{object_type} does not define the signal +@var{name}, then the signal is looked for in @var{object_type}'s parent +type recursively. +@end deftypefun + +@deftypefun gint gtk_signal_emit (GtkObject *@var{object}, gint @var{signal_type}, @dots{}) +Emit the signal specified by the integer identifier @var{signal_type} +from @var{object}. If an error occurs, @code{gtk_signal_emit} will +return @code{FALSE} and will return @code{TRUE} on success. The signal +definition determines the parameters passed in the variable argument +list (@code{@dots{}}). For example, if the signal is defined as: + +@example + gint (* event) (GtkWidget *widget, GdkEvent *event); +@end example + +Then a call to emit the ``event'' signal would look like: + +@example + GdkEvent event; + gint return_val; + @dots{} + gtk_signal_emit (some_object, + gtk_signal_lookup ("event", + GTK_OBJECT_TYPE (some_object)), + &event, &return_val); +@end example + +Notice that the @code{widget} argument is implicit in that the first +argument to every signal is a type derived from @code{GtkObject}. The +@var{return_val} argument is actually a pointer to the return value type +since the signal mechanism needs to be able to place the return value in +an actual location. And lastly, the @code{gtk_signal_lookup} call is +normally avoided by using the @code{gtk_signal_emit_by_name} function +instead. @code{gtk_signal_emit} is normally used internally by widgets +which know the signal identifier (since they defined the signal) and can +therefore side-step the cost of calling @code{gtk_signal_lookup}. +@end deftypefun + +@deftypefun gint gtk_signal_emit_by_name (GtkObject *@var{object}, gchar *@var{name}, @dots{}) +Similar to @code{gtk_signal_emit} except that the signal is referenced +by @var{name} instead of by its integer identifier. +@end deftypefun + +@deftypefun void gtk_signal_emit_stop (GtkObject *@var{object}, gint @var{signal_type}) +Stop the emission of the signal @var{signal_type} on +@var{object}. @var{signal_type} is the integer identifier for the signal +and can be determined using the function +@code{gtk_signal_lookup}. Alternatively, the function +@code{gtk_signal_emit_stop_by_name} can be used to refer to the signal +by name. Attempting to stop the emission of a signal that isn't being +emitted does nothing. +@end deftypefun + +@deftypefun void gtk_signal_emit_stop_by_name (GtkObject *@var{object}, gchar *@var{name}) +Similar to @code{gtk_signal_emit_stop} except that the signal is +referenced by @var{name} instead of by its integer identifier. +@end deftypefun + +@deftypefun gint gtk_signal_connect (GtkObject *@var{object}, gchar *@var{name}, GtkSignalFunc @var{func}, gpointer @var{func_data}) +Connects a signal handling function to a signal emitting +object. @var{func} is connected to the signal @var{name} emitted by +@var{object}. The arguments and returns type of @var{func} should match +the arguments and return type of the signal @var{name}. However, +@var{func} may take the extra argument of @var{func_data}. Due to the C +calling convention it is ok to ignore the extra argument. (It is ok to +ignore all the arguments in fact). + +@code{gtk_signal_connect} returns an integer identifier for the +connection which can be used to refer to it in the future. Specifically +it is useful for removing the connection and/or blocking it from being +used. +@end deftypefun + +@deftypefun gint gtk_signal_connect_after (GtkObject *@var{object}, gchar *@var{name}, GtkSignalFunc @var{func}, gpointer @var{func_data}) +Similar to @code{gtk_signal_connect} except the signal handler is +connected in the ``after'' slot. This allows a signal handler to be +guaranteed to run after other signal handlers connected to the same +signal on the same object and after the class function associated with +the signal. + +Like @code{gtk_signal_connect}, @code{gtk_signal_connect_after} returns +an integer identifier which can be used to refer to the connection. +@end deftypefun + +@deftypefun gint gtk_signal_connect_object (GtkObject *@var{object}, gchar *@var{name}, GtkSignalFunc @var{func}, GtkObject *@var{slot_object}) +Connects @var{func} to the signal @var{name} emitted by +@var{object}. Similar to @code{gtk_signal_connect} with the difference +that @var{slot_object} is passed as the first parameter to @var{func} +instead of the signal emitting object. This can be useful for connecting +a signal emitted by one object to a signal in another object. A common +usage is to connect the ``destroy'' signal of dialog to the ``clicked'' +signal emitted by a ``close'' button in the dialog. That is, the +``clicked'' signal emitted by the button will caused the ``destroy'' +signal to be emitted for the dialog. This is also the ``right'' way to +handle closing of a dialog since the ``destroy'' signal will be sent if +the dialog is deleted using a window manager function and this enables +the two methods of closing the window to be handled by the same +mechanism. Returns an integer identifier which can be used to refer to +the connection. +@end deftypefun + +@deftypefun gint gtk_signal_connect_object_after (GtkObject *@var{object}, gchar *@var{name}, GtkSignalFunc @var{func}, GtkObject *@var{slot_object}) +Similar to @code{gtk_signal_connect_object} except the signal handler is +connected in the ``after'' slot. This allows a signal handler to be +guaranteed to run after other signal handlers connected to the same +signal on the same object and after the class function associated with +the signal. Returns an integer identifier which can be used to refer to +the connection. +@end deftypefun + +@deftypefun void gtk_signal_disconnect (GtkObject *@var{object}, gint @var{id}) +Disconnects a signal handler from an object. The signal handler is +identified by the integer @var{id} which is returned by the +@code{gtk_signal_connect*} family of functions. +@end deftypefun + +@deftypefun void gtk_signal_disconnect_by_data (GtkObject *@var{object}, gpointer @var{data}) +Disconnects a signal handler from an object. The signal handler is +identified by the @var{data} argument specified as the @var{func_data} +argument to the @code{gtk_signal_connect*} family of functions. For the +@code{gtk_signal_connect_object*} functions, @var{data} refers to the +@var{slot_object}. + +@strong{Note:} This will remove all signal handlers connected to +@var{object} which were connected using @var{data} as their +@var{func_data} argument. Multiple signal handlers may be disconnected +with this call. +@end deftypefun + +@deftypefun void gtk_signal_handler_block (GtkObject *@var{object}, gint @var{id}) +Blocks calling of a signal handler during signal emission. The signal +handler is identified by the integer @var{id} which is returned by the +@code{gtk_signal_connect*} family of functions. If the signal is already +blocked no change is made. +@end deftypefun + +@deftypefun void gtk_signal_handler_block_by_data (GtkObject *@var{object}, gint @var{data}) +Blocks calling of a signal handler during signal emission. The signal +handler is identified by the @var{data} argument specified as the +@var{func_data} argument to the @code{gtk_signal_connect*} family of +functions. For the @code{gtk_signal_connect_object*} functions, +@var{data} refers to the @var{slot_object}. If the signal is already +blocked no change is made. + +@strong{Note:} This will block all signal handlers connected to +@var{object} which were connected using @var{data} as their +@var{func_data} argument. Multiple signal handlers may be blocked +with this call. +@end deftypefun + +@deftypefun void gtk_signal_handler_unblock (GtkObject *@var{object}, gint @var{id}) +Unblocks calling of a signal handler during signal emission. The signal +handler is identified by the integer @var{id} which is returned by the +@code{gtk_signal_connect*} family of functions. If the signal is already +unblocked no change is made. +@end deftypefun + +@deftypefun void gtk_signal_handler_unblock_by_data (GtkObject *@var{object}, gint @var{data}) +Unblocks calling of a signal handler during signal emission. The signal +handler is identified by the @var{data} argument specified as the +@var{func_data} argument to the @code{gtk_signal_connect*} family of +functions. For the @code{gtk_signal_connect_object*} functions, +@var{data} refers to the @var{slot_object}. If the signal is already +unblocked no change is made. + +@strong{Note:} This will unblock all signal handlers connected to +@var{object} which were connected using @var{data} as their +@var{func_data} argument. Multiple signal handlers may be unblocked +with this call. +@end deftypefun + +@deftypefun void gtk_signal_handlers_destroy (GtkObject *@var{object}) +Destroy all of the signal handlers connected to @var{object}. There +should normally never be reason to call this function as it is called +automatically when @var{object} is destroyed. +@end deftypefun + +@deftypefun void gtk_signal_default_marshaller (GtkObject *@var{object}, GtkSignalFunc @var{func}, gpointer @var{func_data}, GtkSignalParam *@var{params}) +@code{gtk_signal_new} requires a callback in order to actually call a +signal handler for a particular signal. The vast majority of signals are +of the particular form: + +@example + (* std_signal) (gpointer std_arg); +@end example + +@code{gtk_signal_default_marshaller} is a signal marshaller which +marshals arguments for a signal of that form. +@end deftypefun + + +@node Widgets, Other Objects, Signals, Top +@comment node-name, next, previous, up +@chapter Widget Overview +@cindex Widgets + + +Widgets are the general term used to describe user interface objects. A +widget defines a class interface that all user interface objects conform +to. This interface allows a uniform method for dealing with operations +common to all objects such as hiding and showing, size requisition and +allocation and events. + +The common interface that widgets must adhere to is described by the +GtkWidget and GtkWidgetClass structure. For the purposes of using GTK +these structures can be considered read-only and, for the most part, +opaque. + +All widget creation routines in GTK return pointers to GtkWidget +structures. In reality, all widget creation routines create structures +that can be viewed as equivalent to the GtkWidget structure, but often +have contain additional information. @xref{Object Implementation} + +The widgets available for use are implemented in a hierarchy. Several +widgets exist solely as common bases for more specific widgets. For +example, it is not possible to create a ruler widget itself, but the +ruler widget provides a base and functionality common to the horizontal +and vertical rulers. + +The available widgets (in alphabetical order): + +@menu +* GtkAlignment:: The alignment widget. +* GtkArrow:: The arrow widget. +* GtkBin:: The bin widget. +* GtkBox:: The box widget. +* GtkButton:: The button widget. +* GtkCheckButton:: The check button widget. +* GtkCheckMenuItem:: The check menu item widget. +* GtkContainer:: The container widget. +* GtkDialog:: The dialog widget. +* GtkDrawingArea:: The drawing area widget. +* GtkEntry:: The entry widget. +* GtkFileSelection:: The file selection dialog widget. +* GtkFrame:: The frame widget. +* GtkHBox:: The horizontal box widget. +* GtkHRuler:: The horizontal ruler widget. +* GtkHScale:: The horizontal scale widget. +* GtkHScrollbar:: The horizontal scrollbar widget. +* GtkHSeparator:: The horizontal separator widget. +* GtkImage:: The image widget. +* GtkItem:: The item widget. +* GtkLabel:: The label widget. +* GtkList:: The list widget. +* GtkListItem:: The list item widget. +* GtkMenu:: The menu widget. +* GtkMenuBar:: The menu bar widget. +* GtkMenuItem:: The menu item widget. +* GtkMenuShell:: The menu shell widget. +* GtkMisc:: The misc widget. +* GtkNotebook:: The notebook widget. +* GtkOptionMenu:: The option menu widget. +* GtkPixmap:: The pixmap widget. +* GtkPreview:: The preview widget. +* GtkProgressBar:: The progress bar widget. +* GtkRadioButton:: The radio button widget. +* GtkRadioMenuItem:: The radio menu item widget. +* GtkRange:: The range widget. +* GtkRuler:: The ruler widget. +* GtkScale:: The scale widget. +* GtkScrollbar:: The scrollbar widget. +* GtkScrolledWindow:: The scrolled window widget. +* GtkSeparator:: The separator widget. +* GtkTable:: The table widget. +* GtkText:: The text widget. +* GtkToggleButton:: The toggle button widget. +* GtkTree:: The tree widget. +* GtkTreeItem:: The tree item widget. +* GtkVBox:: The vertical box widget. +* GtkViewport:: The viewport widget. +* GtkVRuler:: The vertical ruler widget. +* GtkVScale:: The vertical scale widget. +* GtkVScrollbar:: The vertical scrollbar widget. +* GtkVSeparator:: The vertical separator widget. +* GtkWidget:: The base widget type. +* GtkWindow:: The window widget. +@end menu + + +@node GtkAlignment, GtkArrow, Widgets, Widgets +@comment node-name, next, previous, up +@section The alignment widget + + +@subsection Description + +The alignment widget is a container (@pxref{GtkContainer}) derived from +the bin widget (@pxref{GtkBin}). Its entire purpose is to give the +programmer flexibility in how the child it manages is positioned when a +window is resized. + +Normally, a widget is allocated at least as much size as it +requests. (@pxref{GtkContainer} for a discussion of geometry +management). When a widget is allocated more size than it requests there +is a question of how the widget should expand. By convention, most GTK +widgets expand to fill their allocated space. Sometimes this behavior is +not desired. The alignment widget allows the programmer to specify how a +widget should expand and position itself to fill the area it is +allocated. + +@subsection Options + +@defopt xscale +@defoptx yscale +The @var{xscale} and @var{yscale} options specify how to scale the child +widget. If the scale value is 0.0, the child widget is allocated exactly +the size it requested in that dimension. If the scale value is 1.0, the +child widget is allocated all of the space in a dimension. A scale value +of 1.0 for both x and y is equivalent to not using an alignment widget. +@end defopt + +@defopt xalign +@defoptx yalign +The @var{xalign} and @var{yalign} options specify how to position the +child widget when it is not allocated all the space available to it +(because the @var{xscale} and/or @var{yscale} options are less than +1.0). If an alignment value is 0.0 the widget is positioned to the left +(or top) of its allocated space. An alignment value of 1.0 positions the +widget to the right (or bottom) of its allocated space. A common usage +is to specify @var{xalign} and @var{yalign} to be 0.5 which causes the +widget to be centered within its allocated area. +@end defopt + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_alignment_get_type (void) +Returns the @code{GtkAlignment} type identifier. +@end deftypefun + +@deftypefun GtkWidget* gtk_alignment_new (gfloat @var{xalign}, gfloat @var{yalign}, gfloat @var{xscale}, gfloat @var{yscale}) +Create a new @code{GtkAlignment} object and initialize it with the +values @var{xalign}, @var{yalign}, @var{xscale} and @var{yscale}. The +new widget is returned as a pointer to a @code{GtkWidget} +object. @code{NULL} is returned on failure. +@end deftypefun + +@deftypefun void gtk_alignment_set (GtkAlignment *@var{alignment}, gfloat @var{xalign}, gfloat @var{yalign}, gfloat @var{xscale}, gfloat @var{yscale}) +Set the @var{xalign}, @var{yalign}, @var{xscale} and @var{yscale} options +of an alignment widget. It is important to not set the fields of the +@code{GtkAlignment} structure directly (or, for that matter, any type +derived from @code{GtkObject}). +@end deftypefun + +@gtkstdmacros{Alignment, ALIGNMENT} + + +@page +@node GtkArrow, GtkBin, GtkAlignment, Widgets +@comment node-name, next, previous, up +@section The arrow widget + +@subsection Description + +The arrow widget is derived from the misc widget (@pxref{GtkMisc}) and +is intended for use where a directional arrow (in one of the four +cardinal directions) is desired. As such, it has very limited +functionality and basically only draws itself in a particular direction +and with a particular shadow type. The arrow widget will expand to fill +all the space it is allocated. + +@subsection Options + +@defopt arrow_type +The @var{arrow_type} option specifies which direction the arrow will +point. It can be one of @code{GTK_ARROW_UP}, @code{GTK_ARROW_DOWN}, +@code{GTK_ARROW_LEFT} or @code{GTK_ARROW_RIGHT}. +@end defopt + +@defopt shadow_type +The @var{shadow_type} option specifies how to draw the shadow for the +arrow. Currently, only the @code{GTK_SHADOW_IN} and +@code{GTK_SHADOW_OUT} shadow types are supported for drawing +arrows. Other shadow types will cause nothing to be drawn. +@end defopt + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_arrow_get_type (void) +Returns the @code{GtkArrow} type identifier. +@end deftypefun + +@deftypefun GtkWidget* gtk_arrow_new (GtkArrowType @var{arrow_type}, GtkShadowType @var{shadow_type}) +Create a new @code{GtkArrow} object and initialize it with the values +@var{arrow_type} and @var{shadow_type}. The new widget is returned as a +pointer to a @code{GtkWidget} object. @code{NULL} is returned on +failure. +@end deftypefun + +@deftypefun void gtk_arrow_set (GtkArrow *@var{arrow}, GtkArrowType @var{arrow_type}, GtkShadowType @var{shadow_type}) +Set the @var{arrow_type} and @var{shadow_type} options of an arrow +widget. It is important to not set the fields of the @code{GtkArrow} +structure directly (or, for that matter, any type derived from +@code{GtkObject}). +@end deftypefun + +@gtkstdmacros{Arrow, ARROW} + + +@page +@node GtkBin, GtkBox, GtkArrow, Widgets +@comment node-name, next, previous, up +@section The bin widget + +@subsection Description + +The bin widget is a container (@pxref{GtkContainer}) derived from the +container widget. It is an abstract base class. That is, it is not +possible to create an actual bin widget. It exists only to provide a +base of functionality for other widgets. Specifically, the bin widget +provides a base for several other widgets that contain only a single +child. These widgets include alignments (@pxref{GtkAlignment}), frames +(@pxref{GtkFrame}), items (@pxref{GtkItem}), viewports +(@pxref{GtkViewport}) and windows (@pxref{GtkWindow}) + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_bin_get_type (void) +Returns the @code{GtkBin} type identifier. +@end deftypefun + +@gtkstdmacros{Bin, BIN} + + +@page +@node GtkBox, GtkButton, GtkBin, Widgets +@comment node-name, next, previous, up +@section The box widget + + +@subsection Description + +The box widget is a container (@pxref{GtkContainer}) derived from the +container widget. It is an abstract base class used by the horizontal +box (@pxref{GtkHBox}) and vertical box (@pxref{GtkVBox}) widgets to +provide a base of common functionality. + +A box provides an abstraction for organizing the position and size of +widgets. Widgets in a box are layed out horizontally or vertically. By +using a box widget appropriately, a programmer can control how widgets +are positioned and how they will be allocated space when a window gets +resized. + +The key attribute of boxes is that they position their children in a +single row (horizontal boxes) or column (vertical boxes). In the case of +horizontal boxes, all children are stretched vertically. The vertical +size of the box is determined by the largest vertical requisition of all +of its children. Similarly, a vertical box streches all of its children +horizontally. The horizontal size (of the vertical box) is determined by +the largest horizontal requisition of all of its children. An alignment +widget (@pxref{GtkAlignment}) can be used to control child allocation +more precisely on a per child basis. + +The second attribute of boxes is how they expand children. In the case +of a horizontal box, the main control is over how children are expanded +horizontally to fill the allocated area. (The rest of this discussion +will focus on horizontal boxes but it applies to vertical boxes as +well). + +There are two flags which can be set controlling how a widget is +expanded horizontally in a horizontal box. These are the @code{expand} +and @code{fill}. There operation is fairly simple. If @code{expand} is +set, the childs potentially allocated area will expand to fill available +space. If @code{fill} is set, the childs actual allocated area will be +its potentially allocated area. There is a difference between +the potentially area (which is the area the box widget sets aside for +the child) and the actual allocated area (which is the area the box +widget actual allocates for the widget via +@code{gtk_widget_size_allocate}). + +The allocation of space to children occurs as follows (for horizontal +boxes): +@enumerate +@item +All children are allocated at least their requested size horizontally +and the maximum requested child size vertically. + +@item +Any child with the @code{expand} flag set is allocated @code{extra_width +/ nexpand_children} extra pixels horizontally. If the @code{homogeneous} +flag was set, all children are considered to have the @code{expand} flag +set. That is, all children will be allocated the same area.The +horizontal box is a fair widget and, as such, divides up any extra +allocated space evenly among the ``expand'' children. (Those children +which have the @code{expand} flag set). The exception occurs when +@code{extra_width / nexpand_children} does not divide cleanly. The extra +space is given to the last widget. + +@item +@code{spacing} number of pixels separate each child. Note: The +separation is between the potentially allocated area for each child and +not the actual allocated area. The @code{padding} value associated with +each child causes that many pixels to be left empty to each side of the +child. + +@item +If a child has the @code{fill} flag set it is allocated its potentially +allocated area. If it does not, it is allocated its requested size +horizontally and centered within its potentially allocated area. Its +vertical allocation is still the maximum requested size of any child. + +@item +Children placed at the start of the box are placed in order of addition +to the box from left to right in the boxes allocated area.. Children +placed at the end of the box are placed in order of addition from right +to left in the boxes allocated area. +@end enumerate + +@xref{GtkHBox}, and @ref{GtkVBox}, for code examples of using horizontal +and vertical boxes. + +@subsection Options + +@c FIXME: options for GtkBox + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_box_get_type (void) +Returns the @code{GtkBox} type identifier. +@end deftypefun + +@deftypefun void gtk_box_pack_start (GtkBox *@var{box}, GtkWidget *@var{child}, gint @var{expand}, gint @var{fill}, gint @var{padding}) +Add @var{child} to the front of @var{box}. The flags @var{expand} and +@var{fill} and the padding value of @var{padding} are associated with +@var{child}. +@end deftypefun + +@deftypefun void gtk_box_pack_end (GtkBox *@var{box}, GtkWidget *@var{child}, gint @var{expand}, gint @var{fill}, gint @var{padding}) +Add @var{child} to the end of @var{box}. The flags @var{expand} and +@var{fill} and the padding value of @var{padding} are associated with +@var{child}. +@end deftypefun + +@deftypefun void gtk_box_pack_start_defaults (GtkBox *@var{box}, GtkWidget *@var{widget}) +A convenience function which is equivalent to the following: + +@example + gtk_box_pack_start (@var{box}, @var{widget}, TRUE, TRUE, 0); +@end example +@end deftypefun + +@deftypefun void gtk_box_pack_end_defaults (GtkBox *@var{box}, GtkWidget *@var{widget}) +A convenience function which is equivalent to the following: + +@example + gtk_box_pack_start (@var{box}, @var{widget}, TRUE, TRUE, 0); +@end example +@end deftypefun + +@gtkstdmacros{Box, BOX} + + +@page +@node GtkButton, GtkCheckButton, GtkBox, Widgets +@comment node-name, next, previous, up +@section The button widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkButton::pressed (GtkButton *@var{button}) +@end deftypefn + +@deftypefn Signal void GtkButton::released (GtkButton *@var{button}) +@end deftypefn + +@deftypefn Signal void GtkButton::clicked (GtkButton *@var{button}) +@end deftypefn + +@deftypefn Signal void GtkButton::enter (GtkButton *@var{button}) +@end deftypefn + +@deftypefn Signal void GtkButton::leave (GtkButton *@var{button}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_button_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_button_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_button_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_button_pressed (GtkButton *@var{button}) +@end deftypefun + +@deftypefun void gtk_button_released (GtkButton *@var{button}) +@end deftypefun + +@deftypefun void gtk_button_clicked (GtkButton *@var{button}) +@end deftypefun + +@deftypefun void gtk_button_enter (GtkButton *@var{button}) +@end deftypefun + +@deftypefun void gtk_button_leave (GtkButton *@var{button}) +@end deftypefun + +@gtkstdmacros{Button, BUTTON} + + +@page +@node GtkCheckButton, GtkCheckMenuItem, GtkButton, Widgets +@comment node-name, next, previous, up +@section The check button widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_check_button_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_check_button_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_check_button_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun GtkCheckButton* GTK_CHECK_BUTTON (gpointer @var{obj}) +@end deftypefun + +@deftypefun GtkCheckButtonClass* GTK_CHECK_BUTTON_CLASS (gpointer @var{class}) +@end deftypefun + +@deftypefun gint GTK_IS_CHECK_BUTTON (gpointer @var{obj}) +@end deftypefun + +@gtkstdmacros{CheckButton, CHECK_BUTTON} + + +@page +@node GtkCheckMenuItem, GtkContainer, GtkCheckButton, Widgets, +@comment node-name, next, previous, up +@section The check menu item widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkCheckMenuItem::toggled (GtkCheckMenuItem *@var{check_menu_item}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_check_menu_item_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_check_menu_item_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_check_menu_item_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_check_menu_item_set_state (GtkCheckMenuItem *@var{check_menu_item}, gint @var{state}) +@end deftypefun + +@deftypefun void gtk_check_menu_item_toggled (GtkCheckMenuItem *@var{check_menu_item}) +@end deftypefun + +@gtkstdmacros{CheckMenuItem, CHECK_MENU_ITEM} + + +@page +@node GtkContainer, GtkDialog, GtkCheckMenuItem, Widgets +@comment node-name, next, previous, up +@section The container widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkContainer::add (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkContainer::remove (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkContainer::need_resize (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkContainer::foreach (GtkContainer *@var{container}, GtkCallback @var{callback}, gpointer @var{callback_data}) +@end deftypefn + +@deftypefn Signal gint GtkContainer::focus (GtkContainer *@var{container}, GtkDirectionType @var{direction}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_container_get_type (void) +@end deftypefun + +@deftypefun void gtk_container_border_width (GtkContainer *@var{container}, gint @var{border_width}) +@end deftypefun + +@deftypefun void gtk_container_add (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_container_remove (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_container_disable_resize (GtkContainer *@var{container}) +@end deftypefun + +@deftypefun void gtk_container_enable_resize (GtkContainer *@var{container}) +@end deftypefun + +@deftypefun void gtk_container_block_resize (GtkContainer *@var{container}) +@end deftypefun + +@deftypefun void gtk_container_unblock_resize (GtkContainer *@var{container}) +@end deftypefun + +@deftypefun gint gtk_container_need_resize (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_container_check_resize (GtkContainer *@var{container}, GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_container_foreach (GtkContainer *@var{container}, GtkCallback @var{callback}, gpointer @var{callback_data}) +@end deftypefun + +@deftypefun void gtk_container_focus (GtkContainer *@var{container}, GtkDirectionType @var{direction}) +@end deftypefun + +@deftypefun GList* gtk_container_children (GtkContainer @var{container}) +@end deftypefun + +@gtkstdmacros{Container, CONTAINER} + + +@page +@node GtkDialog, GtkDrawingArea, GtkContainer, Widgets +@comment node-name, next, previous, up +@section The dialog widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_dialog_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_dialog_new (void) +@end deftypefun + +@gtkstdmacros{Dialog, DIALOG} + + +@page +@node GtkDrawingArea, GtkEntry, GtkDialog, Widgets +@comment node-name, next, previous, up +@section The drawing area widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_drawing_area_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_drawing_area_new (void) +@end deftypefun + +@deftypefun void gtk_drawing_area_size (GtkDrawingArea *@var{darea}, gint @var{width}, gint @var{height}) +@end deftypefun + +@gtkstdmacros{DrawingArea, DRAWING_AREA} + + +@page +@node GtkEntry, GtkFileSelection, GtkDrawingArea, Widgets +@comment node-name, next, previous, up +@section The entry widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkEntry::insert (GtkEntry *@var{entry}, gchar *@var{text}, gint @var{length}, gint *@var{position}) +@end deftypefn + +@deftypefn Signal void GtkEntry::delete (GtkEntry *@var{entry}, gint @var{start_pos}, gint @var{end_pos}) +@end deftypefn + +@deftypefn Signal void GtkEntry::changed (GtkEntry *@var{entry}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_entry_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_entry_new (void) +@end deftypefun + +@deftypefun void gtk_entry_set_text (GtkEntry *@var{entry}, gchar *@var{text}) +@end deftypefun + +@deftypefun void gtk_entry_append_text (GtkEntry *@var{entry}, gchar *@var{text}) +@end deftypefun + +@deftypefun void gtk_entry_prepend_text (GtkEntry *@var{entry}, gchar *@var{text}) +@end deftypefun + +@deftypefun void gtk_entry_set_position (GtkEntry *@var{entry}, gint @var{position}) +@end deftypefun + +@deftypefun gchar* gtk_entry_get_text (GtkEntry *@var{entry}) +@end deftypefun + +@gtkstdmacros{Entry, ENTRY} + + +@page +@node GtkFileSelection, GtkFrame, GtkEntry, Widgets +@comment node-name, next, previous, up +@section The file selection dialog widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_file_selection_get_Type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_file_selection_new (gchar *@var{title}) +@end deftypefun + +@deftypefun void gtk_file_selection_set_filename (GtkFileSelection *@var{filesel}, gchar *@var{filename}) +@end deftypefun + +@deftypefun gchar* gtk_file_selection_get_filename (GtkFileSelection *@var{filesel}) +@end deftypefun + +@gtkstdmacros{FileSelection, FILE_SELECTION} + + +@page +@node GtkFrame, GtkHBox, GtkFileSelection, Widgets +@comment node-name, next, previous, up +@section The frame widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_frame_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_frame_new (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_frame_set_label (GtkFrame *@var{frame}, gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_frame_set_label_align (GtkFrame *@var{frame}, gfloat @var{xalign}, gfloat @var{yalign}) +@end deftypefun + +@deftypefun void gtk_frame_set_shadow_type (GtkFrame *@var{frame}, GtkShadowType @var{type}) +@end deftypefun + +@gtkstdmacros{Frame, FRAME} + + +@page +@node GtkHBox, GtkHRuler, GtkFrame, Widgets +@comment node-name, next, previous, up +@section The horizontal box widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hbox_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hbox_new (gint @var{homogeneous}, gint @var{spacing}) +@end deftypefun + +@gtkstdmacros{HBox, HBOX} + + +@page +@node GtkHRuler, GtkHScale, GtkHBox, Widgets +@comment node-name, next, previous, up +@section The horizontal ruler widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hruler_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hruler_new (void) +@end deftypefun + +@gtkstdmacros{HRuler, HRULER} + + +@page +@node GtkHScale, GtkHScrollbar, GtkHRuler, Widgets +@comment node-name, next, previous, up +@section The horizontal scale widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hscale_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hscale_new (GtkAdjustment *@var{adjustment}) +@end deftypefun + +@gtkstdmacros{HScale, HSCALE} + + +@page +@node GtkHScrollbar, GtkHSeparator, GtkHScale, Widgets +@comment node-name, next, previous, up +@section The horizontal scrollbar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hscrollbar_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hscrollbar_new (GtkAdjustment *@var{adjustment}) +@end deftypefun + +@gtkstdmacros{HScrollbar, HSCROLLBAR} + + +@page +@node GtkHSeparator, GtkImage, GtkHScrollbar, Widgets +@comment node-name, next, previous, up +@section The horizontal separator widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_hseparator_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_hseparator_new (void) +@end deftypefun + +@gtkstdmacros{HSeparator, HSEPARATOR} + + +@page +@node GtkImage, GtkItem, GtkHSeparator, Widgets +@comment node-name, next, previous, up +@section The image widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_image_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_image_new (GdkImage *@var{val}) +@end deftypefun + +@deftypefun void gtk_image_set (GtkImage *@var{image}, GdkImage *@var{val}) +@end deftypefun + +@deftypefun void gtk_image_get (GtkImage *@var{image}, GdkImage **@var{val}) +@end deftypefun + +@gtkstdmacros{Image, IMAGE} + + +@page +@node GtkItem, GtkLabel, GtkImage, Widgets +@comment node-name, next, previous, up +@section The item widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkItem::select (GtkItem *@var{item}) +@end deftypefn + +@deftypefn Signal void GtkItem::deselect (GtkItem *@var{item}) +@end deftypefn + +@deftypefn Signal void GtkItem::toggle (GtkItem *@var{toggle}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_item_get_type (void) +@end deftypefun + +@deftypefun void gtk_item_select (GtkItem *@var{item}) +@end deftypefun + +@deftypefun void gtk_item_deselect (GtkItem *@var{item}) +@end deftypefun + +@deftypefun void gtk_item_toggle (GtkItem *@var{item}) +@end deftypefun + +@gtkstdmacros{Item, ITEM} + + +@page +@node GtkLabel, GtkList, GtkItem, Widgets +@comment node-name, next, previous, up +@section The label widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_label_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_label_new (GtkLabel *@var{label}, gchar *@var{str}) +@end deftypefun + +@deftypefun void gtk_label_set (GtkLabel *@var{label}, gchar *@var{str}) +@end deftypefun + +@deftypefun void gtk_label_get (GtkLabel *@var{label}, gchar **@var{str}) +@end deftypefun + +@gtkstdmacros{Label, LABEL} + + +@page +@node GtkList, GtkListItem, GtkLabel, Widgets +@comment node-name, next, previous, up +@section The list widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkList::selection_changed (GtkList *@var{list}) +@end deftypefn + +@deftypefn Signal void GtkList::select_child (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefn + +@deftypefn Signal void GtkList::unselect_child (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_list_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_list_new (void) +@end deftypefun + +@deftypefun void gtk_list_insert_items (GtkList *@var{list}, GList *@var{items}, gint @var{position}) +@end deftypefun + +@deftypefun void gtk_list_append_items (GtkList *@var{list}, GList *@var{items}) +@end deftypefun + +@deftypefun void gtk_list_prepend_items (GtkList *@var{list}, GList *@var{items}) +@end deftypefun + +@deftypefun void gtk_list_remove_items (GtkList *@var{list}, GList *@var{items}) +@end deftypefun + +@deftypefun void gtk_list_clear_items (GtkList *@var{list}, gint @var{start}, gint @var{end}) +@end deftypefun + +@deftypefun void gtk_list_select_item (GtkList *@var{list}, gint @var{item}) +@end deftypefun + +@deftypefun void gtk_list_unselect_item (GtkList *@var{list}, gint @var{item}) +@end deftypefun + +@deftypefun void gtk_list_select_child (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_list_unselect_child (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun gint gtk_list_child_position (GtkList *@var{list}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_list_set_selection_mode (GtkList *@var{list}, GtkSelectionMode @var{mode}) +@end deftypefun + +@gtkstdmacros{List, LIST} + + +@page +@node GtkListItem, GtkMenu, GtkList, Widgets +@comment node-name, next, previous, up +@section The list item widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_list_item_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_list_item_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_list_item_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_list_item_select (GtkListItem *@var{list_item}) +@end deftypefun + +@deftypefun void gtk_list_item_deselect (GtkListItem *@var{list_item}) +@end deftypefun + +@gtkstdmacros{ListItem, LIST_ITEM} + + +@page +@node GtkMenu, GtkMenuBar, GtkListItem, Widgets +@comment node-name, next, previous, up +@section The menu widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_menu_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_new (void) +@end deftypefun + +@deftypefun void gtk_menu_append (GtkMenu *@var{menu}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_prepend (GtkMenu *@var{menu}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_insert (GtkMenu *@var{menu}, GtkWidget *@var{child}, gint @var{position}) +@end deftypefun + +@deftypefun void gtk_menu_popup (GtkMenu *@var{menu}, GtkWidget *@var{parent_menu_shell}, GtkWidget *@var{parent_menu_item}, GtkMenuPositionFunc @var{func}, gpointer @var{data}, gint @var{button}) +@end deftypefun + +@deftypefun void gtk_menu_popdown (GtkMenu *@var{menu}) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_get_active (GtkMenu *@var{menu}) +@end deftypefun + +@deftypefun void gtk_menu_set_active (GtkMenu *@var{menu}) +@end deftypefun + +@deftypefun void gtk_menu_set_accelerator_table (GtkMenu *@var{menu}, GtkAcceleratorTable *@var{table}) +@end deftypefun + +@gtkstdmacros{Menu, MENU} + + +@page +@node GtkMenuBar, GtkMenuItem, GtkMenu, Widgets +@comment node-name, next, previous, up +@section The menu bar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_menu_bar_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_bar_new (void) +@end deftypefun + +@deftypefun void gtk_menu_bar_append (GtkMenuBar *@var{menu_bar}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_bar_prepend (GtkMenuBar *@var{menu_bar}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_bar_insert (GtkMenuBar *@var{menu_bar}, GtkWidget *@var{child}, gint @var{position}) +@end deftypefun + +@gtkstdmacros{MenuBar, MENU_BAR} + + +@page +@node GtkMenuItem, GtkMenuShell, GtkMenuBar, Widgets +@comment node-name, next, previous, up +@section The menu item widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkMenuItem::activate (GtkMenuItem *@var{menu_item}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_menu_item_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_item_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_menu_item_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_menu_item_set_submenu (GtkMenuItem *@var{menu_item}, GtkWidget *@var{submenu}) +@end deftypefun + +@deftypefun void gtk_menu_item_set_placement (GtkMenuItem *@var{menu_item}, GtkSubmenuPlacement @var{placement}) +@end deftypefun + +@deftypefun void gtk_menu_item_accelerator_size (GtkMenuItem *@var{menu_item}) +@end deftypefun + +@deftypefun void gtk_menu_item_accelerator_text (GtkMenuItem *@var{menu_item}, gchar *@var{buffer}) +@end deftypefun + +@deftypefun void gtk_menu_item_configure (GtkMenuItem *@var{menu_item}, gint @var{show_toggle_indicator}, gint @var{show_submenu_indicator}) +@end deftypefun + +@deftypefun void gtk_menu_item_select (GtkMenuItem *@var{menu_item}) +@end deftypefun + +@deftypefun void gtk_menu_item_deselect (GtkMenuItem *@var{menu_item}) +@end deftypefun + +@deftypefun void gtk_menu_item_activate (GtkMenuItem *@var{menu_item}) +@end deftypefun + +@gtkstdmacros{MenuItem, MENU_ITEM} + + +@page +@node GtkMenuShell, GtkMisc, GtkMenuItem, Widgets +@comment node-name, next, previous, up +@section The menu shell widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkMenuShell::deactivate (GtkMenuShell *@var{menu_shell}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_menu_shell_get_type (void) +@end deftypefun + +@deftypefun void gtk_menu_shell_append (GtkMenuShell *@var{menu_shell}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_shell_prepend (GtkMenuShell *@var{menu_shell}, GtkWidget *@var{child}) +@end deftypefun + +@deftypefun void gtk_menu_shell_insert (GtkMenuShell *@var{menu_shell}, GtkWidget *@var{child}, gint @var{position}) +@end deftypefun + +@deftypefun void gtk_menu_shell_deactivate (GtkMenuShell *@var{menu_shell}) +@end deftypefun + +@gtkstdmacros{MenuShell, MENU_SHELL} + + +@page +@node GtkMisc, GtkNotebook, GtkMenuShell, Widgets +@comment node-name, next, previous, up +@section The misc widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_misc_get_type (void) +@end deftypefun + +@deftypefun void gtk_misc_set_alignment (GtkMisc *@var{misc}, gfloat @var{xalign}, gfloat @var{yalign}) +@end deftypefun + +@deftypefun void gtk_misc_set_padding (GtkMisc *@var{misc}, gint @var{xpad}, gint @var{ypad}) +@end deftypefun + +@gtkstdmacros{Misc, MISC} + + +@page +@node GtkNotebook, GtkOptionMenu, GtkMisc, Widgets +@comment node-name, next, previous, up +@section The notebook widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_notebook_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_notebook_new (void) +@end deftypefun + +@deftypefun void gtk_notebook_append_page (GtkNotebook *@var{notebook}, GtkWidget *@var{child}, GtkWidget *@var{tab_label}) +@end deftypefun + +@deftypefun void gtk_notebook_prepend_page (GtkNotebook *@var{notebook}, GtkWidget *@var{child}, GtkWidget *@var{tab_label}) +@end deftypefun + +@deftypefun void gtk_notebook_insert_page (GtkNotebook *@var{notebook}, GtkWidget *@var{child}, GtkWidget *@var{tab_label}, gint @var{position}) +@end deftypefun + +@deftypefun void gtk_notebook_remove_page (GtkNotebook *@var{notebook}, gint @var{page_num}) +@end deftypefun + +@deftypefun void gtk_notebook_set_page (GtkNotebook *@var{notebook}, gint @var{page_num}) +@end deftypefun + +@deftypefun void gtk_notebook_next_page (GtkNotebook *@var{notebook}) +@end deftypefun + +@deftypefun void gtk_notebook_prev_page (GtkNotebook *@var{notebook}) +@end deftypefun + +@deftypefun void gtk_notebook_set_tab_pos (GtkNotebook *@var{notebook}, GtkPositionType @var{pos}) +@end deftypefun + +@deftypefun void gtk_notebook_set_show_tabs (GtkNotebook *@var{notebook}, gint @var{show_tabs}) +@end deftypefun + +@deftypefun void gtk_notebook_set_show_border (GtkNotebook *@var{notebook}, gint @var{show_border}) +@end deftypefun + +@gtkstdmacros{Notebook, NOTEBOOK} + + +@page +@node GtkOptionMenu, GtkPixmap, GtkNotebook, Widgets +@comment node-name, next, previous, up +@section The option menu widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_option_menu_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_option_menu_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_option_menu_get_menu (GtkOptionMenu *@var{option_menu}) +@end deftypefun + +@deftypefun void gtk_option_menu_set_menu (GtkOptionMenu *@var{option_menu}, GtkWidget *@var{menu}) +@end deftypefun + +@deftypefun void gtk_option_menu_remove_menu (GtkOptionMenu *@var{option_menu}) +@end deftypefun + +@deftypefun void gtk_option_menu_set_history (GtkOptionMenu *@var{option_menu}, gint @var{index}) +@end deftypefun + +@gtkstdmacros{OptionMenu, OPTION_MENU} + + +@page +@node GtkPixmap, GtkPreview, GtkOptionMenu, Widgets +@comment node-name, next, previous, up +@section The pixmap widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_pixmap_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_pixmap_new (GdkPixmap *@var{normal}, GdkPixmap *@var{active}, GdkPixmap *@var{prelight}, GdkPixmap *@var{selected}, GdkPixmap *@var{insensitive}) +@end deftypefun + +@deftypefun void gtk_pixmap_set (GtkPixmap *@var{pixmap}, GdkPixmap *@var{val}, GtkStateType @var{state}) +@end deftypefun + +@deftypefun void gtk_pixmap_get (GtkPixmap *@var{pixmap}, GdkPixmap **@var{val}, GtkStateType @var{state}) +@end deftypefun + +@gtkstdmacros{Pixmap, PIXMAP} + + +@page +@node GtkPreview, GtkProgressBar, GtkPixmap, Widgets +@comment node-name, next, previous, up +@section The preview widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_preview_get_type (void) +@end deftypefun + +@deftypefun void gtk_preview_uninit (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_preview_new (GtkPreviewType @var{type}) +@end deftypefun + +@deftypefun void gtk_preview_size (GtkPreview *@var{preview}, gint @var{width}, gint @var{height}) +@end deftypefun + +@deftypefun void gtk_preview_put (GtkPreview *@var{preview}, GdkWindow *@var{window}, GdkGC *@var{gc}, gint @var{srcx}, gint @var{srcy}, gint @var{destx}, gint @var{desty}, gint @var{width}, gint @var{height}) +@end deftypefun + +@deftypefun void gtk_preview_put_row (GtkPreview *@var{preview}, guchar *@var{src}, guchar *@var{dest}, gint @var{x}, gint @var{y}, gint @var{w}) +@end deftypefun + +@deftypefun void gtk_preview_draw_row (GtkPreview *@var{preview}, guchar @var{data}, gint @var{x}, gint @var{y}, gint @var{w}) +@end deftypefun + +@deftypefun void gtk_preview_set_expand (GtkPreview *@var{preview}, gint @var{expand}) +@end deftypefun + +@deftypefun void gtk_preview_set_gamma (double @var{gamma}) +@end deftypefun + +@deftypefun void gtk_preview_set_color_cube (guint @var{nred_shades}, guint @var{ngreen_shades}, guint @var{nblue_shades}, guint @var{ngray_shades}) +@end deftypefun + +@deftypefun void gtk_preview_set_install_cmap (gint @var{install_cmap}) +@end deftypefun + +@deftypefun void gtk_preview_set_reserved (gint @var{nreserved}) +@end deftypefun + +@deftypefun GdkVisual* gtk_preview_get_visual (void) +@end deftypefun + +@deftypefun GdkColormap* gtk_preview_get_cmap (void) +@end deftypefun + +@deftypefun GtkPreviewInfo* gtk_preview_get_info (void) +@end deftypefun + +@gtkstdmacros{Preview, PREVIEW} + + +@page +@node GtkProgressBar, GtkRadioButton, GtkPreview, Widgets +@comment node-name, next, previous, up +@section The progress bar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_progress_bar_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_progress_bar_new (void) +@end deftypefun + +@deftypefun void gtk_progress_bar_update (GtkProgressBar *@var{pbar}, gfloat @var{percentage}) +@end deftypefun + +@gtkstdmacros{ProgressBar, PROGRESS_BAR} + + +@page +@node GtkRadioButton, GtkRadioMenuItem, GtkProgressBar, Widgets +@comment node-name, next, previous, up +@section The radio button widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_radio_button_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_radio_button_new (GSList *@var{group}) +@end deftypefun + +@deftypefun GtkWidget* gtk_radio_button_new_with_label (GSList *@var{group}, gchar *@var{label}) +@end deftypefun + +@deftypefun GSList* gtk_radio_button_group (GtkRadioButton *@var{radio_button}) +@end deftypefun + +@gtkstdmacros{RadioButton, RADIO_BUTTON} + + +@page +@node GtkRadioMenuItem, GtkRange, GtkRadioButton, Widgets +@comment node-name, next, previous, up +@section The radio button widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_radio_menu_item_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_radio_menu_item_new (GSList *@var{group}) +@end deftypefun + +@deftypefun GtkWidget* gtk_radio_menu_item_new_with_label (GSList *@var{group}, gchar *@var{label}) +@end deftypefun + +@deftypefun GSList* gtk_radio_menu_item_group (GtkRadioMenuItem *@var{radio_menu_item}) +@end deftypefun + +@gtkstdmacros{RadioMenuItem, RADIO_MENU_ITEM} + + +@page +@node GtkRange, GtkRuler, GtkRadioMenuItem, Widgets +@comment node-name, next, previous, up +@section The range widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_range_get_type (void) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_range_get_adjustment (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_set_update_policy (GtkRange *@var{range}, GtkUpdatePolicy @var{policy}) +@end deftypefun + +@deftypefun void gtk_range_set_adjustment (GtkRange *@var{range}, GtkAdjustment *@var{adjustment}) +@end deftypefun + +@deftypefun void gtk_range_draw_background (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_draw_trough (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_draw_slider (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_draw_step_forw (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_draw_step_back (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_slider_update (GtkRange *@var{range}) +@end deftypefun + +@deftypefun gint gtk_range_trough_click (GtkRange *@var{range}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun void gtk_range_default_hslider_update (GtkRange *@var{range}) +@end deftypefun + +@deftypefun void gtk_range_default_vslider_update (GtkRange *@var{range}) +@end deftypefun + +@deftypefun gint gtk_range_default_htrough_click (GtkRange *@var{range}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun gint gtk_range_default_vtrough_click (GtkRange *@var{range}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun void gtk_range_default_hmotion (GtkRange *@var{range}, gint @var{xdelta}, gint @var{ydelta}) +@end deftypefun + +@deftypefun void gtk_range_default_vmotion (GtkRange *@var{range}, gint @var{xdelta}, gint @var{ydelta}) +@end deftypefun + +@deftypefun gfloat gtk_range_calc_value (GtkRange *@var{ragne}, gint @var{position}) +@end deftypefun + +@gtkstdmacros{Range, RANGE} + + +@page +@node GtkRuler, GtkScale, GtkRange, Widgets +@comment node-name, next, previous, up +@section The ruler widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_ruler_get_type (void) +@end deftypefun + +@deftypefun void gtk_ruler_set_metric (GtkRuler *@var{ruler}, GtkMetricType @var{metric}) +@end deftypefun + +@deftypefun void gtk_ruler_set_range (GtkRuler *@var{ruler}, gfloat @var{lower}, gfloat @var{upper}, gfloat @var{position}, gfloat @var{max_size}) +@end deftypefun + +@deftypefun void gtk_ruler_draw_ticks (GtkRuler *@var{ruler}) +@end deftypefun + +@deftypefun void gtk_ruler_draw_pos (GtkRuler *@var{ruler}) +@end deftypefun + +@gtkstdmacros{Ruler, RULER} + + +@page +@node GtkScale, GtkScrollbar, GtkRuler, Widgets +@comment node-name, next, previous, up +@section The scale widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_scale_get_type (void) +@end deftypefun + +@deftypefun void gtk_scale_set_digits (GtkScale *@var{scale}, gint @var{digits}) +@end deftypefun + +@deftypefun void gtk_scale_set_draw_value (GtkScale *@var{scale}, gint @var{draw_value}) +@end deftypefun + +@deftypefun void gtk_scale_set_value_pos (GtkScale *@var{scale}, gint @var{pos}) +@end deftypefun + +@deftypefun gint gtk_scale_value_width (GtkScale *@var{scale}) +@end deftypefun + +@deftypefun void gtk_scale_draw_value (GtkScale *@var{scale}) +@end deftypefun + +@gtkstdmacros{Scale, SCALE} + + +@page +@node GtkScrollbar, GtkScrolledWindow, GtkScale, Widgets +@comment node-name, next, previous, up +@section The scrollbar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_scrollbar_get_type (void) +@end deftypefun + +@gtkstdmacros{Scrollbar, SCROLLBAR} + + +@page +@node GtkScrolledWindow, GtkSeparator, GtkScrollbar, Widgets +@comment node-name, next, previous, up +@section The scrolled window widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_scrolled_window_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_scrolled_window_new (GtkAdjustment *@var{hadjustment}, GtkAdjustment *@var{vadjustment}) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *@var{scrolled_window}) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *@var{scrolled_window}) +@end deftypefun + +@deftypefun void gtk_scrolled_window_set_policy (GtkScrolledWindow *@var{scrolled_window}, GtkPolicyType @var{hscrollbar_policy}, GtkPolicyType @var{vscrollbar_policy}) +@end deftypefun + +@gtkstdmacros{ScrolledWindow, SCROLLED_WINDOW} + + +@page +@node GtkSeparator, GtkTable, GtkScrolledWindow, Widgets +@comment node-name, next, previous, up +@section The separator widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_separator_get_type (void) +@end deftypefun + +@gtkstdmacros{Separator, SEPARATOR} + + +@page +@node GtkTable, GtkText, GtkSeparator, Widgets +@comment node-name, next, previous, up +@section The table widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_table_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_table_new (gint @var{rows}, gint @var{columns}, gint @var{homogeneous}) +@end deftypefun + +@deftypefun void gtk_table_attach (GtkTable *@var{table}, GtkWidget *@var{child}, gint @var{left_attach}, gint @var{right_attach}, gint @var{top_attach}, gint @var{bottom_attach}, gint @var{xoptions}, gint @var{yoptions}, gint @var{xpadding}, gint @var{ypadding}) +@end deftypefun + +@deftypefun void gtk_table_attach_defaults (GtkTable *@var{table}, GtkWidget *@var{widget}, gint @var{left_attach}, gint @var{right_attach}, gint @var{top_attach}, gint @var{bottom_attach}) +@end deftypefun + +@deftypefun void gtk_table_set_row_spacing (GtkTable *@var{table}, gint @var{row}, gint @var{spacing}) +@end deftypefun + +@deftypefun void gtk_table_set_col_spacing (GtkTable *@var{table}, gint @var{col}, gint @var{spacing}) +@end deftypefun + +@deftypefun void gtk_table_set_row_spacings (GtkTable *@var{table}, gint @var{spacing}) +@end deftypefun + +@deftypefun void gtk_table_set_col_spacings (GtkTable *@var{table}, gint @var{spacing}) +@end deftypefun + +@gtkstdmacros{Table, TABLE} + + +@page +@node GtkText, GtkToggleButton, GtkTable, Widgets +@comment node-name, next, previous, up +@section The text widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_text_get_type (void) +@end deftypefun + +@gtkstdmacros{Text, TEXT} + + +@page +@node GtkToggleButton, GtkTree, GtkText, Widgets +@comment node-name, next, previous, up +@section The toggle button widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkToggleButton::toggled (GtkToggleButton *@var{toggle_button}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_toggle_button_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_toggle_button_new (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_toggle_button_new_with_label (gchar *@var{label}) +@end deftypefun + +@deftypefun void gtk_toggle_button_set_mode (GtkToggleButton *@var{toggle_button}, gint @var{draw_indicator}) +@end deftypefun + +@deftypefun void gtk_toggle_button_set_state (GtkToggleButton *@var{toggle_button}, gint @var{state}) +@end deftypefun + +@deftypefun void gtk_toggle_button_toggled (GtkToggleButotn *@var{toggle_button}) +@end deftypefun + +@gtkstdmacros{ToggleButton, TOGGLE_BUTTON} + + +@page +@node GtkTree, GtkTreeItem, GtkToggleButton, Widgets +@comment node-name, next, previous, up +@section The tree widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_tree_get_type (void) +@end deftypefun + +@gtkstdmacros{Tree, TREE} + + +@page +@node GtkTreeItem, GtkVBox, GtkTree, Widgets +@comment node-name, next, previous, up +@section The tree item widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_tree_item_get_type (void) +@end deftypefun + +@gtkstdmacros{TreeItem, TREE_ITEM} + + +@page +@node GtkVBox, GtkViewport, GtkTreeItem, Widgets +@comment node-name, next, previous, up +@section The vertical box widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vbox_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vbox_new (gint @var{homogeneous}, gint @var{spacing}) +@end deftypefun + +@gtkstdmacros{VBox, VBOX} + + +@page +@node GtkViewport, GtkVRuler, GtkVBox, Widgets +@comment node-name, next, previous, up +@section The viewport widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_viewport_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_viewport_new (GtkAdjustment *@var{hadjustment}, GtkAdjustment *@var{vadjustment}) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_viewport_get_hadjustment (GtkViewport *@var{viewport}) +@end deftypefun + +@deftypefun GtkAdjustment* gtk_viewport_get_vadjustment (GtkViewport *@var{viewport}) +@end deftypefun + +@deftypefun void gtk_viewport_set_hadjustment (GtkViewport *@var{viewport}, GtkAdjustment *@var{adjustment}) +@end deftypefun + +@deftypefun void gtk_viewport_set_vadjustment (GtkViewport *@var{viewport}, GtkAdjustment *@var{adjustment}) +@end deftypefun + +@deftypefun void gtk_viewport_set_shadow_type (GtkViewport *@var{viewport}, GtkShadowType @var{type}) +@end deftypefun + +@gtkstdmacros{Viewport, VIEWPORT} + + +@page +@node GtkVRuler, GtkVScale, GtkViewport, Widgets +@comment node-name, next, previous, up +@section The vertical ruler widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vruler_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vruler_new (void) +@end deftypefun + +@gtkstdmacros{VRuler, VRULER} + + +@page +@node GtkVScale, GtkVScrollbar, GtkVRuler, Widgets +@comment node-name, next, previous, up +@section The vertical ruler widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vscale_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vscale_new (GtkAdjustment *@var{adjustment}) +@end deftypefun + +@gtkstdmacros{VScale, VSCALE} + + +@page +@node GtkVScrollbar, GtkVSeparator, GtkVScale, Widgets +@comment node-name, next, previous, up +@section The vertical scrollbar widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vscrollbar_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vscrollbar_new (GtkAdjustment *@var{adjustment}) +@end deftypefun + +@gtkstdmacros{VScrollbar, VSCROLLBAR} + + +@page +@node GtkVSeparator, GtkWidget, GtkVScrollbar, Widgets +@comment node-name, next, previous, up +@section The vertical separator widget + + +@subsection Description + +@subsection Signals + +@subsection Functions + +@deftypefun guint gtk_vseparator_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_vseparator_new (void) +@end deftypefun + +@gtkstdmacros{VSeparator, VSEPARATOR} + + +@page +@node GtkWidget, GtkWindow, GtkVSeparator, Widgets +@comment node-name, next, previous, up +@section The base widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkWidget::show (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::hide (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::map (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::unmap (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::realize (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::unrealize (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::draw (GtkWidget *@var{widget}, GdkRectangle *@var{area}) +@end deftypefn + +@deftypefn Signal void GtkWidget::draw_focus (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::draw_default (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal void GtkWidget::size_request (GtkWidget *@var{widget}, GtkRequisition *@var{requisition}) +@end deftypefn + +@deftypefn Signal void GtkWidget::size_allocate (GtkWidget *@var{widget}, GtkAllocation *@var{allocation}) +@end deftypefn + +@deftypefn Signal void GtkWidget::state_changed (GtkWidget *@var{widget}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::install_accelerator (GtkWidget *@var{widget}, gchar *@var{signal_name}, gchar @var{key}, guint8 @var{modifiers}) +@end deftypefn + +@deftypefn Signal void GtkWidget::remove_accelerator (GtkWidget *@var{widget}, gchar *@var{signal_name}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::event (GtkWidget *@var{widget}, GdkEvent *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::button_press_event (GtkWidget *@var{widget}, GdkEventButton *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::button_release_event (GtkWidget *@var{widget}, GdkEventButton *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::motion_notify_event (GtkWidget *@var{widget}, GdkEventMotion *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::delete_event (GtkWidget *@var{widget}, GdkEventAny *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::destroy_event (GtkWidget *@var{widget}, GdkEventAny *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::expose_event (GtkWidget *@var{widget}, GdkEventExpose *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::key_press_event (GtkWidget *@var{widget}, GdkEventKey *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::key_release_event (GtkWidget *@var{widget}, GdkEventKey *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::enter_notify_event (GtkWidget *@var{widget}, GdkEventCrossing *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::leave_notify_event (GtkWidget *@var{widget}, GdkEventCrossing *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::configure_event (GtkWidget *@var{widget}, GdkEventConfigure *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::focus_in_event (GtkWidget *@var{widget}, GdkEventFocus *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::focus_out_event (GtkWidget *@var{widget}, GdkEventFocus *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::map_event (GtkWidget *@var{widget}, GdkEventAny *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::unmap_event (GtkWidget *@var{widget}, GdkEventAny *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::property_notify_event (GtkWidget *@var{widget}, GdkEventProperty *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::selection_clear_event (GtkWidget *@var{widget}, GdkEventSelection *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::selection_request_event (GtkWidget *@var{widget}, GdkEventSelection *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::selection_notify_event (GtkWidget *@var{widget}, GdkEventSelection *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::drop_event (GtkWidget *@var{widget}, GdkEventDrop *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::drag_begin_event (GtkWidget *@var{widget}, GdkEventDragBegin *@var{event}) +@end deftypefn + +@deftypefn Signal gint GtkWidget::other_event (GtkWidget *@var{widget}, GdkEventOther *@var{event}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_widget_get_type (void) +@end deftypefun + +@deftypefun void gtk_widget_class_init (GtkWidgetClass *@var{class}) +@end deftypefun + +@deftypefun void gtk_widget_init (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_destroy (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_show (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_hide (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_map (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_unmap (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_realize (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_unrealize (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_draw (GtkWidget *@var{widget}, GdkRectangle *@var{area}) +@end deftypefun + +@deftypefun void gtk_widget_draw_focus (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_draw_children (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_size_request (GtkWidget *@var{widget}, GtkRequisition *@var{requisition}) +@end deftypefun + +@deftypefun void gtk_widget_size_allocate (GtkWidget *@var{widget}, GtkAllocation *@var{allocation}) +@end deftypefun + +@deftypefun void gtk_widget_install_accelerator (GtkWidget *@var{widget}, GtkAcceleratorTable *@var{table}, gchar *@var{signal_name}, gchar @var{key}, guint8 @var{modifiers}) +@end deftypefun + +@deftypefun void gtk_widget_remove_accelerator (GtkWidget *@var{widget}, GtkAcceleratorTable *@var{table}, gchar *@var{signal_name}) +@end deftypefun + +@deftypefun gint gtk_widget_event (GtkWidget *@var{widget}, GdkEvent *@var{event}) +@end deftypefun + +@deftypefun void gtk_widget_reparent (GtkWidget *@var{widget}, GtkWidget *@var{new_parent}) +@end deftypefun + +@deftypefun void gtk_widget_popup (GtkWidget *@var{widget}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun gint gtk_widget_intersect (GtkWidget *@var{widget}, GdkRectangle *@var{area}, GdkRectangle *@var{intersection}) +@end deftypefun + +@deftypefun void gtk_widget_grab_focus (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_grab_default (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_restore_state (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun void gtk_widget_set_name (GtkWidget *@var{widget}, gchar *@var{name}) +@end deftypefun + +@deftypefun void gtk_widget_set_state (GtkWidget *@var{widget}, GtkStateType @var{state}) +@end deftypefun + +@deftypefun void gtk_widget_set_sensitive (GtkWidget *@var{widget}, gint sensitive) +@end deftypefun + +@deftypefun void gtk_widget_set_parent (GtkWidget *@var{widget}, GtkWidget *@var{parent}) +@end deftypefun + +@deftypefun void gtk_widget_set_style (GtkWidget *@var{widget}, GtkStyle *@var{style}) +@end deftypefun + +@deftypefun void gtk_widget_set_uposition (GtkWidget *@var{widget}, gint @var{x}, gint @var{y}) +@end deftypefun + +@deftypefun void gtk_widget_set_usize (GtkWidget *@var{widget}, gint @var{width}, gint @var{height}) +@end deftypefun + +@deftypefun GtkWidget* gtk_widget_get_toplevel (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun GtkWidget* gtk_widget_get_ancestor (GtkWidget *@var{widget}, gint @var{type}) +@end deftypefun + +@deftypefun GdkColormap* gtk_widget_get_colormap (GtkWidget *@var{widget}) +@end deftypefun + +@deftypefun GdkVisual* gtk_widget_get_visual (GtkWidget *@var{visual}) +@end deftypefun + +@deftypefun GtkStyle* gtk_widget_get_style (GtkWidget *@var{style}) +@end deftypefun + +@gtkstdmacros{Widget, WIDGET} + + +@page +@node GtkWindow, , GtkWidget, Widgets +@comment node-name, next, previous, up +@section The window widget + + +@subsection Description + +@subsection Signals + +@deftypefn Signal void GtkWindow::move_resize (GtkWindow *@var{window}, gint *@var{x}, gint *@var{y}, gint @var{width}, gint @var{height}) +@end deftypefn + +@subsection Functions + +@deftypefun guint gtk_window_get_type (void) +@end deftypefun + +@deftypefun GtkWidget* gtk_window_new (GtkWindowType @var{type}) +@end deftypefun + +@deftypefun void gtk_window_set_title (GtkWindow *@var{window}, gchar *@var{title}) +@end deftypefun + +@deftypefun void gtk_window_set_focus (GtkWindow *@var{window}, GtkWidget *@var{focus}) +@end deftypefun + +@deftypefun void gtk_window_set_default (GtkWindow *@var{window}, GtkWidget *@var{defaultw}) +@end deftypefun + +@deftypefun void gtk_window_set_policy (GtkWindow *@var{window}, gint @var{allow_shrink}, gint @var{allow_grow}, gint @var{auto_shrink}) +@end deftypefun + +@deftypefun void gtk_window_add_accelerator_table (GtkWindow *@var{window}, GtkAcceleratorTable *@var{table}) +@end deftypefun + +@deftypefun void gtk_window_remove_accelerator_table (GtkWindow *@var{window}, GtkAcceleratorTable *@var{table}) +@end deftypefun + +@deftypefun void gtk_window_position (GtkWindow *@var{window}, GtkWindowPosition @var{position}) +@end deftypefun + +@gtkstdmacros{Window, WINDOW} + + +@node Other Objects, Miscellaneous, Widgets, Top +@comment node-name, next, previous, up +@chapter Utility objects + + +@menu +* GtkAdjustment:: The adjustment object. +* GtkData:: The data object. +@end menu + + +@node GtkAdjustment, GtkData, Other Objects, Other Objects +@comment node-name, next, previous, up +@section The adjustment object + + +@node GtkData, , GtkAdjustment, Other Objects +@comment node-name, next, previous, up +@section The data object + + +@node Miscellaneous, Examples, Other Objects, Top +@comment node-name, next, previous, up +@chapter Initialization, exit and other features + + +@menu +* Initialization and exit:: Initializing and exiting GTK. +* Menu Factories:: Simplified menu creation. +* Tree Factories:: Simplified tree creation. +* Tool Tips:: Pop up help mechanism. +* Resource Files:: Resource files. +* Standard Macros:: Macros defined by all objects. +@end menu + + +@node Initialization and exit, Menu Factories, Miscellaneous, Miscellaneous +@comment node-name, next, previous, up +@section Initializing and exiting GTK + + +@node Menu Factories, Tree Factories, Initialization and exit, Miscellaneous +@comment node-name, next, previous, up +@section Simplified menu creation + + +@node Tree Factories, Tool Tips, Menu Factories, Miscellaneous +@comment node-name, next, previous, up +@section Simplified tree creation + + +@node Tool Tips, Resource Files, Tree Factories, Miscellaneous +@comment node-name, next, previous, up +@section Pop up help mechanism + + +@node Resource Files, Standard Macros, Tool Tips, Miscellaneous +@comment node-name, next, previous, up +@section Pop up help mechanism + + +@node Standard Macros, , Resource Files, Miscellaneous +@comment node-name, next, previous, up +@section Macros defined by all objects + +There are three macros that are defined by all object types. The first +two are used for performing casts and the last is for querying whether +an object is of a particular type. These macros are both conveniences +and debugging tools. If the GTK library was compiled with @code{NDEBUG} +defined as a preprocessor symbol (via the -DNDEBUG to cc), then the +macros check the object type and emit a warning if the cast is +invalid. Doing such checking is fairly expensive since the cast macros +are used everywhere in GTK and would normally be turned off in a public +release of a product. Note: The functions below are indeed macros, but +they may be considered functions for most purposes. + +@deftypefun Gtk* GTK_ (gpointer @var{obj}) +Cast a generic pointer to @code{Gtk*}. This function is +provided in order to be able to provide checking during development +stages of code development since it is possible to examine the actual +type of object (using @code{gtk_type_is_a}) before performing the cast. +@end deftypefun + +@deftypefun GtkClass* GTK__CLASS (gpointer @var{class}) +Cast a generic pointer to @code{GtkClass*}. Like +@code{GTK_}, this function is, in reality, a macro. +@end deftypefun + +@deftypefun gint GTK_IS_ (gpointer @var{obj}) +Determine if a generic pointer refers to a @code{Gtk} +object. This function is, in reality, a macro wrapper around the +@code{gtk_type_is_a} function (@pxref{Objects}). +@end deftypefun + + +@node Examples, Object Implementation, Miscellaneous, Top +@comment node-name, next, previous, up +@chapter Using GTK + + +@menu +* Simple:: The simplest GTK program. +* Hello World:: Hello world in GTK. +* Hello World II:: An enhanced hello world. +* Hello World III:: Making Hello World II robust. +@end menu + + +@node Simple, Hello World, Examples, Examples +@comment node-name, next, previous, up +@section The simplest GTK program + + +The 16 line GTK program shown below is just about the simplest possible +program which uses GTK. (Well, technically, you don't have to create the +window and it would still be a program which uses GTK). The program, +when compiled and run, will create a single window 200x200 pixels in +size. The program does not exit until its is explicitly killed using the +shell or a window manager function. + +@example +#include + +int +main (int argc, char *argv[]) +@{ + GtkWidget *window; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_show (window); + + gtk_main (); + + return 0; +@} +@end example + +The first point of interest in this program is the standard +initialization line. + +@example + gtk_init (&argc, &argv); +@end example + +Almost every GTK program will contain such a line. GTK will initialize +itself and GDK and remove any command line arguments it recognizes from +@var{argc} and @var{argv}. + +The next two lines of code create and display a window. + +@example + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_show (window); +@end example + +The @code{GTK_WINDOW_TOPLEVEL} argument specifies that we want the +window to undergo window manager decoration and placement. One might be +lead to think that the window, since it has no children, would be 0x0 +pixels in size. But, this is not the case because a window that has no +children defaults to 200x200 pixels in size. Mainly because 0x0 windows +are annoying to manipulate or even see in some cases. + +The last line enters the GTK main processing loop. + +@example + gtk_main (); +@end example + +Normally, @code{gtk_main} is called once and the program should exit +when it returns. @xref{Initialization and exit}. + + +@node Hello World, Hello World II, Simple, Examples +@comment node-name, next, previous, up +@section Hello world in GTK + + +@example +#include + +int +main (int argc, char *argv[]) +@{ + GtkWidget *window; + GtkWidget *label; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + label = gtk_label_new ("Hello World"); + gtk_container_add (GTK_CONTAINER (window), label); + gtk_widget_show (label); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +@} +@end example + + +@node Hello World II, Hello World III, Hello World, Examples +@comment node-name, next, previous, up +@section An enhanced hello world + + +@example +#include "gtk.h" + +void +hello (void) +@{ + g_print ("Hello World\n"); + gtk_exit (0); +@} + +int +main (int argc, char *argv[]) +@{ + GtkWidget *window; + GtkWidget *button; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + button = gtk_button_new_with_label ("Hello World"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (hello), NULL); + gtk_container_add (GTK_CONTAINER (window), button); + gtk_widget_show (button); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +@} +@end example + + +@node Hello World III, , Hello World II, Examples +@comment node-name, next, previous, up +@section Making Hello World II robust + + +@example +#include "gtk.h" + +void +hello (void) +@{ + g_print ("Hello World\n"); + gtk_exit (0); +@} + +void +destroy (void) +@{ + gtk_exit (0); +@} + +int +main (int argc, char *argv[]) +@{ + GtkWidget *window; + GtkWidget *button; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (destroy), NULL); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + button = gtk_button_new_with_label ("Hello World"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (hello), NULL); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_container_add (GTK_CONTAINER (window), button); + gtk_widget_show (button); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +@} +@end example + + +@node Object Implementation, Signal Implementation, Examples, Top +@comment node-name, next, previous, up +@chapter Object internals +@cindex Object Implementaton + +Objects (or the @code{GtkObject} type) and the class hierarchy in +general is implemented via a hierarchy of structs and type casting. Be +aware that when classes are mentioned it is the conceptual idea of +classes that is being referred to. GTK is written entirely in C which +provides no direct support for classes. + +The first part to the class mechanism is the object fields. These are +fields that will be used on a per object basis. For example, the widget +type contains a field for the widgets parent. Every derived type needs a +reference to its parent type. A descendant class of @code{GtkObject} +would define itself like: + +@example +struct Descendant +@{ + GtkObject object; + + @dots{} +@}; +@end example + +It is important to note that the @code{GtkObject} field needs to appear +first in the descendant type structure. This allows pointers to objects +of type @code{Descendant} to be cast to pointers to @code{GtkObjects}'s +and vice-versa. + +The second part to the class mechanism is the class fields. These fields +are defined on a per class basis. In the case of widgets, the class +fields are all the ``virtual'' functions for widgets. The +@code{GtkObject} class defines the @code{destroy} virtual function and +the necessary fields for the signal mechanism as well as a field for +determining the runtime type of an object. A virtual function is +semantically the same as it is in C++. That is, the actual function that +is called is determined based on the type of the object. Or, more +specifically, the actual function call depends on the class structure +that is pointed to by the @code{klass} field of the @code{GtkObject} +structure. + +To see how the class fields work it is necessary to see the object +fields for a @code{GtkObject}. The @code{GtkObject} type is defined as +follows: + +@example +typedef struct _GtkObject GtkObject; + +struct _GtkObject +@{ + guint32 flags; + GtkObjectClass *klass; + gpointer object_data; +@}; +@end example + +The @code{class} field actually points to a class structure derived from +@code{GtkObjectClass}. By convention, each new type defines its own +class structure even if it is unnecessary. As an example, the +hypothetical @code{Descendant} class would define its class structure +as: + +@example +struct DescendantClass +@{ + GtkObjectClass parent_class; + + @dots{} +@}; +@end example + +It is convention to name the parent class field (@code{GtkObjectClass} +in this case), @code{parent_class}. For the same reason as stated above +for the object structure, the parent class field must be the first field +in the class structure. + +@strong{Note:} GTK assumes that the first field in a structure will be +placed by the compiler at the start of the structure. This is certainly +true for gcc, however, from my precursory reading of the C standard I +was unable to come to a definite conclusion as to whether this was +required or simply done for simplicity. I'm not too worried about this +assumption, though, as every C compiler I've ever encountered would work +with GTK. + +The @code{flags} field of the @code{GtkObject} structure is used to keep +track of a relatively few object flags and is also used by the +@code{GtkWidget} type to store additional flags. At this time, the upper +16 bits of the flags field are reserved but unused. + +The @code{object_data} field of the @code{GtkObject} structure is an +opaque pointer used by the object data mechanism. In truth, it is a +pointer to the beginning of the data list which is composed of the +following structures. + +@example +typedef struct _GtkObjectData GtkObjectData; + +struct _GtkObjectData +@{ + guint id; + gpointer data; + GtkObjectData *next; +@}; +@end example + +The data mechanism allows arbitrary data to be associated with a +character string key in any object. A hash table is used to transform +the character string key into the data id and then a search through the +list is made to see if the data exists. The assumption being that the +data list will usually be short and therefore a linear search is +ok. Future work on the data mechanism might make use of a resizable +array instead of a linked list. This would shrink the overhead of the +@code{GtkObjectData} structure by 4 bytes on 32 bit architectures. + + +@node Signal Implementation, Widget Implementation, Object Implementation, Top +@comment node-name, next, previous, up +@chapter Signal internals +@cindex Signal Implementation + + +@node Widget Implementation, Function Index, Signal Implementation, Top +@comment node-name, next, previous, up +@chapter Widget internals +@cindex Widget Implementation + + +@node Function Index, Concept Index, Widget Implementation, Top +@comment node-name, next, previous, up +@unnumbered Function Index + +@printindex fn + + +@node Concept Index, , Function Index, Top +@comment node-name, next, previous, up +@unnumbered Concept Index + +@printindex cp + + +@summarycontents +@contents +@bye diff --git a/docs/macros.texi b/docs/macros.texi new file mode 100644 index 000000000..f8df89a46 --- /dev/null +++ b/docs/macros.texi @@ -0,0 +1,18 @@ +@macro gtkstdmacros {p, q} + +@deftypefun Gtk\p\* GTK_\q\ (gpointer @var{obj}) +Cast a generic pointer to @code{Gtk\p\*}. @xref{Standard Macros}, for +more info. +@end deftypefun + +@deftypefun Gtk\p\Class* GTK_\q\_CLASS (gpointer @var{class}) +Cast a generic pointer to @code{Gtk\p\Class*}. @xref{Standard Macros}, +for more info. +@end deftypefun + +@deftypefun gint GTK_IS_\q\ (gpointer @var{obj}) +Determine if a generic pointer refers to a @code{Gtk\p\} +object. @xref{Standard Macros}, for more info. +@end deftypefun + +@end macro diff --git a/docs/texinfo.tex b/docs/texinfo.tex new file mode 100644 index 000000000..7d62f26f7 --- /dev/null +++ b/docs/texinfo.tex @@ -0,0 +1,4692 @@ +%% TeX macros to handle texinfo files + +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, +% 94, 95, 1996 Free Software Foundation, Inc. + +%This texinfo.tex file is free software; you can redistribute it and/or +%modify it under the terms of the GNU General Public License as +%published by the Free Software Foundation; either version 2, or (at +%your option) any later version. + +%This texinfo.tex file 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. See the GNU +%General Public License for more details. + +%You should have received a copy of the GNU General Public License +%along with this texinfo.tex file; see the file COPYING. If not, write +%to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +%Boston, MA 02111-1307, USA. + + +%In other words, you are welcome to use, share and improve this program. +%You are forbidden to forbid anyone else to use, share and improve +%what you give them. Help stamp out software-hoarding! + + +% Send bug reports to bug-texinfo@prep.ai.mit.edu. +% Please include a *precise* test case in each bug report. + + +% Make it possible to create a .fmt file just by loading this file: +% if the underlying format is not loaded, start by loading it now. +% Added by gildea November 1993. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi + +% This automatically updates the version number based on RCS. +\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}} +\deftexinfoversion$Revision$ +\message{Loading texinfo package [Version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{} + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv = \equiv +\let\ptexi=\i +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexstar=\* +\let\ptext=\t +\let\ptextilde=\~ + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} +\let\~ = \tie % And make it available as @~. + + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English. +\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi% +\def\putwordInfo{Info}% +\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi% +\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi% +\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi% +\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi% +\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi% +\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi% +\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi% +\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi% +\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi% + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset +\newdimen \normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% + +%---------------------Begin change----------------------- +% +%%%% For @cropmarks command. +% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\cornerlong \newdimen\cornerthick +\newdimen \topandbottommargin +\newdimen \outerhsize \newdimen \outervsize +\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks +\outerhsize=7in +%\outervsize=9.5in +% Alternative @smallbook page size is 9.25in +\outervsize=9.25in +\topandbottommargin=.75in +% +%---------------------End change----------------------- + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}} +\def\onepageout#1{% + \hoffset=\normaloffset + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + {% + \escapechar = `\\ % use backslash in output files. + \indexdummies + \shipout\vbox{% + {\let\hsize=\pagewidth \makeheadline}% + \pagebody{#1}% + {\let\hsize=\pagewidth \makefootline}% + }% + }% + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +%%%% For @cropmarks command %%%% + +% Here is a modification of the main output routine for Near East Publications +% This provides right-angle cropmarks at all four corners. +% The contents of the page are centerlined into the cropmarks, +% and any desired binding offset is added as an \hskip on either +% site of the centerlined box. (P. A. MacKay, 12 November, 1986) +% +\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up +{\escapechar=`\\\relax % makes sure backslash is used in output files. + \shipout + \vbox to \outervsize{\hsize=\outerhsize + \vbox{\line{\ewtop\hfill\ewtop}} + \nointerlineskip + \line{\vbox{\moveleft\cornerthick\nstop} + \hfill + \vbox{\moveright\cornerthick\nstop}} + \vskip \topandbottommargin + \centerline{\ifodd\pageno\hskip\bindingoffset\fi + \vbox{ + {\let\hsize=\pagewidth \makeheadline} + \pagebody{#1} + {\let\hsize=\pagewidth \makefootline}} + \ifodd\pageno\else\hskip\bindingoffset\fi} + \vskip \topandbottommargin plus1fill minus1fill + \boxmaxdepth\cornerthick + \line{\vbox{\moveleft\cornerthick\nsbot} + \hfill + \vbox{\moveright\cornerthick\nsbot}} + \nointerlineskip + \vbox{\line{\ewbot\hfill\ewbot}} + }} + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi} +% +% Do @cropmarks to get crop marks +\def\cropmarks{\let\onepageout=\croppageout } + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment. Type Return to continue.} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Type to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt \char '100}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt \char '173}} +\def\myrbrace {{\tt \char '175}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef@lbracecmd[\{]% + @gdef@rbracecmd[\}]% +@endgroup + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown +% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @enddots{} is an end-of-sentence ellipsis. +\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000} + +% @! is an end-of-sentence bang. +\gdef\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\gdef\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000 +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output some dots + +\def\dots{$\ldots$} + +% @page forces the start of a new page + +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other% +\parsearg \commentxxx} + +\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 } + +\let\c=\comment + +% @paragraphindent is defined for the Info formatting commands only. +\let\paragraphindent=\comment + +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% +\let\chapter=\relax +\let\unnumbered=\relax +\let\top=\relax +\let\unnumberedsec=\relax +\let\unnumberedsection=\relax +\let\unnumberedsubsec=\relax +\let\unnumberedsubsection=\relax +\let\unnumberedsubsubsec=\relax +\let\unnumberedsubsubsection=\relax +\let\section=\relax +\let\subsec=\relax +\let\subsubsec=\relax +\let\subsection=\relax +\let\subsubsection=\relax +\let\appendix=\relax +\let\appendixsec=\relax +\let\appendixsection=\relax +\let\appendixsubsec=\relax +\let\appendixsubsection=\relax +\let\appendixsubsubsec=\relax +\let\appendixsubsubsection=\relax +\let\contents=\relax +\let\smallbook=\relax +\let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% Also ignore @macro ... @end macro. The user must run texi2dvi, +% which runs makeinfo to do macro expansion. Ignore @unmacro, too. +\def\macro{\doignore{macro}} +\let\unmacro = \comment + + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory = \comment + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + \long\def\doignoretext##1\end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.ai.mit.edu/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}} +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. Make sure the catcode of space is correct to avoid +% losing inside @example, for instance. +% +\def\set{\begingroup\catcode` =10 \parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +\def\value#1{\expandafter + \ifx\csname SET#1\endcsname\relax + {\{No value for ``#1''\}} + \else \csname SET#1\endcsname \fi} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex always succeeds; we read the text following, through @end +% iftex). But `@end iftex' should be valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\defineunmatchedend{iftex} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +\def\donoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\setref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\unnumbnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\appendixnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +% @refill is a no-op. +\let\refill=\relax + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \readauxfile + \opencontents + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + \comment % Ignore the actual filename. +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + +% \def\macro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\macroxxx} +% \def\macroxxx#1#2 \end macro{% +% \expandafter\gdef\macrotemp#1{#2}% +% \endgroup} + +%\def\linemacro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\linemacroxxx} +%\def\linemacroxxx#1#2 \end linemacro{% +%\let\parsearg=\relax +%\edef\macrotempx{\csname M\butfirst\expandafter\string\macrotemp\endcsname}% +%\expandafter\xdef\macrotemp{\parsearg\macrotempx}% +%\expandafter\gdef\macrotempx#1{#2}% +%\endgroup} + +%\def\butfirst#1{} + + +\message{fonts,} + +% Font-change commands. + +% Texinfo supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +%% Try out Computer Modern fonts at \magstephalf +\let\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples (9pt). +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\setfont\ninett\ttshape{9}{1000} +\setfont\indrm\rmshape{9}{1000} +\setfont\indit\slshape{9}{1000} +\let\indsl=\indit +\let\indtt=\ninett +\let\indttsl=\ninett +\let\indsf=\indrm +\let\indbf=\indrm +\setfont\indsc\scshape{10}{900} +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Chapter (and unnumbered) fonts (17.28pt). +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{12}{\magstep2} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +% Subsection fonts (13.15pt). +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{\magstep1} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled \magstep1 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\let\authorrm = \secrm + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts \setleading{12pt}} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartitalic +\let\dfn=\smartitalic +\let\emph=\smartitalic +\let\cite=\smartitalic + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp #1{`\tclose{#1}'\null} +\setfont\smallrm\rmshape{8}{1000} +\font\smallsy=cmsy9 +\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{% + \raise0.4pt\hbox{$\langle$}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{$\langle$}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{$\rangle$}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +\let\file=\samp +\let\url=\samp % perhaps include a hypertex \special eventually +\def\email#1{$\langle${\tt #1}$\rangle$} + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ +\catcode`\-=\active +\catcode`\_=\active +\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex} +% The following is used by \doprintindex to insure that long function names +% wrap around. It is necessary for - and _ to be active before the index is +% read from the file, as \entry parses the arguments long before \code is +% ever called. -- mycroft +\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder} +} + +\def\realdash{-} +\def\realunder{_} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\normalunderscore\discretionary{}{}{}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. +% +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\ttsl\look}}\fi +\else{\tclose{\ttsl\look}}\fi} + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of +% @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +\def\r#1{{\rm #1}} % roman font +% Use of \lowercase was suggested. +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @pounds{} is a sterling sign. +\def\pounds{{\it\$}} + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\def\titlefont#1{{\titlerm #1}} + +\newif\ifseenauthor +\newif\iffinishedtitlepage + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm +% I deinstalled the following change because \cmr12 is undefined. +% This change was not in the ChangeLog anyway. --rms. +% \let\subtitlerm=\cmr12 + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefont{##1}} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks \evenheadline % Token sequence for heading line of even pages +\newtoks \oddheadline % Token sequence for heading line of odd pages +\newtoks \evenfootline % Token sequence for footing line of even pages +\newtoks \oddfootline % Token sequence for footing line of odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish} +\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish} +\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{\number\day\space +\ifcase\month\or +January\or February\or March\or April\or May\or June\or +July\or August\or September\or October\or November\or December\fi +\space\number\year} + +% Use this if you want the Month Day, Year style of output. +%\def\today{\ifcase\month\or +%January\or February\or March\or April\or May\or June\or +%July\or August\or September\or October\or November\or December\fi +%\space\number\day, \number\year} + +% @settitle line... specifies the title of the document, for headings +% It generates no output of its own + +\def\thistitle{No Title} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + + +\message{tables,} + +% @tabs -- simple alignment + +% These don't work. For one thing, \+ is defined as outer. +% So these macros cannot even be defined. + +%\def\tabs{\parsearg\tabszzz} +%\def\tabszzz #1{\settabs\+#1\cr} +%\def\tabline{\parsearg\tablinezzz} +%\def\tablinezzz #1{\+#1\cr} +%\def\&{&} + +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % Be sure we are not still in the middle of a paragraph. + %{\parskip = 0in + %\par + %}% + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. Since that + % text will be indented by \tableindent, we make the item text be in + % a zero-width box. + \noindent + \rlap{\hskip -\tableindent\box0}\ignorespaces% + \endgroup% + \itemxneedsnegativevskiptrue% + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +%% Contains a kludge to get @end[description] to work +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemsize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{\in hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. +% +% For those who want to use more than one line's worth of words in +% the preamble, break the line within one argument and it +% will parse correctly, i.e., +% +% @multitable {Column 1 template} {Column 2 template} {Column 3 +% template} +% Not: +% @multitable {Column 1 template} {Column 2 template} +% {Column 3 template} + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multitable or @end multitable do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. + +%%%% +% Dimensions + +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +%%%% +% Macros used to set up halign preamble: +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +%% 2/1/96, to allow fractions to be given with more than one digit. +\def\pickupwholefraction#1 {\global\advance\colcount by1 % +\expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}% +\setuptable} + +\newcount\colcount +\def\setuptable#1{\def\firstarg{#1}% +\ifx\firstarg\xendsetuptable\let\go\relax% +\else + \ifx\firstarg\xcolumnfractions\global\setpercenttrue% + \else + \ifsetpercent + \let\go\pickupwholefraction % In this case arg of setuptable + % is the decimal point before the + % number given in percent of hsize. + % We don't need this so we don't use it. + \else + \global\advance\colcount by1 + \setbox0=\hbox{#1 }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi% + \fi% +\ifx\go\pickupwholefraction\else\let\go\setuptable\fi% +\fi\go} + +%%%% +% multitable syntax +\def\tab{&\hskip1sp\relax} % 2/2/96 + % tiny skip here makes sure this column space is + % maintained, even if it is never used. + + +%%%% +% @multitable ... @end multitable definitions: + +\def\multitable{\parsearg\dotable} + +\def\dotable#1{\bgroup +\let\item\cr +\tolerance=9500 +\hbadness=9500 +\setmultitablespacing +\parskip=\multitableparskip +\parindent=\multitableparindent +\overfullrule=0pt +\global\colcount=0\relax% +\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}% + % To parse everything between @multitable and @item : +\setuptable#1 \endsetuptable + % Need to reset this to 0 after \setuptable. +\global\colcount=0\relax% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. +\halign\bgroup&\global\advance\colcount by 1\relax% +\multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % If user has set preamble in terms of percent of \hsize + % we will use that dimension as the width of the column, and + % the \leftskip will keep entries from bumping into each other. + % Table will start at left margin and final column will justify at + % right margin. +\ifnum\colcount=1 +\else + \ifsetpercent + \else + % If user has set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: +\leftskip=\multitablecolspace +\fi +\noindent##\multistrut}\cr% + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. +\global\everycr{\noalign{% +\filbreak%% keeps underfull box messages off when table breaks over pages. +\global\colcount=0\relax}} +} + +\def\setmultitablespacing{% test to see if user has set \multitablelinespace. +% If so, do nothing. If not, give it an appropriate dimension based on +% current baselineskip. +\ifdim\multitablelinespace=0pt +%% strut to put in table in case some entry doesn't have descenders, +%% to keep lines equally spaced +\let\multistrut = \strut +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\else +\gdef\multistrut{\vrule height\multitablelinespace depth\dp0 +width0pt\relax} \fi +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. + +\def\newindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +\def\synindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +% (Must be a way to avoid doing expansion at all, and thus not have to +% laboriously list every single command here.) +\def\@{@}% will be @@ when we switch to @ as escape char. +%\let\{ = \lbracecmd +%\let\} = \rbracecmd +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +%\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +%\def\char{\realbackslash char}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\copyright{\realbackslash copyright }% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\dotless##1{\realbackslash dotless {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\,##1{\realbackslash ,{##1}}% +\def\t##1{\realbackslash t {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\unsepspaces +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\,=\indexdummyfont +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +\let\dotless=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +\def\@{@}% +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other +@gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. + +\let\SETmarginindex=\relax %initialize! +% workhorse for all \fooindexes +% #1 is name of index, #2 is stuff to put there +\def\doind #1#2{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio=0 % We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + % First process the index-string with all font commands turned off + % to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2}}% + % + % Now produce the complete index entry, with both the sort key and the + % original text, including any font commands. + \toks0 = {#2}% + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + \temp + }% + }% + \penalty\count255 + }% +} + +\def\dosubind #1#2#3{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% +\def\rawbackslashxx{\indexbackslash}% +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2 #3}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}{#3}}}% +\temp }% +}\penalty\count10}} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% This is what you call to cause a particular index to get printed. +% Write +% @unnumbered Function Index +% @printindex fn + +\def\printindex{\parsearg\doprintindex} + +\def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \indexfonts \rm + \tolerance = 9500 + \indexbreaks + \def\indexbackslash{\rawbackslashxx}% + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \catcode`\\ = 0 + \catcode`\@ = 11 + \escapechar = `\\ + \begindoublecolumns + % + % See if the index file exists and is nonempty. + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + \input \jobname.#1s + \fi + \fi + \closein 1 + \enddoublecolumns +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +% Same as \bigskipamount except no shrink. +% \balancecolumns gets confused if there is any shrink. +\newskip\initialskipamount \initialskipamount 12pt plus4pt + +\def\initial #1{% +{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt +\ifdim\lastskip<\initialskipamount +\removelastskip \penalty-200 \vskip \initialskipamount\fi +\line{\secbf#1\hfill}\kern 2pt\penalty10000}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry #1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent=2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {\global\setbox\partialpage + =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}% + \eject + % + % Now switch to the double-column output routine. + \output={\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it once. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +- < + % 1pt) as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize +} +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage + % box0 will be the left-hand column, box1 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 \penalty\outputpenalty +} +\def\pagesofar{% + % The contents of the output page -- any previous material, + % followed by the two boxes we just split. + \unvbox\partialpage + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% +} +\def\enddoublecolumns{% + \output={\balancecolumns}\eject % split what we have + \endgroup + % Back to normal single-column typesetting, but take account of the + % fact that we just accumulated some stuff on the output page. + \pagegoal=\vsize +} +\def\balancecolumns{% + % Called on the last page of the double column material. + \setbox0=\vbox{\unvbox255}% + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {\vbadness=10000 \loop \global\setbox3=\copy0 + \global\setbox1=\vsplit3 to\dimen@ + \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt \repeat}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + \pagesofar +} +\catcode `\@=\other + + +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount \chapno +\newcount \secno \secno=0 +\newcount \subsecno \subsecno=0 +\newcount \subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount \appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +\newwrite \contentsfile +% This is called from \setfilename. +\def\opencontents{\openout \contentsfile = \jobname.toc} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise + +\def\thischapter{} \def\thissection{} +\def\seccheck#1{\if \pageno<0 % +\errmessage{@#1 not allowed after generating table of contents}\fi +% +} + +\def\chapternofonts{% +\let\rawbackslash=\relax% +\let\frenchspacing=\relax% +\def\result{\realbackslash result} +\def\equiv{\realbackslash equiv} +\def\expansion{\realbackslash expansion} +\def\print{\realbackslash print} +\def\TeX{\realbackslash TeX} +\def\dots{\realbackslash dots} +\def\copyright{\realbackslash copyright} +\def\tt{\realbackslash tt} +\def\bf{\realbackslash bf } +\def\w{\realbackslash w} +\def\less{\realbackslash less} +\def\gtr{\realbackslash gtr} +\def\hat{\realbackslash hat} +\def\char{\realbackslash char} +\def\tclose##1{\realbackslash tclose {##1}} +\def\code##1{\realbackslash code {##1}} +\def\samp##1{\realbackslash samp {##1}} +\def\r##1{\realbackslash r {##1}} +\def\b##1{\realbackslash b {##1}} +\def\key##1{\realbackslash key {##1}} +\def\file##1{\realbackslash file {##1}} +\def\kbd##1{\realbackslash kbd {##1}} +% These are redefined because @smartitalic wouldn't work inside xdef. +\def\i##1{\realbackslash i {##1}} +\def\cite##1{\realbackslash cite {##1}} +\def\var##1{\realbackslash var {##1}} +\def\emph##1{\realbackslash emph {##1}} +\def\dfn##1{\realbackslash dfn {##1}} +} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + + +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{\seccheck{chapter}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +}} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{\seccheck{appendix}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 \message{Appendix \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry + {#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +}} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\def\centerchap{\parsearg\centerchapyyy} +\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + +\outer\def\top{\parsearg\unnumberedyyy} +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{\seccheck{unnumbered}% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the to achieve this: TeX expands \the only once, +% simply yielding the contents of the . +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +}} + +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{\seccheck{section}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{\seccheck{appendixsection}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{\seccheck{unnumberedsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{\seccheck{subsection}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{\seccheck{appendixsubsec}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}% +\plainsubsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{\seccheck{subsubsection}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry % + {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno} + {\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry{#1}% + {\appendixletter} + {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}% +\plainsubsubsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and +% such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +% @heading, @subheading, @subsubheading. +\def\heading{\parsearg\plainsecheading} +\def\subheading{\parsearg\plainsubsecheading} +\def\subsubheading{\parsearg\plainsubsubsecheading} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{ +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{ +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain +\global\let\centerchapmacro=\centerchfplain} + +% Plain chapter opening. +% #1 is the text, #2 the chapter number or empty if unnumbered. +\def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% Plain opening for unnumbered. +\def\unnchfplain#1{\chfplain{#1}{}} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% +}} + +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\penalty 10000 % +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen +\global\let\centerchapmacro=\centerchfopen} + + +% Section titles. +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} +\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} +\def\plainsecheading#1{\sectionheading{sec}{}{#1}} + +% Subsection titles. +\newskip \subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} +\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} +\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + +% Subsubsection titles. +\let\subsubsecheadingskip = \subsecheadingskip +\let\subsubsecheadingbreak = \subsecheadingbreak +\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} +\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + +% Print any size section title. +% +% #1 is the section type (sec/subsec/subsubsec), #2 is the section +% number (maybe empty), #3 the text. +\def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak +} + + +\message{toc printing,} +% Finish up the main text and prepare to read what we've written +% to \contentsfile. + +\newskip\contentsrightmargin \contentsrightmargin=1in +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout \contentsfile + \ifnum \pageno>0 + \pageno = -1 % Request roman numbered pages. + \fi + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + \catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. +} + + +% Normal (long) toc. +\outer\def\contents{% + \startcontents{\putwordTableofContents}% + \input \jobname.toc + \endgroup + \vfill \eject +} + +% And just the chapters. +\outer\def\summarycontents{% + \startcontents{\putwordShortContents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \endgroup + \vfill \eject +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +% +% \turnoffactive is for the sake of @" used for umlauts. +\def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + \entry{\turnoffactive #1}{\turnoffactive #2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup +\catcode `\\=0 \catcode `\{=1 \catcode `\}=2 +\catcode `\$=3 \catcode `\&=4 \catcode `\#=6 +\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie +\catcode `\%=14 +\catcode 43=12 % plus +\catcode`\"=12 +\catcode`\==12 +\catcode`\|=12 +\catcode`\<=12 +\catcode`\>=12 +\escapechar=`\\ +% +\let\,=\ptexcomma +\let\~=\ptextilde +\let\{=\ptexlbrace +\let\}=\ptexrbrace +\let\.=\ptexdot +\let\*=\ptexstar +\let\dots=\ptexdots +\def\endldots{\mathinner{\ldots\ldots\ldots\ldots}} +\def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi} +\def\@{@}% +\let\bullet=\ptexbullet +\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext +% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \cartouche: draw rectangle w/rounded corners around argument +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% To ending an @example-like environment, we first end the paragraph +% (via \afterenvbreak's vertical glue), and then the group. That way we +% keep the zero \parskip that the environments set -- \parskip glue +% will be inserted at the beginning of the next paragraph in the +% document, after the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup}% + +% This macro is +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \rawbackslash % have \ input char produce \ char from current font + \gobble +} + +% Define the \E... control sequence only if we are inside the +% environment, so the error checking in \end will work. +% +% We must call \lisp last in the definition, since it reads the +% return following the @example (or whatever) command. +% +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} +\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% @smallexample and @smalllisp. This is not used unless the @smallbook +% command is given. Originally contributed by Pavel@xerox. +% +\def\smalllispx{\begingroup + \nonfillstart + \let\Esmalllisp = \nonfillfinish + \let\Esmallexample = \nonfillfinish + % + % Smaller fonts for small examples. + \indexfonts \tt + \rawbackslash % make \ output the \ character from the current font (tt) + \gobble +} + +% This is @display; same as @lisp except use roman font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% This is @format; same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @flushleft (same as @format) and @flushright. +% +\def\flushleft{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushleft = \nonfillfinish + \gobble +} +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested % +\global\advance\parencount by 1 } +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. +% also in that case restore the outer-level definition of (. +\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi +\global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\dimen3=\rightskip +\advance\dimen3 by -\defbodyindent +\noindent % +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 % +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 \advance \hsize by -\dimen3 +\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +\def\defmethparsebody #1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does, putting the result in \tptemp. +% +\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}% + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + \removeemptybraces#2\relax + #1{\tptemp}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Function}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Macro}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Special Form}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}} + +% @defmethod, and so on + +% @defop {Funny Method} foo-class frobnicate argument + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{} on #1}% +\defunargs {#3}\endgroup % +} + +% @defmethod == @defop Method + +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} + +\def\defmethodheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% entry in function index +\begingroup\defname {#2}{Method on #1}% +\defunargs {#3}\endgroup % +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype{} of #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{Instance Variable of #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{Variable}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{User Option}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name. +\def\deftypevarheader #1#2{% +\doind {vr}{\code{#2}}% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + + +\message{cross reference,} +% Define cross-reference macros +\newwrite \auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% \setref{foo} defines a cross-reference point named foo. + +\def\setref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ysectionnumberandtype}} + +\def\unnumbsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ynothing}} + +\def\appendixsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Yappendixletterandtype}} + +% \xref, \pxref, and \ref generate cross-references to specified points. +% For \xrefX, #1 is the node name, #2 the name of the Info +% cross-reference, #3 the printed node name, #4 the name of the Info +% file, #5 the name of the printed manual. All but the node name can be +% omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1>0pt% + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive \refx{#1-snt}{}}% + \space [\printednodename],\space + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \turnoffactive so that punctuation chars such as underscore +% work in node names. +\def\dosetq #1#2{{\let\folio=0 \turnoffactive \auxhat% +\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% +\next}} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + $\langle$un\-de\-fined$\rangle$% + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% Read the last existing aux file, if any. No error if none exists. + +% This is the macro invoked by entries in the aux file. +\def\xrdef #1#2{ +{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}} + +\def\readauxfile{% +\begingroup +\catcode `\^^@=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\^^C=\other +\catcode `\^^D=\other +\catcode `\^^E=\other +\catcode `\^^F=\other +\catcode `\^^G=\other +\catcode `\^^H=\other +\catcode `\ =\other +\catcode `\^^L=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode 26=\other +\catcode `\^^[=\other +\catcode `\^^\=\other +\catcode `\^^]=\other +\catcode `\^^^=\other +\catcode `\^^_=\other +\catcode `\@=\other +\catcode `\^=\other +\catcode `\~=\other +\catcode `\[=\other +\catcode `\]=\other +\catcode`\"=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode `\$=\other +\catcode `\#=\other +\catcode `\&=\other +% `\+ does not work, so use 43. +\catcode 43=\other +% Make the characters 128-255 be printing characters +{% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% +}% +% the aux file uses ' as the escape. +% Turn off \ as an escape so we do not lose on +% entries which were dumped with control sequences in their names. +% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ +% Reference to such entries still does not work the way one would wish, +% but at least they do not bomb out when the aux file is read in. +\catcode `\{=1 \catcode `\}=2 +\catcode `\%=\other +\catcode `\'=0 +\catcode`\^=7 % to make ^^e4 etc usable in xref tags +\catcode `\\=\other +\openin 1 \jobname.aux +\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue +\global\warnedobstrue +\fi +% Open the new aux file. Tex will close it automatically at exit. +\openout \auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only.. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +\long\gdef\footnotezzz#1{\insert\footins{% + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + #1\strut}% +} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + + +% End of control word definitions. + +\message{and turning on texinfo input format.} + +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% Set some numeric style parameters, for 8.5 x 11 format. + +\hsize = 6in +\hoffset = .25in +\newdimen\defaultparindent \defaultparindent = 15pt +\parindent = \defaultparindent +\parskip 3pt plus 2pt minus 1pt +\setleading{13.2pt} +\advance\topskip by 1.2cm + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness=10000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. This makes it come to about 9pt for the 8.5x11 format. +% +\ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% +\else + \emergencystretch = \hsize + \divide\emergencystretch by 45 +\fi + +% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) +\def\smallbook{ + \global\chapheadingskip = 15pt plus 4pt minus 2pt + \global\secheadingskip = 12pt plus 3pt minus 2pt + \global\subsecheadingskip = 9pt plus 2pt minus 2pt + % + \global\lispnarrowing = 0.3in + \setleading{12pt} + \advance\topskip by -1cm + \global\parskip 2pt plus 1pt + \global\hsize = 5in + \global\vsize=7.5in + \global\tolerance=700 + \global\hfuzz=1pt + \global\contentsrightmargin=0pt + \global\deftypemargin=0pt + \global\defbodyindent=.5cm + % + \global\pagewidth=\hsize + \global\pageheight=\vsize + % + \global\let\smalllisp=\smalllispx + \global\let\smallexample=\smalllispx + \global\def\Esmallexample{\Esmalllisp} +} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{ +\global\tolerance=700 +\global\hfuzz=1pt +\setleading{12pt} +\global\parskip 15pt plus 1pt + +\global\vsize= 53\baselineskip +\advance\vsize by \topskip +%\global\hsize= 5.85in % A4 wide 10pt +\global\hsize= 6.5in +\global\outerhsize=\hsize +\global\advance\outerhsize by 0.5in +\global\outervsize=\vsize +\global\advance\outervsize by 0.6in + +\global\pagewidth=\hsize +\global\pageheight=\vsize +} + +\bindingoffset=0pt +\normaloffset=\hoffset +\pagewidth=\hsize +\pageheight=\vsize + +% Allow control of the text dimensions. Parameters in order: textheight; +% textwidth; voffset; hoffset; binding offset; topskip. +% All require a dimension; +% header is additional; added length extends the bottom of the page. + +\def\changepagesizes#1#2#3#4#5#6{ + \global\vsize= #1 + \global\topskip= #6 + \advance\vsize by \topskip + \global\voffset= #3 + \global\hsize= #2 + \global\outerhsize=\hsize + \global\advance\outerhsize by 0.5in + \global\outervsize=\vsize + \global\advance\outervsize by 0.6in + \global\pagewidth=\hsize + \global\pageheight=\vsize + \global\normaloffset= #4 + \global\bindingoffset= #5} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex + {\global\tolerance=700 + \global\hfuzz=1pt + \setleading{12pt} + \global\parskip 15pt plus 1pt + \advance\baselineskip by 1.6pt + \changepagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm} + } + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{\afourpaper +\changepagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt \char '042}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt \char '176}} +\chardef\hat=`\^ +\catcode`\^=\active +\def\auxhat{\def^{'hat}} +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt \char '174}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} + +%% These look ok in all fonts, so just make them not special. The @rm below +%% makes sure that the current font starts out as the newly loaded cmr10 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c page-delimiter: "^\\\\message" +@c End: diff --git a/gdk/.cvsignore b/gdk/.cvsignore new file mode 100644 index 000000000..79680c82c --- /dev/null +++ b/gdk/.cvsignore @@ -0,0 +1,6 @@ +*.lo +Makefile +.deps +_libs +libgdk.la + diff --git a/gdk/Makefile.am b/gdk/Makefile.am new file mode 100644 index 000000000..f298e2c3a --- /dev/null +++ b/gdk/Makefile.am @@ -0,0 +1,75 @@ +## Process this file with automake to produce Makefile.in + +gdkincludedir = $(includedir)/gdk + +lib_LTLIBRARIES = libgdk.la + +libgdk_la_SOURCES = \ + gdk.c \ + gdkcolor.c \ + gdkcursor.c \ + gdkdraw.c \ + gdkfont.c \ + gdkgc.c \ + gdkglobals.c \ + gdkimage.c \ + gdkinput.c \ + gdkpixmap.c \ + gdkproperty.c \ + gdkrectangle.c \ + gdkselection.c \ + gdkvisual.c \ + gdkwindow.c \ + gdkxid.c \ + gxid_lib.c +## this last one is ifdef'd out unless XINPUT_GXI is defined +## It's easier than trying to get automake to handle compiling +## it conditionally + +gdkinclude_HEADERS = \ + gdk.h \ + gdkcursors.h \ + gdkkeysyms.h \ + gdkprivate.h \ + gdktypes.h \ + gdkinput.h \ + gdkinputnone.h \ + gdkinputcommon.h\ + gdkinputgxi.h \ + gdkinputxfree.h \ + gxid_lib.h \ + gxid_proto.h \ + gdkx.h + +libgdk_la_LDFLAGS = -version-info 1:0:0 \ + @x_ldflags@ @x_libs@ + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/glib @x_cflags@ + +EXTRA_PROGRAMS = gxid + +bin_PROGRAMS = @xinput_progs@ + +gxid_SOURCES = gxid.c + +gxid_LDADD = \ + @x_ldflags@ \ + @x_libs@ \ + -lm + +BUILT_SOURCES = gdkcursors.h gdkkeysyms.h + +EXTRA_DIST = makecursors makecursors.sed makekeysyms makekeysyms.sed + +gdkcursors.h: + $(srcdir)/makecursors @x_includes@/X11/cursorfont.h > $@ + +gdkkeysyms.h: + $(srcdir)/makekeysyms @x_includes@/X11/keysymdef.h > $@ + +.PHONY: files + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done diff --git a/gdk/gdk.c b/gdk/gdk.c new file mode 100644 index 000000000..d5f85dd1e --- /dev/null +++ b/gdk/gdk.c @@ -0,0 +1,2897 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* HAVE_SYS_SELECT_H_ */ + +#define XLIB_ILLEGAL_ACCESS +#include +#include +#include +#include +#include +#include +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +#ifndef X_GETTIMEOFDAY +#define X_GETTIMEOFDAY(tv) gettimeofday (tv, NULL) +#endif /* X_GETTIMEOFDAY */ + + +#define DOUBLE_CLICK_TIME 250 +#define TRIPLE_CLICK_TIME 500 +#define DOUBLE_CLICK_DIST 5 +#define TRIPLE_CLICK_DIST 5 + + +#ifndef NO_FD_SET +# define SELECT_MASK fd_set +#else +# ifndef _AIX + typedef long fd_mask; +# endif +# if defined(_IBMR2) +# define SELECT_MASK void +# else +# define SELECT_MASK int +# endif +#endif + + +typedef struct _GdkInput GdkInput; +typedef struct _GdkPredicate GdkPredicate; + +struct _GdkInput +{ + gint tag; + gint source; + GdkInputCondition condition; + GdkInputFunction function; + gpointer data; +}; + +struct _GdkPredicate +{ + GdkEventFunc func; + gpointer data; +}; + +/* + * Private function declarations + */ +static gint gdk_event_wait (void); +static gint gdk_event_translate (GdkEvent *event, + XEvent *xevent); +static Bool gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg); +static void gdk_synthesize_click (GdkEvent *event, + gint nclicks); + +static void gdk_dnd_drag_begin (GdkWindow *initial_window); +static void gdk_dnd_drag_enter (Window dest); +static void gdk_dnd_drag_leave (Window dest); +static void gdk_dnd_drag_end (Window dest, + GdkPoint coords); +static GdkAtom gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent); +static void gdk_print_atom (GdkAtom anatom); + +/* + * old junk from offix, we might use it though so leave it + */ +static Window gdk_drop_get_client_window (Display *dpy, + Window win); +static GdkWindow * gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y); +static void gdk_exit_func (void); +static int gdk_x_error (Display *display, + XErrorEvent *error); +static int gdk_x_io_error (Display *display); +static RETSIGTYPE gdk_signal (int signum); + + +/* Private variable declarations + */ +static int initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +static int connection_number = 0; /* The file descriptor number of our + * connection to the X server. This + * is used so that we may determine + * when events are pending by using + * the "select" system call. + */ + +static gint received_destroy_notify = FALSE; /* Did we just receive a destroy notify + * event? If so, we need to actually + * destroy the window which received + * it now. + */ +static GdkWindow *window_to_destroy = NULL; /* If we previously received a destroy + * notify event then this is the window + * which received that event. + */ + +static struct timeval start; /* The time at which the library was + * last initialized. + */ +static struct timeval timer; /* Timeout interval to use in the call + * to "select". This is used in + * conjunction with "timerp" to create + * a maximum time to wait for an event + * to arrive. + */ +static struct timeval *timerp; /* The actual timer passed to "select" + * This may be NULL, in which case + * "select" will block until an event + * arrives. + */ +static guint32 timer_val; /* The timeout length as specified by + * the user in milliseconds. + */ +static GList *inputs; /* A list of the input file descriptors + * that we care about. Each list node + * contains a GdkInput struct that describes + * when we are interested in the specified + * file descriptor. That is, when it is + * available for read, write or has an + * exception pending. + */ +static guint32 button_click_time[2]; /* The last 2 button click times. Used + * to determine if the latest button click + * is part of a double or triple click. + */ +static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses. + * Also used to determine if the latest button + * click is part of a double or triple click. + */ +static guint button_number[2]; /* The last 2 buttons to be pressed. + */ + +#define OTHER_XEVENT_BUFSIZE 4 +static XEvent other_xevent[OTHER_XEVENT_BUFSIZE]; /* XEvents passed along to user */ +static int other_xevent_i = 0; +static GList *putback_events = NULL; + +static gulong base_id; +static gint autorepeat; + + +/* + *-------------------------------------------------------------- + * gdk_init + * + * Initialize the library for use. + * + * Arguments: + * "argc" is the number of arguments. + * "argv" is an array of strings. + * + * Results: + * "argc" and "argv" are modified to reflect any arguments + * which were not handled. (Such arguments should either + * be handled by the application or dismissed). + * + * Side effects: + * The library is initialized. + * + *-------------------------------------------------------------- + */ + +void +gdk_init (int *argc, + char ***argv) +{ + XKeyboardState keyboard_state; + int synchronize; + int i, j, k; + XClassHint *class_hint; + int argc_orig = *argc; + char **argv_orig; + + argv_orig = malloc ((argc_orig + 1) * sizeof (char*)); + for (i = 0; i < argc_orig; i++) + argv_orig[i] = g_strdup ((*argv)[i]); + argv_orig[argc_orig] = NULL; + + X_GETTIMEOFDAY (&start); + + signal (SIGHUP, gdk_signal); + signal (SIGINT, gdk_signal); + signal (SIGQUIT, gdk_signal); + signal (SIGBUS, gdk_signal); + signal (SIGSEGV, gdk_signal); + signal (SIGPIPE, gdk_signal); + signal (SIGTERM, gdk_signal); + + gdk_display_name = NULL; + + XSetErrorHandler (gdk_x_error); + XSetIOErrorHandler (gdk_x_io_error); + + synchronize = FALSE; + + if (argc && argv) + { + if (*argc > 0) + gdk_progname = (*argv)[0]; + + for (i = 1; i < *argc;) + { + if (strcmp ("--display", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + + if ((i + 1) < *argc) + { + gdk_display_name = g_strdup ((*argv)[i + 1]); + (*argv)[i + 1] = NULL; + i += 1; + } + } + else if (strcmp ("--sync", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + synchronize = TRUE; + } + else if (strcmp ("--show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = TRUE; + } + else if (strcmp ("--no-show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = FALSE; + } + else if (strcmp ("--no-xshm", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_use_xshm = FALSE; + } + else if (strcmp ("--debug-level", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_debug_level = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("-name", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progname = (*argv)[i]; + (*argv)[i] = NULL; + } + } + else if (strcmp ("-class", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progclass = (*argv)[i]; + (*argv)[i] = NULL; + } + } +#ifdef XINPUT_GXI + else if (strcmp ("--gxid_host", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_input_gxid_host = ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("--gxid_port", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_input_gxid_port = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } +#endif + i += 1; + } + + for (i = 1; i < *argc; i++) + { + for (k = i; k < *argc; k++) + if ((*argv)[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < *argc; j++) + (*argv)[j-k] = (*argv)[j]; + *argc -= k; + } + } + } + else + { + gdk_progname = ""; + } + + gdk_display = XOpenDisplay (gdk_display_name); + if (!gdk_display) + g_error ("cannot open display: %s", XDisplayName (gdk_display_name)); + + /* This is really crappy. We have to look into the display structure + * to find the base resource id. This is only needed for recording + * and playback of events. + */ + /* base_id = RESOURCE_BASE; */ + base_id = 0; + if (gdk_show_events) + g_print ("base id: %lu\n", base_id); + + connection_number = ConnectionNumber (gdk_display); + if (gdk_debug_level >= 1) + g_print ("connection number: %d\n", connection_number); + + if (synchronize) + XSynchronize (gdk_display, True); + + gdk_screen = DefaultScreen (gdk_display); + gdk_root_window = RootWindow (gdk_display, gdk_screen); + + gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window, + 10, 10, 10, 10, 0, 0 , 0); + class_hint = XAllocClassHint(); + class_hint->res_name = gdk_progname; + class_hint->res_class = gdk_progclass; + XSetClassHint(gdk_display, gdk_leader_window, class_hint); + XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig); + XFree (class_hint); + + gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True); + gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True); + gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True); + gdk_wm_window_protocols[0] = gdk_wm_delete_window; + gdk_wm_window_protocols[1] = gdk_wm_take_focus; + gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False); + + gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE); + gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE); + gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE); + gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE); + gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE); + gdk_dnd.gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity); + gdk_dnd.gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart); + + XGetKeyboardControl (gdk_display, &keyboard_state); + autorepeat = keyboard_state.global_auto_repeat; + + timer.tv_sec = 0; + timer.tv_usec = 0; + timerp = NULL; + + button_click_time[0] = 0; + button_click_time[1] = 0; + button_window[0] = NULL; + button_window[1] = NULL; + button_number[0] = -1; + button_number[1] = -1; + + if (ATEXIT (gdk_exit_func)) + g_warning ("unable to register exit function"); + + gdk_visual_init (); + gdk_window_init (); + gdk_image_init (); + gdk_input_init (); + + initialized = 1; +} + +/* + *-------------------------------------------------------------- + * gdk_exit + * + * Restores the library to an un-itialized state and exits + * the program using the "exit" system call. + * + * Arguments: + * "errorcode" is the error value to pass to "exit". + * + * Results: + * Allocated structures are freed and the program exits + * cleanly. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_exit (int errorcode) +{ + /* de-initialisation is done by the gdk_exit_funct(), + no need to do this here (Alex J.) */ + exit (errorcode); +} + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale () +{ + if (!setlocale (LC_ALL,"")) + g_print ("locale not supported by C library\n"); + + if (!XSupportsLocale ()) + { + g_print ("locale not supported by Xlib, locale set to C\n"); + setlocale (LC_ALL, "C"); + } + + if (!XSetLocaleModifiers ("")) + { + g_print ("can not set locale modifiers\n"); + } + + return setlocale (LC_ALL,NULL); +} + +/* + *-------------------------------------------------------------- + * gdk_events_pending + * + * Returns the number of events pending on the queue. + * These events have already been read from the server + * connection. + * + * Arguments: + * + * Results: + * Returns the number of events on XLib's event queue. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_events_pending () +{ + return XPending (gdk_display); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get + * + * Gets the next event. + * + * Arguments: + * "event" is used to hold the received event. + * If "event" is NULL an event is received as normal + * however it is not placed in "event" (and thus no + * error occurs). + * + * Results: + * Returns TRUE if an event was received that we care about + * and FALSE otherwise. This function will also return + * before an event is received if the timeout interval + * runs out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_event_get (GdkEvent *event, + GdkEventFunc pred, + gpointer data) +{ + GdkEvent *temp_event; + GdkPredicate event_pred; + GList *temp_list; + XEvent xevent; + + /* If the last event we received was a destroy notify + * event then we will actually destroy the "gdk" data + * structures now. We don't want to destroy them at the + * time of receiving the event since the main program + * may try to access them and may need to destroy user + * data that has been attached to the window + */ + if (received_destroy_notify) + { + if (gdk_show_events) + g_print ("destroying window:\twindow: %ld\n", + ((GdkWindowPrivate*) window_to_destroy)->xwindow - base_id); + + gdk_window_real_destroy (window_to_destroy); + received_destroy_notify = FALSE; + window_to_destroy = NULL; + } + + /* Initially we haven't received an event and want to + * return FALSE. If "event" is non-NULL, then initialize + * it to the nothing event. + */ + if (event) + { + event->any.type = GDK_NOTHING; + event->any.window = NULL; + event->any.send_event = FALSE; + } + + if (pred) + { + temp_list = putback_events; + while (temp_list) + { + temp_event = temp_list->data; + + if ((* pred) (temp_event, data)) + { + if (event) + *event = *temp_event; + putback_events = g_list_remove_link (putback_events, temp_list); + g_list_free (temp_list); + return TRUE; + } + + temp_list = temp_list->next; + } + + event_pred.func = pred; + event_pred.data = data; + + if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) &event_pred)) + if (event) + return gdk_event_translate (event, &xevent); + } + else + { + if (putback_events) + { + temp_event = putback_events->data; + *event = *temp_event; + + temp_list = putback_events; + putback_events = putback_events->next; + if (putback_events) + putback_events->prev = NULL; + + temp_list->next = NULL; + temp_list->prev = NULL; + g_list_free (temp_list); + g_free (temp_event); + + return TRUE; + } + + /* Wait for an event to occur or the timeout to elapse. + * If an event occurs "gdk_event_wait" will return TRUE. + * If the timeout elapses "gdk_event_wait" will return + * FALSE. + */ + if (gdk_event_wait ()) + { + /* If we get here we can rest assurred that an event + * has occurred. Read it. + */ + XNextEvent (gdk_display, &xevent); + + event->any.send_event = xevent.xany.send_event; + + /* If "event" non-NULL. + */ + if (event) + return gdk_event_translate (event, &xevent); + } + } + + return FALSE; +} + +void +gdk_event_put (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_if_fail (event != NULL); + + new_event = g_new (GdkEvent, 1); + *new_event = *event; + + putback_events = g_list_prepend (putback_events, new_event); +} + +/* + *-------------------------------------------------------------- + * gdk_event_copy + * + * Copy a event structure into new storage. + * + * Arguments: + * "event" is the event struct to copy. + * + * Results: + * A new event structure. Free it with gdk_event_free. + * + * Side effects: + * The reference count of the window in the event is increased. + * + *-------------------------------------------------------------- + */ + +static GMemChunk *event_chunk; + +GdkEvent* +gdk_event_copy (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_val_if_fail (event != NULL, NULL); + + if (event_chunk == NULL) + event_chunk = g_mem_chunk_new ("events", + sizeof (GdkEvent), + 4096, + G_ALLOC_AND_FREE); + + new_event = g_chunk_new (GdkEvent, event_chunk); + *new_event = *event; + gdk_window_ref (new_event->any.window); + return new_event; +} + +/* + *-------------------------------------------------------------- + * gdk_event_free + * + * Free a event structure obtained from gdk_event_copy. Do not use + * with other event structures. + * + * Arguments: + * "event" is the event struct to free. + * + * Results: + * + * Side effects: + * The reference count of the window in the event is decreased and + * might be freed, too. + * + *-------------------------------------------------------------- */ + +void +gdk_event_free (GdkEvent *event) +{ + g_assert (event_chunk != NULL); + g_return_if_fail (event != NULL); + + gdk_window_unref (event->any.window); + g_mem_chunk_free (event_chunk, event); +} + +/* + *-------------------------------------------------------------- + * gdk_set_debug_level + * + * Sets the debugging level. + * + * Arguments: + * "level" is the new debugging level. + * + * Results: + * + * Side effects: + * Other function calls to "gdk" use the debugging + * level to determine what kind of debugging information + * to print out. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_debug_level (int level) +{ + gdk_debug_level = level; +} + +/* + *-------------------------------------------------------------- + * gdk_set_show_events + * + * Turns on/off the showing of events. + * + * Arguments: + * "show_events" is a boolean describing whether or + * not to show the events gdk receives. + * + * Results: + * + * Side effects: + * When "show_events" is TRUE, calls to "gdk_event_get" + * will output debugging informatin regarding the event + * received to stdout. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_show_events (int show_events) +{ + gdk_show_events = show_events; +} + +void +gdk_set_use_xshm (gint use_xshm) +{ + gdk_use_xshm = use_xshm; +} + +gint +gdk_get_debug_level () +{ + return gdk_debug_level; +} + +gint +gdk_get_show_events () +{ + return gdk_show_events; +} + +gint +gdk_get_use_xshm () +{ + return gdk_use_xshm; +} + +/* + *-------------------------------------------------------------- + * gdk_time_get + * + * Get the number of milliseconds since the library was + * initialized. + * + * Arguments: + * + * Results: + * The time since the library was initialized is returned. + * This time value is accurate to milliseconds even though + * a more accurate time down to the microsecond could be + * returned. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_time_get () +{ + struct timeval end; + struct timeval elapsed; + guint32 milliseconds; + + X_GETTIMEOFDAY (&end); + + if (start.tv_usec > end.tv_usec) + { + end.tv_usec += 1000000; + end.tv_sec--; + } + elapsed.tv_sec = end.tv_sec - start.tv_sec; + elapsed.tv_usec = end.tv_usec - start.tv_usec; + + milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000); + + return milliseconds; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_get + * + * Returns the current timer. + * + * Arguments: + * + * Results: + * Returns the current timer interval. This interval is + * in units of milliseconds. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_timer_get () +{ + return timer_val; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_set + * + * Sets the timer interval. + * + * Arguments: + * "milliseconds" is the new value for the timer. + * + * Results: + * + * Side effects: + * Calls to "gdk_event_get" will last for a maximum + * of time of "milliseconds". However, a value of 0 + * milliseconds will cause "gdk_event_get" to block + * indefinately until an event is received. + * + *-------------------------------------------------------------- + */ + +void +gdk_timer_set (guint32 milliseconds) +{ + timer_val = milliseconds; + timer.tv_sec = milliseconds / 1000; + timer.tv_usec = (milliseconds % 1000) * 1000; + +} + +void +gdk_timer_enable () +{ + timerp = &timer; +} + +void +gdk_timer_disable () +{ + timerp = NULL; +} + +gint +gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data) +{ + static gint next_tag = 1; + GList *list; + GdkInput *input; + gint tag; + + tag = 0; + list = inputs; + + while (list) + { + input = list->data; + list = list->next; + + if ((input->source == source) && (input->condition == condition)) + { + input->function = function; + input->data = data; + tag = input->tag; + } + } + + if (!tag) + { + input = g_new (GdkInput, 1); + input->tag = next_tag++; + input->source = source; + input->condition = condition; + input->function = function; + input->data = data; + tag = input->tag; + + inputs = g_list_prepend (inputs, input); + } + + return tag; +} + +void +gdk_input_remove (gint tag) +{ + GList *list; + GList *temp_list; + GdkInput *input; + + list = inputs; + while (list) + { + input = list->data; + + if (input->tag == tag) + { + temp_list = list; + + if (list->next) + list->next->prev = list->prev; + if (list->prev) + list->prev->next = list->next; + if (inputs == list) + inputs = list->next; + + temp_list->next = NULL; + temp_list->prev = NULL; + + g_free (temp_list->data); + g_list_free (temp_list); + break; + } + + list = list->next; + } +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_grab + * + * Grabs the pointer to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "event_mask" masks only interesting events + * "confine_to" limits the cursor movement to the specified window + * "cursor" changes the cursor for the duration of the grab + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_pointer_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time) +{ + /* From gdkwindow.c */ + extern int nevent_masks; + extern int event_mask_table[]; + + gint return_val; + GdkWindowPrivate *window_private; + GdkWindowPrivate *confine_to_private; + GdkCursorPrivate *cursor_private; + guint xevent_mask; + Window xwindow; + Window xconfine_to; + Cursor xcursor; + int i; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + confine_to_private = (GdkWindowPrivate*) confine_to; + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = window_private->xwindow; + + if (!confine_to) + xconfine_to = None; + else + xconfine_to = confine_to_private->xwindow; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + + xevent_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + if (((GdkWindowPrivate *)window)->extension_events && + gdk_input_vtable.grab_pointer) + return_val = gdk_input_vtable.grab_pointer (window, + owner_events, + event_mask, + confine_to, + time); + else + return_val = Success;; + + if (return_val == Success) + return_val = XGrabPointer (window_private->xdisplay, + xwindow, + owner_events, + xevent_mask, + GrabModeAsync, GrabModeAsync, + xconfine_to, + xcursor, + time); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_ungrab + * + * Releases any pointer grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_pointer_ungrab (guint32 time) +{ + if (gdk_input_vtable.ungrab_pointer) + gdk_input_vtable.ungrab_pointer (time); + + XUngrabPointer (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_grab + * + * Grabs the keyboard to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_keyboard_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time) +{ + GdkWindowPrivate *window_private; + Window xwindow; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + xwindow = window_private->xwindow; + + return XGrabKeyboard (window_private->xdisplay, + xwindow, + owner_events, + GrabModeAsync, GrabModeAsync, + time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_ungrab + * + * Releases any keyboard grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_keyboard_ungrab (guint32 time) +{ + XUngrabKeyboard (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width + * + * Return the width of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width () +{ + gint return_val; + + return_val = DisplayWidth (gdk_display, gdk_screen); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height () +{ + gint return_val; + + return_val = DisplayHeight (gdk_display, gdk_screen); + + return return_val; +} + +void +gdk_key_repeat_disable () +{ + XAutoRepeatOff (gdk_display); +} + +void +gdk_key_repeat_restore () +{ + if (autorepeat) + XAutoRepeatOn (gdk_display); + else + XAutoRepeatOff (gdk_display); +} + + +/* + *-------------------------------------------------------------- + * gdk_flush + * + * Flushes the Xlib output buffer and then waits + * until all requests have been received and processed + * by the X server. The only real use for this function + * is in dealing with XShm. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void gdk_flush () +{ + XSync (gdk_display, False); +} + + +void +gdk_beep () +{ + XBell(gdk_display, 100); +} + + +/* + *-------------------------------------------------------------- + * gdk_event_wait + * + * Waits until an event occurs or the timer runs out. + * + * Arguments: + * + * Results: + * Returns TRUE if an event is ready to be read and FALSE + * if the timer ran out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static gint +gdk_event_wait () +{ + GList *list; + GdkInput *input; + GdkInputCondition condition; + SELECT_MASK readfds; + SELECT_MASK writefds; + SELECT_MASK exceptfds; + int max_input; + int nfd; + + /* If there are no events pending we will wait for an event. + * The time we wait is dependant on the "timer". If no timer + * has been specified then we'll block until an event arrives. + * If a timer has been specified we'll block until an event + * arrives or the timer expires. (This is all done using the + * "select" system call). + */ + + if (XPending (gdk_display) == 0) + { + FD_ZERO (&readfds); + FD_ZERO (&writefds); + FD_ZERO (&exceptfds); + + FD_SET (connection_number, &readfds); + max_input = connection_number; + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + if (input->condition & GDK_INPUT_READ) + FD_SET (input->source, &readfds); + if (input->condition & GDK_INPUT_WRITE) + FD_SET (input->source, &writefds); + if (input->condition & GDK_INPUT_EXCEPTION) + FD_SET (input->source, &exceptfds); + + max_input = MAX (max_input, input->source); + } + + nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp); + + timerp = NULL; + timer_val = 0; + + if (nfd > 0) + { + if (FD_ISSET (connection_number, &readfds)) + { + if (XPending (gdk_display) == 0) + { + if (nfd == 1) + { + XNoOp (gdk_display); + XFlush (gdk_display); + } + return FALSE; + } + else + return TRUE; + } + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + condition = 0; + if (FD_ISSET (input->source, &readfds)) + condition |= GDK_INPUT_READ; + if (FD_ISSET (input->source, &writefds)) + condition |= GDK_INPUT_WRITE; + if (FD_ISSET (input->source, &exceptfds)) + condition |= GDK_INPUT_EXCEPTION; + + if (condition && input->function) + (* input->function) (input->data, input->source, condition); + } + } + } + else + return TRUE; + + return FALSE; +} + +static gint +gdk_event_translate (GdkEvent *event, + XEvent *xevent) +{ + + GdkWindow *window; + GdkWindowPrivate *window_private; + XComposeStatus compose; + int charcount; + char buf[16]; + gint return_val; + + /* Are static variables used for this purpose thread-safe? */ + static GdkPoint dnd_drag_start = {0,0}, + dnd_drag_oldpos = {0,0}; + static GdkRectangle dnd_drag_dropzone = {0,0,0,0}; + static gint dnd_drag_perhaps = 0; + static GdkWindowPrivate *real_sw = NULL; + static Window dnd_drag_curwin = None, dnd_drag_target = None; + + return_val = FALSE; + + /* Find the GdkWindow that this event occurred in. + * All events occur in some GdkWindow (otherwise, why + * would we be receiving them). It really is an error + * to receive an event for which we cannot find the + * corresponding GdkWindow. We handle events with window=None + * specially - they are generated by XFree86's XInput under + * some circumstances. + */ + + if ((xevent->xany.window == None) && + gdk_input_vtable.window_none_event) + { + return_val = gdk_input_vtable.window_none_event (event,xevent); + + if (return_val >= 0) /* was handled */ + return return_val; + else + return_val = FALSE; + } + + window = gdk_window_lookup (xevent->xany.window); + window_private = (GdkWindowPrivate *) window; + + /* We do a "manual" conversion of the XEvent to a + * GdkEvent. The structures are mostly the same so + * the conversion is fairly straightforward. We also + * optionally print debugging info regarding events + * received. + */ + /* Addendum: + * During drag & drop you get events where the pointer is + * in other windows. Need to just do finer-grained checking + */ + switch (xevent->type) + { + case KeyPress: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key press:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_PRESS; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case KeyRelease: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key release:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_RELEASE; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case ButtonPress: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button press[%d]:\t\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_PRESS; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + gdk_synthesize_click (event, 3); + + button_click_time[1] = 0; + button_click_time[0] = 0; + button_window[1] = NULL; + button_window[0] = 0; + button_number[1] = -1; + button_number[0] = -1; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + gdk_synthesize_click (event, 2); + + button_click_time[1] = button_click_time[0]; + button_click_time[0] = event->button.time; + button_window[1] = button_window[0]; + button_window[0] = event->button.window; + button_number[1] = button_number[0]; + button_number[0] = event->button.button; + } + else + { + button_click_time[1] = 0; + button_click_time[0] = event->button.time; + button_window[1] = NULL; + button_window[0] = event->button.window; + button_number[1] = -1; + button_number[0] = event->button.button; + } + if(window_private + && window_private->dnd_drag_enabled + && !dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + dnd_drag_perhaps = 1; + dnd_drag_start.x = xevent->xbutton.x_root; + dnd_drag_start.y = xevent->xbutton.y_root; + real_sw = window_private; + + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0; + + { + /* Set motion mask for first DnD'd window, since it + will be the one that is actually dragged */ + XWindowAttributes dnd_winattr; + XSetWindowAttributes dnd_setwinattr; + Status rv; + + /* We need to get motion events while the button is down, so + we can know whether to really start dragging or not... */ + XGetWindowAttributes(gdk_display, (Window)window_private->xwindow, + &dnd_winattr); + + window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask; + dnd_setwinattr.event_mask = + window_private->dnd_drag_eventmask = ButtonMotionMask; + XChangeWindowAttributes(gdk_display, window_private->xwindow, + CWEventMask, &dnd_setwinattr); + } + } + return_val = window_private?(!window_private->destroyed):FALSE; + break; + + case ButtonRelease: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button release[%d]:\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_RELEASE; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if(dnd_drag_perhaps) + { + if(gdk_dnd.drag_really) + { + GdkPoint foo = {xevent->xbutton.x_root, + xevent->xbutton.y_root}; + XUngrabPointer(gdk_display, CurrentTime); + + if(dnd_drag_target != None) + gdk_dnd_drag_end(dnd_drag_target, foo); + gdk_dnd.drag_really = 0; + + if(gdk_dnd.drag_numwindows) + { + XSetWindowAttributes attrs; + /* Reset event mask to pre-drag value, assuming event_mask + doesn't change during drag */ + attrs.event_mask = real_sw->dnd_drag_savedeventmask; + XChangeWindowAttributes(gdk_display, real_sw->xwindow, + CWEventMask, &attrs); + } + + gdk_dnd.drag_numwindows = 0; + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + + real_sw = NULL; + } + + dnd_drag_perhaps = 0; + dnd_drag_start.x = dnd_drag_start.y = 0; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_curwin = None; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case MotionNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s d:%d r%d\n", + xevent->xmotion.window - base_id, + xevent->xmotion.x, xevent->xmotion.y, + (xevent->xmotion.is_hint) ? "true" : "false", + dnd_drag_perhaps, gdk_dnd.drag_really); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = window; + event->motion.time = xevent->xmotion.time; + event->motion.x = xevent->xmotion.x; + event->motion.y = xevent->xmotion.y; + event->motion.pressure = 0.5; + event->motion.xtilt = 0; + event->motion.ytilt = 0; + event->motion.state = (GdkModifierType) xevent->xmotion.state; + event->motion.is_hint = xevent->xmotion.is_hint; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + +#define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \ + && cy >= dnd_drag_dropzone.y \ + && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \ + && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height)) + + if(dnd_drag_perhaps && gdk_dnd.drag_really) + { + /* First, we have to find what window the motion was in... */ + /* XXX there has to be a better way to do this, perhaps with + XTranslateCoordinates or XQueryTree - I don't know how, + and this sort of works */ + Window curwin, childwin = gdk_root_window, rootwinret; + int x, y; + unsigned int mask; + while(childwin != None) + { + curwin = childwin; + XQueryPointer(gdk_display, curwin, &rootwinret, &childwin, + &x, &y, &x, &y, &mask); + } + if(curwin != dnd_drag_curwin) + { + /* We have left one window and entered another + (do leave & enter bits) */ + if(dnd_drag_curwin != real_sw->xwindow && dnd_drag_curwin != None) + gdk_dnd_drag_leave(dnd_drag_curwin); + dnd_drag_curwin = curwin; + gdk_dnd_drag_enter(dnd_drag_curwin); + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_target = None; + XChangeActivePointerGrab(gdk_display, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragdefault, + CurrentTime); + } + else if(dnd_drag_dropzone.width > 0 + && dnd_drag_dropzone.height > 0) + { + /* Handle all that dropzone stuff - thanks John ;-) */ + if(dnd_drag_target != None + && IS_IN_ZONE(dnd_drag_oldpos.x, dnd_drag_oldpos.y) + && !IS_IN_ZONE(xevent->xmotion.x_root, + xevent->xmotion.y_root)) + { + /* We were in the drop zone and moved out */ + dnd_drag_target = None; + gdk_dnd_drag_leave(curwin); + } + else + { + /* We were outside drop zone but in the window + - have to send enter events */ + gdk_dnd_drag_enter(curwin); + dnd_drag_curwin = curwin; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_target = None; + } + } else + dnd_drag_curwin = None; + return_val = FALSE; + } + else + return_val = window?(!window_private->destroyed):FALSE; + break; + + case EnterNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("enter notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, + xevent->xcrossing.subwindow - base_id); + + /* Tell XInput stuff about it if appropriate */ + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.enter_event) + gdk_input_vtable.enter_event (&xevent->xcrossing, window); + + event->crossing.type = GDK_ENTER_NOTIFY; + event->crossing.window = window; + + /* If the subwindow field of the XEvent is non-NULL, then + * lookup the corresponding GdkWindow. + */ + if (xevent->xcrossing.subwindow != None) + event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); + else + event->crossing.subwindow = NULL; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + + if(dnd_drag_perhaps + && gdk_dnd.drag_really + && xevent->xcrossing.window == real_sw->xwindow) + { + gdk_dnd.drag_really = 0; + XUngrabPointer(gdk_display, CurrentTime); + } + + return_val = (window ? !window_private->destroyed : FALSE); + break; + + case LeaveNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("leave notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id); + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = window; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + if(dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + gdk_dnd_drag_addwindow((GdkWindow *) real_sw); + gdk_dnd_drag_begin((GdkWindow *) real_sw); + XGrabPointer(gdk_display, real_sw->xwindow, False, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + GrabModeAsync, GrabModeAsync, gdk_root_window, + gdk_dnd.gdk_cursor_dragdefault, CurrentTime); + gdk_dnd.drag_really = 1; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case FocusIn: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus in:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = TRUE; + + return_val = !window_private->destroyed; + break; + + case FocusOut: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus out:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = FALSE; + + return_val = !window_private->destroyed; + break; + + case KeymapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("keymap notify\n"); + + /* Not currently handled */ + break; + + case Expose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d\n", + xevent->xexpose.window - base_id, xevent->xexpose.count, + xevent->xexpose.x, xevent->xexpose.y, + xevent->xexpose.width, xevent->xexpose.height); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xexpose.x; + event->expose.area.y = xevent->xexpose.y; + event->expose.area.width = xevent->xexpose.width; + event->expose.area.height = xevent->xexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case GraphicsExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("graphics expose:\tdrawable: %ld\n", + xevent->xgraphicsexpose.drawable - base_id); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xgraphicsexpose.x; + event->expose.area.y = xevent->xgraphicsexpose.y; + event->expose.area.width = xevent->xgraphicsexpose.width; + event->expose.area.height = xevent->xgraphicsexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case NoExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("no expose:\t\tdrawable: %ld\n", + xevent->xnoexpose.drawable - base_id); + + /* Not currently handled */ + break; + + case VisibilityNotify: + /* Print debugging info. + */ + if (gdk_show_events) + switch (xevent->xvisibility.state) + { + case VisibilityFullyObscured: + g_print ("visibility notify:\twindow: %ld none\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityPartiallyObscured: + g_print ("visibility notify:\twindow: %ld partial\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityUnobscured: + g_print ("visibility notify:\twindow: %ld full\n", + xevent->xvisibility.window - base_id); + break; + } + + /* Not currently handled */ + break; + + case CreateNotify: + /* Not currently handled */ + break; + + case DestroyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("destroy notify:\twindow: %ld\n", + xevent->xdestroywindow.window - base_id); + + event->any.type = GDK_DESTROY; + event->any.window = window; + + /* Remeber which window received the destroy notify + * event so that we can destroy our associated + * data structures the next time the user asks + * us for an event. + */ + received_destroy_notify = TRUE; + window_to_destroy = window; + + return_val = !window_private->destroyed; + break; + + case UnmapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("unmap notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_UNMAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case MapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("map notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_MAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case ReparentNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("reparent notify:\twindow: %ld\n", + xevent->xreparent.window - base_id); + + /* Not currently handled */ + break; + + case ConfigureNotify: + /* Print debugging info. + */ + while ((XPending(gdk_display) > 0) && + XCheckTypedWindowEvent(gdk_display, xevent->xany.window, + ConfigureNotify, xevent)) + /*XSync(gdk_display, 0)*/; + + if (gdk_show_events) + g_print ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d\n", + xevent->xconfigure.window - base_id, + xevent->xconfigure.x, xevent->xconfigure.y, + xevent->xconfigure.width, xevent->xconfigure.height); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&xevent->xconfigure, window); + + if ((window_private->window_type != GDK_WINDOW_CHILD) && + ((window_private->width != xevent->xconfigure.width) || + (window_private->height != xevent->xconfigure.height))) + { + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + event->configure.x = xevent->xconfigure.x; + event->configure.y = xevent->xconfigure.y; + event->configure.width = xevent->xconfigure.width; + event->configure.height = xevent->xconfigure.height; + + window_private->x = xevent->xconfigure.x; + window_private->y = xevent->xconfigure.y; + window_private->width = xevent->xconfigure.width; + window_private->height = xevent->xconfigure.height; + if (window_private->resize_count > 1) + window_private->resize_count -= 1; + + return_val = !window_private->destroyed; + } + break; + + case PropertyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("property notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->property.type = GDK_PROPERTY_NOTIFY; + event->property.window = window; + event->property.atom = xevent->xproperty.atom; + event->property.time = xevent->xproperty.time; + event->property.state = xevent->xproperty.state; + + return_val = !window_private->destroyed; + break; + + case SelectionClear: + if (gdk_show_events) + g_print ("selection clear:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = xevent->xselectionclear.selection; + event->selection.time = xevent->xselectionclear.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionRequest: + if (gdk_show_events) + g_print ("selection request:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = xevent->xselectionrequest.selection; + event->selection.target = xevent->xselectionrequest.target; + event->selection.property = xevent->xselectionrequest.property; + event->selection.requestor = xevent->xselectionrequest.requestor; + event->selection.time = xevent->xselectionrequest.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionNotify: + if (gdk_show_events) + g_print ("selection notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + + event->selection.type = GDK_SELECTION_NOTIFY; + event->selection.window = window; + event->selection.selection = xevent->xselection.selection; + event->selection.target = xevent->xselection.target; + event->selection.property = xevent->xselection.property; + event->selection.time = xevent->xselection.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case ColormapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("colormap notify:\twindow: %ld\n", + xevent->xcolormap.window - base_id); + + /* Not currently handled */ + break; + + case ClientMessage: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("client message:\twindow: %ld\n", + xevent->xclient.window - base_id); + + /* Client messages are the means of the window manager + * communicating with a program. We'll first check to + * see if this is really the window manager talking + * to us. + */ + if (xevent->xclient.message_type == gdk_wm_protocols) + { + if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window) + { + /* The delete window request specifies a window + * to delete. We don't actually destroy the + * window because "it is only a request". (The + * window might contain vital data that the + * program does not want destroyed). Instead + * the event is passed along to the program, + * which should then destroy the window. + */ + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("delete window:\t\twindow: %ld\n", + xevent->xclient.window - base_id); + + event->any.type = GDK_DELETE; + event->any.window = window; + + return_val = !window_private->destroyed; + } + else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus) + { + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter) + { + Atom reptype = 0; + + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + if (gdk_show_events) + g_print ("GDK_DROP_ENTER\n"); + return_val = FALSE; + + /* Now figure out if we really want this drop... + * If someone is trying funky clipboard stuff, ignore + */ + if (window_private + && window_private->dnd_drop_enabled + && event->dropenter.u.flags.sendreply + && (reptype = gdk_dnd_check_types (window, xevent))) + { + XEvent replyev; + + replyev.xclient.type = ClientMessage; + replyev.xclient.window = xevent->xclient.data.l[0]; + replyev.xclient.format = 32; + replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest; + replyev.xclient.data.l[0] = window_private->xwindow; + + event->dragrequest.u.allflags = 0; + event->dragrequest.u.flags.protocol_version = + DND_PROTOCOL_VERSION; + event->dragrequest.u.flags.willaccept = 1; + event->dragrequest.u.flags.delete_data = + (window_private->dnd_drop_destructive_op) ? 1 : 0; + + replyev.xclient.data.l[1] = event->dragrequest.u.allflags; + replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0; + replyev.xclient.data.l[4] = reptype; + + XSendEvent (gdk_display, replyev.xclient.window, + False, NoEventMask, &replyev); + + event->any.type = GDK_DROP_ENTER; + event->dropenter.requestor = replyev.xclient.window; + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave) + { + if (gdk_show_events) + g_print ("GDK_DROP_LEAVE\n"); + if (window_private && window_private->dnd_drop_enabled) + { + event->dropleave.type = GDK_DROP_LEAVE; + event->dropleave.window = window; + event->dropleave.requestor = xevent->xclient.data.l[0]; + event->dropleave.u.allflags = xevent->xclient.data.l[1]; + return_val = TRUE; + } + else + return_val = FALSE; + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest) + { + /* + * make sure to only handle requests from the window the cursor is + * over + */ + if (gdk_show_events) + g_print ("GDK_DRAG_REQUEST\n"); + event->dragrequest.u.allflags = xevent->xclient.data.l[1]; + return_val = FALSE; + + if (window && gdk_dnd.drag_really && + xevent->xclient.data.l[0] == dnd_drag_curwin && + event->dragrequest.u.flags.sendreply == 0) + { + /* Got request - do we need to ask user? */ + if (!event->dragrequest.u.flags.willaccept + && event->dragrequest.u.flags.senddata) + { + /* Yes we do :) */ + event->dragrequest.type = GDK_DRAG_REQUEST; + event->dragrequest.window = window; + event->dragrequest.requestor = xevent->xclient.data.l[0]; + event->dragrequest.isdrop = 0; + event->dragrequest.drop_coords.x = + event->dragrequest.drop_coords.y = 0; + return_val = TRUE; + } + else if (event->dragrequest.u.flags.willaccept) + { + window_private->dnd_drag_destructive_op = + event->dragrequest.u.flags.delete_data; + window_private->dnd_drag_accepted = 1; + window_private->dnd_drag_data_type = + xevent->xclient.data.l[4]; + + dnd_drag_target = dnd_drag_curwin; + XChangeActivePointerGrab (gdk_display, + ButtonMotionMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragok, + CurrentTime); + } + dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535; + dnd_drag_dropzone.y = + (xevent->xclient.data.l[2] >> 16) & 65535; + dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535; + dnd_drag_dropzone.height = + (xevent->xclient.data.l[3] >> 16) & 65535; + } + } + else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable) + { + gint tmp_int; Atom tmp_atom; + gulong tmp_long; + guchar *tmp_charptr; + gpointer tmp_ptr; + + if(gdk_show_events) + g_print("GDK_DROP_DATA_AVAIL\n"); + event->dropdataavailable.u.allflags = xevent->xclient.data.l[1]; + if(window + /* No preview of data ATM */ + && event->dropdataavailable.u.flags.isdrop) + { + event->dropdataavailable.type = GDK_DROP_DATA_AVAIL; + event->dropdataavailable.window = window; + event->dropdataavailable.requestor = xevent->xclient.data.l[0]; + event->dropdataavailable.data_type = + gdk_atom_name(xevent->xclient.data.l[2]); + if(XGetWindowProperty (gdk_display, + event->dropdataavailable.requestor, + xevent->xclient.data.l[2], + 0, LONG_MAX - 1, + False, XA_PRIMARY, &tmp_atom, + &tmp_int, + &event->dropdataavailable.data_numbytes, + &tmp_long, + &tmp_charptr) + != Success) + { + g_warning("XGetWindowProperty on %#x may have failed\n", + event->dropdataavailable.requestor); + event->dropdataavailable.data = NULL; + } + else + { + g_print("XGetWindowProperty got us %d bytes\n", + event->dropdataavailable.data_numbytes); + event->dropdataavailable.data = + g_malloc(event->dropdataavailable.data_numbytes); + memcpy(event->dropdataavailable.data, + tmp_charptr, event->dropdataavailable.data_numbytes); + XFree(tmp_charptr); + return_val = TRUE; + } + return_val = TRUE; + } + } else { + /* Send unknown ClientMessage's on to Gtk for it to use */ + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = xevent->xclient.message_type; + event->client.data_format = xevent->xclient.format; + memcpy(&event->client.data, &xevent->xclient.data, + sizeof(event->client.data)); + return_val = TRUE; + } + return_val = return_val && !window_private->destroyed; + break; + + case MappingNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("mapping notify\n"); + + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&xevent->xmapping); + break; + + default: + /* something else - (e.g., a Xinput event) */ + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.other_event) + return_val = gdk_input_vtable.other_event(event, xevent, window); + + if (return_val < 0) /* not an XInput event, convert */ + { + event->other.type = GDK_OTHER_EVENT; + event->other.window = window; + event->other.xevent = &other_xevent[other_xevent_i]; + memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent)); + other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE; + return_val = TRUE; + } + + return_val = return_val && !window_private->destroyed; + break; + } + + return return_val; +} + +static Bool +gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg) +{ + GdkEvent event; + GdkPredicate *pred; + + if (gdk_event_translate (&event, xevent)) + { + pred = (GdkPredicate*) arg; + return (* pred->func) (&event, pred->data); + } + + return FALSE; +} + +static void +gdk_synthesize_click (GdkEvent *event, + gint nclicks) +{ + GdkEvent temp_event; + + g_return_if_fail (event != NULL); + + temp_event = *event; + temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; + + gdk_event_put (&temp_event); +} + +/* + *-------------------------------------------------------------- + * gdk_exit_func + * + * This is the "atexit" function that makes sure the + * library gets a chance to cleanup. + * + * Arguments: + * + * Results: + * + * Side effects: + * The library is un-initialized and the program exits. + * + *-------------------------------------------------------------- + */ + +static void +gdk_exit_func () +{ + if (initialized) + { + gdk_image_exit (); + gdk_input_exit (); + gdk_key_repeat_restore (); + + XCloseDisplay (gdk_display); + initialized = 0; + } +} + +/* + *-------------------------------------------------------------- + * gdk_x_error + * + * The X error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * "error" is the XErrorEvent that we are handling. + * + * Results: + * Either we were expecting some sort of error to occur, + * in which case we set the "gdk_error_code" flag, or this + * error was unexpected, in which case we will print an + * error message and exit. (Since trying to continue will + * most likely simply lead to more errors). + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_error (Display *display, + XErrorEvent *error) +{ + char buf[64]; + + if (gdk_error_warnings) + { + XGetErrorText (display, error->error_code, buf, 63); + g_error ("%s", buf); + } + + gdk_error_code = -1; + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_x_io_error + * + * The X I/O error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * + * Results: + * An X I/O error basically means we lost our connection + * to the X server. There is not much we can do to + * continue, so simply print an error message and exit. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_io_error (Display *display) +{ + g_error ("an x io error occurred"); + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_signal + * + * The signal handler. + * + * Arguments: + * "sig_num" is the number of the signal we received. + * + * Results: + * The signals we catch are all fatal. So we simply build + * up a nice little error message and print it and exit. + * If in the process of doing so another signal is received + * we notice that we are already exiting and simply kill + * our process. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static RETSIGTYPE +gdk_signal (int sig_num) +{ + static int caught_fatal_sig = 0; + char *sig; + + if (caught_fatal_sig) + kill (getpid (), sig_num); + caught_fatal_sig = 1; + + switch (sig_num) + { + case SIGHUP: + sig = "sighup"; + break; + case SIGINT: + sig = "sigint"; + break; + case SIGQUIT: + sig = "sigquit"; + break; + case SIGBUS: + sig = "sigbus"; + break; + case SIGSEGV: + sig = "sigsegv"; + break; + case SIGPIPE: + sig = "sigpipe"; + break; + case SIGTERM: + sig = "sigterm"; + break; + default: + sig = "unknown signal"; + break; + } + + g_print ("\n** ERROR **: %s caught\n", sig); + gdk_exit (1); +} + +static void +gdk_dnd_drag_begin (GdkWindow *initial_window) +{ + GdkEventDragBegin tev; + tev.type = GDK_DRAG_BEGIN; + tev.window = initial_window; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + + gdk_event_put ((GdkEvent *) &tev); +} + +static void +gdk_dnd_drag_enter (Window dest) +{ + XEvent sev; + GdkEventDropEnter tev; + int i; + GdkWindowPrivate *wp; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeEnter; + sev.xclient.window = dest; + + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.u.flags.sendreply = 1; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_data_numtypesavail) + { + sev.xclient.data.l[0] = wp->xwindow; + tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0; + sev.xclient.data.l[1] = tev.u.allflags; + sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0]; + if (wp->dnd_drag_data_numtypesavail > 1) + { + sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1]; + if (wp->dnd_drag_data_numtypesavail > 2) + { + sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2]; + } + else + sev.xclient.data.l[4] = None; + } + else + sev.xclient.data.l[3] = sev.xclient.data.l[4] = None; + XSendEvent (gdk_display, dest, False, NoEventMask, &sev); + } + + } +} + +static void +gdk_dnd_drag_leave (Window dest) +{ + XEvent sev; + GdkEventDropLeave tev; + int i; + GdkWindowPrivate *wp; + + tev.u.allflags = 0; + + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + sev.xclient.type = ClientMessage; + sev.xclient.window = dest; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeLeave; + sev.xclient.data.l[1] = tev.u.allflags; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + sev.xclient.data.l[0] = wp->xwindow; + XSendEvent(gdk_display, dest, False, NoEventMask, &sev); + wp->dnd_drag_accepted = 0; + } +} + +/* + * when a drop occurs, we go through the list of windows being dragged and + * tell them that it has occurred, so that they can set things up and reply + * to 'dest' window + */ +static void +gdk_dnd_drag_end (Window dest, + GdkPoint coords) +{ + GdkWindowPrivate *wp; + GdkEventDragRequest tev; + gchar *tmp_cptr; + int i; + + tev.type = GDK_DRAG_REQUEST; + tev.drop_coords = coords; + tev.requestor = dest; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.isdrop = 1; + + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_accepted) + { + tev.window = (GdkWindow *) wp; + tev.u.flags.delete_data = wp->dnd_drag_destructive_op; + tev.data_type = + gdk_atom_name(wp->dnd_drag_data_type); + + gdk_event_put((GdkEvent *) &tev); + } + } +} + +static GdkAtom +gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent) +{ + GdkWindowPrivate *wp = (GdkWindowPrivate *) window; + int i, j; + GdkEventDropEnter event; + + g_return_val_if_fail(window != NULL, 0); + g_return_val_if_fail(xevent != NULL, 0); + g_return_val_if_fail(xevent->type == ClientMessage, 0); + g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0); + + if(wp->dnd_drop_data_numtypesavail <= 0 || + !wp->dnd_drop_data_typesavail) + return 0; + + for (i = 2; i <= 4; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j]) + return xevent->xclient.data.l[i]; + } + } + + /* Now we get the extended type list if it's available */ + event.u.allflags = xevent->xclient.data.l[1]; + if (event.u.flags.extended_typelist) + { + Atom *exttypes, realtype; + gulong nitems, nbar; + gint realfmt; + + if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0], + gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1, + False, AnyPropertyType, &realtype, &realfmt, + &nitems, &nbar, (unsigned char **) &exttypes) + != Success) + return 0; + + if (realfmt != (sizeof(Atom) * 8)) + { + g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n", + realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]); + return 0; + } + + for (i = 0; i <= nitems; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (exttypes[i] == wp->dnd_drop_data_typesavail[j]) + { + XFree (exttypes); + return exttypes[i]; + } + } + } + XFree (exttypes); + } + return 0; +} + +/* + * used for debugging only + */ +static void +gdk_print_atom (GdkAtom anatom) +{ + gchar *tmpstr = NULL; + tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)"; + g_print("Atom %lu has name %s\n", anatom, tmpstr); + if(tmpstr) + g_free(tmpstr); +} + +/* + * used only by below routine and itself + */ +static Window +getchildren (Display *dpy, + Window win, + Atom WM_STATE) +{ + Window root, parent, *children, inf = 0; + Atom type = None; + unsigned int nchildren, i; + int format; + unsigned long nitems, after; + unsigned char *data; + + if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0) + return 0; + + for (i = 0; !inf && (i < nchildren); i++) + { + XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, + &after, &data); + if (type != 0) + inf = children[i]; + } + + for (i = 0; !inf && (i < nchildren); i++) + inf = getchildren (dpy, children[i], WM_STATE); + + if (children != 0) + XFree ((char *) children); + + return inf; +} + +/* + * find a window with WM_STATE, else return win itself, as per ICCCM + * + * modification of the XmuClientWindow() routine from X11R6.3 + */ +Window +gdk_get_client_window (Display *dpy, + Window win) +{ + Atom WM_STATE; + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + Window inf; + + if (win == 0) + return DefaultRootWindow(dpy); + + if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0) + return win; + + XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &data); + if (type) + return win; + + inf = getchildren (dpy, win, WM_STATE); + + if (inf == 0) + return win; + else + return inf; +} + +static GdkWindow * +gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y) +{ + GdkWindow *retval = w; + GdkWindowPrivate *awin; + GList *children; + gint16 myx = *x, myy = *y; + + g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL); + + myx = *x; + myy = *y; + +descend: + for (children = gdk_window_get_children(retval); + children && children->next; + children = children->next) + { + awin = (GdkWindowPrivate *) children->data; + if ((myx >= awin->x) && (myy >= awin->y) + && (myx < (awin->x + awin->width)) + && (myy < (awin->y + awin->height))) + { + retval = (GdkWindow *) awin; + myx -= awin->x; + myy -= awin->y; + goto descend; + } + } + + *x = myx; + *y = myy; + + return retval; +} + +/* Sends a ClientMessage to all toplevel client windows */ +void +gdk_event_send_clientmessage_toall(GdkEvent *event) +{ + XEvent sev; + Window *ret_children, ret_root, ret_parent, curwin; + unsigned int ret_nchildren; + int i; + + g_return_if_fail(event != NULL); + + /* Set up our event to send, with the exception of its target window */ + sev.xclient.type = ClientMessage; + sev.xclient.display = gdk_display; + sev.xclient.format = event->client.data_format; + sev.xclient.serial = CurrentTime; + memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data)); + sev.xclient.message_type = event->client.message_type; + + /* OK, we're all set, now let's find some windows to send this to */ + if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent, + &ret_children, &ret_nchildren) != True) + return; + + /* foreach true child window of the root window, send an event to it */ + for(i = 0; i < ret_nchildren; i++) { + curwin = gdk_get_client_window(gdk_display, ret_children[i]); + sev.xclient.window = curwin; + XSendEvent(gdk_display, curwin, False, NoEventMask, &sev); + } + + XFree(ret_children); +} diff --git a/gdk/gdk.h b/gdk/gdk.h new file mode 100644 index 000000000..ac341b206 --- /dev/null +++ b/gdk/gdk.h @@ -0,0 +1,614 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_H__ +#define __GDK_H__ + + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Initialization, exit and events + */ +void gdk_init (int *argc, + char ***argv); +void gdk_exit (int error_code); +gchar* gdk_set_locale (void); + +gint gdk_events_pending (void); +gint gdk_event_get (GdkEvent *event, + GdkEventFunc pred, + gpointer data); +void gdk_event_put (GdkEvent *event); + +GdkEvent *gdk_event_copy (GdkEvent *event); +void gdk_event_free (GdkEvent *event); + +void gdk_set_debug_level (gint level); +void gdk_set_show_events (gint show_events); +void gdk_set_use_xshm (gint use_xshm); + +gint gdk_get_debug_level (void); +gint gdk_get_show_events (void); +gint gdk_get_use_xshm (void); + +guint32 gdk_time_get (void); +guint32 gdk_timer_get (void); +void gdk_timer_set (guint32 milliseconds); +void gdk_timer_enable (void); +void gdk_timer_disable (void); + +gint gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data); +void gdk_input_remove (gint tag); + +gint gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time); +void gdk_pointer_ungrab (guint32 time); + +gint gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time); +void gdk_keyboard_ungrab (guint32 time); + +gint gdk_screen_width (void); +gint gdk_screen_height (void); + +void gdk_flush (void); +void gdk_beep (void); + +void gdk_key_repeat_disable (void); +void gdk_key_repeat_restore (void); + + +/* Visuals + */ +gint gdk_visual_get_best_depth (void); +GdkVisualType gdk_visual_get_best_type (void); +GdkVisual* gdk_visual_get_system (void); +GdkVisual* gdk_visual_get_best (void); +GdkVisual* gdk_visual_get_best_with_depth (gint depth); +GdkVisual* gdk_visual_get_best_with_type (GdkVisualType visual_type); +GdkVisual* gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type); + +/* Actually, these are no-ops... */ +GdkVisual* gdk_visual_ref (GdkVisual *visual); +void gdk_visual_unref (GdkVisual *visual); + +void gdk_query_depths (gint **depths, + gint *count); +void gdk_query_visual_types (GdkVisualType **visual_types, + gint *count); +void gdk_query_visuals (GdkVisual **visuals, + gint *count); + + +/* Windows + */ +GdkWindow* gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask); + +GdkWindow * gdk_window_foreign_new (guint32 anid); +void gdk_window_destroy (GdkWindow *window); +GdkWindow* gdk_window_ref (GdkWindow *window); +void gdk_window_unref (GdkWindow *window); + +void gdk_window_show (GdkWindow *window); +void gdk_window_hide (GdkWindow *window); +void gdk_window_move (GdkWindow *window, + gint x, + gint y); +void gdk_window_resize (GdkWindow *window, + gint width, + gint height); +void gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y); +void gdk_window_clear (GdkWindow *window); +void gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_clear_area_e(GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height); +void gdk_window_raise (GdkWindow *window); +void gdk_window_lower (GdkWindow *window); + +void gdk_window_set_user_data (GdkWindow *window, + gpointer user_data); + + +/* + * This allows for making shaped (partially transparent) windows + * - cool feature, needed for Drag and Drag for example. + * The shape_mask can be the mask + * from gdk_pixmap_create_from_xpm. Stefan Wille + */ +void gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y); + +/* + * Drag & Drop + * Algorithm (drop source): + * A window being dragged will be sent a GDK_DRAG_BEGIN message. + * It will then do gdk_dnd_drag_addwindow() for any other windows that are to be + * dragged. + * When we get a DROP_ENTER incoming, we send it on to the window in question. + * That window needs to use gdk_dnd_drop_enter_reply() to indicate the state of + * things (it must call that even if it's not going to accept the drop) + * + * These two turn on/off drag or drop, and if enabling it also + * sets the list of types supported. The list of types passed in + * should be in order of decreasing preference. + */ +void gdk_window_dnd_drag_set (GdkWindow *window, + guint8 drag_enable, + gchar **typelist, + guint numtypes); + +/* + *XXX todo: add a GDK_DROP_ENTER which can look at actual data + */ +void gdk_window_dnd_drop_set (GdkWindow *window, + guint8 drop_enable, + gchar **typelist, + guint numtypes, + guint8 destructive_op); + +/* + * This is used by the GDK_DRAG_BEGIN handler. An example of usage would be a + * file manager where multiple icons were selected and the drag began. + * The icon that the drag actually began on would gdk_dnd_drag_addwindow + * for all the other icons that were being dragged... + */ +void gdk_dnd_drag_addwindow (GdkWindow *window); +void gdk_window_dnd_data_set (GdkWindow *window, + GdkEvent *event, + gpointer data, + gulong data_numbytes); + + +void gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags); +void gdk_window_set_title (GdkWindow *window, + const gchar *title); +void gdk_window_set_background (GdkWindow *window, + GdkColor *color); +void gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative); +void gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor); +void gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap); +void gdk_window_get_user_data (GdkWindow *window, + gpointer *data); +void gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth); +void gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y); +void gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height); +GdkVisual* gdk_window_get_visual (GdkWindow *window); +GdkColormap* gdk_window_get_colormap (GdkWindow *window); +GdkWindowType gdk_window_get_type (GdkWindow *window); +gint gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y); +GdkWindow* gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask); +GdkWindow* gdk_window_get_parent (GdkWindow *window); +GdkWindow* gdk_window_get_toplevel (GdkWindow *window); +GList* gdk_window_get_children (GdkWindow *window); +GdkEventMask gdk_window_get_events (GdkWindow *window); +void gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask); + +/* Cursors + */ +GdkCursor* gdk_cursor_new (GdkCursorType cursor_type); +void gdk_cursor_destroy (GdkCursor *cursor); + + +/* GCs + */ +GdkGC* gdk_gc_new (GdkWindow *window); +GdkGC* gdk_gc_new_with_values (GdkWindow *window, + GdkGCValues *values, + GdkGCValuesMask values_mask); +void gdk_gc_destroy (GdkGC *gc); +void gdk_gc_get_values (GdkGC *gc, + GdkGCValues *values); +void gdk_gc_set_foreground (GdkGC *gc, + GdkColor *color); +void gdk_gc_set_background (GdkGC *gc, + GdkColor *color); +void gdk_gc_set_font (GdkGC *gc, + GdkFont *font); +void gdk_gc_set_function (GdkGC *gc, + GdkFunction function); +void gdk_gc_set_fill (GdkGC *gc, + GdkFill fill); +void gdk_gc_set_tile (GdkGC *gc, + GdkPixmap *tile); +void gdk_gc_set_stipple (GdkGC *gc, + GdkPixmap *stipple); +void gdk_gc_set_ts_origin (GdkGC *gc, + gint x, + gint y); +void gdk_gc_set_clip_origin (GdkGC *gc, + gint x, + gint y); +void gdk_gc_set_clip_mask (GdkGC *gc, + GdkBitmap *mask); +void gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle); +void gdk_gc_set_subwindow (GdkGC *gc, + GdkSubwindowMode mode); +void gdk_gc_set_exposures (GdkGC *gc, + gint exposures); +void gdk_gc_set_line_attributes (GdkGC *gc, + gint line_width, + GdkLineStyle line_style, + GdkCapStyle cap_style, + GdkJoinStyle join_style); + + +/* Pixmaps + */ +GdkPixmap* gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth); +GdkBitmap* gdk_bitmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height); +GdkPixmap* gdk_pixmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg); +GdkPixmap* gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename); +GdkPixmap* gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data); +void gdk_pixmap_destroy (GdkPixmap *pixmap); + + + +/* Images + */ +GdkImage* gdk_image_new_bitmap(GdkVisual *, + gpointer, + gint, + gint); +GdkImage* gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height); +GdkImage* gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height); +void gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel); +guint32 gdk_image_get_pixel (GdkImage *image, + gint x, + gint y); +void gdk_image_destroy (GdkImage *image); + + +/* Color + */ +GdkColormap* gdk_colormap_new (GdkVisual *visual, + gint allocate); +void gdk_colormap_destroy (GdkColormap *colormap); + +GdkColormap* gdk_colormap_ref (GdkColormap *cmap); +void gdk_colormap_unref (GdkColormap *cmap); + +GdkColormap* gdk_colormap_get_system (void); +gint gdk_colormap_get_system_size (void); + +void gdk_colormap_change (GdkColormap *colormap, + gint ncolors); +void gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors); +gint gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels); +void gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes); +gint gdk_color_white (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_black (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_parse (const gchar *spec, + GdkColor *color); +gint gdk_color_alloc (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_change (GdkColormap *colormap, + GdkColor *color); +gint gdk_color_equal (GdkColor *colora, + GdkColor *colorb); + + +/* Fonts + */ +GdkFont* gdk_font_load (const gchar *font_name); +GdkFont* gdk_fontset_load (gchar *fontset_name); +void gdk_font_free (GdkFont *font); +void gdk_fontset_free (GdkFont *font); +GdkFont* gdk_font_ref (GdkFont *font); +gint gdk_font_id (GdkFont *font); +gint gdk_font_equal (GdkFont *fonta, + GdkFont *fontb); +gint gdk_string_width (GdkFont *font, + const gchar *string); +gint gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length); +gint gdk_char_width (GdkFont *font, + gchar character); +gint gdk_string_measure (GdkFont *font, + const gchar *string); +gint gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length); +gint gdk_char_measure (GdkFont *font, + gchar character); + + +/* Drawing + */ +void gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y); +void gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2); +void gdk_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height); +void gdk_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2); +void gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints); +void gdk_draw_string (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *string); +void gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length); +void gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkDrawable *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_bitmap (GdkDrawable *drawable, + GdkGC *gc, + GdkDrawable *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +void gdk_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints); +void gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs); + + +/* Selections + */ +gint gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event); +GdkWindow* gdk_selection_owner_get (GdkAtom selection); +void gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time); +gint gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *prop_type, + gint *prop_format); +void gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time); + +/* Properties + */ +GdkAtom gdk_atom_intern (const gchar *atom_name, + gint only_if_exists); +gchar* gdk_atom_name (GdkAtom atom); +gint gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format, + gint *actual_length, + guchar **data); + +void gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements); +void gdk_property_delete (GdkWindow *window, + GdkAtom property); + + +/* Rectangle utilities + */ +gint gdk_rectangle_intersect (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest); + +/* XInput support + */ + +void gdk_input_init (void); +void gdk_input_exit (void); +GList *gdk_input_list_devices (void); +void gdk_input_set_extension_events (GdkWindow *window, + gint mask, + GdkExtensionMode mode); +void gdk_input_set_source (guint32 deviceid, + GdkInputSource source); +gint gdk_input_set_mode (guint32 deviceid, + GdkInputMode mode); +void gdk_input_set_axes (guint32 deviceid, + GdkAxisUse *axes); +void gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +GdkTimeCoord *gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); + +/* Miscellaneous */ +void gdk_event_send_clientmessage_toall(GdkEvent *event); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_H__ */ diff --git a/gdk/gdkcolor.c b/gdk/gdkcolor.c new file mode 100644 index 000000000..5e66f089b --- /dev/null +++ b/gdk/gdkcolor.c @@ -0,0 +1,718 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gdk.h" +#include "gdkprivate.h" + + +static gint gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available); +static void gdk_colormap_add (GdkColormap *cmap); +static void gdk_colormap_remove (GdkColormap *cmap); +static guint gdk_colormap_hash (Colormap *cmap); +static gint gdk_colormap_cmp (Colormap *a, + Colormap *b); + +static GHashTable *colormap_hash = NULL; + + +GdkColormap* +gdk_colormap_new (GdkVisual *visual, + gint private_cmap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + Visual *xvisual; + XColor default_colors[256]; + int size; + int i; + + g_return_val_if_fail (visual != NULL, NULL); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->visual = visual; + private->next_color = 0; + private->ref_count = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + private->private_val = private_cmap; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, (private_cmap) ? (AllocAll) : (AllocNone)); + + if (private_cmap) + { + for (i = 0; i < 256; i++) + default_colors[i].pixel = i; + + XQueryColors (private->xdisplay, + DefaultColormap (private->xdisplay, gdk_screen), + default_colors, visual->colormap_size); + + for (i = 0; i < visual->colormap_size; i++) + { + colormap->colors[i].pixel = default_colors[i].pixel; + colormap->colors[i].red = default_colors[i].red; + colormap->colors[i].green = default_colors[i].green; + colormap->colors[i].blue = default_colors[i].blue; + } + + gdk_colormap_change (colormap, visual->colormap_size); + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + private->private_val = TRUE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocAll); + + size = 1 << visual->red_prec; + for (i = 0; i < size; i++) + colormap->colors[i].red = i * 65535 / (size - 1); + + size = 1 << visual->green_prec; + for (i = 0; i < size; i++) + colormap->colors[i].green = i * 65535 / (size - 1); + + size = 1 << visual->blue_prec; + for (i = 0; i < size; i++) + colormap->colors[i].blue = i * 65535 / (size - 1); + + gdk_colormap_change (colormap, visual->colormap_size); + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + private->private_val = FALSE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocNone); + break; + } + + gdk_colormap_add (colormap); + + return colormap; +} + +void +gdk_colormap_real_destroy (GdkColormap *colormap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate*) colormap; + + g_return_if_fail (colormap != NULL); + + if (private->ref_count > 0) + return; + + gdk_colormap_remove (colormap); + XFreeColormap (private->xdisplay, private->xcolormap); + g_free (colormap); +} + +void +gdk_colormap_destroy (GdkColormap *colormap) +{ + gdk_colormap_unref (colormap); +} + +GdkColormap* +gdk_colormap_ref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_val_if_fail (cmap != NULL, NULL); + + private->ref_count += 1; + return cmap; +} + +void +gdk_colormap_unref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_if_fail (cmap != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_colormap_real_destroy (cmap); +} + +GdkColormap* +gdk_colormap_get_system (void) +{ + static GdkColormap *colormap = NULL; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + if (!colormap) + { + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = DefaultColormap (gdk_display, gdk_screen); + private->visual = gdk_visual_get_system (); + private->private_val = FALSE; + private->next_color = 0; + private->ref_count = 1; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + } + + return colormap; +} + +gint +gdk_colormap_get_system_size (void) +{ + return DisplayCells (gdk_display, gdk_screen); +} + +void +gdk_colormap_change (GdkColormap *colormap, + gint ncolors) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor palette[256]; + gint shift; + int max_colors; + int size; + int i; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + for (i = 0; i < ncolors; i++) + { + palette[i].pixel = colormap->colors[i].pixel; + palette[i].red = colormap->colors[i].red; + palette[i].green = colormap->colors[i].green; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoRed | DoGreen | DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors); + private->next_color = MAX (private->next_color, ncolors); + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + + shift = visual->red_shift; + max_colors = 1 << visual->red_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].red = colormap->colors[i].red; + palette[i].flags = DoRed; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->green_shift; + max_colors = 1 << visual->green_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].green = colormap->colors[i].green; + palette[i].flags = DoGreen; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->blue_shift; + max_colors = 1 << visual->blue_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + break; + + default: + break; + } +} + +void +gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + gint i; + + for (i = 0; i < ncolors; i++) + { + colormap->colors[i].pixel = colors[i].pixel; + colormap->colors[i].red = colors[i].red; + colormap->colors[i].green = colors[i].green; + colormap->colors[i].blue = colors[i].blue; + } + + gdk_colormap_change (colormap, ncolors); +} + +gint +gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels) +{ + GdkColormapPrivate *private; + gint return_val; + + g_return_val_if_fail (colormap != NULL, 0); + + private = (GdkColormapPrivate*) colormap; + + return_val = XAllocColorCells (private->xdisplay, private->xcolormap, + contiguous, planes, nplanes, pixels, npixels); + + return return_val; +} + +void +gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes) +{ + GdkColormapPrivate *private; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + + XFreeColors (private->xdisplay, private->xcolormap, + pixels, npixels, planes); +} + +gint +gdk_color_white (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = WhitePixel (gdk_display, gdk_screen); + color->red = 65535; + color->green = 65535; + color->blue = 65535; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_black (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = BlackPixel (gdk_display, gdk_screen); + color->red = 0; + color->green = 0; + color->blue = 0; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_parse (const gchar *spec, + GdkColor *color) +{ + Colormap xcolormap; + XColor xcolor; + gint return_val; + + g_return_val_if_fail (spec != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolormap = DefaultColormap (gdk_display, gdk_screen); + + if (XParseColor (gdk_display, xcolormap, spec, &xcolor)) + { + return_val = TRUE; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_alloc (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor xcolor; + gchar available[256]; + gint available_init; + gint return_val; + gint i, index; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.pixel = color->pixel; + xcolor.flags = DoRed | DoGreen | DoBlue; + + return_val = FALSE; + private = (GdkColormapPrivate*) colormap; + + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + if (private->private_val) + { + if (private->next_color > 255) + { + for (i = 0; i < 256; i++) + available[i] = TRUE; + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + *color = colormap->colors[index]; + return_val = TRUE; + } + else + { + return_val = FALSE; + } + } + else + { + xcolor.pixel = 255 - private->next_color; + color->pixel = xcolor.pixel; + private->next_color += 1; + + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + return_val = TRUE; + } + } + else + { + available_init = 1; + + while (1) + { + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + + colormap->colors[color->pixel] = *color; + + return_val = TRUE; + break; + } + else + { + if (available_init) + { + available_init = 0; + for (i = 0; i < 256; i++) + available[i] = TRUE; + } + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + xcolor.red = colormap->colors[index].red; + xcolor.green = colormap->colors[index].green; + xcolor.blue = colormap->colors[index].blue; + } + else + { + return_val = FALSE; + break; + } + } + } + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + xcolor.pixel = (((xcolor.red >> (16 - visual->red_prec)) << visual->red_shift) + + ((xcolor.green >> (16 - visual->green_prec)) << visual->green_shift) + + ((xcolor.blue >> (16 - visual->blue_prec)) << visual->blue_shift)); + color->pixel = xcolor.pixel; + return_val = TRUE; + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + return_val = TRUE; + } + else + return_val = FALSE; + break; + } + + return return_val; +} + +gint +gdk_color_change (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.pixel = color->pixel; + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.flags = DoRed | DoGreen | DoBlue; + + private = (GdkColormapPrivate*) colormap; + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + + return TRUE; +} + +gint +gdk_color_equal (GdkColor *colora, + GdkColor *colorb) +{ + g_return_val_if_fail (colora != NULL, FALSE); + g_return_val_if_fail (colorb != NULL, FALSE); + + return ((colora->red == colorb->red) && + (colora->green == colorb->green) && + (colora->blue == colorb->blue)); +} + +GdkColormap* +gdkx_colormap_get (Colormap xcolormap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + colormap = gdk_colormap_lookup (xcolormap); + if (colormap) + return colormap; + + if (xcolormap == DefaultColormap (gdk_display, gdk_screen)) + return gdk_colormap_get_system (); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = xcolormap; + private->visual = NULL; + private->private_val = TRUE; + private->next_color = 0; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + + return colormap; +} + + +static gint +gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available) +{ + GdkColor *colors; + guint sum, max; + gint rdiff, gdiff, bdiff; + gint i, index; + + g_return_val_if_fail (cmap != NULL, 0); + g_return_val_if_fail (color != NULL, 0); + + colors = cmap->colors; + max = 3 * (65536); + index = -1; + + for (i = 0; i < 256; i++) + { + if ((!available) || (available && available[i])) + { + rdiff = (color->red - colors[i].red); + gdiff = (color->green - colors[i].green); + bdiff = (color->blue - colors[i].blue); + + sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); + + if (sum < max) + { + index = i; + max = sum; + } + } + } + + return index; +} + + +GdkColormap* +gdk_colormap_lookup (Colormap xcolormap) +{ + GdkColormap *cmap; + + if (!colormap_hash) + return NULL; + + cmap = g_hash_table_lookup (colormap_hash, &xcolormap); + return cmap; +} + +static void +gdk_colormap_add (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_insert (colormap_hash, &private->xcolormap, cmap); +} + +static void +gdk_colormap_remove (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_remove (colormap_hash, &private->xcolormap); +} + +static guint +gdk_colormap_hash (Colormap *cmap) +{ + return *cmap; +} + +static gint +gdk_colormap_cmp (Colormap *a, + Colormap *b) +{ + return (*a == *b); +} diff --git a/gdk/gdkcursor.c b/gdk/gdkcursor.c new file mode 100644 index 000000000..22bfd250b --- /dev/null +++ b/gdk/gdkcursor.c @@ -0,0 +1,52 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +GdkCursor* +gdk_cursor_new (GdkCursorType cursor_type) +{ + GdkCursorPrivate *private; + GdkCursor *cursor; + Cursor xcursor; + + xcursor = XCreateFontCursor (gdk_display, cursor_type); + private = g_new (GdkCursorPrivate, 1); + private->xdisplay = gdk_display; + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = cursor_type; + + return cursor; +} + +void +gdk_cursor_destroy (GdkCursor *cursor) +{ + GdkCursorPrivate *private; + + g_return_if_fail (cursor != NULL); + + private = (GdkCursorPrivate *) cursor; + XFreeCursor (private->xdisplay, private->xcursor); + + g_free (private); +} diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c new file mode 100644 index 000000000..47482f72e --- /dev/null +++ b/gdk/gdkdraw.c @@ -0,0 +1,383 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +void +gdk_draw_point (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawPoint (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y); +} + +void +gdk_draw_line (GdkDrawable *drawable, + GdkGC *gc, + gint x1, + gint y1, + gint x2, + gint y2) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawLine (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x1, y1, x2, y2); +} + +void +gdk_draw_rectangle (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + if (filled) + XFillRectangle (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height); + else + XDrawRectangle (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height); +} + +void +gdk_draw_arc (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + gint x, + gint y, + gint width, + gint height, + gint angle1, + gint angle2) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = drawable_private->width; + if (height == -1) + height = drawable_private->height; + + if (filled) + XFillArc (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height, angle1, angle2); + else + XDrawArc (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, width, height, angle1, angle2); +} + +void +gdk_draw_polygon (GdkDrawable *drawable, + GdkGC *gc, + gint filled, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + if (filled) + { + XFillPolygon (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, (XPoint*) points, npoints, Complex, CoordModeOrigin); + } + else + { + XDrawLines (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, (XPoint*) points, npoints, CoordModeOrigin); + + if ((points[0].x != points[npoints-1].x) || + (points[0].y != points[npoints-1].y)) + XDrawLine (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, points[npoints-1].x, points[npoints-1].y, + points[0].x, points[0].y); + } +} + +/* gdk_draw_string + * + * Modified by Li-Da Lho to draw 16 bits and Multibyte strings + * + * Interface changed: add "GdkFont *font" to specify font or fontset explicitely + */ +void +gdk_draw_string (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *string) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (string != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + XFontStruct *xfont = (XFontStruct *) font_private->xfont; + XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid); + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XDrawString (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, string, strlen (string)); + } + else + { + XDrawString16 (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, (XChar2b *) string, + strlen (string) / 2); + } + } + else if (font->type == GDK_FONT_FONTSET) + { + XFontSet fontset = (XFontSet) font_private->xfont; + XmbDrawString (drawable_private->xdisplay, drawable_private->xwindow, + fontset, gc_private->xgc, x, y, string, strlen (string)); + } + else + g_error("undefined font type\n"); +} + +/* gdk_draw_text + * + * Modified by Li-Da Lho to draw 16 bits and Multibyte strings + * + * Interface changed: add "GdkFont *font" to specify font or fontset explicitely + */ +void +gdk_draw_text (GdkDrawable *drawable, + GdkFont *font, + GdkGC *gc, + gint x, + gint y, + const gchar *text, + gint text_length) +{ + GdkWindowPrivate *drawable_private; + GdkFontPrivate *font_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (font != NULL); + g_return_if_fail (gc != NULL); + g_return_if_fail (text != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + XFontStruct *xfont = (XFontStruct *) font_private->xfont; + XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid); + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XDrawString (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, text, text_length); + } + else + { + XDrawString16 (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, x, y, (XChar2b *) text, text_length / 2); + } + } + else if (font->type == GDK_FONT_FONTSET) + { + XFontSet fontset = (XFontSet) font_private->xfont; + XmbDrawString (drawable_private->xdisplay, drawable_private->xwindow, + fontset, gc_private->xgc, x, y, text, text_length); + } + else + g_error("undefined font type\n"); +} + +void +gdk_draw_pixmap (GdkDrawable *drawable, + GdkGC *gc, + GdkPixmap *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkWindowPrivate *src_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (src != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + src_private = (GdkWindowPrivate*) src; + gc_private = (GdkGCPrivate*) gc; + + if (width == -1) + width = src_private->width; + if (height == -1) + height = src_private->height; + + XCopyArea (drawable_private->xdisplay, + src_private->xwindow, + drawable_private->xwindow, + gc_private->xgc, + xsrc, ysrc, + width, height, + xdest, ydest); +} + +void +gdk_draw_image (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkImagePrivate *image_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + image_private = (GdkImagePrivate*) image; + + g_return_if_fail (image_private->image_put != NULL); + + if (width == -1) + width = image->width; + if (height == -1) + height = image->height; + + (* image_private->image_put) (drawable, gc, image, xsrc, ysrc, + xdest, ydest, width, height); +} + +void +gdk_draw_points (GdkDrawable *drawable, + GdkGC *gc, + GdkPoint *points, + gint npoints) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail ((points != NULL) && (npoints > 0)); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawPoints (drawable_private->xdisplay, + drawable_private->xwindow, + gc_private->xgc, + (XPoint *) points, + npoints, + CoordModeOrigin); +} + +void +gdk_draw_segments (GdkDrawable *drawable, + GdkGC *gc, + GdkSegment *segs, + gint nsegs) +{ + GdkWindowPrivate *drawable_private; + GdkGCPrivate *gc_private; + + if (nsegs <= 0) + return; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (segs != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + gc_private = (GdkGCPrivate*) gc; + + XDrawSegments (drawable_private->xdisplay, + drawable_private->xwindow, + gc_private->xgc, + (XSegment *) segs, + nsegs); +} diff --git a/gdk/gdkfont.c b/gdk/gdkfont.c new file mode 100644 index 000000000..e1b1e7254 --- /dev/null +++ b/gdk/gdkfont.c @@ -0,0 +1,379 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + private->xfont = XLoadQueryFont (private->xdisplay, font_name); + private->ref_count = 1; + + if (!private->xfont) + { + g_free (font); + return NULL; + } + else + { + font->type = GDK_FONT_FONT; + font->ascent = ((XFontStruct *) private->xfont)->ascent; + font->descent = ((XFontStruct *) private->xfont)->descent; + } + + gdk_xid_table_insert (&((XFontStruct *) private->xfont)->fid, font); + + return font; +} + +GdkFont* +gdk_fontset_load(gchar *fontset_name) +{ + GdkFont *font; + GdkFontPrivate *private; + XFontSet fontset; + gint missing_charset_count; + gchar **missing_charset_list; + gchar *def_string; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + fontset = XCreateFontSet (gdk_display, fontset_name, + &missing_charset_list, &missing_charset_count, + &def_string); + + if (missing_charset_count) + { + g_print ("Missing charsets in FontSet creation"); + XFreeStringList (missing_charset_list); + } + + private->ref_count = 1; + + if (!fontset) + { + g_free (font); + return NULL; + } + else + { + XFontSetExtents *extent = XExtentsOfFontSet(fontset); + + private->xfont = fontset; + font->type = GDK_FONT_FONTSET; + /* how to define ascent and descent for fontset ??? */ + font->ascent = extent->max_logical_extent.height; + font->descent = font->ascent / 4 ; + } + return font; +} +void +gdk_font_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid); + XFreeFont (private->xdisplay, (XFontStruct *) private->xfont); + g_free (font); + } +} + +void +gdk_fontset_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + XFreeFontSet (private->xdisplay, (XFontSet) private->xfont); + g_free (font); + } +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + return font; +} + +gint +gdk_font_id (GdkFont *font) +{ + GdkFontPrivate *font_private; + + g_return_val_if_fail (font != NULL, 0); + + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + return ((XFontStruct *) font_private->xfont)->fid; + } + else + { + return 0; + } +} + +gint +gdk_font_equal (GdkFont *fonta, + GdkFont *fontb) +{ + GdkFontPrivate *privatea; + GdkFontPrivate *privateb; + + g_return_val_if_fail (fonta != NULL, FALSE); + g_return_val_if_fail (fontb != NULL, FALSE); + + privatea = (GdkFontPrivate*) fonta; + privateb = (GdkFontPrivate*) fontb; + + if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT) + { + return (((XFontStruct *) privatea->xfont)->fid == + ((XFontStruct *) privateb->xfont)->fid); + } + else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET) + { + /* how to compare two fontsets ?? by basename or XFontSet ?? */ + return (((XFontSet) privatea->xfont) == ((XFontSet) privateb->xfont)); + } + else + /* fontset != font */ + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + GdkFontPrivate *font_private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + font_private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) font_private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, string, strlen (string)); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) string, strlen (string) / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) font_private->xfont; + width = XmbTextEscapement (fontset, string, strlen(string)); + break; + default: + width = 0; + } + + return width; +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, text, text_length); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, text, text_length); + break; + default: + width = 0; + } + return width; +} + +/* Problem: What if a character is a 16 bits character ?? */ +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + GdkFontPrivate *private; + XCharStruct *chars; + gint width; + guint ch = character & 0xff; /* get rid of sign-extension */ + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + /* only 8 bits characters are considered here */ + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && + (xfont->max_byte1 == 0) && + (ch >= xfont->min_char_or_byte2) && + (ch <= xfont->max_char_or_byte2)) + { + chars = xfont->per_char; + if (chars) + width = chars[ch - xfont->min_char_or_byte2].width; + else + width = xfont->min_bounds.width; + } + else + { + width = XTextWidth (xfont, &character, 1); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, &character, 1) ; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_string_measure (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_measure (font, string, strlen (string)); +} + +gint +gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + XCharStruct overall; + XFontStruct *xfont; + XFontSet fontset; + XRectangle ink, log; + int direction; + int font_ascent; + int font_descent; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XTextExtents (xfont, text, text_length, + &direction, &font_ascent, &font_descent, + &overall); + } + else + { + XTextExtents16 (xfont, (XChar2b *) text, text_length / 2, + &direction, &font_ascent, &font_descent, + &overall); + } + width = overall.rbearing; + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + XmbTextExtents (fontset, text, text_length, &ink, &log); + width = log.width; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + return gdk_text_measure (font, &character, 1); +} diff --git a/gdk/gdkgc.c b/gdk/gdkgc.c new file mode 100644 index 000000000..3dc11ce6c --- /dev/null +++ b/gdk/gdkgc.c @@ -0,0 +1,636 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +GdkGC* +gdk_gc_new (GdkWindow *window) +{ + return gdk_gc_new_with_values (window, NULL, 0); +} + +GdkGC* +gdk_gc_new_with_values (GdkWindow *window, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkGC *gc; + GdkGCPrivate *private; + Window xwindow; + XGCValues xvalues; + unsigned long xvalues_mask; + + private = g_new (GdkGCPrivate, 1); + gc = (GdkGC*) private; + + xwindow = ((GdkWindowPrivate*) window)->xwindow; + private->xdisplay = ((GdkWindowPrivate*) window)->xdisplay; + + xvalues.function = GXcopy; + xvalues.fill_style = FillSolid; + xvalues.arc_mode = ArcPieSlice; + xvalues.subwindow_mode = ClipByChildren; + xvalues.graphics_exposures = True; + xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures; + + if (values_mask & GDK_GC_FOREGROUND) + { + xvalues.foreground = values->foreground.pixel; + xvalues_mask |= GCForeground; + } + if (values_mask & GDK_GC_BACKGROUND) + { + xvalues.background = values->background.pixel; + xvalues_mask |= GCBackground; + } + if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT)) + { + xvalues.font = ((XFontStruct *) ((GdkFontPrivate*) values->font)->xfont)->fid; + xvalues_mask |= GCFont; + } + if (values_mask & GDK_GC_FUNCTION) + { + switch (values->function) + { + case GDK_COPY: + xvalues.function = GXcopy; + break; + case GDK_INVERT: + xvalues.function = GXinvert; + break; + case GDK_XOR: + xvalues.function = GXxor; + break; + } + xvalues_mask |= GCFunction; + } + if (values_mask & GDK_GC_FILL) + { + switch (values->fill) + { + case GDK_SOLID: + xvalues.fill_style = FillSolid; + break; + case GDK_TILED: + xvalues.fill_style = FillTiled; + break; + case GDK_STIPPLED: + xvalues.fill_style = FillStippled; + break; + case GDK_OPAQUE_STIPPLED: + xvalues.fill_style = FillOpaqueStippled; + break; + } + xvalues_mask |= GCFillStyle; + } + if (values_mask & GDK_GC_TILE) + { + xvalues.tile = ((GdkPixmapPrivate*) values->tile)->xwindow; + xvalues_mask |= GCTile; + } + if (values_mask & GDK_GC_STIPPLE) + { + xvalues.stipple = ((GdkPixmapPrivate*) values->stipple)->xwindow; + xvalues_mask |= GCStipple; + } + if (values_mask & GDK_GC_CLIP_MASK) + { + xvalues.clip_mask = ((GdkPixmapPrivate*) values->clip_mask)->xwindow; + xvalues_mask |= GCClipMask; + } + if (values_mask & GDK_GC_SUBWINDOW) + { + xvalues.subwindow_mode = values->subwindow_mode; + xvalues_mask |= GCSubwindowMode; + } + if (values_mask & GDK_GC_TS_X_ORIGIN) + { + xvalues.ts_x_origin = values->ts_x_origin; + xvalues_mask |= GCTileStipXOrigin; + } + if (values_mask & GDK_GC_TS_Y_ORIGIN) + { + xvalues.ts_y_origin = values->ts_y_origin; + xvalues_mask |= GCTileStipYOrigin; + } + if (values_mask & GDK_GC_CLIP_X_ORIGIN) + { + xvalues.clip_x_origin = values->clip_x_origin; + xvalues_mask |= GCClipXOrigin; + } + if (values_mask & GDK_GC_CLIP_Y_ORIGIN) + { + xvalues.clip_y_origin = values->clip_y_origin; + xvalues_mask |= GCClipYOrigin; + } + if (values_mask & GDK_GC_EXPOSURES) + { + xvalues.graphics_exposures = values->graphics_exposures; + xvalues_mask |= GCGraphicsExposures; + } + if (values_mask & GDK_GC_LINE_WIDTH) + { + xvalues.line_width = values->line_width; + xvalues_mask |= GCLineWidth; + } + if (values_mask & GDK_GC_LINE_STYLE) + { + switch (values->line_style) + { + case GDK_LINE_SOLID: + xvalues.line_style = LineSolid; + break; + case GDK_LINE_ON_OFF_DASH: + xvalues.line_style = LineOnOffDash; + break; + case GDK_LINE_DOUBLE_DASH: + xvalues.line_style = LineDoubleDash; + break; + } + xvalues_mask |= GCLineStyle; + } + if (values_mask & GDK_GC_CAP_STYLE) + { + switch (values->cap_style) + { + case GDK_CAP_NOT_LAST: + xvalues.cap_style = CapNotLast; + break; + case GDK_CAP_BUTT: + xvalues.cap_style = CapButt; + break; + case GDK_CAP_ROUND: + xvalues.cap_style = CapRound; + break; + case GDK_CAP_PROJECTING: + xvalues.cap_style = CapProjecting; + break; + } + xvalues_mask |= GCCapStyle; + } + if (values_mask & GDK_GC_JOIN_STYLE) + { + switch (values->join_style) + { + case GDK_JOIN_MITER: + xvalues.join_style = JoinMiter; + break; + case GDK_JOIN_ROUND: + xvalues.join_style = JoinRound; + break; + case GDK_JOIN_BEVEL: + xvalues.join_style = JoinBevel; + break; + } + xvalues_mask |= GCJoinStyle; + } + + private->xgc = XCreateGC (private->xdisplay, xwindow, xvalues_mask, &xvalues); + + return gc; +} + +void +gdk_gc_destroy (GdkGC *gc) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + XFreeGC (private->xdisplay, private->xgc); + + memset (gc, 0, sizeof (GdkGCPrivate)); + g_free (gc); +} + +void +gdk_gc_get_values (GdkGC *gc, + GdkGCValues *values) +{ + GdkGCPrivate *private; + XGCValues xvalues; + + g_return_if_fail (gc != NULL); + g_return_if_fail (values != NULL); + + private = (GdkGCPrivate*) gc; + + if (XGetGCValues (private->xdisplay, private->xgc, + GCForeground | GCBackground | GCFont | + GCFunction | GCTile | GCStipple | /* GCClipMask | */ + GCSubwindowMode | GCGraphicsExposures | + GCTileStipXOrigin | GCTileStipYOrigin | + GCClipXOrigin | GCClipYOrigin | + GCLineWidth | GCLineStyle | GCCapStyle | + GCFillStyle | GCJoinStyle, &xvalues)) + { + values->foreground.pixel = xvalues.foreground; + values->background.pixel = xvalues.background; + values->font = gdk_font_lookup (xvalues.font); + + switch (xvalues.function) + { + case GXcopy: + values->function = GDK_COPY; + break; + case GXinvert: + values->function = GDK_INVERT; + break; + case GXxor: + values->function = GDK_XOR; + break; + } + + switch (xvalues.fill_style) + { + case FillSolid: + values->fill = GDK_SOLID; + break; + case FillTiled: + values->fill = GDK_TILED; + break; + case FillStippled: + values->fill = GDK_STIPPLED; + break; + case FillOpaqueStippled: + values->fill = GDK_OPAQUE_STIPPLED; + break; + } + + values->tile = gdk_pixmap_lookup (xvalues.tile); + values->stipple = gdk_pixmap_lookup (xvalues.stipple); + values->clip_mask = NULL; + values->subwindow_mode = xvalues.subwindow_mode; + values->ts_x_origin = xvalues.ts_x_origin; + values->ts_y_origin = xvalues.ts_y_origin; + values->clip_x_origin = xvalues.clip_x_origin; + values->clip_y_origin = xvalues.clip_y_origin; + values->graphics_exposures = xvalues.graphics_exposures; + values->line_width = xvalues.line_width; + + switch (xvalues.line_style) + { + case LineSolid: + values->line_style = GDK_LINE_SOLID; + break; + case LineOnOffDash: + values->line_style = GDK_LINE_ON_OFF_DASH; + break; + case LineDoubleDash: + values->line_style = GDK_LINE_DOUBLE_DASH; + break; + } + + switch (xvalues.cap_style) + { + case CapNotLast: + values->cap_style = GDK_CAP_NOT_LAST; + break; + case CapButt: + values->cap_style = GDK_CAP_BUTT; + break; + case CapRound: + values->cap_style = GDK_CAP_ROUND; + break; + case CapProjecting: + values->cap_style = GDK_CAP_PROJECTING; + break; + } + + switch (xvalues.join_style) + { + case JoinMiter: + values->join_style = GDK_JOIN_MITER; + break; + case JoinRound: + values->join_style = GDK_JOIN_ROUND; + break; + case JoinBevel: + values->join_style = GDK_JOIN_BEVEL; + break; + } + } + else + { + memset (values, 0, sizeof (GdkGCValues)); + } +} + +void +gdk_gc_set_foreground (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + XSetForeground (private->xdisplay, private->xgc, color->pixel); +} + +void +gdk_gc_set_background (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (color != NULL); + + private = (GdkGCPrivate*) gc; + XSetBackground (private->xdisplay, private->xgc, color->pixel); +} + +void +gdk_gc_set_font (GdkGC *gc, + GdkFont *font) +{ + GdkGCPrivate *gc_private; + GdkFontPrivate *font_private; + + g_return_if_fail (gc != NULL); + g_return_if_fail (font != NULL); + + gc_private = (GdkGCPrivate*) gc; + font_private = (GdkFontPrivate*) font; + + XSetFont (gc_private->xdisplay, gc_private->xgc, + ((XFontStruct *) font_private->xfont)->fid); +} + +void +gdk_gc_set_function (GdkGC *gc, + GdkFunction function) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + switch (function) + { + case GDK_COPY: + XSetFunction (private->xdisplay, private->xgc, GXcopy); + break; + case GDK_INVERT: + XSetFunction (private->xdisplay, private->xgc, GXinvert); + break; + case GDK_XOR: + XSetFunction (private->xdisplay, private->xgc, GXor); + break; + } +} + +void +gdk_gc_set_fill (GdkGC *gc, + GdkFill fill) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + switch (fill) + { + case GDK_SOLID: + XSetFillStyle (private->xdisplay, private->xgc, FillSolid); + break; + case GDK_TILED: + XSetFillStyle (private->xdisplay, private->xgc, FillTiled); + break; + case GDK_STIPPLED: + XSetFillStyle (private->xdisplay, private->xgc, FillStippled); + break; + case GDK_OPAQUE_STIPPLED: + XSetFillStyle (private->xdisplay, private->xgc, FillOpaqueStippled); + break; + } +} + +void +gdk_gc_set_tile (GdkGC *gc, + GdkPixmap *tile) +{ + GdkGCPrivate *private; + GdkPixmapPrivate *pixmap_private; + Pixmap pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = None; + if (tile) + { + pixmap_private = (GdkPixmapPrivate*) tile; + pixmap = pixmap_private->xwindow; + } + + XSetTile (private->xdisplay, private->xgc, pixmap); +} + +void +gdk_gc_set_stipple (GdkGC *gc, + GdkPixmap *stipple) +{ + GdkGCPrivate *private; + GdkPixmapPrivate *pixmap_private; + Pixmap pixmap; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + pixmap = None; + if (stipple) + { + pixmap_private = (GdkPixmapPrivate*) stipple; + pixmap = pixmap_private->xwindow; + } + + XSetStipple (private->xdisplay, private->xgc, pixmap); +} + +void +gdk_gc_set_ts_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetTSOrigin (private->xdisplay, private->xgc, x, y); +} + +void +gdk_gc_set_clip_origin (GdkGC *gc, + gint x, + gint y) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetClipOrigin (private->xdisplay, private->xgc, x, y); +} + +void +gdk_gc_set_clip_mask (GdkGC *gc, + GdkBitmap *mask) +{ + GdkGCPrivate *private; + Pixmap xmask; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + if (mask) + xmask = ((GdkWindowPrivate*) mask)->xwindow; + else + xmask = None; + + XSetClipMask (private->xdisplay, private->xgc, xmask); +} + + +void +gdk_gc_set_clip_rectangle (GdkGC *gc, + GdkRectangle *rectangle) +{ + GdkGCPrivate *private; + XRectangle xrectangle; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + xrectangle.x = rectangle->x; + xrectangle.y = rectangle->y; + xrectangle.width = rectangle->width; + xrectangle.height = rectangle->height; + + XSetClipRectangles (private->xdisplay, private->xgc, 0, 0, + &xrectangle, 1, Unsorted); +} + +void +gdk_gc_set_subwindow (GdkGC *gc, + GdkSubwindowMode mode) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetSubwindowMode (private->xdisplay, private->xgc, mode); +} + +void +gdk_gc_set_exposures (GdkGC *gc, + gint exposures) +{ + GdkGCPrivate *private; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + XSetGraphicsExposures (private->xdisplay, private->xgc, exposures); +} + +void +gdk_gc_set_line_attributes (GdkGC *gc, + gint line_width, + GdkLineStyle line_style, + GdkCapStyle cap_style, + GdkJoinStyle join_style) +{ + GdkGCPrivate *private; + int xline_style; + int xcap_style; + int xjoin_style; + + g_return_if_fail (gc != NULL); + + private = (GdkGCPrivate*) gc; + + switch (line_style) + { + case GDK_LINE_SOLID: + xline_style = LineSolid; + break; + case GDK_LINE_ON_OFF_DASH: + xline_style = LineOnOffDash; + break; + case GDK_LINE_DOUBLE_DASH: + xline_style = LineDoubleDash; + break; + default: + xline_style = None; + } + + switch (cap_style) + { + case GDK_CAP_NOT_LAST: + xcap_style = CapNotLast; + break; + case GDK_CAP_BUTT: + xcap_style = CapButt; + break; + case GDK_CAP_ROUND: + xcap_style = CapRound; + break; + case GDK_CAP_PROJECTING: + xcap_style = CapProjecting; + break; + default: + xcap_style = None; + } + + switch (join_style) + { + case GDK_JOIN_MITER: + xjoin_style = JoinMiter; + break; + case GDK_JOIN_ROUND: + xjoin_style = JoinRound; + break; + case GDK_JOIN_BEVEL: + xjoin_style = JoinBevel; + break; + default: + xjoin_style = None; + } + + XSetLineAttributes (private->xdisplay, private->xgc, line_width, + xline_style, xcap_style, xjoin_style); +} diff --git a/gdk/gdkglobals.c b/gdk/gdkglobals.c new file mode 100644 index 000000000..58f7bf844 --- /dev/null +++ b/gdk/gdkglobals.c @@ -0,0 +1,47 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdktypes.h" +#include "gdkprivate.h" + +gint gdk_debug_level = 0; +gint gdk_show_events = FALSE; +gint gdk_use_xshm = TRUE; +gchar *gdk_display_name = NULL; +Display *gdk_display = NULL; +gint gdk_screen; +Window gdk_root_window; +Window gdk_leader_window; +GdkWindowPrivate gdk_root_parent; +Atom gdk_wm_delete_window; +Atom gdk_wm_take_focus; +Atom gdk_wm_protocols; +Atom gdk_wm_window_protocols[2]; +Atom gdk_selection_property; +GdkDndGlobals gdk_dnd = {None,None,None, + None,None,None, + None, + None,None, + NULL, + 0, 0, + {0,0}}; +gchar *gdk_progname = NULL; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; diff --git a/gdk/gdkimage.c b/gdk/gdkimage.c new file mode 100644 index 000000000..bcda3119f --- /dev/null +++ b/gdk/gdkimage.c @@ -0,0 +1,492 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" + +#include + +#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) +#define USE_SHM +#endif + +#ifdef USE_SHM +#include +#include +#endif /* USE_SHM */ + +#include +#include + +#ifdef USE_SHM +#include +#endif /* USE_SHM */ + +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static void gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); + + +static GList *image_list = NULL; + + +void +gdk_image_exit () +{ + GdkImage *image; + + while (image_list) + { + image = image_list->data; + gdk_image_destroy (image); + } +} + +GdkImage * +gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h) +/* + * Desc: create a new bitmap image + */ +{ + Visual *xvisual; + GdkImage *image; + GdkImagePrivate *private; + private = g_new(GdkImagePrivate, 1); + image = (GdkImage *) private; + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + image->type = GDK_IMAGE_NORMAL; + image->visual = visual; + image->width = w; + image->height = h; + image->depth = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap, + 0, 0, w ,h, 8, 0); + private->ximage->data = data; + private->ximage->bitmap_bit_order = MSBFirst; + private->ximage->byte_order = MSBFirst; + image->byte_order = MSBFirst; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + return(image); +} /* gdk_image_new_bitmap() */ + +static int +gdk_image_check_xshm(Display *display) +/* + * Desc: query the server for support for the MIT_SHM extension + * Return: 0 = not available + * 1 = shared XImage support available + * 2 = shared Pixmap support available also + */ +{ +#ifdef USE_SHM + int major, minor, ignore; + Bool pixmaps; + + if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) + { + if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True) + { + return (pixmaps==True) ? 2 : 1; + } + } +#endif /* USE_SHM */ + return 0; +} + +void +gdk_image_init () +{ + if (gdk_use_xshm) + { + if (!gdk_image_check_xshm (gdk_display)) + { + g_warning ("MIT-SHM Extension not availible on server"); + gdk_use_xshm = False; + } + } +} + +GdkImage* +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + Visual *xvisual; + + switch (type) + { + case GDK_IMAGE_FASTEST: + image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height); + + if (!image) + image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height); + break; + + default: + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = NULL; + + image->type = type; + image->visual = visual; + image->width = width; + image->height = height; + image->depth = visual->depth; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (type) + { + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + if (gdk_use_xshm) + { + private->image_put = gdk_image_put_shared; + + private->x_shm_info = g_new (XShmSegmentInfo, 1); + x_shm_info = private->x_shm_info; + + private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, NULL, x_shm_info, width, height); + if (private->ximage == NULL) + { + g_warning ("XShmCreateImage failed"); + + g_free (image); + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->shmid = shmget (IPC_PRIVATE, + private->ximage->bytes_per_line * private->ximage->height, + IPC_CREAT | 0777); + + if (x_shm_info->shmid == -1) + { + g_warning ("shmget failed!"); + + XDestroyImage (private->ximage); + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->readOnly = False; + x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0); + private->ximage->data = x_shm_info->shmaddr; + + if (x_shm_info->shmaddr == (char*) -1) + { + g_warning ("shmat failed!"); + + XDestroyImage (private->ximage); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + return NULL; + } + +#ifdef IPC_RMID_DEFERRED_RELEASE + if (x_shm_info->shmaddr != (char*) -1) + shmctl (x_shm_info->shmid, IPC_RMID, 0); +#endif + + gdk_error_code = 0; + gdk_error_warnings = 0; + + XShmAttach (private->xdisplay, x_shm_info); + XSync (private->xdisplay, False); + + gdk_error_warnings = 1; + if (gdk_error_code == -1) + { + g_warning ("XShmAttach failed!"); + + XDestroyImage (private->ximage); + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + return NULL; + } + + if (image) + image_list = g_list_prepend (image_list, image); + } + else + { + g_free (image); + return NULL; + } + break; +#else /* USE_SHM */ + g_free (image); + return NULL; +#endif /* USE_SHM */ + case GDK_IMAGE_NORMAL: + private->image_put = gdk_image_put_normal; + + private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, 0, 0, width, height, 32, 0); + + private->ximage->data = g_new (char, private->ximage->bytes_per_line * + private->ximage->height); + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + if (image) + { + image->byte_order = private->ximage->byte_order; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + + switch (private->ximage->bits_per_pixel) + { + case 8: + image->bpp = 1; + break; + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + } + } + } + + return image; +} + +GdkImage* +gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; + GdkWindowPrivate *win_private; + + g_return_val_if_fail (window != NULL, NULL); + + win_private = (GdkWindowPrivate *) window; + + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + private->ximage = XGetImage (private->xdisplay, + win_private->xwindow, + x, y, width, height, + AllPlanes, ZPixmap); + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_window_get_visual (window); + image->width = width; + image->height = height; + image->depth = private->ximage->depth; + + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + + return image; +} + +guint32 +gdk_image_get_pixel (GdkImage *image, + gint x, + gint y) +{ + guint32 pixel; + GdkImagePrivate *private; + + g_return_val_if_fail (image != NULL, 0); + + private = (GdkImagePrivate *) image; + + pixel = XGetPixel (private->ximage, x, y); + + return pixel; +} + +void +gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate *) image; + + pixel = XPutPixel (private->ximage, x, y, pixel); +} + +void +gdk_image_destroy (GdkImage *image) +{ + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate*) image; + switch (image->type) + { + case GDK_IMAGE_NORMAL: + XDestroyImage (private->ximage); + break; + + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + XShmDetach (private->xdisplay, private->x_shm_info); + XDestroyImage (private->ximage); + + x_shm_info = private->x_shm_info; + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + + image_list = g_list_remove (image_list, image); +#else /* USE_SHM */ + g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + g_free (image); +} + +static void +gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_NORMAL); + + XPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height); +} + +static void +gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ +#ifdef USE_SHM + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_SHARED); + + XShmPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height, False); +#else /* USE_SHM */ + g_error ("trying to draw shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ +} diff --git a/gdk/gdkinput.c b/gdk/gdkinput.c new file mode 100644 index 000000000..ad4b1fcc9 --- /dev/null +++ b/gdk/gdkinput.c @@ -0,0 +1,324 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "../config.h" +#include "gdk.h" +#include "gdkx.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +/* Forward declarations */ + +static gint gdk_input_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static GdkInputWindow *gdk_input_window_find (GdkWindow *window); +static GdkDevicePrivate *gdk_input_find_device (guint32 id); + + +/* Incorporate the specific routines depending on compilation options */ + +static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y }; + +static GdkDeviceInfo gdk_input_core_info = +{ + GDK_CORE_POINTER, + "Core Pointer", + GDK_SOURCE_MOUSE, + GDK_MODE_SCREEN, + TRUE, + 2, + gdk_input_core_axes +}; + +/* Global variables */ + +GdkInputVTable gdk_input_vtable; +/* information about network port and host for gxid daemon */ +gchar *gdk_input_gxid_host; +gint gdk_input_gxid_port; +gint gdk_input_ignore_core; + +/* Local variables */ + +static GList *gdk_input_devices; +static GList *gdk_input_windows; + +#include "gdkinputnone.h" +#include "gdkinputcommon.h" +#include "gdkinputxfree.h" +#include "gdkinputgxi.h" + +GList * +gdk_input_list_devices () +{ + return gdk_input_devices; +} + +void +gdk_input_set_source (guint32 deviceid, GdkInputSource source) +{ + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + gdkdev->info.source = source; +} + +gint +gdk_input_set_mode (guint32 deviceid, GdkInputMode mode) +{ + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + if (gdk_input_vtable.set_mode) + return gdk_input_vtable.set_mode(deviceid,mode); + else + return FALSE; +} + +void +gdk_input_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_axes) + gdk_input_vtable.set_axes (deviceid, axes); +} + +GdkTimeCoord * +gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + XTimeCoord *xcoords; + GdkTimeCoord *coords; + int i; + + if (deviceid == GDK_CORE_POINTER) + { + xcoords = XGetMotionEvents (gdk_display, + ((GdkWindowPrivate *)window)->xwindow, + start, stop, nevents_return); + if (xcoords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + for (i=0; i<*nevents_return; i++) + { + coords[i].time = xcoords[i].time; + coords[i].x = xcoords[i].x; + coords[i].y = xcoords[i].y; + coords[i].pressure = 0.5; + coords[i].xtilt = 0.0; + coords[i].ytilt = 0.0; + } + + XFree(xcoords); + + return coords; + } + else + return NULL; + } + else + { + if (gdk_input_vtable.motion_events) + { + return gdk_input_vtable.motion_events(window, + deviceid, start, stop, + nevents_return); + } + else + { + *nevents_return = 0; + return NULL; + } + } +} + +static gint +gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.enable_window) + return gdk_input_vtable.enable_window (window, gdkdev); + else + return TRUE; +} + +static gint +gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.disable_window) + return gdk_input_vtable.disable_window(window,gdkdev); + else + return TRUE; +} + + +static GdkInputWindow * +gdk_input_window_find(GdkWindow *window) +{ + GList *tmp_list; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + if (((GdkInputWindow *)(tmp_list->data))->window == window) + return (GdkInputWindow *)(tmp_list->data); + + return NULL; /* Not found */ +} + +/* FIXME: this routine currently needs to be called between creation + and the corresponding configure event (because it doesn't get the + root_relative_geometry). This should work with + gtk_window_set_extension_events, but will likely fail in other + cases */ + +void +gdk_input_set_extension_events (GdkWindow *window, gint mask, + GdkExtensionMode mode) +{ + GList *tmp_list; + GdkInputWindow *iw; + + g_return_if_fail (window != NULL); + + if (mode == GDK_EXTENSION_EVENTS_NONE) + mask = 0; + + if (mask != 0) + { + iw = g_new(GdkInputWindow,1); + + iw->window = window; + iw->mode = mode; + + iw->obscuring = NULL; + iw->num_obscuring = 0; + iw->grabbed = FALSE; + + gdk_input_windows = g_list_append(gdk_input_windows,iw); + ((GdkWindowPrivate *)window)->extension_events = mask; + + /* Add enter window events to the event mask */ + /* FIXME, this is not needed for XINPUT_NONE */ + gdk_window_set_events (window, + gdk_window_get_events (window) | + GDK_ENTER_NOTIFY_MASK); + } + else + { + iw = gdk_input_window_find (window); + if (iw) + { + gdk_input_windows = g_list_remove(gdk_input_windows,iw); + g_free(iw); + } + + ((GdkWindowPrivate *)window)->extension_events = 0; + } + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED + && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL)) + gdk_input_enable_window(window,gdkdev); + else + gdk_input_disable_window(window,gdkdev); + } + } +} + +void +gdk_input_window_destroy (GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_windows = g_list_remove(gdk_input_windows,input_window); + g_free(input_window); +} + +void +gdk_input_exit (void) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + gdk_input_set_mode(gdkdev->info.deviceid,GDK_MODE_DISABLED); + + g_free(gdkdev->info.name); +#ifndef XINPUT_NONE + g_free(gdkdev->axes); +#endif + g_free(gdkdev->info.axes); + g_free(gdkdev); + } + } + + g_list_free(gdk_input_devices); + + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + g_free(tmp_list->data); + } + g_list_free(gdk_input_windows); +} + +static GdkDevicePrivate * +gdk_input_find_device(guint32 id) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid == id) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/gdkinput.h b/gdk/gdkinput.h new file mode 100644 index 000000000..21aee6000 --- /dev/null +++ b/gdk/gdkinput.h @@ -0,0 +1,143 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __GDK_INPUT_H__ +#define __GDK_INPUT_H__ + +#ifndef XINPUT_NONE +#include +#endif + +typedef struct _GdkAxisInfo GdkAxisInfo; +typedef struct _GdkInputVTable GdkInputVTable; +typedef struct _GdkDevicePrivate GdkDevicePrivate; +typedef struct _GdkInputWindow GdkInputWindow; + +struct _GdkInputVTable { + gint (*set_mode) (guint32 deviceid, GdkInputMode mode); + void (*set_axes) (guint32 deviceid, GdkAxisUse *axes); + GdkTimeCoord* (*motion_events) (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); + void (*get_pointer) (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + gint (*grab_pointer) (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); + void (*ungrab_pointer) (guint32 time); + + void (*configure_event) (XConfigureEvent *xevent, GdkWindow *window); + void (*enter_event) (XCrossingEvent *xevent, GdkWindow *window); + gint (*other_event) (GdkEvent *event, XEvent *xevent, GdkWindow *window); + /* Handle an unidentified event. Returns TRUE if handled, FALSE + otherwise */ + gint (*window_none_event) (GdkEvent *event, XEvent *xevent); + gint (*enable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev); + gint (*disable_window) (GdkWindow *window, GdkDevicePrivate *gdkdev); +}; + +/* information about a device axis */ +struct _GdkAxisInfo +{ + /* reported x resolution */ + gint xresolution; + + /* reported x minimum/maximum values */ + gint xmin_value, xmax_value; + + /* calibrated resolution (for aspect ration) - only relative values + between axes used */ + gint resolution; + + /* calibrated minimum/maximum values */ + gint min_value, max_value; +}; + +#define GDK_INPUT_NUM_EVENTC 6 + +struct _GdkDevicePrivate { + GdkDeviceInfo info; + +#ifndef XINPUT_NONE + /* information about the axes */ + GdkAxisInfo *axes; + + /* reverse lookup on axis use type */ + gint axis_for_use[GDK_AXIS_LAST]; + + /* Information about XInput device */ + XDevice *xdevice; + + int buttonpress_type, buttonrelease_type, motionnotify_type, + proximityin_type, proximityout_type, changenotify_type; + + /* true if we need to select a different set of events, but + can't because this is the core pointer */ + gint needs_update; + + /* Mask of buttons (used for button grabs) */ + gint button_state; + + /* true if we've claimed the device as active. (used only for XINPUT_GXI) */ + gint claimed; +#endif /* !XINPUT_NONE */ +}; + +struct _GdkInputWindow +{ + /* gdk window */ + GdkWindow *window; + + /* Extension mode (GDK_EXTENSION_EVENTS_ALL/CURSOR) */ + GdkExtensionMode mode; + + /* position relative to root window */ + gint16 root_x; + gint16 root_y; + + /* rectangles relative to window of windows obscuring this one */ + GdkRectangle *obscuring; + gint num_obscuring; + + /* Is there a pointer grab for this window ? */ + gint grabbed; +}; + +/* Global data */ + +extern GdkInputVTable gdk_input_vtable; +/* information about network port and host for gxid daemon */ +extern gchar *gdk_input_gxid_host; +extern gint gdk_input_gxid_port; +extern gint gdk_input_ignore_core; + +/* Function declarations */ + +void gdk_input_window_destroy (GdkWindow *window); + +#endif __GDK_INPUT_H__ diff --git a/gdk/gdkinputcommon.h b/gdk/gdkinputcommon.h new file mode 100644 index 000000000..5e457e0aa --- /dev/null +++ b/gdk/gdkinputcommon.h @@ -0,0 +1,687 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if defined(XINPUT_GXI) || defined(XINPUT_XFREE) + +/* Forward declarations */ +static void gdk_input_get_root_relative_geometry (Display *dpy, Window w, + int *x_ret, int *y_ret, + int *width_ret, + int *height_ret); +static GdkDevicePrivate *gdk_input_device_new(XDeviceInfo *device, + gint include_core); +static void gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes); +static void gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static void gdk_input_translate_coordinates(GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, + gdouble *pressure, + gdouble *xtilt, gdouble *ytilt); +static guint gdk_input_translate_state(guint state, guint device_state); +static gint gdk_input_common_init(gint include_core); +static gint gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev); +static void gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes); +static GdkTimeCoord * gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +/* Global variables */ + +static gint gdk_input_root_width; +static gint gdk_input_root_height; + +static void +gdk_input_get_root_relative_geometry(Display *dpy, Window w, int *x_ret, int *y_ret, + int *width_ret, int *height_ret) +{ + Window root,parent; + Window *children; + int nchildren; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&x,&y,&width,&height,&border_widthc, + &depthc); + x += border_widthc; + y += border_widthc; + + while (root != parent) + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&xc,&yc,&widthc,&heightc, + &border_widthc,&depthc); + x += xc + border_widthc; + y += yc + border_widthc; + } + + if (x_ret) + *x_ret = x; + if (y_ret) + *y_ret = y; + if (width_ret) + *width_ret = width; + if (height_ret) + *height_ret = height; +} + +static GdkDevicePrivate * +gdk_input_device_new(XDeviceInfo *device, gint include_core) +{ + GdkDevicePrivate *gdkdev; + gchar *tmp_name, *p; + XAnyClassPtr class; + gint i,j; + + gdkdev = g_new(GdkDevicePrivate,1); + + gdkdev->info.deviceid = device->id; + if (device->name[0]) { + gdkdev->info.name = g_new(char, strlen(device->name)+1); + strcpy(gdkdev->info.name,device->name); + } else { + /* XFree86 3.2 gives an empty name to the default core devices, + (fixed in 3.2A) */ + gdkdev->info.name = g_strdup("pointer"); + strcpy(gdkdev->info.name,"pointer"); + gdkdev->info.source = GDK_SOURCE_MOUSE; + } + + gdkdev->info.mode = GDK_MODE_DISABLED; + + /* Try to figure out what kind of device this is by its name - + could invite a very, very, long list... Lowercase name + for comparison purposes */ + + tmp_name = g_strdup(gdkdev->info.name); + for (p = tmp_name; *p; p++) + { + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; + } + + if (!strcmp (tmp_name, "pointer")) + gdkdev->info.source = GDK_SOURCE_MOUSE; + else if (!strcmp (tmp_name, "wacom") || + !strcmp (tmp_name, "pen")) + gdkdev->info.source = GDK_SOURCE_PEN; + else if (!strcmp (tmp_name, "eraser")) + gdkdev->info.source = GDK_SOURCE_ERASER; + else if (!strcmp (tmp_name, "cursor")) + gdkdev->info.source = GDK_SOURCE_CURSOR; + else + gdkdev->info.source = GDK_SOURCE_PEN; + + g_free(tmp_name); + + gdkdev->xdevice = NULL; + + /* step through the classes */ + + gdkdev->info.num_axes = 0; + gdkdev->axes = 0; + gdkdev->info.has_cursor = 0; + gdkdev->needs_update = FALSE; + gdkdev->claimed = FALSE; + gdkdev->button_state = 0; + + class = device->inputclassinfo; + for (i=0;inum_classes;i++) + { + switch (class->class) { + case ButtonClass: + { + break; + } + case ValuatorClass: + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + gdkdev->info.num_axes = xvi->num_axes; + gdkdev->axes = g_new(GdkAxisInfo, xvi->num_axes); + gdkdev->info.axes = g_new(GdkAxisUse, xvi->num_axes); + for (j=0;jnum_axes;j++) + { + gdkdev->axes[j].resolution = + gdkdev->axes[j].xresolution = xvi->axes[j].resolution; + gdkdev->axes[j].min_value = + gdkdev->axes[j].xmin_value = xvi->axes[j].min_value; + gdkdev->axes[j].max_value = + gdkdev->axes[j].xmax_value = xvi->axes[j].max_value; + gdkdev->info.axes[j] = GDK_AXIS_IGNORE; + } + j=0; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_X; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_Y; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_PRESSURE; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_XTILT; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_YTILT; + + /* set up reverse lookup on axis use */ + for (j=GDK_AXIS_IGNORE;jaxis_for_use[j] = -1; + + for (j=0;jnum_axes;j++) + if (gdkdev->info.axes[j] != GDK_AXIS_IGNORE) + gdkdev->axis_for_use[gdkdev->info.axes[j]] = j; + + break; + } + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + /* return NULL if no axes */ + if (!gdkdev->info.num_axes || !gdkdev->axes || + (!include_core && device->use == IsXPointer)) + { + g_free(gdkdev->info.name); + if (gdkdev->axes) + g_free(gdkdev->axes); + g_free(gdkdev); + return NULL; + } + + if (device->use != IsXPointer) + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + + return gdkdev; +} + +static void +gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes) +{ + gint i; + XEventClass class; + + i = 0; + /* We have to track press and release events in pairs to keep + track of button state correctly and implement grabbing */ + if (mask & GDK_BUTTON_PRESS_MASK || mask & GDK_BUTTON_RELEASE_MASK) + { + DeviceButtonPress (gdkdev->xdevice, gdkdev->buttonpress_type, + class); + if (class != 0) + classes[i++] = class; + DeviceButtonRelease (gdkdev->xdevice, gdkdev->buttonrelease_type, + class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_MASK) + { + DeviceMotionNotify (gdkdev->xdevice, gdkdev->motionnotify_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_HINT_MASK) + { + /* We'll get into trouble if the macros change, but at least we'll + know about it, and we avoid warnings now */ + DevicePointerMotionHint (gdkdev->xdevice, 0, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_IN_MASK) + { + ProximityIn (gdkdev->xdevice, gdkdev->proximityin_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_OUT_MASK) + { + ProximityOut (gdkdev->xdevice, gdkdev->proximityout_type, class); + if (class != 0) + classes[i++] = class; + } + + *num_classes = i; +} + +static void +gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + XEventClass classes[6]; + gint num_classes; + + if (gdkdev->info.mode == GDK_MODE_DISABLED) + gdk_input_common_find_events(window, gdkdev, 0, classes, &num_classes); + else + gdk_input_common_find_events(window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + classes, &num_classes); + + XSelectExtensionEvent (gdk_display, + GDK_WINDOW_XWINDOW(window), + classes, num_classes); +} + +gint +gdk_input_common_init(gint include_core) +{ + char **extensions; + XDeviceInfo *devices; + int num_devices; + int num_extensions, loop; + Display *display = gdk_display; + + /* Init global vars */ + gdk_window_get_geometry(NULL, /* use root window */ + NULL,NULL, + &gdk_input_root_width,&gdk_input_root_height, + NULL); + + /* Init XInput extension */ + + extensions = XListExtensions(display, &num_extensions); + for (loop = 0; loop < num_extensions && + (strcmp(extensions[loop], "XInputExtension") != 0); loop++); + XFreeExtensionList(extensions); + if (loop == num_extensions) /* XInput extension not found */ + return FALSE; + + gdk_input_devices = 0; + devices = XListInputDevices(display, &num_devices); + + for(loop=0; loopwindow; + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE]; + xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT]; + ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT]; + + device_width = gdkdev->axes[x_axis].max_value - + gdkdev->axes[x_axis].min_value; + device_height = gdkdev->axes[y_axis].max_value - + gdkdev->axes[y_axis].min_value; + + if (gdkdev->info.mode == GDK_MODE_SCREEN) + { + x_scale = gdk_input_root_width / device_width; + y_scale = gdk_input_root_height / device_height; + + x_offset = - input_window->root_x; + y_offset = - input_window->root_y; + } + else /* GDK_MODE_WINDOW */ + { + double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / + (device_width*gdkdev->axes[x_axis].resolution); + + if (device_aspect * win_priv->width >= win_priv->height) + { + /* device taller than window */ + x_scale = win_priv->width / device_width; + y_scale = (x_scale * gdkdev->axes[x_axis].resolution) + / gdkdev->axes[y_axis].resolution; + + x_offset = 0; + y_offset = -(device_height * y_scale - + win_priv->height)/2; + } + else + { + /* window taller than device */ + y_scale = win_priv->height / device_height; + x_scale = (y_scale * gdkdev->axes[y_axis].resolution) + / gdkdev->axes[x_axis].resolution; + + y_offset = 0; + x_offset = - (device_width * x_scale - win_priv->width)/2; + } + } + + if (x) *x = x_offset + x_scale*axis_data[x_axis]; + if (y) *y = y_offset + y_scale*axis_data[y_axis]; + + if (pressure) + { + if (pressure_axis != -1) + *pressure = ((double)axis_data[pressure_axis] + - gdkdev->axes[pressure_axis].min_value) + / (gdkdev->axes[pressure_axis].max_value + - gdkdev->axes[pressure_axis].min_value); + else + *pressure = 0.5; + } + + if (xtilt) + { + if (xtilt_axis != -1) + { + *xtilt = 2. * (double)(axis_data[xtilt_axis] - + (gdkdev->axes[xtilt_axis].min_value + + gdkdev->axes[xtilt_axis].max_value)/2) / + (gdkdev->axes[xtilt_axis].max_value - + gdkdev->axes[xtilt_axis].min_value); + } + else *xtilt = 0; + } + + if (ytilt) + { + if (ytilt_axis != -1) + { + *ytilt = 2. * (double)(axis_data[ytilt_axis] - + (gdkdev->axes[ytilt_axis].min_value + + gdkdev->axes[ytilt_axis].max_value)/2) / + (gdkdev->axes[ytilt_axis].max_value - + gdkdev->axes[ytilt_axis].min_value); + } + else + *ytilt = 0; + } +} + +/* combine the state of the core device and the device state + into one - for now we do this in a simple-minded manner - + we just take the keyboard portion of the core device and + the button portion (all of?) the device state. + Any button remapping should go on here. */ +static guint +gdk_input_translate_state(guint state, guint device_state) +{ + return device_state | (state & 0xFF); +} + +static gint +gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev) +{ + if ((xevent->type == gdkdev->buttonpress_type) || + (xevent->type == gdkdev->buttonrelease_type)) + { + XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent); + + if (xdbe->type == gdkdev->buttonpress_type) + { + event->button.type = GDK_BUTTON_PRESS; + gdkdev->button_state |= 1 << xdbe->button; + } + else + { + event->button.type = GDK_BUTTON_RELEASE; + gdkdev->button_state &= ~(1 << xdbe->button); + } + event->button.window = input_window->window; + event->button.time = xdbe->time; + event->button.source = gdkdev->info.source; + event->button.deviceid = xdbe->deviceid; + + gdk_input_translate_coordinates (gdkdev,input_window, xdbe->axis_data, + &event->button.x,&event->button.y, + &event->button.pressure, + &event->button.xtilt, + &event->button.ytilt); + event->button.state = gdk_input_translate_state(xdbe->state,xdbe->device_state); + event->button.button = xdbe->button; + + return TRUE; + } + + if (xevent->type == gdkdev->motionnotify_type) + { + XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent); + + gdk_input_translate_coordinates(gdkdev,input_window,xdme->axis_data, + &event->motion.x,&event->motion.y, + &event->motion.pressure, + &event->motion.xtilt, + &event->motion.ytilt); + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = input_window->window; + event->motion.time = xdme->time; + event->motion.deviceid = xdme->deviceid; + event->motion.state = gdk_input_translate_state(xdme->state, + xdme->device_state); + event->motion.source = gdkdev->info.source; + event->motion.deviceid = xdme->deviceid; + + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f hint: %s\n", + xdme->window, + xdme->deviceid, + event->motion.x, event->motion.y, + (xevent->xmotion.is_hint) ? "true" : "false"); + + + return TRUE; + } + + if (xevent->type == gdkdev->proximityin_type || + xevent->type == gdkdev->proximityout_type) + { + XProximityNotifyEvent *xpne = (XProximityNotifyEvent *)(xevent); + + event->proximity.type = (xevent->type == gdkdev->proximityin_type)? + GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT; + event->proximity.window = input_window->window; + event->proximity.time = xpne->time; + event->proximity.source = gdkdev->info.source; + event->proximity.deviceid = xpne->deviceid; + + return TRUE; + } + + return -1; /* wasn't one of our event types */ +} + +static void +gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + int i; + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + for (i=GDK_AXIS_IGNORE;iaxis_for_use[i] = -1; + } + + for (i=0;iinfo.num_axes;i++) + { + gdkdev->info.axes[i] = axes[i]; + gdkdev->axis_for_use[axes[i]] = i; + } +} + +static GdkTimeCoord * +gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkTimeCoord *coords; + XDeviceTimeCoord *device_coords; + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + + int mode_return; + int axis_count_return; + int i; + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_val_if_fail (gdkdev != NULL, NULL); + g_return_val_if_fail (gdkdev->xdevice != NULL, NULL); + g_return_val_if_fail (input_window != NULL, NULL); + + device_coords = XGetDeviceMotionEvents (gdk_display, + gdkdev->xdevice, + start, stop, + nevents_return, &mode_return, + &axis_count_return); + + if (device_coords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + + for (i=0; i<*nevents_return; i++) + { + gdk_input_translate_coordinates (gdkdev, input_window, + device_coords[i].data, + &coords[i].x, &coords[i].y, + &coords[i].pressure, + &coords[i].xtilt, &coords[i].ytilt); + } + XFreeDeviceMotionEvents (device_coords); + + return coords; + } + else + return NULL; +} + +static void +gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + GdkInputWindow *input_window; + XDeviceState *state; + XInputClass *input_class; + gint x_int, y_int; + gint i; + + /* we probably need to get the mask in any case */ + + if (deviceid == GDK_CORE_POINTER) + { + gdk_window_get_pointer (window, &x_int, &y_int, mask); + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; + } + else + { + if (mask) + gdk_window_get_pointer (window, NULL, NULL, mask); + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_if_fail (gdkdev != NULL); + g_return_if_fail (gdkdev->xdevice != NULL); + g_return_if_fail (input_window != NULL); + + state = XQueryDeviceState (gdk_display, gdkdev->xdevice); + input_class = state->data; + for (i=0; inum_classes; i++) + { + switch (input_class->class) + { + case ValuatorClass: + gdk_input_translate_coordinates(gdkdev, input_window, + ((XValuatorState *)input_class)->valuators, + x, y, pressure, + xtilt, ytilt); + + + break; + case ButtonClass: + if (mask) + { + *mask &= ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | + GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | + GDK_BUTTON5_MASK); + for (i=0; i < ((XButtonState *)input_class)->num_buttons; i++) + { + if (((XButtonState *)input_class)->buttons[i]) + *mask |= GDK_BUTTON1_MASK << i; + } + } + break; + } + input_class = (XInputClass *)(((char *)input_class)+input_class->length); + } + } +} + +#endif diff --git a/gdk/gdkinputgxi.h b/gdk/gdkinputgxi.h new file mode 100644 index 000000000..a30e05f95 --- /dev/null +++ b/gdk/gdkinputgxi.h @@ -0,0 +1,628 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_GXI + +/* #define DEBUG_SWITCHING */ + +#include + +/* Forward declarations */ +static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode); +static gint gdk_input_is_extension_device (guint32 deviceid); +static void gdk_input_gxi_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev); + +static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent); +static gint gdk_input_gxi_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static Window gdk_input_find_root_child(Display *dpy, Window w); +static void gdk_input_compute_obscuring(GdkInputWindow *input_window); +static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, + gdouble y); +static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); +static gint gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_gxi_ungrab_pointer (guint32 time); + +/* Local variables */ + +static GdkDevicePrivate *gdk_input_current_device; +static GdkDevicePrivate *gdk_input_core_pointer; + +void +gdk_input_init(void) +{ + GList *tmp_list; + + gdk_input_vtable.set_mode = gdk_input_gxi_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_gxi_motion_events; + gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_gxi_configure_event; + gdk_input_vtable.enter_event = gdk_input_gxi_enter_event; + gdk_input_vtable.other_event = gdk_input_gxi_other_event; + gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event; + gdk_input_vtable.enable_window = gdk_input_gxi_enable_window; + gdk_input_vtable.disable_window = gdk_input_gxi_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_core_pointer = NULL; + + if (!gdk_input_gxid_host) + { + gdk_input_gxid_host = getenv("GXID_HOST"); + } + if (!gdk_input_gxid_port) + { + char *t = getenv("GXID_PORT"); + if (t) + gdk_input_gxid_port = atoi(t); + } + + gdk_input_common_init(TRUE); + + /* find initial core pointer */ + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdk_input_is_extension_device(gdkdev->info.deviceid)) + { + gdk_input_gxi_select_notify (gdkdev); + } + else + { + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + gdk_input_core_pointer = gdkdev; + } + } +} + +static void +gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev) +{ + XEventClass class; + + ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class); + + XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1); +} + +/* Set the core pointer. Device should already be enabled. */ +static gint +gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev) +{ + int x_axis,y_axis; + + g_return_val_if_fail(gdkdev->xdevice,FALSE); + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + + g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE); + + /* core_pointer might not be up to date so we check with the server + before change the pointer */ + + if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) ) + { +#if 0 + if (gdkdev != gdk_input_core_pointer) + g_warning("core pointer inconsistency"); +#endif + return TRUE; + } + + if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis) + != Success ) + { + return FALSE; + } + else + { + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + return TRUE; + } +} + + +/* FIXME, merge with gdk_input_xfree_set_mode */ + +static gint +gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (old_mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + if (mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + if (!gdk_input_enable_window(input_window->window, gdkdev)) + { + gdk_input_set_mode(deviceid, old_mode); + return FALSE; + } + } + } + + return TRUE; + +} + +gint +gdk_input_is_extension_device (guint32 deviceid) +{ + XDeviceInfo *devices; + int num_devices, loop; + + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + devices = XListInputDevices(gdk_display, &num_devices); + for(loop=0; looproot_x = root_x; + input_window->root_y = root_y; + gdk_input_compute_obscuring(input_window); +} + +static void +gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_compute_obscuring(input_window); +} + +static gint +gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (gdkdev->info.mode == GDK_MODE_DISABLED || + input_window->mode == GDK_EXTENSION_EVENTS_CURSOR) + return FALSE; + + if (gdkdev != gdk_input_current_device && + xevent->type != gdkdev->changenotify_type) + { + gdk_input_current_device = gdkdev; + } + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_MOTION_NOTIFY && + (!gdkdev->button_state) && (!input_window->grabbed) && + ((event->motion.x < 0) || (event->motion.y < 0) || + (event->motion.x > ((GdkWindowPrivate *)window)->width) || + (event->motion.y > ((GdkWindowPrivate *)window)->height) || + gdk_input_is_obscured(input_window,event->motion.x,event->motion.y))) + { +#ifdef DEBUG_SWITCHING + g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n", + gdkdev->info.deviceid,event->motion.x,event->motion.y); + g_print(" window geometry is: %dx%d\n", + ((GdkWindowPrivate *)window)->width, + ((GdkWindowPrivate *)window)->height); +#endif + gdk_input_gxi_set_core_pointer(gdkdev); + return FALSE; + } + else + return return_val; + +} + +static void +gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev) +{ + GList *t; + + if (gdk_input_is_extension_device (gdkdev->info.deviceid)) + { + if (!gdkdev->xdevice) + { + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + gdk_input_gxi_select_notify (gdkdev); + gdkdev->needs_update = 1; + } + if (gdkdev->needs_update && gdkdev->xdevice) + { + for (t = gdk_input_windows; t; t = t->next) + gdk_input_common_select_events (((GdkInputWindow *)t->data)->window, + gdkdev); + gdkdev->needs_update = 0; + } + } +} + +static gint +gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent) +{ + GdkDevicePrivate *gdkdev = + gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (xevent->type == gdkdev->changenotify_type) + { + if (gdk_input_core_pointer != gdkdev) + { +#ifdef DEBUG_SWITCHING + g_print("ChangeNotify from %d to %d:\n", + gdk_input_core_pointer->info.deviceid, + gdkdev->info.deviceid); +#endif + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + } + } + + return FALSE; +} + +static gint +gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (!gdkdev->claimed) + { + if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window), FALSE) != + GXID_RETURN_OK) + { + g_warning("Could not get device (is gxid running?)\n"); + return FALSE; + } + gdkdev->claimed = TRUE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (gdkdev->claimed) + { + gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window)); + + gdkdev->claimed = FALSE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y) +{ + int i; + for (i=0;inum_obscuring;i++) + { + GdkRectangle *rect = &input_window->obscuring[i]; + if ((x >= rect->x) && + (y >= rect->y) && + (x < rect->x + rect->width) && + (y < rect->y + rect->height)) + return TRUE; + } + return FALSE; +} + +/* If this routine needs fixing, the corresponding routine + in gxid.c will need it too. */ + +static Window +gdk_input_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +void +gdk_input_compute_obscuring(GdkInputWindow *input_window) +{ + int i; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + Window root,parent; + Window *children; + int nchildren; + + Window w = GDK_WINDOW_XWINDOW(input_window->window); + Window root_child = gdk_input_find_root_child(gdk_display,w); + gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height); + + input_window->root_x = x; + input_window->root_y = y; + + XQueryTree(gdk_display,GDK_ROOT_WINDOW(), + &root,&parent,&children,&nchildren); + + + if (input_window->obscuring) + g_free(input_window->obscuring); + input_window->obscuring = 0; + input_window->num_obscuring = 0; + + for (i=0;i=nchildren-1) + { + if (nchildren) + XFree(children); + return; + } + + input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1)); + + for (i=i+1;ix ? xc : x; + xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width; + ymin = yc>y ? yc : y; + ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height; + if ((xmin < xmax) && (ymin < ymax)) + { + XWindowAttributes attributes; + XGetWindowAttributes(gdk_display,children[i],&attributes); + if (attributes.map_state == IsViewable) + { + GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring]; + + /* we store the whole window, not just the obscuring part */ + rect->x = xc - x; + rect->y = yc - y; + rect->width = widthc; + rect->height = heightc; + input_window->num_obscuring++; + } + } + } + + if (nchildren) + XFree(children); +} + +static void +gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + if (gdkdev == gdk_input_core_pointer) + gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y, + pressure, xtilt, ytilt, mask); + else + gdk_input_common_get_pointer (window, deviceid, x, y, + pressure, xtilt, ytilt, mask); +} + +static GdkTimeCoord * +gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_val_if_fail (gdkdev != NULL, NULL); + + + if (gdkdev == gdk_input_core_pointer) + return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop, + nevents_return); + else + return gdk_input_common_motion_events (window, deviceid, start, stop, + nevents_return); + +} + +static gint +gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + new_window = input_window; + + tmp_list = tmp_list->next; + } + + new_window->grabbed = TRUE; + return Success; +} + +static void +gdk_input_gxi_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + input_window->grabbed = FALSE; + tmp_list = tmp_list->next; + } +} + +#endif /* XINPUT_GXI */ diff --git a/gdk/gdkinputnone.h b/gdk/gdkinputnone.h new file mode 100644 index 000000000..8ae8c4189 --- /dev/null +++ b/gdk/gdkinputnone.h @@ -0,0 +1,72 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_NONE + +static void gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +void +gdk_input_init () +{ + gdk_input_vtable.set_mode = NULL; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_none_get_pointer; + gdk_input_vtable.grab_pointer = NULL; + gdk_input_vtable.ungrab_pointer = NULL; + gdk_input_vtable.configure_event = NULL; + gdk_input_vtable.enter_event = NULL; + gdk_input_vtable.other_event = NULL; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = NULL; + gdk_input_vtable.disable_window = NULL; + + gdk_input_devices = g_list_append (NULL, &gdk_input_core_info); + + gdk_input_ignore_core = FALSE; +} + +static void +gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + gint x_int, y_int; + + gdk_window_get_pointer (window, &x_int, &y_int, mask); + + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; +} + +#endif /* XINPUT_NONE */ diff --git a/gdk/gdkinputxfree.h b/gdk/gdkinputxfree.h new file mode 100644 index 000000000..f74249008 --- /dev/null +++ b/gdk/gdkinputxfree.h @@ -0,0 +1,368 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_XFREE + +/* forward declarations */ + +static gint gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode); +static void gdk_input_check_proximity(); +static void gdk_input_xfree_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_enable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_disable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_xfree_ungrab_pointer (guint32 time); + +void +gdk_input_init(void) +{ + gdk_input_vtable.set_mode = gdk_input_xfree_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_common_motion_events; + gdk_input_vtable.get_pointer = gdk_input_common_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_xfree_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_xfree_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_xfree_configure_event; + gdk_input_vtable.enter_event = gdk_input_xfree_enter_event; + gdk_input_vtable.other_event = gdk_input_xfree_other_event; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = gdk_input_xfree_enable_window; + gdk_input_vtable.disable_window = gdk_input_xfree_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_common_init(FALSE); +} + +static gint +gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (mode == GDK_MODE_WINDOW) + { + gdkdev->info.has_cursor = FALSE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_enable_window (input_window->window, gdkdev); + else + if (old_mode != GDK_MODE_DISABLED) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + else if (mode == GDK_MODE_SCREEN) + { + gdkdev->info.has_cursor = TRUE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + gdk_input_enable_window (((GdkInputWindow *)tmp_list->data)->window, + gdkdev); + } + else /* mode == GDK_MODE_DISABLED */ + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (old_mode != GDK_MODE_WINDOW || + input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + return TRUE; + +} + +static void +gdk_input_check_proximity() +{ + gint new_proximity = 0; + GList *tmp_list = gdk_input_devices; + + while (tmp_list && !new_proximity) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.mode != GDK_MODE_DISABLED + && gdkdev->info.deviceid != GDK_CORE_POINTER + && gdkdev->xdevice) + { + XDeviceState *state = XQueryDeviceState(GDK_DISPLAY(), + gdkdev->xdevice); + XInputClass *xic; + int i; + + xic = state->data; + for (i=0; inum_classes; i++) + { + if (xic->class == ValuatorClass) + { + XValuatorState *xvs = (XValuatorState *)xic; + if ((xvs->mode & ProximityState) == InProximity) + { + new_proximity = TRUE; + } + break; + } + xic = (XInputClass *)((char *)xic + xic->length); + } + } + tmp_list = tmp_list->next; + } + + gdk_input_ignore_core = new_proximity; +} + +static void +gdk_input_xfree_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_check_proximity(); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static gint +gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + /* FIXME: It would be nice if we could just get rid of the events + entirely, instead of having to ignore them */ + if (gdkdev->info.mode == GDK_MODE_DISABLED || + (gdkdev->info.mode == GDK_MODE_WINDOW + && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)) + return FALSE; + + if (!gdk_input_ignore_core) + gdk_input_check_proximity(); + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_PROXIMITY_OUT && + gdk_input_ignore_core) + gdk_input_check_proximity(); + + /* Do a passive button grab. We have to be careful not to release + an explicit grab, if any. Doubling the grab should be harmless, + but we check anyways. */ + + /* FIXME, finding the proper events here is going to be SLOW - but + we might have different sets for each window/device combination */ + + if (return_val> 0 && !input_window->grabbed) + { + if (event->type == GDK_BUTTON_PRESS) + { + XEventClass event_classes[6]; + gint num_classes; + + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, event->button.time); + } + else if (event->type == GDK_BUTTON_RELEASE) + XUngrabDevice( GDK_DISPLAY(), gdkdev->xdevice, event->button.time); + } + + return return_val; +} + +static gint +gdk_input_xfree_enable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + /* FIXME: watchout, gdkdev might be core pointer, never opened */ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + XEventClass event_classes[6]; + gint num_classes; + + tmp_list = gdk_input_windows; + new_window = NULL; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + { + new_window = input_window; + break; + } + + tmp_list = tmp_list->next; + } + + g_return_if_fail (new_window == NULL); + + new_window->grabbed = TRUE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + /* FIXME: we should do something on failure */ + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, time); + } + tmp_list = tmp_list->next; + } + + return Success; +} + +static void +gdk_input_xfree_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + break; + tmp_list = tmp_list->next; + } + + if (tmp_list) /* we found a grabbed window */ + { + input_window->grabbed = FALSE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + XUngrabDevice( gdk_display, gdkdev->xdevice, time); + } + tmp_list = tmp_list->next; + } + } +} + +#endif /* XINPUT_XFREE */ diff --git a/gdk/gdkpixmap.c b/gdk/gdkpixmap.c new file mode 100644 index 000000000..d2d96b6da --- /dev/null +++ b/gdk/gdkpixmap.c @@ -0,0 +1,657 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" +#include +#include +#include +#include + +#include "gdk.h" +#include "gdkprivate.h" + +typedef struct +{ + gchar *color_string; + GdkColor color; + gint transparent; +} _GdkPixmapColor; + +GdkPixmap* +gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow, + width, height, depth); + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap * +gdk_bitmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreateBitmapFromData (private->xdisplay, + window_private->xwindow, + data, width, height); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (fg != NULL, NULL); + g_return_val_if_fail (bg != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay, + window_private->xwindow, + data, width, height, + fg->pixel, bg->pixel, depth); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +gint +gdk_pixmap_seek_string (FILE *infile, + const gchar *str, + gint skip_comments) +{ + char instr[1024]; + + while (!feof (infile)) + { + fscanf (infile, "%s", instr); + if (skip_comments == TRUE && strcmp (instr, "/*") == 0) + { + fscanf (infile, "%s", instr); + while (!feof (infile) && strcmp (instr, "*/") != 0) + fscanf (infile, "%s", instr); + fscanf(infile, "%s", instr); + } + if (strcmp (instr, str)==0) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_seek_char (FILE *infile, + gchar c) +{ + gchar b, oldb; + + while (!feof (infile)) + { + fscanf(infile, "%c", &b); + if (c != b && b == '/') + { + fscanf (infile, "%c", &b); + if (b == '*') + { + oldb = b; + while (!feof (infile) && !(oldb == '*' && b == '/')) + { + oldb = b; + fscanf (infile, "%c", &b); + } + fscanf (infile, "%c", &b); + } + } + if (c == b) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_read_string (FILE *infile, + gchar **buffer, + int *buffer_size) +{ + gchar c; + gint cnt = 0; + + if ((*buffer) == NULL) + { + (*buffer_size) = 10 * sizeof (gchar); + (*buffer) = (gchar *) malloc (*buffer_size); + } + + do + fscanf (infile, "%c", &c); + while (!feof (infile) && c != '"'); + + if (c != '"') + return FALSE; + + while (!feof (infile)) + { + fscanf (infile, "%c", &c); + + if (cnt == (*buffer_size)) + { + (*buffer_size) *= 2; + (*buffer) = (gchar *) realloc ((*buffer), *buffer_size); + } + + if (c != '"') + (*buffer)[cnt++] = c; + else + { + (*buffer)[cnt++] = 0; + return TRUE; + } + } + + return FALSE; +} + +gchar* +gdk_pixmap_skip_whitespaces (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_skip_string (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_extract_color (gchar *buffer) +{ + gint counter, finished = FALSE, numnames; + gchar *ptr = NULL, ch, temp[128]; + gchar color[128], *retcol; + + counter = 0; + while (ptr == NULL) + { + if (buffer[counter] == 'c') + { + ch = buffer[counter + 1]; + if (ch == 0x20 || ch == 0x09) + ptr = &buffer[counter + 1]; + } + else if (buffer[counter] == 0) + return NULL; + + counter++; + } + + if (ptr == NULL) + return NULL; + + ptr = gdk_pixmap_skip_whitespaces (ptr); + + if (ptr[0] == 0) + return NULL; + else if (ptr[0] == '#') + { + retcol = g_new(gchar, strlen (ptr) + 1); + strcpy (retcol, ptr); + return retcol; + } + + color[0] = 0; + numnames = 0; + + while (finished == FALSE) + { + sscanf (ptr, "%s", temp); + + if ((gint)ptr[0] == 0 || strcmp ("s", temp) == 0 || strcmp ("m", temp) == 0 || + strcmp ("g", temp) == 0 || strcmp ("g4", temp) == 0) + finished = TRUE; + else + { + if (numnames > 0) + strcat (color, " "); + strcat (color, temp); + ptr = gdk_pixmap_skip_string (ptr); + ptr = gdk_pixmap_skip_whitespaces (ptr); + numnames++; + } + } + + retcol = g_new(gchar, strlen (color) + 1); + strcpy (retcol, color); + return retcol; +} + + +GdkPixmap* +gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + FILE *infile = NULL; + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt; + gchar *buffer = NULL, *color_name = NULL, pixel_str[32]; + guint buffer_size = 0; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + infile = fopen (filename, "rb"); + if (infile != NULL) + { + if (gdk_pixmap_seek_string (infile, "XPM", FALSE) == TRUE) + { + if (gdk_pixmap_seek_char (infile,'{') == TRUE) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + } + } + + fclose (infile); + free (buffer); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + } + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt, i; + gchar *buffer, *color_name = NULL, pixel_str[32]; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + i = 0; + buffer = data[i++]; + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + buffer = data[i++]; + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + buffer = data[i++]; + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + + return pixmap; +} + +void +gdk_pixmap_destroy (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private; + + g_return_if_fail (pixmap != NULL); + + private = (GdkPixmapPrivate*) pixmap; + if (private->ref_count <= 0) + { + XFreePixmap (private->xdisplay, private->xwindow); + gdk_xid_table_remove (private->xwindow); + g_free (pixmap); + } + else + { + private->ref_count -= 1; + } +} diff --git a/gdk/gdkprivate.h b/gdk/gdkprivate.h new file mode 100644 index 000000000..3c1677e41 --- /dev/null +++ b/gdk/gdkprivate.h @@ -0,0 +1,197 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_PRIVATE_H__ +#define __GDK_PRIVATE_H__ + + +#include +#include +#include + +#define DND_PROTOCOL_VERSION 0 + +#define gdk_window_lookup(xid) ((GdkWindow*) gdk_xid_table_lookup (xid)) +#define gdk_pixmap_lookup(xid) ((GdkPixmap*) gdk_xid_table_lookup (xid)) +#define gdk_font_lookup(xid) ((GdkFont*) gdk_xid_table_lookup (xid)) + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GdkWindowPrivate GdkWindowPrivate; +typedef struct _GdkWindowPrivate GdkPixmapPrivate; +typedef struct _GdkImagePrivate GdkImagePrivate; +typedef struct _GdkGCPrivate GdkGCPrivate; +typedef struct _GdkColormapPrivate GdkColormapPrivate; +typedef struct _GdkVisualPrivate GdkVisualPrivate; +typedef struct _GdkFontPrivate GdkFontPrivate; +typedef struct _GdkCursorPrivate GdkCursorPrivate; + + +struct _GdkWindowPrivate +{ + GdkWindow window; + GdkWindow *parent; + Window xwindow; + Display *xdisplay; + gint16 x; + gint16 y; + guint16 width; + guint16 height; + guint8 resize_count; + guint8 ref_count; + guint8 window_type; + guint8 destroyed : 2; + guint8 dnd_drag_enabled : 1, + dnd_drag_datashow : 1, + dnd_drag_destructive_op : 1, + dnd_drag_accepted : 1, + dnd_drop_enabled : 1, + dnd_drop_destructive_op : 1; + GdkAtom dnd_drag_data_type, *dnd_drag_data_typesavail; + guint dnd_drag_data_numtypesavail; + /* We have to turn on MotionMask/EnterWindowMask/LeaveWindowMask + during drags, then set it back to what it was after */ + glong dnd_drag_savedeventmask, dnd_drag_eventmask; + GdkAtom *dnd_drop_data_typesavail; + guint dnd_drop_data_numtypesavail; + /* need to allow custom drag/drop cursors */ + + gint extension_events; +}; + +struct _GdkImagePrivate +{ + GdkImage image; + XImage *ximage; + Display *xdisplay; + gpointer x_shm_info; + + void (*image_put) (GdkDrawable *window, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +}; + +struct _GdkGCPrivate +{ + GdkGC gc; + GC xgc; + Display *xdisplay; +}; + +struct _GdkColormapPrivate +{ + GdkColormap colormap; + Colormap xcolormap; + Display *xdisplay; + GdkVisual *visual; + gint private_val; + gint next_color; + gint ref_count; +}; + +struct _GdkVisualPrivate +{ + GdkVisual visual; + Visual *xvisual; +}; + +struct _GdkFontPrivate +{ + GdkFont font; + /* XFontStruct *xfont; */ + /* generic pointer point to XFontStruct or XFontSet */ + gpointer xfont; + Display *xdisplay; + gint ref_count; +}; + +struct _GdkCursorPrivate +{ + GdkCursor cursor; + Cursor xcursor; + Display *xdisplay; +}; + +struct _GdkDndGlobals { + GdkAtom gdk_XdeEnter, gdk_XdeLeave, gdk_XdeRequest; + GdkAtom gdk_XdeDataAvailable, gdk_XdeDataShow, gdk_XdeCancel; + GdkAtom gdk_XdeTypelist; + Cursor gdk_cursor_dragdefault, gdk_cursor_dragok; + GdkWindow **drag_startwindows; + guint drag_numwindows; + guint8 drag_really; + GdkPoint drag_dropcoords; +}; +typedef struct _GdkDndGlobals GdkDndGlobals; + +void gdk_window_init (void); +void gdk_visual_init (void); + +void gdk_image_init (void); +void gdk_image_exit (void); + +GdkColormap* gdk_colormap_lookup (Colormap xcolormap); +GdkVisual* gdk_visual_lookup (Visual *xvisual); + +void gdk_window_real_destroy (GdkWindow *window); +void gdk_window_add_colormap_windows (GdkWindow *window); + +void gdk_xid_table_insert (XID *xid, + gpointer data); +void gdk_xid_table_remove (XID xid); +gpointer gdk_xid_table_lookup (XID xid); + + +extern gint gdk_debug_level; +extern gint gdk_show_events; +extern gint gdk_use_xshm; +extern gint gdk_stack_trace; +extern gchar *gdk_display_name; +extern Display *gdk_display; +extern gint gdk_screen; +extern Window gdk_root_window; +extern Window gdk_leader_window; +extern GdkWindowPrivate gdk_root_parent; +extern Atom gdk_wm_delete_window; +extern Atom gdk_wm_take_focus; +extern Atom gdk_wm_protocols; +extern Atom gdk_wm_window_protocols[]; +extern Atom gdk_selection_property; +extern GdkDndGlobals gdk_dnd; +extern GdkWindow *selection_owner[]; +extern gchar *gdk_progname; +extern gchar *gdk_progclass; +extern gint gdk_error_code; +extern gint gdk_error_warnings; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_PRIVATE_H__ */ diff --git a/gdk/gdkproperty.c b/gdk/gdkproperty.c new file mode 100644 index 000000000..35d8a50cf --- /dev/null +++ b/gdk/gdkproperty.c @@ -0,0 +1,194 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +GdkAtom +gdk_atom_intern (const gchar *atom_name, + gint only_if_exists) +{ + return XInternAtom (gdk_display, atom_name, only_if_exists); +} + +gchar * +gdk_atom_name (GdkAtom atom) +{ + gchar *t; + gchar *name; + + /* If this atom doesn't exist, we'll die with an X error unless + we take precautions */ + + gdk_error_warnings = 0; + t = XGetAtomName (gdk_display, atom); + gdk_error_warnings = 1; + + if (gdk_error_code == -1) + { + return NULL; + } + else + { + name = g_strdup (t); + XFree (t); + + return name; + } +} + +gint +gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format_type, + gint *actual_length, + guchar **data) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + Atom ret_prop_type; + gint ret_format; + gulong ret_nitems; + gulong ret_bytes_after; + gulong ret_length; + guchar *ret_data; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XGetWindowProperty (xdisplay, xwindow, property, + offset, (length + 3) / 4, pdelete, + type, &ret_prop_type, &ret_format, + &ret_nitems, &ret_bytes_after, + &ret_data); + + if ((ret_prop_type == None) && (ret_format == 0)) + return FALSE; + + if (actual_property_type) + *actual_property_type = ret_prop_type; + if (actual_format_type) + *actual_format_type = ret_format; + + if (ret_prop_type != property) + { + XFree (ret_data); + return FALSE; + } + + /* FIXME: ignoring bytes_after could have very bad effects */ + + if (data) + { + switch (ret_format) + { + case 8: + ret_length = ret_nitems; + break; + case 16: + ret_length = 2 * ret_nitems; + break; + case 32: + ret_length = 4 * ret_nitems; + break; + default: + g_warning ("unknown property return format: %d", ret_format); + XFree (ret_data); + return FALSE; + } + + *data = g_new (guchar, ret_length); + memcpy (*data, ret_data, ret_length); + if (actual_length) + *actual_length = ret_length; + } + + XFree (ret_data); + + return TRUE; +} + +void +gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XChangeProperty (xdisplay, xwindow, property, type, + format, mode, data, nelements); +} + +void +gdk_property_delete (GdkWindow *window, + GdkAtom property) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XDeleteProperty (xdisplay, xwindow, property); +} diff --git a/gdk/gdkrectangle.c b/gdk/gdkrectangle.c new file mode 100644 index 000000000..dbb35b664 --- /dev/null +++ b/gdk/gdkrectangle.c @@ -0,0 +1,83 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gdk.h" + + +gint +gdk_rectangle_intersect (GdkRectangle *src1, + GdkRectangle *src2, + GdkRectangle *dest) +{ + GdkRectangle *temp; + gint src1_x2, src1_y2; + gint src2_x2, src2_y2; + gint return_val; + + g_return_val_if_fail (src1 != NULL, FALSE); + g_return_val_if_fail (src2 != NULL, FALSE); + g_return_val_if_fail (dest != NULL, FALSE); + + return_val = FALSE; + + if (src2->x < src1->x) + { + temp = src1; + src1 = src2; + src2 = temp; + } + dest->x = src2->x; + + src1_x2 = src1->x + src1->width; + src2_x2 = src2->x + src2->width; + + if (src2->x < src1_x2) + { + if (src1_x2 < src2_x2) + dest->width = src1_x2 - dest->x; + else + dest->width = src2_x2 - dest->x; + + if (src2->y < src1->y) + { + temp = src1; + src1 = src2; + src2 = temp; + } + dest->y = src2->y; + + src1_y2 = src1->y + src1->height; + src2_y2 = src2->y + src2->height; + + if (src2->y < src1_y2) + { + return_val = TRUE; + + if (src1_y2 < src2_y2) + dest->height = src1_y2 - dest->y; + else + dest->height = src2_y2 - dest->y; + + if (dest->height == 0) + return_val = FALSE; + if (dest->width == 0) + return_val = FALSE; + } + } + + return return_val; +} diff --git a/gdk/gdkselection.c b/gdk/gdkselection.c new file mode 100644 index 000000000..6bd425110 --- /dev/null +++ b/gdk/gdkselection.c @@ -0,0 +1,168 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (owner) + { + private = (GdkWindowPrivate*) owner; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = None; + } + + XSetSelectionOwner (xdisplay, selection, xwindow, time); + + return (XGetSelectionOwner (xdisplay, selection) == xwindow); +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + Window xwindow; + + xwindow = XGetSelectionOwner (gdk_display, selection); + if (xwindow == None) + return NULL; + + return gdk_window_lookup (xwindow); +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GdkWindowPrivate *private; + + g_return_if_fail (requestor != NULL); + + private = (GdkWindowPrivate*) requestor; + + XConvertSelection (private->xdisplay, selection, target, + gdk_selection_property, private->xwindow, time); +} + +gint +gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *ret_type, + gint *ret_format) +{ + GdkWindowPrivate *private; + gulong nitems; + gulong nbytes; + gulong length; + GdkAtom prop_type; + gint prop_format; + guchar *t; + + g_return_val_if_fail (requestor != NULL, 0); + + /* If retrieved chunks are typically small, (and the ICCM says the + should be) it would be a win to try first with a buffer of + moderate length, to avoid two round trips to the server */ + + private = (GdkWindowPrivate*) requestor; + + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, 0, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (ret_type) + *ret_type = prop_type; + if (ret_format) + *ret_format = prop_format; + + if (prop_type == None) + { + *data = NULL; + return 0; + } + + XFree (t); + + /* Add on an extra byte to handle null termination. X guarantees + that t will be 1 longer than nbytes and null terminated */ + length = nbytes + 1; + + /* We can't delete the selection here, because it might be the INCR + protocol, in which case the client has to make sure they'll be + notified of PropertyChange events _before_ the property is deleted. + Otherwise there's no guarantee we'll win the race ... */ + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, (nbytes + 3) / 4, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (prop_type != None) + { + *data = g_new (guchar, length); + memcpy (*data, t, length); + XFree (t); + return length-1; + } + else + { + *data = NULL; + return 0; + } +} + + +void +gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time) +{ + XSelectionEvent xevent; + + xevent.type = SelectionNotify; + xevent.serial = 0; + xevent.send_event = True; + xevent.display = gdk_display; + xevent.requestor = requestor; + xevent.selection = selection; + xevent.target = target; + xevent.property = property; + xevent.time = time; + + XSendEvent (gdk_display, requestor, False, NoEventMask, (XEvent*) &xevent); +} diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h new file mode 100644 index 000000000..7fc7434ac --- /dev/null +++ b/gdk/gdktypes.h @@ -0,0 +1,967 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_TYPES_H__ +#define __GDK_TYPES_H__ + + +/* GDK uses "glib". (And so does GTK). + */ +#include + + +#define GDK_NONE 0L +#define GDK_CURRENT_TIME 0L +#define GDK_PARENT_RELATIVE 1L + +/* special deviceid for core pointer events */ +#define GDK_CORE_POINTER 0xfedc + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Type definitions for the basic structures. + */ + +typedef gulong GdkAtom; +typedef struct _GdkColor GdkColor; +typedef struct _GdkColormap GdkColormap; +typedef struct _GdkVisual GdkVisual; +typedef struct _GdkWindowAttr GdkWindowAttr; +typedef struct _GdkWindow GdkWindow; +typedef struct _GdkWindow GdkPixmap; +typedef struct _GdkWindow GdkBitmap; +typedef struct _GdkWindow GdkDrawable; +typedef struct _GdkImage GdkImage; +typedef struct _GdkGCValues GdkGCValues; +typedef struct _GdkGC GdkGC; +typedef struct _GdkPoint GdkPoint; +typedef struct _GdkRectangle GdkRectangle; +typedef struct _GdkSegment GdkSegment; +typedef struct _GdkFont GdkFont; +typedef struct _GdkCursor GdkCursor; + +typedef struct _GdkEventAny GdkEventAny; +typedef struct _GdkEventExpose GdkEventExpose; +typedef struct _GdkEventMotion GdkEventMotion; +typedef struct _GdkEventButton GdkEventButton; +typedef struct _GdkEventKey GdkEventKey; +typedef struct _GdkEventFocus GdkEventFocus; +typedef struct _GdkEventCrossing GdkEventCrossing; +typedef struct _GdkEventConfigure GdkEventConfigure; +typedef struct _GdkEventProperty GdkEventProperty; +typedef struct _GdkEventSelection GdkEventSelection; +typedef struct _GdkEventProximity GdkEventProximity; +typedef struct _GdkEventOther GdkEventOther; +typedef struct _GdkEventDragBegin GdkEventDragBegin; +typedef struct _GdkEventDragRequest GdkEventDragRequest; +typedef struct _GdkEventDropEnter GdkEventDropEnter; +typedef struct _GdkEventDropDataAvailable GdkEventDropDataAvailable; +typedef struct _GdkEventDropLeave GdkEventDropLeave; +typedef struct _GdkEventClient GdkEventClient; +typedef union _GdkEvent GdkEvent; +typedef struct _GdkDeviceInfo GdkDeviceInfo; +typedef struct _GdkTimeCoord GdkTimeCoord; +typedef gint (*GdkEventFunc) (GdkEvent *event, + gpointer data); + + +/* Types of windows. + * Root: There is only 1 root window and it is initialized + * at startup. Creating a window of type GDK_WINDOW_ROOT + * is an error. + * Toplevel: Windows which interact with the window manager. + * Child: Windows which are children of some other type of window. + * (Any other type of window). Most windows are child windows. + * Dialog: A special kind of toplevel window which interacts with + * the window manager slightly differently than a regular + * toplevel window. Dialog windows should be used for any + * transient window. + * Pixmap: Pixmaps are really just another kind of window which + * doesn't actually appear on the screen. It can't have + * children, either and is really just a convenience so + * that the drawing functions can work on both windows + * and pixmaps transparently. (ie. You shouldn't pass a + * pixmap to any procedure which accepts a window with the + * exception of the drawing functions). + */ +typedef enum +{ + GDK_WINDOW_ROOT, + GDK_WINDOW_TOPLEVEL, + GDK_WINDOW_CHILD, + GDK_WINDOW_DIALOG, + GDK_WINDOW_TEMP, + GDK_WINDOW_PIXMAP +} GdkWindowType; + +/* Classes of windows. + * InputOutput: Almost every window should be of this type. Such windows + * receive events and are also displayed on screen. + * InputOnly: Used only in special circumstances when events need to be + * stolen from another window or windows. Input only windows + * have no visible output, so they are handy for placing over + * top of a group of windows in order to grab the events (or + * filter the events) from those windows. + */ +typedef enum +{ + GDK_INPUT_OUTPUT, + GDK_INPUT_ONLY +} GdkWindowClass; + +/* Types of images. + * Normal: Normal X image type. These are slow as they involve passing + * the entire image through the X connection each time a draw + * request is required. + * Shared: Shared memory X image type. These are fast as the X server + * and the program actually use the same piece of memory. They + * should be used with care though as there is the possibility + * for both the X server and the program to be reading/writing + * the image simultaneously and producing undesired results. + */ +typedef enum +{ + GDK_IMAGE_NORMAL, + GDK_IMAGE_SHARED, + GDK_IMAGE_FASTEST +} GdkImageType; + +/* Types of visuals. + * StaticGray: + * Grayscale: + * StaticColor: + * PseudoColor: + * TrueColor: + * DirectColor: + */ +typedef enum +{ + GDK_VISUAL_STATIC_GRAY, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR +} GdkVisualType; + +/* Types of font. + * GDK_FONT_FONT: the font is an XFontStruct. + * GDK_FONT_FONTSET: the font is an XFontSet used for I18N. + */ +typedef enum +{ + GDK_FONT_FONT, + GDK_FONT_FONTSET +} GdkFontType; + +/* Window attribute mask values. + * GDK_WA_TITLE: The "title" field is valid. + * GDK_WA_X: The "x" field is valid. + * GDK_WA_Y: The "y" field is valid. + * GDK_WA_CURSOR: The "cursor" field is valid. + * GDK_WA_COLORMAP: The "colormap" field is valid. + * GDK_WA_VISUAL: The "visual" field is valid. + */ +typedef enum +{ + GDK_WA_TITLE = 1 << 1, + GDK_WA_X = 1 << 2, + GDK_WA_Y = 1 << 3, + GDK_WA_CURSOR = 1 << 4, + GDK_WA_COLORMAP = 1 << 5, + GDK_WA_VISUAL = 1 << 6, + GDK_WA_WMCLASS = 1 << 7 +} GdkWindowAttributesType; + +/* Size restriction enumeration. + */ +typedef enum +{ + GDK_HINT_POS = 1 << 0, + GDK_HINT_MIN_SIZE = 1 << 1, + GDK_HINT_MAX_SIZE = 1 << 2 +} GdkWindowHints; + +/* GC function types. + * Copy: Overwrites destination pixels with the source pixels. + * Invert: Inverts the destination pixels. + * Xor: Xor's the destination pixels with the source pixels. + */ +typedef enum +{ + GDK_COPY, + GDK_INVERT, + GDK_XOR +} GdkFunction; + +/* GC fill types. + * Solid: + * Tiled: + * Stippled: + * OpaqueStippled: + */ +typedef enum +{ + GDK_SOLID, + GDK_TILED, + GDK_STIPPLED, + GDK_OPAQUE_STIPPLED +} GdkFill; + +/* GC line styles + * Solid: + * OnOffDash: + * DoubleDash: + */ +typedef enum +{ + GDK_LINE_SOLID, + GDK_LINE_ON_OFF_DASH, + GDK_LINE_DOUBLE_DASH +} GdkLineStyle; + +/* GC cap styles + * CapNotLast: + * CapButt: + * CapRound: + * CapProjecting: + */ +typedef enum +{ + GDK_CAP_NOT_LAST, + GDK_CAP_BUTT, + GDK_CAP_ROUND, + GDK_CAP_PROJECTING +} GdkCapStyle; + +/* GC join styles + * JoinMiter: + * JoinRound: + * JoinBevel: + */ +typedef enum +{ + GDK_JOIN_MITER, + GDK_JOIN_ROUND, + GDK_JOIN_BEVEL +} GdkJoinStyle; + +/* Cursor types. + */ +typedef enum +{ +#include + GDK_LAST_CURSOR +} GdkCursorType; + +/* Event types. + * Nothing: No event occurred. + * Delete: A window delete event was sent by the window manager. + * The specified window should be deleted. + * Destroy: A window has been destroyed. + * Expose: Part of a window has been uncovered. + * MotionNotify: The mouse has moved. + * ButtonPress: A mouse button was pressed. + * ButtonRelease: A mouse button was release. + * KeyPress: A key was pressed. + * KeyRelease: A key was released. + * EnterNotify: A window was entered. + * LeaveNotify: A window was exited. + * FocusChange: The focus window has changed. (The focus window gets + * keyboard events). + * Resize: A window has been resized. + * Map: A window has been mapped. (It is now visible on the screen). + * Unmap: A window has been unmapped. (It is no longer visible on + * the screen). + */ +typedef enum +{ + GDK_NOTHING = -1, + GDK_DELETE = 0, + GDK_DESTROY = 1, + GDK_EXPOSE = 2, + GDK_MOTION_NOTIFY = 3, + GDK_BUTTON_PRESS = 4, + GDK_2BUTTON_PRESS = 5, + GDK_3BUTTON_PRESS = 6, + GDK_BUTTON_RELEASE = 7, + GDK_KEY_PRESS = 8, + GDK_KEY_RELEASE = 9, + GDK_ENTER_NOTIFY = 10, + GDK_LEAVE_NOTIFY = 11, + GDK_FOCUS_CHANGE = 12, + GDK_CONFIGURE = 13, + GDK_MAP = 14, + GDK_UNMAP = 15, + GDK_PROPERTY_NOTIFY = 16, + GDK_SELECTION_CLEAR = 17, + GDK_SELECTION_REQUEST = 18, + GDK_SELECTION_NOTIFY = 19, + GDK_PROXIMITY_IN = 20, + GDK_PROXIMITY_OUT = 21, + GDK_DRAG_BEGIN = 22, + GDK_DRAG_REQUEST = 23, + GDK_DROP_ENTER = 24, + GDK_DROP_LEAVE = 25, + GDK_DROP_DATA_AVAIL = 26, + GDK_CLIENT_EVENT = 27, + GDK_OTHER_EVENT = 9999 +} GdkEventType; + +/* Event masks. (Used to select what types of events a window + * will receive). + */ +typedef enum +{ + GDK_EXPOSURE_MASK = 1 << 1, + GDK_POINTER_MOTION_MASK = 1 << 2, + GDK_POINTER_MOTION_HINT_MASK = 1 << 3, + GDK_BUTTON_MOTION_MASK = 1 << 4, + GDK_BUTTON1_MOTION_MASK = 1 << 5, + GDK_BUTTON2_MOTION_MASK = 1 << 6, + GDK_BUTTON3_MOTION_MASK = 1 << 7, + GDK_BUTTON_PRESS_MASK = 1 << 8, + GDK_BUTTON_RELEASE_MASK = 1 << 9, + GDK_KEY_PRESS_MASK = 1 << 10, + GDK_KEY_RELEASE_MASK = 1 << 11, + GDK_ENTER_NOTIFY_MASK = 1 << 12, + GDK_LEAVE_NOTIFY_MASK = 1 << 13, + GDK_FOCUS_CHANGE_MASK = 1 << 14, + GDK_STRUCTURE_MASK = 1 << 15, + GDK_PROPERTY_CHANGE_MASK = 1 << 16, + GDK_PROXIMITY_IN_MASK = 1 << 17, + GDK_PROXIMITY_OUT_MASK = 1 << 18, + GDK_ALL_EVENTS_MASK = 0x07FFFF +} GdkEventMask; + +/* Types of enter/leave notifications. + * Ancestor: + * Virtual: + * Inferior: + * Nonlinear: + * NonlinearVirtual: + * Unknown: An unknown type of enter/leave event occurred. + */ +typedef enum +{ + GDK_NOTIFY_ANCESTOR = 0, + GDK_NOTIFY_VIRTUAL = 1, + GDK_NOTIFY_INFERIOR = 2, + GDK_NOTIFY_NONLINEAR = 3, + GDK_NOTIFY_NONLINEAR_VIRTUAL = 4, + GDK_NOTIFY_UNKNOWN = 5 +} GdkNotifyType; + +/* Types of modifiers. + */ +typedef enum +{ + GDK_SHIFT_MASK = 1 << 0, + GDK_LOCK_MASK = 1 << 1, + GDK_CONTROL_MASK = 1 << 2, + GDK_MOD1_MASK = 1 << 3, + GDK_MOD2_MASK = 1 << 4, + GDK_MOD3_MASK = 1 << 5, + GDK_MOD4_MASK = 1 << 6, + GDK_MOD5_MASK = 1 << 7, + GDK_BUTTON1_MASK = 1 << 8, + GDK_BUTTON2_MASK = 1 << 9, + GDK_BUTTON3_MASK = 1 << 10, + GDK_BUTTON4_MASK = 1 << 11, + GDK_BUTTON5_MASK = 1 << 12 +} GdkModifierType; + +typedef enum +{ + GDK_CLIP_BY_CHILDREN = 0, + GDK_INCLUDE_INFERIORS = 1 +} GdkSubwindowMode; + +typedef enum +{ + GDK_INPUT_READ = 1 << 0, + GDK_INPUT_WRITE = 1 << 1, + GDK_INPUT_EXCEPTION = 1 << 2 +} GdkInputCondition; + +typedef enum +{ + GDK_OK = 0, + GDK_ERROR = -1, + GDK_ERROR_PARAM = -2, + GDK_ERROR_FILE = -3, + GDK_ERROR_MEM = -4 +} GdkStatus; + +typedef enum +{ + GDK_LSB_FIRST, + GDK_MSB_FIRST +} GdkByteOrder; + +typedef enum +{ + GDK_GC_FOREGROUND = 1 << 0, + GDK_GC_BACKGROUND = 1 << 1, + GDK_GC_FONT = 1 << 2, + GDK_GC_FUNCTION = 1 << 3, + GDK_GC_FILL = 1 << 4, + GDK_GC_TILE = 1 << 5, + GDK_GC_STIPPLE = 1 << 6, + GDK_GC_CLIP_MASK = 1 << 7, + GDK_GC_SUBWINDOW = 1 << 8, + GDK_GC_TS_X_ORIGIN = 1 << 9, + GDK_GC_TS_Y_ORIGIN = 1 << 10, + GDK_GC_CLIP_X_ORIGIN = 1 << 11, + GDK_GC_CLIP_Y_ORIGIN = 1 << 12, + GDK_GC_EXPOSURES = 1 << 13, + GDK_GC_LINE_WIDTH = 1 << 14, + GDK_GC_LINE_STYLE = 1 << 15, + GDK_GC_CAP_STYLE = 1 << 16, + GDK_GC_JOIN_STYLE = 1 << 17 +} GdkGCValuesMask; + +typedef enum +{ + GDK_SELECTION_PRIMARY = 1, + GDK_SELECTION_SECONDARY = 2 +} GdkSelection; + +typedef enum +{ + GDK_PROPERTY_NEW_VALUE, + GDK_PROPERTY_DELETE +} GdkPropertyState; + +typedef enum +{ + GDK_PROP_MODE_REPLACE, + GDK_PROP_MODE_PREPEND, + GDK_PROP_MODE_APPEND +} GdkPropMode; + +/* These definitions are for version 1 of the OffiX D&D protocol, + taken from */ +typedef enum +{ + GDK_DNDTYPE_NOTDND = -1, + GDK_DNDTYPE_UNKNOWN = 0, + GDK_DNDTYPE_RAWDATA = 1, + GDK_DNDTYPE_FILE = 2, + GDK_DNDTYPE_FILES = 3, + GDK_DNDTYPE_TEXT = 4, + GDK_DNDTYPE_DIR = 5, + GDK_DNDTYPE_LINK = 6, + GDK_DNDTYPE_EXE = 7, + GDK_DNDTYPE_URL = 8, + GDK_DNDTYPE_MIME = 9, + GDK_DNDTYPE_END = 10 +} GdkDndType; + +/* Enums for XInput support */ + +typedef enum +{ + GDK_SOURCE_MOUSE, + GDK_SOURCE_PEN, + GDK_SOURCE_ERASER, + GDK_SOURCE_CURSOR +} GdkInputSource; + +typedef enum +{ + GDK_MODE_DISABLED, + GDK_MODE_SCREEN, + GDK_MODE_WINDOW +} GdkInputMode; + +typedef enum +{ + GDK_AXIS_IGNORE, + GDK_AXIS_X, + GDK_AXIS_Y, + GDK_AXIS_PRESSURE, + GDK_AXIS_XTILT, + GDK_AXIS_YTILT, + GDK_AXIS_LAST +} GdkAxisUse; + +/* The next two types define enums for predefined atoms relating + to selections. In general, one will need to use gdk_intern_atom */ + +typedef enum +{ + GDK_TARGET_BITMAP = 5, + GDK_TARGET_COLORMAP = 7, + GDK_TARGET_DRAWABLE = 17, + GDK_TARGET_PIXMAP = 20, + GDK_TARGET_STRING = 31 +} GdkTarget; + +typedef enum +{ + GDK_SELECTION_TYPE_ATOM = 4, + GDK_SELECTION_TYPE_BITMAP = 5, + GDK_SELECTION_TYPE_COLORMAP = 7, + GDK_SELECTION_TYPE_DRAWABLE = 17, + GDK_SELECTION_TYPE_INTEGER = 19, + GDK_SELECTION_TYPE_PIXMAP = 20, + GDK_SELECTION_TYPE_WINDOW = 33, + GDK_SELECTION_TYPE_STRING = 31 +} GdkSelectionType; + +typedef enum +{ + GDK_EXTENSION_EVENTS_NONE, + GDK_EXTENSION_EVENTS_ALL, + GDK_EXTENSION_EVENTS_CURSOR +} GdkExtensionMode; + +typedef void (*GdkInputFunction) (gpointer data, + gint source, + GdkInputCondition condition); + +/* The color type. + * A color consists of red, green and blue values in the + * range 0-65535 and a pixel value. The pixel value is highly + * dependent on the depth and colormap which this color will + * be used to draw into. Therefore, sharing colors between + * colormaps is a bad idea. + */ +struct _GdkColor +{ + gulong pixel; + gushort red; + gushort green; + gushort blue; +}; + +/* The colormap type. + * Colormaps consist of 256 colors. + */ +struct _GdkColormap +{ + GdkColor colors[256]; +}; + +/* The visual type. + * "type" is the type of visual this is (PseudoColor, TrueColor, etc). + * "depth" is the bit depth of this visual. + * "colormap_size" is the size of a colormap for this visual. + * "bits_per_rgb" is the number of significant bits per red, green and blue. + * The red, green and blue masks, shifts and precisions refer + * to value needed to calculate pixel values in TrueColor and DirectColor + * visuals. The "mask" is the significant bits within the pixel. The + * "shift" is the number of bits left we must shift a primary for it + * to be in position (according to the "mask"). "prec" refers to how + * much precision the pixel value contains for a particular primary. + */ +struct _GdkVisual +{ + GdkVisualType type; + gint depth; + GdkByteOrder byte_order; + gint colormap_size; + gint bits_per_rgb; + + guint32 red_mask; + gint red_shift; + gint red_prec; + + guint32 green_mask; + gint green_shift; + gint green_prec; + + guint32 blue_mask; + gint blue_shift; + gint blue_prec; +}; + +struct _GdkWindowAttr +{ + gchar *title; + gint event_mask; + gint16 x, y; + gint16 width; + gint16 height; + GdkWindowClass wclass; + GdkVisual *visual; + GdkColormap *colormap; + GdkWindowType window_type; + GdkCursor *cursor; + gchar *wmclass_name; + gchar *wmclass_class; +}; + +struct _GdkWindow +{ + gpointer user_data; +}; + +struct _GdkImage +{ + GdkImageType type; + GdkVisual *visual; /* visual used to create the image */ + GdkByteOrder byte_order; + guint16 width; + guint16 height; + guint16 depth; + guint16 bpp; /* bytes per pixel */ + guint16 bpl; /* bytes per line */ + gpointer mem; +}; + +struct _GdkGCValues +{ + GdkColor foreground; + GdkColor background; + GdkFont *font; + GdkFunction function; + GdkFill fill; + GdkPixmap *tile; + GdkPixmap *stipple; + GdkPixmap *clip_mask; + GdkSubwindowMode subwindow_mode; + gint ts_x_origin; + gint ts_y_origin; + gint clip_x_origin; + gint clip_y_origin; + gint graphics_exposures; + gint line_width; + GdkLineStyle line_style; + GdkCapStyle cap_style; + GdkJoinStyle join_style; +}; + +struct _GdkGC +{ + gint dummy_var; +}; + +struct _GdkPoint +{ + gint16 x; + gint16 y; +}; + +struct _GdkRectangle +{ + gint16 x; + gint16 y; + guint16 width; + guint16 height; +}; + +struct _GdkSegment +{ + gint16 x1; + gint16 y1; + gint16 x2; + gint16 y2; +}; + +struct _GdkFont +{ + GdkFontType type; + gint ascent; + gint descent; +}; + +struct _GdkCursor +{ + GdkCursorType type; +}; + +/* Types for XInput support */ + +struct _GdkDeviceInfo +{ + guint32 deviceid; + gchar *name; + GdkInputSource source; + GdkInputMode mode; + gint has_cursor; /* TRUE if the X pointer follows device motion */ + gint num_axes; + GdkAxisUse *axes; /* Specifies use for each axis */ +}; + +struct _GdkTimeCoord +{ + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; +}; + +struct _GdkEventAny +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; +}; + +struct _GdkEventExpose +{ + GdkEventType type; + GdkWindow *window; + GdkRectangle area; + gint count; /* If non-zero, how many more events follow. */ +}; + +struct _GdkEventMotion +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + gint16 is_hint; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventButton +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + guint button; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventKey +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + guint state; + guint keyval; +}; + +struct _GdkEventCrossing +{ + GdkEventType type; + GdkWindow *window; + GdkWindow *subwindow; + GdkNotifyType detail; +}; + +struct _GdkEventFocus +{ + GdkEventType type; + GdkWindow *window; + gint16 in; +}; + +struct _GdkEventConfigure +{ + GdkEventType type; + GdkWindow *window; + gint16 x, y; + gint16 width; + gint16 height; +}; + +struct _GdkEventProperty +{ + GdkEventType type; + GdkWindow *window; + GdkAtom atom; + guint32 time; + guint state; +}; + +struct _GdkEventSelection +{ + GdkEventType type; + GdkWindow *window; + GdkAtom selection; + GdkAtom target; + GdkAtom property; + guint32 requestor; + guint32 time; +}; + +/* This event type will be used pretty rarely. It only is important + for XInput aware programs that are drawing their own cursor */ + +struct _GdkEventProximity +{ + GdkEventType type; + GdkWindow *window; + guint32 time; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventDragRequest +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint willaccept:1; + guint delete_data:1; /* Do *not* delete if link is sent, only + if data is sent */ + guint senddata:1; + guint reserved:22; + } flags; + glong allflags; + } u; + guint8 isdrop; /* This gdk event can be generated by a couple of + X events - this lets the app know whether the + drop really occurred or we just set the data */ + + GdkPoint drop_coords; + gchar *data_type; +}; + +struct _GdkEventDragBegin +{ + GdkEventType type; + GdkWindow *window; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropEnter +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint extended_typelist:1; + guint reserved:26; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropLeave +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; +}; + +struct _GdkEventDropDataAvailable +{ + GdkEventType type; + GdkWindow *window; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint isdrop:1; + guint reserved:25; + } flags; + glong allflags; + } u; + gchar *data_type; /* MIME type */ + gulong data_numbytes; + gpointer data; +}; + +struct _GdkEventClient +{ + GdkEventType type; + GdkWindow *window; + GdkAtom message_type; + gushort data_format; + union { + char b[20]; + short s[10]; + long l[5]; + } data; +}; + +#ifndef _XLIB_H_ +#define XEvent void +#endif + +struct _GdkEventOther +{ + GdkEventType type; + GdkWindow *window; + XEvent *xevent; +}; + +union _GdkEvent +{ + GdkEventType type; + GdkEventAny any; + GdkEventExpose expose; + GdkEventMotion motion; + GdkEventButton button; + GdkEventKey key; + GdkEventCrossing crossing; + GdkEventFocus focus_change; + GdkEventConfigure configure; + GdkEventProperty property; + GdkEventSelection selection; + GdkEventProximity proximity; + GdkEventDragBegin dragbegin; + GdkEventDragRequest dragrequest; + GdkEventDropEnter dropenter; + GdkEventDropLeave dropleave; + GdkEventDropDataAvailable dropdataavailable; + GdkEventClient client; + GdkEventOther other; +}; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GDK_TYPES_H__ */ diff --git a/gdk/gdkvisual.c b/gdk/gdkvisual.c new file mode 100644 index 000000000..22acee6f1 --- /dev/null +++ b/gdk/gdkvisual.c @@ -0,0 +1,431 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_visual_add (GdkVisual *visual); +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); +static guint gdk_visual_hash (Visual *key); +static gint gdk_visual_compare (Visual *a, + Visual *b); + + +static GdkVisualPrivate *system_visual; +static GdkVisualPrivate *visuals; +static gint nvisuals; + +static gint available_depths[4]; +static gint navailable_depths; + +static GdkVisualType available_types[6]; +static gint navailable_types; + +static char* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +static GHashTable *visual_hash = NULL; + +void +gdk_visual_init () +{ + static gint possible_depths[5] = { 32, 24, 16, 15, 8 }; + static GdkVisualType possible_types[6] = + { + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_GRAY + }; + + static gint npossible_depths = 5; + static gint npossible_types = 6; + + XVisualInfo *visual_list; + XVisualInfo visual_template; + GdkVisualPrivate temp_visual; + Visual *default_xvisual; + int nxvisuals; + int i, j; + + visual_template.screen = gdk_screen; + visual_list = XGetVisualInfo (gdk_display, VisualScreenMask, &visual_template, &nxvisuals); + visuals = g_new (GdkVisualPrivate, nxvisuals); + + default_xvisual = DefaultVisual (gdk_display, gdk_screen); + + nvisuals = 0; + for (i = 0; i < nxvisuals; i++) + { + if (visual_list[i].depth >= 8) + { +#ifdef __cplusplus + switch (visual_list[i].c_class) +#else /* __cplusplus */ + switch (visual_list[i].class) +#endif /* __cplusplus */ + { + case StaticGray: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY; + break; + case GrayScale: + visuals[nvisuals].visual.type = GDK_VISUAL_GRAYSCALE; + break; + case StaticColor: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + break; + case PseudoColor: + visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR; + break; + case TrueColor: + visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR; + break; + case DirectColor: + visuals[nvisuals].visual.type = GDK_VISUAL_DIRECT_COLOR; + break; + } + + visuals[nvisuals].visual.depth = visual_list[i].depth; + visuals[nvisuals].visual.byte_order = + (ImageByteOrder(gdk_display) == LSBFirst) ? + GDK_LSB_FIRST : GDK_MSB_FIRST; + visuals[nvisuals].visual.red_mask = visual_list[i].red_mask; + visuals[nvisuals].visual.green_mask = visual_list[i].green_mask; + visuals[nvisuals].visual.blue_mask = visual_list[i].blue_mask; + visuals[nvisuals].visual.colormap_size = visual_list[i].colormap_size; + visuals[nvisuals].visual.bits_per_rgb = visual_list[i].bits_per_rgb; + visuals[nvisuals].xvisual = visual_list[i].visual; + + if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) || + (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask, + &visuals[nvisuals].visual.red_shift, + &visuals[nvisuals].visual.red_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask, + &visuals[nvisuals].visual.green_shift, + &visuals[nvisuals].visual.green_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask, + &visuals[nvisuals].visual.blue_shift, + &visuals[nvisuals].visual.blue_prec); + } + else + { + visuals[nvisuals].visual.red_mask = 0; + visuals[nvisuals].visual.red_shift = 0; + visuals[nvisuals].visual.red_prec = 0; + + visuals[nvisuals].visual.green_mask = 0; + visuals[nvisuals].visual.green_shift = 0; + visuals[nvisuals].visual.green_prec = 0; + + visuals[nvisuals].visual.blue_mask = 0; + visuals[nvisuals].visual.blue_shift = 0; + visuals[nvisuals].visual.blue_prec = 0; + } + + nvisuals += 1; + } + } + + XFree (visual_list); + + for (i = 0; i < nvisuals; i++) + { + for (j = i+1; j < nvisuals; j++) + { + if (visuals[j].visual.depth >= visuals[i].visual.depth) + { + if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8)) + { + if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) && + visuals[j].visual.type > visuals[i].visual.type) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + else if ((visuals[j].visual.depth > visuals[i].visual.depth) || + ((visuals[j].visual.depth == visuals[i].visual.depth) && + (visuals[j].visual.type > visuals[i].visual.type))) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + } + } + + for (i = 0; i < nvisuals; i++) + if (default_xvisual->visualid == visuals[i].xvisual->visualid) + { + system_visual = &visuals[i]; + break; + } + + if (gdk_debug_level >= 1) + for (i = 0; i < nvisuals; i++) + g_print ("visual: %s: %d\n", + visual_names[visuals[i].visual.type], + visuals[i].visual.depth); + + navailable_depths = 0; + for (i = 0; i < npossible_depths; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.depth == possible_depths[i]) + { + available_depths[navailable_depths++] = visuals[j].visual.depth; + break; + } + } + } + + if (navailable_depths == 0) + g_error ("unable to find a usable depth"); + + navailable_types = 0; + for (i = 0; i < npossible_types; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.type == possible_types[i]) + { + available_types[navailable_types++] = visuals[j].visual.type; + break; + } + } + } + + for (i = 0; i < nvisuals; i++) + gdk_visual_add ((GdkVisual*) &visuals[i]); + + if (npossible_types == 0) + g_error ("unable to find a usable visual type"); +} + +GdkVisual* +gdk_visual_ref (GdkVisual *visual) +{ + return visual; +} + +void +gdk_visual_unref (GdkVisual *visual) +{ + return; +} + +gint +gdk_visual_get_best_depth () +{ + return available_depths[0]; +} + +GdkVisualType +gdk_visual_get_best_type () +{ + return available_types[0]; +} + +GdkVisual* +gdk_visual_get_system () +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best () +{ + return ((GdkVisual*) &(visuals[0])); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (depth == visuals[i].visual.depth) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (visual_type == visuals[i].visual.type) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if ((depth == visuals[i].visual.depth) && + (visual_type == visuals[i].visual.type)) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = navailable_depths; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = navailable_types; + *visual_types = available_types; +} + +void +gdk_query_visuals (GdkVisual **visual_return, + gint *count) +{ + *count = nvisuals; + *visual_return = (GdkVisual*) visuals; +} + + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + GdkVisual *visual; + + if (!visual_hash) + return NULL; + + visual = g_hash_table_lookup (visual_hash, xvisual); + return visual; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + int i; + + for (i = 0; i < nvisuals; i++) + if (xvisualid == visuals[i].xvisual->visualid) + return (GdkVisual*) &visuals[i]; + + return NULL; +} + + +static void +gdk_visual_add (GdkVisual *visual) +{ + GdkVisualPrivate *private; + + if (!visual_hash) + visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash, + (GCompareFunc) gdk_visual_compare); + + private = (GdkVisualPrivate*) visual; + + g_hash_table_insert (visual_hash, private->xvisual, visual); +} + +static void +gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) + { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) + { + (*prec)++; + mask >>= 1; + } +} + +static guint +gdk_visual_hash (Visual *key) +{ + return key->visualid; +} + +static gint +gdk_visual_compare (Visual *a, + Visual *b) +{ + return (a->visualid == b->visualid); +} diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c new file mode 100644 index 000000000..aef1367d9 --- /dev/null +++ b/gdk/gdkwindow.c @@ -0,0 +1,1358 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include "gdk.h" +#include "gdkinput.h" +#include "gdkprivate.h" +#include + +int nevent_masks = 16; +int event_mask_table[18] = +{ + ExposureMask, + PointerMotionMask, + PointerMotionHintMask, + ButtonMotionMask, + Button1MotionMask, + Button2MotionMask, + Button3MotionMask, + ButtonPressMask | OwnerGrabButtonMask, + ButtonReleaseMask | OwnerGrabButtonMask, + KeyPressMask, + KeyReleaseMask, + EnterWindowMask, + LeaveWindowMask, + FocusChangeMask, + StructureNotifyMask, + PropertyChangeMask, + 0, /* PROXIMITY_IN */ + 0 /* PROXIMTY_OUT */ +}; + + +void +gdk_window_init () +{ + XWindowAttributes xattributes; + unsigned int width; + unsigned int height; + unsigned int border_width; + unsigned int depth; + int x, y; + + XGetGeometry (gdk_display, gdk_root_window, &gdk_root_window, + &x, &y, &width, &height, &border_width, &depth); + XGetWindowAttributes (gdk_display, gdk_root_window, &xattributes); + + gdk_root_parent.xdisplay = gdk_display; + gdk_root_parent.xwindow = gdk_root_window; + gdk_root_parent.window_type = GDK_WINDOW_ROOT; + gdk_root_parent.window.user_data = NULL; +} + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + GdkColormap *colormap; + Display *parent_display; + Window xparent; + Visual *xvisual; + XSetWindowAttributes xattributes; + long xattributes_mask; + XSizeHints size_hints; + XWMHints wm_hints; + XTextProperty text_property; + XClassHint *class_hint; + int x, y, depth; + unsigned int class; + char *title; + int i; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) &gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + xparent = parent_private->xwindow; + parent_display = parent_private->xdisplay; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + private->xdisplay = parent_display; + private->destroyed = FALSE; + private->resize_count = 0; + private->ref_count = 1; + xattributes_mask = 0; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + private->width = (attributes->width > 1) ? (attributes->width) : (1); + private->height = (attributes->height > 1) ? (attributes->height) : (1); + private->window_type = attributes->window_type; + private->extension_events = FALSE; + private->dnd_drag_data_type = None; + private->dnd_drag_data_typesavail = + private->dnd_drop_data_typesavail = NULL; + private->dnd_drop_enabled = private->dnd_drag_enabled = + private->dnd_drag_accepted = private->dnd_drag_datashow = + private->dnd_drop_data_numtypesavail = + private->dnd_drag_data_numtypesavail = 0; + private->dnd_drag_eventmask = private->dnd_drag_savedeventmask = 0; + + window->user_data = NULL; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_visual_get_system (); + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + xattributes.event_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (attributes->event_mask & (1 << (i + 1))) + xattributes.event_mask |= event_mask_table[i]; + } + + if (xattributes.event_mask) + xattributes_mask |= CWEventMask; + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + class = InputOutput; + depth = visual->depth; + + if (attributes_mask & GDK_WA_COLORMAP) + colormap = attributes->colormap; + else + colormap = gdk_colormap_get_system (); + + xattributes.background_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes.border_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes_mask |= CWBorderPixel | CWBackPixel; + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_CHILD: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + break; + + case GDK_WINDOW_DIALOG: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_TEMP: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + + xattributes.save_under = True; + xattributes.override_redirect = True; + xattributes.cursor = None; + xattributes_mask |= CWSaveUnder | CWOverrideRedirect; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_WINDOW_PIXMAP: + g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)"); + break; + } + } + else + { + depth = 1; + class = InputOnly; + colormap = NULL; + } + + private->xwindow = XCreateWindow (private->xdisplay, xparent, + x, y, private->width, private->height, + 0, depth, class, xvisual, + xattributes_mask, &xattributes); + gdk_xid_table_insert (&private->xwindow, window); + + switch (private->window_type) + { + case GDK_WINDOW_DIALOG: + XSetTransientForHint (private->xdisplay, private->xwindow, xparent); + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_TEMP: + XSetWMProtocols (private->xdisplay, private->xwindow, gdk_wm_window_protocols, 2); + break; + case GDK_WINDOW_CHILD: + if ((attributes->wclass == GDK_INPUT_OUTPUT) && + (colormap != gdk_colormap_get_system ()) && + (colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window)))) + { + g_print ("adding colormap window\n"); + gdk_window_add_colormap_windows (window); + } + break; + default: + break; + } + + size_hints.flags = PSize | PBaseSize; + size_hints.width = private->width; + size_hints.height = private->height; + size_hints.base_width = private->width; + size_hints.base_height = private->height; + + wm_hints.flags = InputHint | StateHint | WindowGroupHint; + wm_hints.window_group = gdk_leader_window; + wm_hints.input = True; + wm_hints.initial_state = NormalState; + + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); + XSetWMHints (private->xdisplay, private->xwindow, &wm_hints); + + if (attributes_mask & GDK_WA_TITLE) + title = attributes->title; + else + title = gdk_progname; + + if (XStringListToTextProperty (&title, 1, &text_property)) + { + XSetWMName (private->xdisplay, private->xwindow, &text_property); + XSetWMIconName (private->xdisplay, private->xwindow, &text_property); + XFree (text_property.value); + } + + if (attributes_mask & GDK_WA_WMCLASS) + { + class_hint = XAllocClassHint (); + class_hint->res_name = attributes->wmclass_name; + class_hint->res_class = attributes->wmclass_class; + XSetClassHint (private->xdisplay, private->xwindow, class_hint); + XFree (class_hint); + } + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + return window; +} + +GdkWindow * +gdk_window_foreign_new (guint32 anid) +{ + GdkWindow *window; + GdkWindowPrivate *private; + XWindowAttributes attrs; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + XGetWindowAttributes (gdk_display, anid, &attrs); + + private->parent = NULL; + private->xwindow = anid; + private->xdisplay = gdk_display; + private->x = attrs.x; + private->y = attrs.y; + private->width = attrs.width; + private->height = attrs.height; + private->resize_count = 0; + private->ref_count = 1; + if (anid == attrs.root) + private->window_type = GDK_WINDOW_ROOT; + else + private->window_type = GDK_WINDOW_TOPLEVEL; + /* the above is probably wrong, but it may not be worth the extra + X call to get it right */ + + private->destroyed = FALSE; + private->extension_events = 0; + + window->user_data = NULL; + + gdk_xid_table_insert (&private->xwindow, window); + + return window; +} + +void +gdk_window_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *temp_private; + GdkWindow *temp_window; + GList *children; + GList *tmp; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if(private->dnd_drag_data_numtypesavail > 0) + { + free(private->dnd_drag_data_typesavail); + private->dnd_drag_data_typesavail = NULL; + } + if(private->dnd_drop_data_numtypesavail > 0) + { + free(private->dnd_drop_data_typesavail); + private->dnd_drop_data_typesavail = NULL; + } + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + if (private->ref_count >= 1) + private->ref_count -= 1; + + if (!private->destroyed || (private->destroyed == 2)) + { + children = gdk_window_get_children (window); + tmp = children; + + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private && !temp_private->destroyed) + /* Removes some nice coredumps... /David */ + { + temp_private->destroyed = 2; + temp_private->ref_count += 1; + gdk_window_destroy (temp_window); + } + } + + g_list_free (children); + + if (!private->destroyed) + XDestroyWindow (private->xdisplay, private->xwindow); + private->destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_WINDOW_PIXMAP: + g_warning ("called gdk_window_destroy on a pixmap (use gdk_pixmap_destroy)"); + gdk_pixmap_destroy (window); + break; + } +} + +void +gdk_window_real_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (private->extension_events != 0) + gdk_input_window_destroy (window); + + if (private->ref_count == 0) + { + gdk_xid_table_remove (private->xwindow); + g_free (window); + } +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count += 1; + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_window_real_destroy (window); +} + +void +gdk_window_show (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + XRaiseWindow (private->xdisplay, private->xwindow); + XMapWindow (private->xdisplay, private->xwindow); + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + XUnmapWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XMoveWindow (private->xdisplay, private->xwindow, x, y); + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + } +} + +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed && + ((private->resize_count > 0) || + (private->width != (guint16) width) || + (private->height != (guint16) height))) + { + XResizeWindow (private->xdisplay, private->xwindow, width, height); + private->resize_count += 1; + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->width = width; + private->height = height; + } + } +} + +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + XMoveResizeWindow (private->xdisplay, private->xwindow, x, y, width, height); + + if (!private->destroyed && + (private->window_type == GDK_WINDOW_CHILD)) + { + private->x = x; + private->y = y; + private->width = width; + private->height = height; + } +} + +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *parent_private; + + g_return_if_fail (window != NULL); + + if (!new_parent) + new_parent = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + parent_private = (GdkWindowPrivate*) new_parent; + + XReparentWindow (window_private->xdisplay, + window_private->xwindow, + parent_private->xwindow, + x, y); +} + +void +gdk_window_clear (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + XClearWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, False); +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, True); +} + +void +gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height) +{ + GdkWindowPrivate *src_private; + GdkWindowPrivate *dest_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (gc != NULL); + + if (source_window == NULL) + source_window = window; + + src_private = (GdkWindowPrivate*) source_window; + dest_private = (GdkWindowPrivate*) window; + gc_private = (GdkGCPrivate*) gc; + + if (!src_private->destroyed && !dest_private->destroyed) + { + XCopyArea (dest_private->xdisplay, src_private->xwindow, dest_private->xwindow, + gc_private->xgc, + source_x, source_y, + width, height, + x, y); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XRaiseWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_lower (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XLowerWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_set_user_data (GdkWindow *window, + gpointer user_data) +{ + g_return_if_fail (window != NULL); + + window->user_data = user_data; +} + +void +gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags) +{ + GdkWindowPrivate *private; + XSizeHints size_hints; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + size_hints.flags = 0; + + if (flags & GDK_HINT_POS) + { + size_hints.flags |= PPosition; + size_hints.x = x; + size_hints.y = y; + } + + if (flags & GDK_HINT_MIN_SIZE) + { + size_hints.flags |= PMinSize; + size_hints.min_width = min_width; + size_hints.min_height = min_height; + } + + if (flags & GDK_HINT_MAX_SIZE) + { + size_hints.flags |= PMaxSize; + size_hints.max_width = max_width; + size_hints.max_height = max_height; + } + + if (flags) + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); +} + +void +gdk_window_set_title (GdkWindow *window, + const gchar *title) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XStoreName (private->xdisplay, private->xwindow, title); + XSetIconName (private->xdisplay, private->xwindow, title); +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XSetWindowBackground (private->xdisplay, private->xwindow, color->pixel); +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *window_private; + GdkPixmapPrivate *pixmap_private; + Pixmap xpixmap; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkPixmapPrivate*) pixmap; + + if (pixmap) + xpixmap = pixmap_private->xwindow; + else + xpixmap = None; + + if (parent_relative) + xpixmap = ParentRelative; + + XSetWindowBackgroundPixmap (window_private->xdisplay, window_private->xwindow, xpixmap); +} + +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowPrivate *window_private; + GdkCursorPrivate *cursor_private; + Cursor xcursor; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + XDefineCursor (window_private->xdisplay, window_private->xwindow, xcursor); +} + +void +gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap) +{ + GdkWindowPrivate *window_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (colormap != NULL); + + window_private = (GdkWindowPrivate*) window; + colormap_private = (GdkColormapPrivate*) colormap; + + XSetWindowColormap (window_private->xdisplay, + window_private->xwindow, + colormap_private->xcolormap); + + if (window_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (window); +} + +void +gdk_window_get_user_data (GdkWindow *window, + gpointer *data) +{ + g_return_if_fail (window != NULL); + + *data = window->user_data; +} + +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + GdkWindowPrivate *window_private; + Window root; + gint tx; + gint ty; + guint twidth; + guint theight; + guint tborder_width; + guint tdepth; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + + XGetGeometry (window_private->xdisplay, window_private->xwindow, + &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth); + + if (x) + *x = tx; + if (y) + *y = ty; + if (width) + *width = twidth; + if (height) + *height = theight; + if (depth) + *depth = tdepth; +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +void +gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (width) + *width = window_private->width; + if (height) + *height = window_private->height; +} + + +GdkVisual* +gdk_window_get_visual (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP)) + window_private = (GdkWindowPrivate*) window_private->parent; + + if (window_private) + { + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_visual_lookup (window_attributes.visual); + } + + return NULL; +} + +GdkColormap* +gdk_window_get_colormap (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_colormap_lookup (window_attributes.colormap); +} + +GdkWindowType +gdk_window_get_type (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, (GdkWindowType) -1); + + window_private = (GdkWindowPrivate*) window; + return window_private->window_type; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + gint return_val; + Window child; + gint tx, ty; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + + return_val = XTranslateCoordinates (private->xdisplay, + private->xwindow, + gdk_root_window, + 0, 0, &tx, &ty, + &child); + + if (x) + *x = tx; + if (y) + *y = ty; + + return return_val; +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowPrivate *private; + GdkWindow *return_val; + Window root; + Window child; + int rootx, rooty; + int winx, winy; + unsigned int xmask; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = (GdkWindowPrivate*) window; + + return_val = NULL; + if (XQueryPointer (private->xdisplay, private->xwindow, &root, &child, + &rootx, &rooty, &winx, &winy, &xmask)) + { + if (x) *x = winx; + if (y) *y = winy; + if (mask) *mask = xmask; + + if (child) + return_val = gdk_window_lookup (child); + } + + return return_val; +} + +GdkWindow* +gdk_window_get_parent (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + while (private->window_type == GDK_WINDOW_CHILD) + { + window = ((GdkWindowPrivate*) window)->parent; + private = (GdkWindowPrivate*) window; + } + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindow *child; + GList *children; + Window root; + Window parent; + Window *xchildren; + unsigned int nchildren; + unsigned int i; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + XQueryTree (private->xdisplay, private->xwindow, + &root, &parent, &xchildren, &nchildren); + + children = NULL; + + if (nchildren > 0) + { + for (i = 0; i < nchildren; i++) + { + child = gdk_window_lookup (xchildren[i]); + if (child) + children = g_list_prepend (children, child); + } + + XFree (xchildren); + } + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + XWindowAttributes attrs; + GdkEventMask event_mask; + int i; + + XGetWindowAttributes (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + &attrs); + + event_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (attrs.your_event_mask & event_mask_table[i]) + event_mask |= 1 << (i + 1); + } + + return event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + long xevent_mask; + int i; + + xevent_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + XSelectInput (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + xevent_mask); +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + GdkWindow *toplevel; + GdkWindowPrivate *toplevel_private; + GdkWindowPrivate *window_private; + Window *old_windows; + Window *new_windows; + int i, count; + + g_return_if_fail (window != NULL); + + toplevel = gdk_window_get_toplevel (window); + toplevel_private = (GdkWindowPrivate*) toplevel; + window_private = (GdkWindowPrivate*) window; + + if (!XGetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + &old_windows, &count)) + { + old_windows = NULL; + count = 0; + } + + for (i = 0; i < count; i++) + if (old_windows[i] == window_private->xwindow) + return; + + new_windows = g_new (Window, count + 1); + + for (i = 0; i < count; i++) + new_windows[i] = old_windows[i]; + new_windows[count] = window_private->xwindow; + + XSetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + new_windows, count + 1); + + g_free (new_windows); + if (old_windows) + XFree (old_windows); +} + +/* + * This needs the X11 shape extension. + * If not available, simply remove the call to + * XShapeCombineMask. Shaped windows will look + * ugly, but programs still work. Stefan Wille + */ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *pixmap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (mask != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkWindowPrivate*) mask; + + XShapeCombineMask (window_private->xdisplay, + window_private->xwindow, + ShapeBounding, + x, y, /* offset */ + (Pixmap)pixmap_private->xwindow, + ShapeSet); +} + +void +gdk_dnd_drag_addwindow (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + if (window_private->dnd_drag_enabled == 1 && gdk_dnd.drag_really == 0) + { + gdk_dnd.drag_numwindows++; + gdk_dnd.drag_startwindows = g_realloc (gdk_dnd.drag_startwindows, + gdk_dnd.drag_numwindows + * sizeof(GdkWindow *)); + gdk_dnd.drag_startwindows[gdk_dnd.drag_numwindows - 1] = window; + window_private->dnd_drag_accepted = 0; + } + else + g_warning ("dnd_really is 1 or drag is not enabled! can't addwindow\n"); +} + +void +gdk_window_dnd_drag_set (GdkWindow *window, + guint8 drag_enable, + gchar **typelist, + guint numtypes) +{ + GdkWindowPrivate *window_private; + int i, wasset = 0; + + g_return_if_fail (window != NULL); + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drag_enabled = drag_enable ? 1 : 0; + + if (drag_enable) + { + g_return_if_fail(typelist != NULL); + + if (window_private->dnd_drag_data_numtypesavail > 3) + wasset = 1; + window_private->dnd_drag_data_numtypesavail = numtypes; + + window_private->dnd_drag_data_typesavail = + g_realloc (window_private->dnd_drag_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + { + /* Allow blanket use of ALL to get anything... */ + if (strcmp (typelist[i], "ALL")) + window_private->dnd_drag_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + else + window_private->dnd_drag_data_typesavail[i] = None; + } + + /* + * set our extended type list if we need to + */ + if (numtypes > 3) + gdk_property_change(window, gdk_dnd.gdk_XdeTypelist, + XA_PRIMARY, 32, GDK_PROP_MODE_REPLACE, + (guchar *)(window_private->dnd_drag_data_typesavail + + (sizeof(GdkAtom) * 3)), + (numtypes - 3) * sizeof(GdkAtom)); + else if (wasset) + gdk_property_delete (window, gdk_dnd.gdk_XdeTypelist); + } + else + { + free (window_private->dnd_drag_data_typesavail); + window_private->dnd_drag_data_typesavail = NULL; + window_private->dnd_drag_data_numtypesavail = 0; + } +} + +void +gdk_window_dnd_drop_set (GdkWindow *window, + guint8 drop_enable, + gchar **typelist, + guint numtypes, + guint8 destructive_op) +{ + GdkWindowPrivate *window_private; + int i; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drop_enabled = drop_enable ? 1 : 0; + if (drop_enable) + { + g_return_if_fail(typelist != NULL); + + window_private->dnd_drop_data_numtypesavail = numtypes; + + window_private->dnd_drop_data_typesavail = + g_realloc (window_private->dnd_drop_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + window_private->dnd_drop_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + + window_private->dnd_drop_destructive_op = destructive_op; + } +} + +/* + * This is used to reply to a GDK_DRAG_REQUEST event + * (which may be generated by XdeRequest or a confirmed drop... + */ +void +gdk_window_dnd_data_set (GdkWindow *window, + GdkEvent *event, + gpointer data, + gulong data_numbytes) +{ + GdkWindowPrivate *window_private; + XEvent sev; + GdkEventDropDataAvailable tmp_ev; + gchar *tmp; + + g_return_if_fail (window != NULL); + g_return_if_fail (event != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (data_numbytes > 0); + g_return_if_fail (event->type == GDK_DRAG_REQUEST); + + g_free (event->dragrequest.data_type); + event->dragrequest.data_type = NULL; + + window_private = (GdkWindowPrivate *) window; + g_return_if_fail (window_private->dnd_drag_accepted != 0); + + /* We set the property on our window... */ + gdk_property_change (window, window_private->dnd_drag_data_type, + XA_PRIMARY, 8, GDK_PROP_MODE_REPLACE, data, + data_numbytes); + tmp = gdk_atom_name(window_private->dnd_drag_data_type); + g_print("DnD type %s on window %ld\n", tmp, window_private->xwindow); + g_free(tmp); + + /* + * Then we send the event to tell the receiving window that the + * drop has happened + */ + tmp_ev.u.allflags = 0; + tmp_ev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tmp_ev.u.flags.isdrop = event->dragrequest.isdrop; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.window = event->dragrequest.requestor; + sev.xclient.message_type = gdk_dnd.gdk_XdeDataAvailable; + sev.xclient.data.l[0] = window_private->xwindow; + sev.xclient.data.l[1] = tmp_ev.u.allflags; + sev.xclient.data.l[2] = window_private->dnd_drag_data_type; + + if (event->dragrequest.isdrop) + sev.xclient.data.l[3] = event->dragrequest.drop_coords.x + + (event->dragrequest.drop_coords.y << 16); + else + sev.xclient.data.l[3] = 0; + + sev.xclient.data.l[4] = 0; + + XSendEvent (gdk_display, event->dragrequest.requestor, False, + NoEventMask, &sev); +} diff --git a/gdk/gdkx.h b/gdk/gdkx.h new file mode 100644 index 000000000..cb8e33b44 --- /dev/null +++ b/gdk/gdkx.h @@ -0,0 +1,48 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_X_H__ +#define __GDK_X_H__ + +#include + + +#define GDK_ROOT_WINDOW() gdk_root_window +#define GDK_ROOT_PARENT() &gdk_root_parent +#define GDK_DISPLAY() gdk_display +#define GDK_WINDOW_XDISPLAY(win) (((GdkWindowPrivate*) win)->xdisplay) +#define GDK_WINDOW_XWINDOW(win) (((GdkWindowPrivate*) win)->xwindow) +#define GDK_IMAGE_XDISPLAY(image) (((GdkImagePrivate*) image)->xdisplay) +#define GDK_IMAGE_XIMAGE(image) (((GdkImagePrivate*) image)->ximage) +#define GDK_GC_XDISPLAY(gc) (((GdkGCPrivate*) gc)->xdisplay) +#define GDK_GC_XGC(gc) (((GdkGCPrivate*) gc)->xgc) +#define GDK_COLORMAP_XDISPLAY(cmap) (((GdkColormapPrivate*) cmap)->xdisplay) +#define GDK_COLORMAP_XCOLORMAP(cmap) (((GdkColormapPrivate*) cmap)->xcolormap) +#define GDK_VISUAL_XVISUAL(vis) (((GdkVisualPrivate*) vis)->xvisual) +#define GDK_FONT_XDISPLAY(font) (((GdkFontPrivate*) font)->xdisplay) +#define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont) + + +GdkVisual* gdkx_visual_get (VisualID xvisualid); +GdkColormap* gdkx_colormap_get (Colormap xcolormap); +/* Utility function in gdk.c - not sure where it belongs, but it's + needed in more than one place, so make it public */ +Window gdk_get_client_window (Display *dpy, + Window win); + + +#endif /* __GDK_X_H__ */ diff --git a/gdk/gdkxid.c b/gdk/gdkxid.c new file mode 100644 index 000000000..7ee6075c5 --- /dev/null +++ b/gdk/gdkxid.c @@ -0,0 +1,74 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gdkprivate.h" + + +static guint gdk_xid_hash (XID *xid); +static gint gdk_xid_compare (XID *a, + XID *b); + + +GHashTable *xid_ht = NULL; + + +void +gdk_xid_table_insert (XID *xid, + gpointer data) +{ + g_return_if_fail (xid != NULL); + + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_insert (xid_ht, xid, data); +} + +void +gdk_xid_table_remove (XID xid) +{ + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_remove (xid_ht, &xid); +} + +gpointer +gdk_xid_table_lookup (XID xid) +{ + gpointer data; + + data = g_hash_table_lookup (xid_ht, &xid); + + return data; +} + + +static guint +gdk_xid_hash (XID *xid) +{ + return *xid; +} + +static gint +gdk_xid_compare (XID *a, + XID *b) +{ + return (*a == *b); +} diff --git a/gdk/gxid.c b/gdk/gxid.c new file mode 100644 index 000000000..219c08bfe --- /dev/null +++ b/gdk/gxid.c @@ -0,0 +1,844 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gxid_proto.h" + +/* #define DEBUG_CLIENTS */ +/* #define DEBUG_EVENTS */ + +char *program_name; +Display *dpy; +Window root_window; /* default root window of dpy */ +int port = 0; /* port to listen on */ +int socket_fd = 0; /* file descriptor of socket */ +typedef struct GxidWindow_ GxidWindow; + +typedef struct GxidDevice_ GxidDevice; +struct GxidDevice_ { + XID id; + int exclusive; + int ispointer; + + XDevice *xdevice; + int motionnotify_type; + int changenotify_type; +}; + +struct GxidWindow_ { + Window xwindow; + /* Immediate child of root that is ancestor of window */ + Window root_child; + int num_devices; + GxidDevice **devices; +}; + +GxidDevice **devices = NULL; +int num_devices = 0; +GxidWindow **windows = NULL; +int num_windows = 0; + +void +handler(int signal) +{ + fprintf(stderr,"%s: dying on signal %d\n",program_name,signal); + if (socket_fd) + close(socket_fd); + exit(1); +} + +void +init_socket() +{ + struct sockaddr_in sin; + + socket_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if (socket_fd < 0) + { + fprintf (stderr, "%s: error getting socket\n", + program_name); + exit(1); + } + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = INADDR_ANY; + + if (bind(socket_fd,(struct sockaddr *)(&sin), + sizeof(struct sockaddr_in)) < 0) + { + fprintf (stderr,"%s: cannot bind to port %d\n", + program_name,port); + exit(1); + } + + if (listen(socket_fd,5) < 0) + { + fprintf (stderr,"%s: error listening on socket\n", + program_name); + exit(1); + }; +} + +#define NUM_EVENTC 2 +static void +enable_device(GxidDevice *dev) +{ + XEventClass xevc[NUM_EVENTC]; + int num_eventc = NUM_EVENTC; + int i,j; + + if (!dev->xdevice) + { + if (dev->ispointer) return; + + dev->xdevice = XOpenDevice(dpy, dev->id); + if (!dev->xdevice) return; + + DeviceMotionNotify (dev->xdevice, dev->motionnotify_type, + xevc[0]); + ChangeDeviceNotify (dev->xdevice, dev->changenotify_type, + xevc[1]); + + /* compress out zero event classes */ + for (i=0,j=0;iispointer) + old_pointer = devices[i]; + else + if (!new_pointer && !devices[i]->exclusive) + new_pointer = devices[i]; + } + + if (!old_pointer || !new_pointer) + return 0; + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Switching core from %ld to %ld\n", + old_pointer->id,new_pointer->id); +#endif + result = XChangePointerDevice(dpy,new_pointer->xdevice, 0, 1); + if (result != Success) + { + fprintf(stderr,"gxid: Error %d switching core from %ld to %ld\n", + result, old_pointer->id, new_pointer->id); + } + else + { + new_pointer->ispointer = 1; + old_pointer->ispointer = 0; + if (!old_pointer->xdevice) + enable_device(old_pointer); + } + + return 1; +} + +void +disable_device(GxidDevice *dev) +{ + if (dev->xdevice) + { + if (dev->ispointer) + return; + XCloseDevice(dpy,dev->xdevice); + dev->xdevice = 0; + } +} + +GxidDevice * +init_device(XDeviceInfo *xdevice) +{ + GxidDevice *dev = (GxidDevice *)malloc(sizeof(GxidDevice)); + XAnyClassPtr class; + int num_axes, i; + + dev->id = xdevice->id; + dev->exclusive = 0; + dev->xdevice = NULL; + + dev->ispointer = (xdevice->use == IsXPointer); + + /* step through the classes */ + + num_axes = 0; + class = xdevice->inputclassinfo; + for (i=0;inum_classes;i++) + { + if (class->class == ValuatorClass) + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + num_axes = xvi->num_axes; + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + + /* return NULL if insufficient axes */ + if (num_axes < 2) + { + free((void *)dev); + return NULL; + } + + if (!dev->ispointer) + enable_device(dev); + return dev; +} + +void +init_xinput() +{ + char **extensions; + XDeviceInfo *xdevices; + int num_xdevices; + int num_extensions; + int i; + + extensions = XListExtensions(dpy, &num_extensions); + for (i = 0; i < num_extensions && + (strcmp(extensions[i], "XInputExtension") != 0); i++); + XFreeExtensionList(extensions); + if (i == num_extensions) /* XInput extension not found */ + { + fprintf(stderr,"XInput extension not found\n"); + exit(1); + } + + xdevices = XListInputDevices(dpy, &num_xdevices); + devices = (GxidDevice **)malloc(num_xdevices * sizeof(GxidDevice *)); + + num_devices = 0; + for(i=0; idevice); + XID winid = ntohl(msg->window); + int exclusive = ntohl(msg->exclusive); + GxidDevice *device = NULL; + GxidWindow *window = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld claimed (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;iid == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + if (device->exclusive) + { + /* already in use */ + fprintf(stderr, + "%s: Device %ld already claimed in exclusive mode\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + if (exclusive) + { + for (i=0;inum_devices;j++) + if (windows[i]->devices[j]->id == devid) + { + /* already in use */ + fprintf(stderr, + "%s: Can't establish exclusive use of device %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + } + if (device->ispointer) + if (!switch_core_pointer()) + { + fprintf(stderr, + "%s: Can't free up core pointer %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + device->exclusive = 1; + disable_device(device); + XSelectInput(dpy,winid,StructureNotifyMask); + } + else /* !exclusive */ + { + /* FIXME: this is a bit improper. We probably should do this only + when a window is first claimed. But we might be fooled if + an old client died without releasing it's windows. So until + we look for client-window closings, do it here + + (We do look for closings now...) + */ + + XSelectInput(dpy,winid,EnterWindowMask|StructureNotifyMask); + } + + for (i=0;ixwindow == winid) + { + window = windows[i]; + break; + } + } + + /* Create window structure if no devices have been previously + claimed on it */ + if (!window) + { + num_windows++; + windows = (GxidWindow **)realloc(windows, + sizeof(GxidWindow*)*num_windows); + window = (GxidWindow *)malloc(sizeof(GxidWindow)); + windows[num_windows-1] = window; + + window->xwindow = winid; + window->root_child = gxi_find_root_child(dpy,winid); + window->num_devices = 0; + window->devices = 0; + } + + + for (i=0;inum_devices;i++) + { + if (window->devices[i] == device) + return GXID_RETURN_OK; + } + + window->num_devices++; + window->devices = (GxidDevice **)realloc(window->devices, + sizeof(GxidDevice*)*num_devices); + /* we need add the device to the window */ + window->devices[i] = device; + + return GXID_RETURN_OK; +} + +int +handle_release_device(GxidReleaseDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + + GxidDevice *device = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;iid == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + for (i=0;ixwindow == winid) + for (j=0;jnum_devices;j++) + if (w->devices[j]->id == devid) + { + if (jnum_devices-1) + w->devices[j] = w->devices[w->num_devices-1]; + w->num_devices--; + + if (w->num_devices == 0) + { + if (iexclusive) + { + device->exclusive = 0; + enable_device(device); + } + return GXID_RETURN_OK; + } + } + + /* device/window combination not found */ + fprintf(stderr, + "%s: Device %ld not claimed for window 0x%lx\n", + program_name,devid,winid); + return GXID_RETURN_ERROR; +} + +void +handle_connection() +{ + GxidMessage msg; + GxidU32 type; + int length; + GxidI32 retval; + + int conn_fd; + struct sockaddr_in sin; + int sin_length; + int count; + + sin_length = sizeof(struct sockaddr_in); + conn_fd = accept(socket_fd,(struct sockaddr *)&sin,&sin_length); + if (conn_fd < 0) + { + fprintf(stderr,"%s: Error accepting connection\n", + program_name); + exit(1); + } + + /* read type and length of message */ + + count = read(conn_fd,(char *)&msg,2*sizeof(GxidU32)); + if (count != 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message header\n", + program_name); + close(conn_fd); + return; + } + type = ntohl(msg.any.type); + length = ntohl(msg.any.length); + + /* read rest of message */ + + if (length > sizeof(GxidMessage)) + { + fprintf(stderr,"%s: Bad message length\n", + program_name); + close(conn_fd); + return; + } + + count = read(conn_fd,2*sizeof(GxidU32) + (char *)&msg, + length - 2*sizeof(GxidU32)); + if (count != length - 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message body\n", + program_name); + close(conn_fd); + return; + } + + switch (type) + { + case GXID_CLAIM_DEVICE: + retval = handle_claim_device((GxidClaimDevice *)&msg); + break; + case GXID_RELEASE_DEVICE: + retval = handle_release_device((GxidReleaseDevice *)&msg); + break; + default: + fprintf(stderr,"%s: Unknown message type: %ld (ignoring)\n", + program_name,type); + close(conn_fd); + return; + } + + count = write(conn_fd,&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"%s: Error writing return code\n", + program_name); + } + + close(conn_fd); +} + +void +handle_motion_notify(XDeviceMotionEvent *event) +{ + int i,j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + Window w, root, child; + int root_x, root_y, x, y, mask; + + for (j=0;jispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + + if (new_device && !new_device->exclusive && !new_device->ispointer) + { + /* make sure we aren't stealing the pointer back from a slow + client */ + child = root_window; + do + { + w = child; + /* FIXME: this fails disasterously if child vanishes between + calls. (Which is prone to happening since we get events + on root just as the client exits) */ + + XQueryPointer(dpy,w,&root,&child,&root_x,&root_y, + &x,&y,&mask); + } + while (child != None); + + for (i=0;ixwindow == w) + for (j=0;jnum_devices;j++) + if (windows[i]->devices[j] == new_device) + return; + + /* FIXME: do something smarter with axes */ + XChangePointerDevice(dpy,new_device->xdevice, 0, 1); + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_change_notify(XChangeDeviceNotifyEvent *event) +{ + int j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + + + for (j=0;jispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: ChangeNotify event; old = %ld; new = %ld\n", + old_device->id, new_device->id); +#endif + + if (old_device != new_device) + { + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_enter_notify(XEnterWindowEvent *event, GxidWindow *window) +{ + int i; + GxidDevice *old_pointer = NULL; + for (i=0;iispointer) + { + old_pointer = devices[i]; + break; + } + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Enter event; oldpointer = %ld\n", + old_pointer->id); +#endif + + if (old_pointer) + for (i=0;inum_devices;i++) + { + if (window->devices[i] == old_pointer) + { + switch_core_pointer(); + break; + } + } +} + +void +handle_destroy_notify(XDestroyWindowEvent *event) +{ + int i,j; + + for (i=0;ixwindow == event->window) + { + GxidWindow *w = windows[i]; + + for (j=0;jnum_devices;j++) + { +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released on destruction of window 0x%lx.\n", + w->devices[j]->id,w->xwindow); +#endif + + if (w->devices[j]->exclusive) + { + w->devices[j]->exclusive = 0; + enable_device(devices[j]); + } + } + + if (idevices) + free((void *)w->devices); + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + + return; + } +} + +void +handle_xevent() +{ + int i; + XEvent event; + + XNextEvent (dpy, &event); + +#ifdef DEBUG_EVENTS + fprintf(stderr,"Event - type = %d; window = 0x%lx\n", + event.type,event.xany.window); +#endif + + if (event.type == ConfigureNotify) + { +#ifdef DEBUG_EVENTS + XConfigureEvent *xce = (XConfigureEvent *)&event; + fprintf(stderr," configureNotify: window = 0x%lx\n",xce->window); +#endif + } + else if (event.type == EnterNotify) + { + /* pointer entered a claimed window */ + for (i=0;ixwindow) + handle_enter_notify((XEnterWindowEvent *)&event,windows[i]); + } + } + else if (event.type == DestroyNotify) + { + /* A claimed window was destroyed */ + for (i=0;ixwindow) + handle_destroy_notify((XDestroyWindowEvent *)&event); + } + } + else + for (i=0;imotionnotify_type) + { + handle_motion_notify((XDeviceMotionEvent *)&event); + break; + } + else if (event.type == devices[i]->changenotify_type) + { + handle_change_notify((XChangeDeviceNotifyEvent *)&event); + break; + } + } +} + +void +usage() +{ + fprintf(stderr,"Usage: %s [-d display] [-p --gxid-port port]\n", + program_name); + exit(1); +} + +int +main(int argc, char **argv) +{ + int i; + char *display_name = NULL; + fd_set readfds; + + program_name = argv[0]; + + for (i=1;i= argc) usage(); + display_name = argv[i]; + } + else if (!strcmp(argv[i],"--gxid-port") || + !strcmp(argv[i],"-p")) + { + if (++i >= argc) usage(); + port = atoi(argv[i]); + break; + } + else + usage(); + } + + if (!port) + { + char *t = getenv("GXID_PORT"); + if (t) + port = atoi(t); + else + port = 6951; + } + /* set up a signal handler so we can clean up if killed */ + + signal(SIGTERM,handler); + signal(SIGINT,handler); + + /* initialize the X connection */ + + dpy = XOpenDisplay (display_name); + if (!dpy) + { + fprintf (stderr, "%s: unable to open display '%s'\n", + program_name, XDisplayName (display_name)); + exit (1); + } + + root_window = DefaultRootWindow(dpy); + + /* We'll want to do this in the future if we are to support + gxid monitoring visibility information for clients */ +#if 0 + XSelectInput(dpy,root_window,SubstructureNotifyMask); +#endif + init_xinput(); + + /* set up our server connection */ + + init_socket(); + + /* main loop */ + + if (XPending(dpy)) /* this seems necessary to get things + in sync */ + handle_xevent(); + while (1) + { + + FD_ZERO(&readfds); + FD_SET(ConnectionNumber(dpy),&readfds); + FD_SET(socket_fd,&readfds); + + if (select(8*sizeof(readfds),&readfds, + (fd_set *)0,(fd_set *)0, (struct timeval *)0) < 0) + { + fprintf(stderr,"Error in select\n"); + exit(1); + } + + if (FD_ISSET(socket_fd,&readfds)) + handle_connection(socket_fd); + + while (XPending(dpy)) + handle_xevent(); + } + + XCloseDisplay (dpy); + exit (0); +} diff --git a/gdk/gxid_lib.c b/gdk/gxid_lib.c new file mode 100644 index 000000000..357b76451 --- /dev/null +++ b/gdk/gxid_lib.c @@ -0,0 +1,116 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor +*/ + +#include "../config.h" + +#ifdef XINPUT_GXI + +#include +#include +#include +#include +#include +#include +#include + +#include "gxid_lib.h" + +/* handles mechanics of communicating with a client */ +static int +gxid_send_message(char *host, int port, GxidMessage *msg) +{ + int socket_fd; + struct sockaddr_in sin; + int count; + GxidI32 retval; + struct hostent *he; + + if (!port) port = 6951; + + if (!host || strcmp(host,"localhost") ) + { + /* looking it up as localhost can be _SLOW_ on ppp systems */ + /* FIXME: Could localhost be anything other than loopback? */ + host = "127.0.0.1"; + } + + he = gethostbyname(host); + if (!he) + { + fprintf(stderr,"gxid_lib: error looking up %s\n",host); + return GXID_RETURN_ERROR; + } + + sin.sin_family = he->h_addrtype; + sin.sin_port = htons(port); + memcpy(&sin.sin_addr,he->h_addr_list[0],he->h_length); + + socket_fd = socket(AF_INET,SOCK_STREAM,0); + if (socket_fd < 0) + { + fprintf(stderr,"gxid_lib: can't get socket"); + return GXID_RETURN_ERROR; + } + + if (connect(socket_fd, (struct sockaddr *)&sin, + sizeof sin) < 0) + { + fprintf(stderr,"gxid_lib: can't connect to %s:%d\n",host,port); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + count = write(socket_fd,(char *)msg,ntohl(msg->any.length)); + if (count != ntohl(msg->any.length)) + { + fprintf(stderr,"gxid_lib: error writing"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + /* now read the return code */ + count = read(socket_fd,(char *)&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"gxid_lib: error reading return code"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + close (socket_fd); + return ntohl(retval); +} + +/* claim a device. If exclusive, device is claimed exclusively */ +int +gxid_claim_device(char *host, int port, GxidU32 device, GxidU32 window, + int exclusive) +{ + GxidClaimDevice msg; + msg.type = htonl(GXID_CLAIM_DEVICE); + msg.length = htonl(sizeof(GxidClaimDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + msg.exclusive = htonl(exclusive); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +/* release a device/window pair */ +int +gxid_release_device(char *host, int port, GxidU32 device, GxidU32 window) +{ + GxidReleaseDevice msg; + msg.type = htonl(GXID_RELEASE_DEVICE); + msg.length = htonl(sizeof(GxidReleaseDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +#endif /* XINPUT_GXI */ + diff --git a/gdk/gxid_lib.h b/gdk/gxid_lib.h new file mode 100644 index 000000000..6a7103bbe --- /dev/null +++ b/gdk/gxid_lib.h @@ -0,0 +1,6 @@ +#include "gxid_proto.h" + +int gxid_claim_device(char *host, int port, + GxidU32 device, GxidU32 window, int exclusive); +int gxid_release_device(char *host, int port, GxidU32 device, + GxidU32 window); diff --git a/gdk/gxid_proto.h b/gdk/gxid_proto.h new file mode 100644 index 000000000..24959b806 --- /dev/null +++ b/gdk/gxid_proto.h @@ -0,0 +1,39 @@ +#define GXID_CLAIM_DEVICE 1 +#define GXID_RELEASE_DEVICE 2 + +#define GXID_RETURN_OK 0 +#define GXID_RETURN_ERROR -1 + +typedef struct GxidClaimDevice_ GxidClaimDevice; +typedef struct GxidReleaseDevice_ GxidReleaseDevice; +typedef struct GxidMessageAny_ GxidMessageAny; +typedef union GxidMessage_ GxidMessage; + +typedef unsigned long GxidU32; +typedef long GxidI32; + +struct GxidClaimDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; + GxidU32 exclusive; +}; + +struct GxidReleaseDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; +}; + +struct GxidMessageAny_ { + GxidU32 type; + GxidU32 length; +}; + +union GxidMessage_ { + GxidMessageAny any; + GxidClaimDevice claim; + GxidReleaseDevice release; +}; diff --git a/gdk/makecursors b/gdk/makecursors new file mode 100755 index 000000000..664776a2b --- /dev/null +++ b/gdk/makecursors @@ -0,0 +1,5 @@ +#!/bin/sh + +sed -f makecursors.sed $1 > .makecursors.tmp +awk '{printf "%s = %s,\n", $1, $2}' .makecursors.tmp +rm .makecursors.tmp diff --git a/gdk/makecursors.sed b/gdk/makecursors.sed new file mode 100644 index 000000000..107d13f8d --- /dev/null +++ b/gdk/makecursors.sed @@ -0,0 +1,3 @@ +/define/ ! d +/define/ y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ +s/^.*XC_/GDK_/g diff --git a/gdk/makekeysyms b/gdk/makekeysyms new file mode 100755 index 000000000..40b49d4e8 --- /dev/null +++ b/gdk/makekeysyms @@ -0,0 +1,5 @@ +#!/bin/sh + +sed -f makekeysyms.sed $1 > .makekeysms.tmp +awk '{printf "#define %s %s\n", $1, $2}' .makekeysms.tmp +rm .makekeysms.tmp diff --git a/gdk/makekeysyms.sed b/gdk/makekeysyms.sed new file mode 100644 index 000000000..bafbf76c0 --- /dev/null +++ b/gdk/makekeysyms.sed @@ -0,0 +1,3 @@ +/define/ ! d +s/^.*XK_/GDK_/g +s/0X/0x/g diff --git a/gdk/x11/gdkcolor-x11.c b/gdk/x11/gdkcolor-x11.c new file mode 100644 index 000000000..5e66f089b --- /dev/null +++ b/gdk/x11/gdkcolor-x11.c @@ -0,0 +1,718 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gdk.h" +#include "gdkprivate.h" + + +static gint gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available); +static void gdk_colormap_add (GdkColormap *cmap); +static void gdk_colormap_remove (GdkColormap *cmap); +static guint gdk_colormap_hash (Colormap *cmap); +static gint gdk_colormap_cmp (Colormap *a, + Colormap *b); + +static GHashTable *colormap_hash = NULL; + + +GdkColormap* +gdk_colormap_new (GdkVisual *visual, + gint private_cmap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + Visual *xvisual; + XColor default_colors[256]; + int size; + int i; + + g_return_val_if_fail (visual != NULL, NULL); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->visual = visual; + private->next_color = 0; + private->ref_count = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + private->private_val = private_cmap; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, (private_cmap) ? (AllocAll) : (AllocNone)); + + if (private_cmap) + { + for (i = 0; i < 256; i++) + default_colors[i].pixel = i; + + XQueryColors (private->xdisplay, + DefaultColormap (private->xdisplay, gdk_screen), + default_colors, visual->colormap_size); + + for (i = 0; i < visual->colormap_size; i++) + { + colormap->colors[i].pixel = default_colors[i].pixel; + colormap->colors[i].red = default_colors[i].red; + colormap->colors[i].green = default_colors[i].green; + colormap->colors[i].blue = default_colors[i].blue; + } + + gdk_colormap_change (colormap, visual->colormap_size); + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + private->private_val = TRUE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocAll); + + size = 1 << visual->red_prec; + for (i = 0; i < size; i++) + colormap->colors[i].red = i * 65535 / (size - 1); + + size = 1 << visual->green_prec; + for (i = 0; i < size; i++) + colormap->colors[i].green = i * 65535 / (size - 1); + + size = 1 << visual->blue_prec; + for (i = 0; i < size; i++) + colormap->colors[i].blue = i * 65535 / (size - 1); + + gdk_colormap_change (colormap, visual->colormap_size); + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + private->private_val = FALSE; + private->xcolormap = XCreateColormap (private->xdisplay, gdk_root_window, + xvisual, AllocNone); + break; + } + + gdk_colormap_add (colormap); + + return colormap; +} + +void +gdk_colormap_real_destroy (GdkColormap *colormap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate*) colormap; + + g_return_if_fail (colormap != NULL); + + if (private->ref_count > 0) + return; + + gdk_colormap_remove (colormap); + XFreeColormap (private->xdisplay, private->xcolormap); + g_free (colormap); +} + +void +gdk_colormap_destroy (GdkColormap *colormap) +{ + gdk_colormap_unref (colormap); +} + +GdkColormap* +gdk_colormap_ref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_val_if_fail (cmap != NULL, NULL); + + private->ref_count += 1; + return cmap; +} + +void +gdk_colormap_unref (GdkColormap *cmap) +{ + GdkColormapPrivate *private = (GdkColormapPrivate *)cmap; + g_return_if_fail (cmap != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_colormap_real_destroy (cmap); +} + +GdkColormap* +gdk_colormap_get_system (void) +{ + static GdkColormap *colormap = NULL; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + if (!colormap) + { + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = DefaultColormap (gdk_display, gdk_screen); + private->visual = gdk_visual_get_system (); + private->private_val = FALSE; + private->next_color = 0; + private->ref_count = 1; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + } + + return colormap; +} + +gint +gdk_colormap_get_system_size (void) +{ + return DisplayCells (gdk_display, gdk_screen); +} + +void +gdk_colormap_change (GdkColormap *colormap, + gint ncolors) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor palette[256]; + gint shift; + int max_colors; + int size; + int i; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + for (i = 0; i < ncolors; i++) + { + palette[i].pixel = colormap->colors[i].pixel; + palette[i].red = colormap->colors[i].red; + palette[i].green = colormap->colors[i].green; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoRed | DoGreen | DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, ncolors); + private->next_color = MAX (private->next_color, ncolors); + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + + shift = visual->red_shift; + max_colors = 1 << visual->red_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].red = colormap->colors[i].red; + palette[i].flags = DoRed; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->green_shift; + max_colors = 1 << visual->green_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].green = colormap->colors[i].green; + palette[i].flags = DoGreen; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + + shift = visual->blue_shift; + max_colors = 1 << visual->blue_prec; + size = (ncolors < max_colors) ? (ncolors) : (max_colors); + + for (i = 0; i < size; i++) + { + palette[i].pixel = i << shift; + palette[i].blue = colormap->colors[i].blue; + palette[i].flags = DoBlue; + } + + XStoreColors (private->xdisplay, private->xcolormap, palette, size); + break; + + default: + break; + } +} + +void +gdk_colors_store (GdkColormap *colormap, + GdkColor *colors, + gint ncolors) +{ + gint i; + + for (i = 0; i < ncolors; i++) + { + colormap->colors[i].pixel = colors[i].pixel; + colormap->colors[i].red = colors[i].red; + colormap->colors[i].green = colors[i].green; + colormap->colors[i].blue = colors[i].blue; + } + + gdk_colormap_change (colormap, ncolors); +} + +gint +gdk_colors_alloc (GdkColormap *colormap, + gint contiguous, + gulong *planes, + gint nplanes, + gulong *pixels, + gint npixels) +{ + GdkColormapPrivate *private; + gint return_val; + + g_return_val_if_fail (colormap != NULL, 0); + + private = (GdkColormapPrivate*) colormap; + + return_val = XAllocColorCells (private->xdisplay, private->xcolormap, + contiguous, planes, nplanes, pixels, npixels); + + return return_val; +} + +void +gdk_colors_free (GdkColormap *colormap, + gulong *pixels, + gint npixels, + gulong planes) +{ + GdkColormapPrivate *private; + + g_return_if_fail (colormap != NULL); + + private = (GdkColormapPrivate*) colormap; + + XFreeColors (private->xdisplay, private->xcolormap, + pixels, npixels, planes); +} + +gint +gdk_color_white (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = WhitePixel (gdk_display, gdk_screen); + color->red = 65535; + color->green = 65535; + color->blue = 65535; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_black (GdkColormap *colormap, + GdkColor *color) +{ + gint return_val; + + g_return_val_if_fail (colormap != NULL, FALSE); + + if (color) + { + color->pixel = BlackPixel (gdk_display, gdk_screen); + color->red = 0; + color->green = 0; + color->blue = 0; + + return_val = gdk_color_alloc (colormap, color); + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_parse (const gchar *spec, + GdkColor *color) +{ + Colormap xcolormap; + XColor xcolor; + gint return_val; + + g_return_val_if_fail (spec != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolormap = DefaultColormap (gdk_display, gdk_screen); + + if (XParseColor (gdk_display, xcolormap, spec, &xcolor)) + { + return_val = TRUE; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + } + else + return_val = FALSE; + + return return_val; +} + +gint +gdk_color_alloc (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + GdkVisual *visual; + XColor xcolor; + gchar available[256]; + gint available_init; + gint return_val; + gint i, index; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.pixel = color->pixel; + xcolor.flags = DoRed | DoGreen | DoBlue; + + return_val = FALSE; + private = (GdkColormapPrivate*) colormap; + + switch (private->visual->type) + { + case GDK_VISUAL_GRAYSCALE: + case GDK_VISUAL_PSEUDO_COLOR: + if (private->private_val) + { + if (private->next_color > 255) + { + for (i = 0; i < 256; i++) + available[i] = TRUE; + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + *color = colormap->colors[index]; + return_val = TRUE; + } + else + { + return_val = FALSE; + } + } + else + { + xcolor.pixel = 255 - private->next_color; + color->pixel = xcolor.pixel; + private->next_color += 1; + + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + return_val = TRUE; + } + } + else + { + available_init = 1; + + while (1) + { + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + color->red = xcolor.red; + color->green = xcolor.green; + color->blue = xcolor.blue; + + colormap->colors[color->pixel] = *color; + + return_val = TRUE; + break; + } + else + { + if (available_init) + { + available_init = 0; + for (i = 0; i < 256; i++) + available[i] = TRUE; + } + + index = gdk_colormap_match_color (colormap, color, available); + if (index != -1) + { + available[index] = FALSE; + xcolor.red = colormap->colors[index].red; + xcolor.green = colormap->colors[index].green; + xcolor.blue = colormap->colors[index].blue; + } + else + { + return_val = FALSE; + break; + } + } + } + } + break; + + case GDK_VISUAL_DIRECT_COLOR: + visual = private->visual; + xcolor.pixel = (((xcolor.red >> (16 - visual->red_prec)) << visual->red_shift) + + ((xcolor.green >> (16 - visual->green_prec)) << visual->green_shift) + + ((xcolor.blue >> (16 - visual->blue_prec)) << visual->blue_shift)); + color->pixel = xcolor.pixel; + return_val = TRUE; + break; + + case GDK_VISUAL_STATIC_GRAY: + case GDK_VISUAL_STATIC_COLOR: + case GDK_VISUAL_TRUE_COLOR: + if (XAllocColor (private->xdisplay, private->xcolormap, &xcolor)) + { + color->pixel = xcolor.pixel; + return_val = TRUE; + } + else + return_val = FALSE; + break; + } + + return return_val; +} + +gint +gdk_color_change (GdkColormap *colormap, + GdkColor *color) +{ + GdkColormapPrivate *private; + XColor xcolor; + + g_return_val_if_fail (colormap != NULL, FALSE); + g_return_val_if_fail (color != NULL, FALSE); + + xcolor.pixel = color->pixel; + xcolor.red = color->red; + xcolor.green = color->green; + xcolor.blue = color->blue; + xcolor.flags = DoRed | DoGreen | DoBlue; + + private = (GdkColormapPrivate*) colormap; + XStoreColor (private->xdisplay, private->xcolormap, &xcolor); + + return TRUE; +} + +gint +gdk_color_equal (GdkColor *colora, + GdkColor *colorb) +{ + g_return_val_if_fail (colora != NULL, FALSE); + g_return_val_if_fail (colorb != NULL, FALSE); + + return ((colora->red == colorb->red) && + (colora->green == colorb->green) && + (colora->blue == colorb->blue)); +} + +GdkColormap* +gdkx_colormap_get (Colormap xcolormap) +{ + GdkColormap *colormap; + GdkColormapPrivate *private; + XColor xpalette[256]; + gint i; + + colormap = gdk_colormap_lookup (xcolormap); + if (colormap) + return colormap; + + if (xcolormap == DefaultColormap (gdk_display, gdk_screen)) + return gdk_colormap_get_system (); + + private = g_new (GdkColormapPrivate, 1); + colormap = (GdkColormap*) private; + + private->xdisplay = gdk_display; + private->xcolormap = xcolormap; + private->visual = NULL; + private->private_val = TRUE; + private->next_color = 0; + + for (i = 0; i < 256; i++) + { + xpalette[i].pixel = i; + xpalette[i].red = 0; + xpalette[i].green = 0; + xpalette[i].blue = 0; + } + + XQueryColors (gdk_display, private->xcolormap, xpalette, 256); + + for (i = 0; i < 256; i++) + { + colormap->colors[i].pixel = xpalette[i].pixel; + colormap->colors[i].red = xpalette[i].red; + colormap->colors[i].green = xpalette[i].green; + colormap->colors[i].blue = xpalette[i].blue; + } + + gdk_colormap_add (colormap); + + return colormap; +} + + +static gint +gdk_colormap_match_color (GdkColormap *cmap, + GdkColor *color, + const gchar *available) +{ + GdkColor *colors; + guint sum, max; + gint rdiff, gdiff, bdiff; + gint i, index; + + g_return_val_if_fail (cmap != NULL, 0); + g_return_val_if_fail (color != NULL, 0); + + colors = cmap->colors; + max = 3 * (65536); + index = -1; + + for (i = 0; i < 256; i++) + { + if ((!available) || (available && available[i])) + { + rdiff = (color->red - colors[i].red); + gdiff = (color->green - colors[i].green); + bdiff = (color->blue - colors[i].blue); + + sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); + + if (sum < max) + { + index = i; + max = sum; + } + } + } + + return index; +} + + +GdkColormap* +gdk_colormap_lookup (Colormap xcolormap) +{ + GdkColormap *cmap; + + if (!colormap_hash) + return NULL; + + cmap = g_hash_table_lookup (colormap_hash, &xcolormap); + return cmap; +} + +static void +gdk_colormap_add (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_insert (colormap_hash, &private->xcolormap, cmap); +} + +static void +gdk_colormap_remove (GdkColormap *cmap) +{ + GdkColormapPrivate *private; + + if (!colormap_hash) + colormap_hash = g_hash_table_new ((GHashFunc) gdk_colormap_hash, + (GCompareFunc) gdk_colormap_cmp); + + private = (GdkColormapPrivate*) cmap; + + g_hash_table_remove (colormap_hash, &private->xcolormap); +} + +static guint +gdk_colormap_hash (Colormap *cmap) +{ + return *cmap; +} + +static gint +gdk_colormap_cmp (Colormap *a, + Colormap *b) +{ + return (*a == *b); +} diff --git a/gdk/x11/gdkcursor-x11.c b/gdk/x11/gdkcursor-x11.c new file mode 100644 index 000000000..22bfd250b --- /dev/null +++ b/gdk/x11/gdkcursor-x11.c @@ -0,0 +1,52 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +GdkCursor* +gdk_cursor_new (GdkCursorType cursor_type) +{ + GdkCursorPrivate *private; + GdkCursor *cursor; + Cursor xcursor; + + xcursor = XCreateFontCursor (gdk_display, cursor_type); + private = g_new (GdkCursorPrivate, 1); + private->xdisplay = gdk_display; + private->xcursor = xcursor; + cursor = (GdkCursor*) private; + cursor->type = cursor_type; + + return cursor; +} + +void +gdk_cursor_destroy (GdkCursor *cursor) +{ + GdkCursorPrivate *private; + + g_return_if_fail (cursor != NULL); + + private = (GdkCursorPrivate *) cursor; + XFreeCursor (private->xdisplay, private->xcursor); + + g_free (private); +} diff --git a/gdk/x11/gdkfont-x11.c b/gdk/x11/gdkfont-x11.c new file mode 100644 index 000000000..e1b1e7254 --- /dev/null +++ b/gdk/x11/gdkfont-x11.c @@ -0,0 +1,379 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + +GdkFont* +gdk_font_load (const gchar *font_name) +{ + GdkFont *font; + GdkFontPrivate *private; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + private->xfont = XLoadQueryFont (private->xdisplay, font_name); + private->ref_count = 1; + + if (!private->xfont) + { + g_free (font); + return NULL; + } + else + { + font->type = GDK_FONT_FONT; + font->ascent = ((XFontStruct *) private->xfont)->ascent; + font->descent = ((XFontStruct *) private->xfont)->descent; + } + + gdk_xid_table_insert (&((XFontStruct *) private->xfont)->fid, font); + + return font; +} + +GdkFont* +gdk_fontset_load(gchar *fontset_name) +{ + GdkFont *font; + GdkFontPrivate *private; + XFontSet fontset; + gint missing_charset_count; + gchar **missing_charset_list; + gchar *def_string; + + private = g_new (GdkFontPrivate, 1); + font = (GdkFont*) private; + + private->xdisplay = gdk_display; + fontset = XCreateFontSet (gdk_display, fontset_name, + &missing_charset_list, &missing_charset_count, + &def_string); + + if (missing_charset_count) + { + g_print ("Missing charsets in FontSet creation"); + XFreeStringList (missing_charset_list); + } + + private->ref_count = 1; + + if (!fontset) + { + g_free (font); + return NULL; + } + else + { + XFontSetExtents *extent = XExtentsOfFontSet(fontset); + + private->xfont = fontset; + font->type = GDK_FONT_FONTSET; + /* how to define ascent and descent for fontset ??? */ + font->ascent = extent->max_logical_extent.height; + font->descent = font->ascent / 4 ; + } + return font; +} +void +gdk_font_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + gdk_xid_table_remove (((XFontStruct *) private->xfont)->fid); + XFreeFont (private->xdisplay, (XFontStruct *) private->xfont); + g_free (font); + } +} + +void +gdk_fontset_free (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_if_fail (font != NULL); + + private = (GdkFontPrivate*) font; + + private->ref_count -= 1; + if (private->ref_count == 0) + { + XFreeFontSet (private->xdisplay, (XFontSet) private->xfont); + g_free (font); + } +} + +GdkFont* +gdk_font_ref (GdkFont *font) +{ + GdkFontPrivate *private; + + g_return_val_if_fail (font != NULL, NULL); + + private = (GdkFontPrivate*) font; + private->ref_count += 1; + return font; +} + +gint +gdk_font_id (GdkFont *font) +{ + GdkFontPrivate *font_private; + + g_return_val_if_fail (font != NULL, 0); + + font_private = (GdkFontPrivate*) font; + + if (font->type == GDK_FONT_FONT) + { + return ((XFontStruct *) font_private->xfont)->fid; + } + else + { + return 0; + } +} + +gint +gdk_font_equal (GdkFont *fonta, + GdkFont *fontb) +{ + GdkFontPrivate *privatea; + GdkFontPrivate *privateb; + + g_return_val_if_fail (fonta != NULL, FALSE); + g_return_val_if_fail (fontb != NULL, FALSE); + + privatea = (GdkFontPrivate*) fonta; + privateb = (GdkFontPrivate*) fontb; + + if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT) + { + return (((XFontStruct *) privatea->xfont)->fid == + ((XFontStruct *) privateb->xfont)->fid); + } + else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET) + { + /* how to compare two fontsets ?? by basename or XFontSet ?? */ + return (((XFontSet) privatea->xfont) == ((XFontSet) privateb->xfont)); + } + else + /* fontset != font */ + return 0; +} + +gint +gdk_string_width (GdkFont *font, + const gchar *string) +{ + GdkFontPrivate *font_private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + font_private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) font_private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, string, strlen (string)); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) string, strlen (string) / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) font_private->xfont; + width = XmbTextEscapement (fontset, string, strlen(string)); + break; + default: + width = 0; + } + + return width; +} + +gint +gdk_text_width (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + gint width; + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + width = XTextWidth (xfont, text, text_length); + } + else + { + width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, text, text_length); + break; + default: + width = 0; + } + return width; +} + +/* Problem: What if a character is a 16 bits character ?? */ +gint +gdk_char_width (GdkFont *font, + gchar character) +{ + GdkFontPrivate *private; + XCharStruct *chars; + gint width; + guint ch = character & 0xff; /* get rid of sign-extension */ + XFontStruct *xfont; + XFontSet fontset; + + g_return_val_if_fail (font != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + /* only 8 bits characters are considered here */ + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && + (xfont->max_byte1 == 0) && + (ch >= xfont->min_char_or_byte2) && + (ch <= xfont->max_char_or_byte2)) + { + chars = xfont->per_char; + if (chars) + width = chars[ch - xfont->min_char_or_byte2].width; + else + width = xfont->min_bounds.width; + } + else + { + width = XTextWidth (xfont, &character, 1); + } + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + width = XmbTextEscapement (fontset, &character, 1) ; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_string_measure (GdkFont *font, + const gchar *string) +{ + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (string != NULL, -1); + + return gdk_text_measure (font, string, strlen (string)); +} + +gint +gdk_text_measure (GdkFont *font, + const gchar *text, + gint text_length) +{ + GdkFontPrivate *private; + XCharStruct overall; + XFontStruct *xfont; + XFontSet fontset; + XRectangle ink, log; + int direction; + int font_ascent; + int font_descent; + gint width; + + g_return_val_if_fail (font != NULL, -1); + g_return_val_if_fail (text != NULL, -1); + + private = (GdkFontPrivate*) font; + + switch (font->type) + { + case GDK_FONT_FONT: + xfont = (XFontStruct *) private->xfont; + if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) + { + XTextExtents (xfont, text, text_length, + &direction, &font_ascent, &font_descent, + &overall); + } + else + { + XTextExtents16 (xfont, (XChar2b *) text, text_length / 2, + &direction, &font_ascent, &font_descent, + &overall); + } + width = overall.rbearing; + break; + case GDK_FONT_FONTSET: + fontset = (XFontSet) private->xfont; + XmbTextExtents (fontset, text, text_length, &ink, &log); + width = log.width; + break; + default: + width = 0; + } + return width; +} + +gint +gdk_char_measure (GdkFont *font, + gchar character) +{ + g_return_val_if_fail (font != NULL, -1); + + return gdk_text_measure (font, &character, 1); +} diff --git a/gdk/x11/gdkglobals-x11.c b/gdk/x11/gdkglobals-x11.c new file mode 100644 index 000000000..58f7bf844 --- /dev/null +++ b/gdk/x11/gdkglobals-x11.c @@ -0,0 +1,47 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdktypes.h" +#include "gdkprivate.h" + +gint gdk_debug_level = 0; +gint gdk_show_events = FALSE; +gint gdk_use_xshm = TRUE; +gchar *gdk_display_name = NULL; +Display *gdk_display = NULL; +gint gdk_screen; +Window gdk_root_window; +Window gdk_leader_window; +GdkWindowPrivate gdk_root_parent; +Atom gdk_wm_delete_window; +Atom gdk_wm_take_focus; +Atom gdk_wm_protocols; +Atom gdk_wm_window_protocols[2]; +Atom gdk_selection_property; +GdkDndGlobals gdk_dnd = {None,None,None, + None,None,None, + None, + None,None, + NULL, + 0, 0, + {0,0}}; +gchar *gdk_progname = NULL; +gchar *gdk_progclass = NULL; +gint gdk_error_code; +gint gdk_error_warnings = TRUE; diff --git a/gdk/x11/gdkimage-x11.c b/gdk/x11/gdkimage-x11.c new file mode 100644 index 000000000..bcda3119f --- /dev/null +++ b/gdk/x11/gdkimage-x11.c @@ -0,0 +1,492 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" + +#include + +#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) +#define USE_SHM +#endif + +#ifdef USE_SHM +#include +#include +#endif /* USE_SHM */ + +#include +#include + +#ifdef USE_SHM +#include +#endif /* USE_SHM */ + +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); +static void gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height); + + +static GList *image_list = NULL; + + +void +gdk_image_exit () +{ + GdkImage *image; + + while (image_list) + { + image = image_list->data; + gdk_image_destroy (image); + } +} + +GdkImage * +gdk_image_new_bitmap(GdkVisual *visual, gpointer data, gint w, gint h) +/* + * Desc: create a new bitmap image + */ +{ + Visual *xvisual; + GdkImage *image; + GdkImagePrivate *private; + private = g_new(GdkImagePrivate, 1); + image = (GdkImage *) private; + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + image->type = GDK_IMAGE_NORMAL; + image->visual = visual; + image->width = w; + image->height = h; + image->depth = 1; + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + private->ximage = XCreateImage(private->xdisplay, xvisual, 1, XYBitmap, + 0, 0, w ,h, 8, 0); + private->ximage->data = data; + private->ximage->bitmap_bit_order = MSBFirst; + private->ximage->byte_order = MSBFirst; + image->byte_order = MSBFirst; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + return(image); +} /* gdk_image_new_bitmap() */ + +static int +gdk_image_check_xshm(Display *display) +/* + * Desc: query the server for support for the MIT_SHM extension + * Return: 0 = not available + * 1 = shared XImage support available + * 2 = shared Pixmap support available also + */ +{ +#ifdef USE_SHM + int major, minor, ignore; + Bool pixmaps; + + if (XQueryExtension(display, "MIT-SHM", &ignore, &ignore, &ignore)) + { + if (XShmQueryVersion(display, &major, &minor, &pixmaps )==True) + { + return (pixmaps==True) ? 2 : 1; + } + } +#endif /* USE_SHM */ + return 0; +} + +void +gdk_image_init () +{ + if (gdk_use_xshm) + { + if (!gdk_image_check_xshm (gdk_display)) + { + g_warning ("MIT-SHM Extension not availible on server"); + gdk_use_xshm = False; + } + } +} + +GdkImage* +gdk_image_new (GdkImageType type, + GdkVisual *visual, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + Visual *xvisual; + + switch (type) + { + case GDK_IMAGE_FASTEST: + image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height); + + if (!image) + image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height); + break; + + default: + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = NULL; + + image->type = type; + image->visual = visual; + image->width = width; + image->height = height; + image->depth = visual->depth; + + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + switch (type) + { + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + if (gdk_use_xshm) + { + private->image_put = gdk_image_put_shared; + + private->x_shm_info = g_new (XShmSegmentInfo, 1); + x_shm_info = private->x_shm_info; + + private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, NULL, x_shm_info, width, height); + if (private->ximage == NULL) + { + g_warning ("XShmCreateImage failed"); + + g_free (image); + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->shmid = shmget (IPC_PRIVATE, + private->ximage->bytes_per_line * private->ximage->height, + IPC_CREAT | 0777); + + if (x_shm_info->shmid == -1) + { + g_warning ("shmget failed!"); + + XDestroyImage (private->ximage); + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + gdk_use_xshm = False; + return NULL; + } + + x_shm_info->readOnly = False; + x_shm_info->shmaddr = shmat (x_shm_info->shmid, 0, 0); + private->ximage->data = x_shm_info->shmaddr; + + if (x_shm_info->shmaddr == (char*) -1) + { + g_warning ("shmat failed!"); + + XDestroyImage (private->ximage); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + return NULL; + } + +#ifdef IPC_RMID_DEFERRED_RELEASE + if (x_shm_info->shmaddr != (char*) -1) + shmctl (x_shm_info->shmid, IPC_RMID, 0); +#endif + + gdk_error_code = 0; + gdk_error_warnings = 0; + + XShmAttach (private->xdisplay, x_shm_info); + XSync (private->xdisplay, False); + + gdk_error_warnings = 1; + if (gdk_error_code == -1) + { + g_warning ("XShmAttach failed!"); + + XDestroyImage (private->ximage); + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + g_free (image); + + gdk_use_xshm = False; + return NULL; + } + + if (image) + image_list = g_list_prepend (image_list, image); + } + else + { + g_free (image); + return NULL; + } + break; +#else /* USE_SHM */ + g_free (image); + return NULL; +#endif /* USE_SHM */ + case GDK_IMAGE_NORMAL: + private->image_put = gdk_image_put_normal; + + private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth, + ZPixmap, 0, 0, width, height, 32, 0); + + private->ximage->data = g_new (char, private->ximage->bytes_per_line * + private->ximage->height); + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + if (image) + { + image->byte_order = private->ximage->byte_order; + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + + switch (private->ximage->bits_per_pixel) + { + case 8: + image->bpp = 1; + break; + case 16: + image->bpp = 2; + break; + case 24: + image->bpp = 3; + break; + case 32: + image->bpp = 4; + break; + } + } + } + + return image; +} + +GdkImage* +gdk_image_get (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkImage *image; + GdkImagePrivate *private; + GdkWindowPrivate *win_private; + + g_return_val_if_fail (window != NULL, NULL); + + win_private = (GdkWindowPrivate *) window; + + private = g_new (GdkImagePrivate, 1); + image = (GdkImage*) private; + + private->xdisplay = gdk_display; + private->image_put = gdk_image_put_normal; + private->ximage = XGetImage (private->xdisplay, + win_private->xwindow, + x, y, width, height, + AllPlanes, ZPixmap); + + image->type = GDK_IMAGE_NORMAL; + image->visual = gdk_window_get_visual (window); + image->width = width; + image->height = height; + image->depth = private->ximage->depth; + + image->mem = private->ximage->data; + image->bpl = private->ximage->bytes_per_line; + image->bpp = 1; + + return image; +} + +guint32 +gdk_image_get_pixel (GdkImage *image, + gint x, + gint y) +{ + guint32 pixel; + GdkImagePrivate *private; + + g_return_val_if_fail (image != NULL, 0); + + private = (GdkImagePrivate *) image; + + pixel = XGetPixel (private->ximage, x, y); + + return pixel; +} + +void +gdk_image_put_pixel (GdkImage *image, + gint x, + gint y, + guint32 pixel) +{ + GdkImagePrivate *private; + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate *) image; + + pixel = XPutPixel (private->ximage, x, y, pixel); +} + +void +gdk_image_destroy (GdkImage *image) +{ + GdkImagePrivate *private; +#ifdef USE_SHM + XShmSegmentInfo *x_shm_info; +#endif /* USE_SHM */ + + g_return_if_fail (image != NULL); + + private = (GdkImagePrivate*) image; + switch (image->type) + { + case GDK_IMAGE_NORMAL: + XDestroyImage (private->ximage); + break; + + case GDK_IMAGE_SHARED: +#ifdef USE_SHM + XShmDetach (private->xdisplay, private->x_shm_info); + XDestroyImage (private->ximage); + + x_shm_info = private->x_shm_info; + shmdt (x_shm_info->shmaddr); + shmctl (x_shm_info->shmid, IPC_RMID, 0); + + g_free (private->x_shm_info); + + image_list = g_list_remove (image_list, image); +#else /* USE_SHM */ + g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ + break; + + case GDK_IMAGE_FASTEST: + g_assert_not_reached (); + } + + g_free (image); +} + +static void +gdk_image_put_normal (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_NORMAL); + + XPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height); +} + +static void +gdk_image_put_shared (GdkDrawable *drawable, + GdkGC *gc, + GdkImage *image, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) +{ +#ifdef USE_SHM + GdkWindowPrivate *drawable_private; + GdkImagePrivate *image_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (drawable != NULL); + g_return_if_fail (image != NULL); + g_return_if_fail (gc != NULL); + + drawable_private = (GdkWindowPrivate*) drawable; + image_private = (GdkImagePrivate*) image; + gc_private = (GdkGCPrivate*) gc; + + g_return_if_fail (image->type == GDK_IMAGE_SHARED); + + XShmPutImage (drawable_private->xdisplay, drawable_private->xwindow, + gc_private->xgc, image_private->ximage, + xsrc, ysrc, xdest, ydest, width, height, False); +#else /* USE_SHM */ + g_error ("trying to draw shared memory image when gdk was compiled without shared memory support"); +#endif /* USE_SHM */ +} diff --git a/gdk/x11/gdkinput-gxi.c b/gdk/x11/gdkinput-gxi.c new file mode 100644 index 000000000..a30e05f95 --- /dev/null +++ b/gdk/x11/gdkinput-gxi.c @@ -0,0 +1,628 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_GXI + +/* #define DEBUG_SWITCHING */ + +#include + +/* Forward declarations */ +static void gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode); +static gint gdk_input_is_extension_device (guint32 deviceid); +static void gdk_input_gxi_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static void gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev); + +static gint gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent); +static gint gdk_input_gxi_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_gxi_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static Window gdk_input_find_root_child(Display *dpy, Window w); +static void gdk_input_compute_obscuring(GdkInputWindow *input_window); +static gint gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, + gdouble y); +static GdkTimeCoord *gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); +static gint gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_gxi_ungrab_pointer (guint32 time); + +/* Local variables */ + +static GdkDevicePrivate *gdk_input_current_device; +static GdkDevicePrivate *gdk_input_core_pointer; + +void +gdk_input_init(void) +{ + GList *tmp_list; + + gdk_input_vtable.set_mode = gdk_input_gxi_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_gxi_motion_events; + gdk_input_vtable.get_pointer = gdk_input_gxi_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_gxi_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_gxi_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_gxi_configure_event; + gdk_input_vtable.enter_event = gdk_input_gxi_enter_event; + gdk_input_vtable.other_event = gdk_input_gxi_other_event; + gdk_input_vtable.window_none_event = gdk_input_gxi_window_none_event; + gdk_input_vtable.enable_window = gdk_input_gxi_enable_window; + gdk_input_vtable.disable_window = gdk_input_gxi_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_core_pointer = NULL; + + if (!gdk_input_gxid_host) + { + gdk_input_gxid_host = getenv("GXID_HOST"); + } + if (!gdk_input_gxid_port) + { + char *t = getenv("GXID_PORT"); + if (t) + gdk_input_gxid_port = atoi(t); + } + + gdk_input_common_init(TRUE); + + /* find initial core pointer */ + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdk_input_is_extension_device(gdkdev->info.deviceid)) + { + gdk_input_gxi_select_notify (gdkdev); + } + else + { + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + gdk_input_core_pointer = gdkdev; + } + } +} + +static void +gdk_input_gxi_select_notify (GdkDevicePrivate *gdkdev) +{ + XEventClass class; + + ChangeDeviceNotify (gdkdev->xdevice, gdkdev->changenotify_type, class); + + XSelectExtensionEvent (gdk_display, gdk_root_window, &class, 1); +} + +/* Set the core pointer. Device should already be enabled. */ +static gint +gdk_input_gxi_set_core_pointer(GdkDevicePrivate *gdkdev) +{ + int x_axis,y_axis; + + g_return_val_if_fail(gdkdev->xdevice,FALSE); + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + + g_return_val_if_fail(x_axis != -1 && y_axis != -1,FALSE); + + /* core_pointer might not be up to date so we check with the server + before change the pointer */ + + if ( !gdk_input_is_extension_device(gdkdev->info.deviceid) ) + { +#if 0 + if (gdkdev != gdk_input_core_pointer) + g_warning("core pointer inconsistency"); +#endif + return TRUE; + } + + if ( XChangePointerDevice(gdk_display,gdkdev->xdevice, x_axis, y_axis) + != Success ) + { + return FALSE; + } + else + { + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + return TRUE; + } +} + + +/* FIXME, merge with gdk_input_xfree_set_mode */ + +static gint +gdk_input_gxi_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (old_mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + if (mode != GDK_MODE_DISABLED) + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + if (!gdk_input_enable_window(input_window->window, gdkdev)) + { + gdk_input_set_mode(deviceid, old_mode); + return FALSE; + } + } + } + + return TRUE; + +} + +gint +gdk_input_is_extension_device (guint32 deviceid) +{ + XDeviceInfo *devices; + int num_devices, loop; + + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + devices = XListInputDevices(gdk_display, &num_devices); + for(loop=0; looproot_x = root_x; + input_window->root_y = root_y; + gdk_input_compute_obscuring(input_window); +} + +static void +gdk_input_gxi_enter_event (XCrossingEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find(window); + g_return_if_fail (input_window != NULL); + + gdk_input_compute_obscuring(input_window); +} + +static gint +gdk_input_gxi_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (gdkdev->info.mode == GDK_MODE_DISABLED || + input_window->mode == GDK_EXTENSION_EVENTS_CURSOR) + return FALSE; + + if (gdkdev != gdk_input_current_device && + xevent->type != gdkdev->changenotify_type) + { + gdk_input_current_device = gdkdev; + } + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_MOTION_NOTIFY && + (!gdkdev->button_state) && (!input_window->grabbed) && + ((event->motion.x < 0) || (event->motion.y < 0) || + (event->motion.x > ((GdkWindowPrivate *)window)->width) || + (event->motion.y > ((GdkWindowPrivate *)window)->height) || + gdk_input_is_obscured(input_window,event->motion.x,event->motion.y))) + { +#ifdef DEBUG_SWITCHING + g_print("gdkinput: Setting core pointer to %d on motion at (%f,%f)\n", + gdkdev->info.deviceid,event->motion.x,event->motion.y); + g_print(" window geometry is: %dx%d\n", + ((GdkWindowPrivate *)window)->width, + ((GdkWindowPrivate *)window)->height); +#endif + gdk_input_gxi_set_core_pointer(gdkdev); + return FALSE; + } + else + return return_val; + +} + +static void +gdk_input_gxi_update_device (GdkDevicePrivate *gdkdev) +{ + GList *t; + + if (gdk_input_is_extension_device (gdkdev->info.deviceid)) + { + if (!gdkdev->xdevice) + { + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + gdk_input_gxi_select_notify (gdkdev); + gdkdev->needs_update = 1; + } + if (gdkdev->needs_update && gdkdev->xdevice) + { + for (t = gdk_input_windows; t; t = t->next) + gdk_input_common_select_events (((GdkInputWindow *)t->data)->window, + gdkdev); + gdkdev->needs_update = 0; + } + } +} + +static gint +gdk_input_gxi_window_none_event (GdkEvent *event, XEvent *xevent) +{ + GdkDevicePrivate *gdkdev = + gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + if (xevent->type == gdkdev->changenotify_type) + { + if (gdk_input_core_pointer != gdkdev) + { +#ifdef DEBUG_SWITCHING + g_print("ChangeNotify from %d to %d:\n", + gdk_input_core_pointer->info.deviceid, + gdkdev->info.deviceid); +#endif + gdk_input_gxi_update_device (gdk_input_core_pointer); + gdk_input_core_pointer = gdkdev; + } + } + + return FALSE; +} + +static gint +gdk_input_gxi_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (!gdkdev->claimed) + { + if (gxid_claim_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window), FALSE) != + GXID_RETURN_OK) + { + g_warning("Could not get device (is gxid running?)\n"); + return FALSE; + } + gdkdev->claimed = TRUE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_gxi_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_val_if_fail (input_window != NULL, FALSE); + + if (gdkdev->claimed) + { + gxid_release_device(gdk_input_gxid_host, gdk_input_gxid_port, + gdkdev->info.deviceid, + GDK_WINDOW_XWINDOW(window)); + + gdkdev->claimed = FALSE; + } + + if (gdkdev->xdevice && gdkdev != gdk_input_core_pointer) + gdk_input_common_select_events(window, gdkdev); + else + gdkdev->needs_update = TRUE; + + return TRUE; +} + +static gint +gdk_input_is_obscured(GdkInputWindow *input_window, gdouble x, gdouble y) +{ + int i; + for (i=0;inum_obscuring;i++) + { + GdkRectangle *rect = &input_window->obscuring[i]; + if ((x >= rect->x) && + (y >= rect->y) && + (x < rect->x + rect->width) && + (y < rect->y + rect->height)) + return TRUE; + } + return FALSE; +} + +/* If this routine needs fixing, the corresponding routine + in gxid.c will need it too. */ + +static Window +gdk_input_find_root_child(Display *dpy, Window w) +{ + Window root,parent; + Window *children; + int nchildren; + + parent = w; + do + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + } + while (parent != root); + + return w; +} + +void +gdk_input_compute_obscuring(GdkInputWindow *input_window) +{ + int i; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + Window root,parent; + Window *children; + int nchildren; + + Window w = GDK_WINDOW_XWINDOW(input_window->window); + Window root_child = gdk_input_find_root_child(gdk_display,w); + gdk_input_get_root_relative_geometry(gdk_display,w,&x,&y,&width,&height); + + input_window->root_x = x; + input_window->root_y = y; + + XQueryTree(gdk_display,GDK_ROOT_WINDOW(), + &root,&parent,&children,&nchildren); + + + if (input_window->obscuring) + g_free(input_window->obscuring); + input_window->obscuring = 0; + input_window->num_obscuring = 0; + + for (i=0;i=nchildren-1) + { + if (nchildren) + XFree(children); + return; + } + + input_window->obscuring = g_new(GdkRectangle,(nchildren-i-1)); + + for (i=i+1;ix ? xc : x; + xmax = (xc+widthc)<(x+width) ? xc+widthc : x+width; + ymin = yc>y ? yc : y; + ymax = (yc+heightc)<(y+height) ? yc+heightc : y+height; + if ((xmin < xmax) && (ymin < ymax)) + { + XWindowAttributes attributes; + XGetWindowAttributes(gdk_display,children[i],&attributes); + if (attributes.map_state == IsViewable) + { + GdkRectangle *rect = &input_window->obscuring[input_window->num_obscuring]; + + /* we store the whole window, not just the obscuring part */ + rect->x = xc - x; + rect->y = yc - y; + rect->width = widthc; + rect->height = heightc; + input_window->num_obscuring++; + } + } + } + + if (nchildren) + XFree(children); +} + +static void +gdk_input_gxi_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_if_fail (gdkdev != NULL); + + if (gdkdev == gdk_input_core_pointer) + gdk_input_common_get_pointer (window, GDK_CORE_POINTER, x, y, + pressure, xtilt, ytilt, mask); + else + gdk_input_common_get_pointer (window, deviceid, x, y, + pressure, xtilt, ytilt, mask); +} + +static GdkTimeCoord * +gdk_input_gxi_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkDevicePrivate *gdkdev; + + gdkdev = gdk_input_find_device (deviceid); + g_return_val_if_fail (gdkdev != NULL, NULL); + + + if (gdkdev == gdk_input_core_pointer) + return gdk_input_motion_events (window, GDK_CORE_POINTER, start, stop, + nevents_return); + else + return gdk_input_common_motion_events (window, deviceid, start, stop, + nevents_return); + +} + +static gint +gdk_input_gxi_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + new_window = input_window; + + tmp_list = tmp_list->next; + } + + new_window->grabbed = TRUE; + return Success; +} + +static void +gdk_input_gxi_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + input_window->grabbed = FALSE; + tmp_list = tmp_list->next; + } +} + +#endif /* XINPUT_GXI */ diff --git a/gdk/x11/gdkinput-none.c b/gdk/x11/gdkinput-none.c new file mode 100644 index 000000000..8ae8c4189 --- /dev/null +++ b/gdk/x11/gdkinput-none.c @@ -0,0 +1,72 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_NONE + +static void gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +void +gdk_input_init () +{ + gdk_input_vtable.set_mode = NULL; + gdk_input_vtable.set_axes = NULL; + gdk_input_vtable.motion_events = NULL; + gdk_input_vtable.get_pointer = gdk_input_none_get_pointer; + gdk_input_vtable.grab_pointer = NULL; + gdk_input_vtable.ungrab_pointer = NULL; + gdk_input_vtable.configure_event = NULL; + gdk_input_vtable.enter_event = NULL; + gdk_input_vtable.other_event = NULL; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = NULL; + gdk_input_vtable.disable_window = NULL; + + gdk_input_devices = g_list_append (NULL, &gdk_input_core_info); + + gdk_input_ignore_core = FALSE; +} + +static void +gdk_input_none_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + gint x_int, y_int; + + gdk_window_get_pointer (window, &x_int, &y_int, mask); + + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; +} + +#endif /* XINPUT_NONE */ diff --git a/gdk/x11/gdkinput-x11.c b/gdk/x11/gdkinput-x11.c new file mode 100644 index 000000000..5e457e0aa --- /dev/null +++ b/gdk/x11/gdkinput-x11.c @@ -0,0 +1,687 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if defined(XINPUT_GXI) || defined(XINPUT_XFREE) + +/* Forward declarations */ +static void gdk_input_get_root_relative_geometry (Display *dpy, Window w, + int *x_ret, int *y_ret, + int *width_ret, + int *height_ret); +static GdkDevicePrivate *gdk_input_device_new(XDeviceInfo *device, + gint include_core); +static void gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes); +static void gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static void gdk_input_translate_coordinates(GdkDevicePrivate *gdkdev, + GdkInputWindow *input_window, + gint *axis_data, + gdouble *x, gdouble *y, + gdouble *pressure, + gdouble *xtilt, gdouble *ytilt); +static guint gdk_input_translate_state(guint state, guint device_state); +static gint gdk_input_common_init(gint include_core); +static gint gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev); +static void gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes); +static GdkTimeCoord * gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return); +static void gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask); + +/* Global variables */ + +static gint gdk_input_root_width; +static gint gdk_input_root_height; + +static void +gdk_input_get_root_relative_geometry(Display *dpy, Window w, int *x_ret, int *y_ret, + int *width_ret, int *height_ret) +{ + Window root,parent; + Window *children; + int nchildren; + int x,y,width,height; + int xc,yc,widthc,heightc,border_widthc,depthc; + + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&x,&y,&width,&height,&border_widthc, + &depthc); + x += border_widthc; + y += border_widthc; + + while (root != parent) + { + w = parent; + XQueryTree(dpy,w,&root,&parent,&children,&nchildren); + if (children) XFree(children); + XGetGeometry(dpy,w,&root,&xc,&yc,&widthc,&heightc, + &border_widthc,&depthc); + x += xc + border_widthc; + y += yc + border_widthc; + } + + if (x_ret) + *x_ret = x; + if (y_ret) + *y_ret = y; + if (width_ret) + *width_ret = width; + if (height_ret) + *height_ret = height; +} + +static GdkDevicePrivate * +gdk_input_device_new(XDeviceInfo *device, gint include_core) +{ + GdkDevicePrivate *gdkdev; + gchar *tmp_name, *p; + XAnyClassPtr class; + gint i,j; + + gdkdev = g_new(GdkDevicePrivate,1); + + gdkdev->info.deviceid = device->id; + if (device->name[0]) { + gdkdev->info.name = g_new(char, strlen(device->name)+1); + strcpy(gdkdev->info.name,device->name); + } else { + /* XFree86 3.2 gives an empty name to the default core devices, + (fixed in 3.2A) */ + gdkdev->info.name = g_strdup("pointer"); + strcpy(gdkdev->info.name,"pointer"); + gdkdev->info.source = GDK_SOURCE_MOUSE; + } + + gdkdev->info.mode = GDK_MODE_DISABLED; + + /* Try to figure out what kind of device this is by its name - + could invite a very, very, long list... Lowercase name + for comparison purposes */ + + tmp_name = g_strdup(gdkdev->info.name); + for (p = tmp_name; *p; p++) + { + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; + } + + if (!strcmp (tmp_name, "pointer")) + gdkdev->info.source = GDK_SOURCE_MOUSE; + else if (!strcmp (tmp_name, "wacom") || + !strcmp (tmp_name, "pen")) + gdkdev->info.source = GDK_SOURCE_PEN; + else if (!strcmp (tmp_name, "eraser")) + gdkdev->info.source = GDK_SOURCE_ERASER; + else if (!strcmp (tmp_name, "cursor")) + gdkdev->info.source = GDK_SOURCE_CURSOR; + else + gdkdev->info.source = GDK_SOURCE_PEN; + + g_free(tmp_name); + + gdkdev->xdevice = NULL; + + /* step through the classes */ + + gdkdev->info.num_axes = 0; + gdkdev->axes = 0; + gdkdev->info.has_cursor = 0; + gdkdev->needs_update = FALSE; + gdkdev->claimed = FALSE; + gdkdev->button_state = 0; + + class = device->inputclassinfo; + for (i=0;inum_classes;i++) + { + switch (class->class) { + case ButtonClass: + { + break; + } + case ValuatorClass: + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + gdkdev->info.num_axes = xvi->num_axes; + gdkdev->axes = g_new(GdkAxisInfo, xvi->num_axes); + gdkdev->info.axes = g_new(GdkAxisUse, xvi->num_axes); + for (j=0;jnum_axes;j++) + { + gdkdev->axes[j].resolution = + gdkdev->axes[j].xresolution = xvi->axes[j].resolution; + gdkdev->axes[j].min_value = + gdkdev->axes[j].xmin_value = xvi->axes[j].min_value; + gdkdev->axes[j].max_value = + gdkdev->axes[j].xmax_value = xvi->axes[j].max_value; + gdkdev->info.axes[j] = GDK_AXIS_IGNORE; + } + j=0; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_X; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_Y; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_PRESSURE; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_XTILT; + if (jnum_axes) + gdkdev->info.axes[j++] = GDK_AXIS_YTILT; + + /* set up reverse lookup on axis use */ + for (j=GDK_AXIS_IGNORE;jaxis_for_use[j] = -1; + + for (j=0;jnum_axes;j++) + if (gdkdev->info.axes[j] != GDK_AXIS_IGNORE) + gdkdev->axis_for_use[gdkdev->info.axes[j]] = j; + + break; + } + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + /* return NULL if no axes */ + if (!gdkdev->info.num_axes || !gdkdev->axes || + (!include_core && device->use == IsXPointer)) + { + g_free(gdkdev->info.name); + if (gdkdev->axes) + g_free(gdkdev->axes); + g_free(gdkdev); + return NULL; + } + + if (device->use != IsXPointer) + gdkdev->xdevice = XOpenDevice(gdk_display, gdkdev->info.deviceid); + + return gdkdev; +} + +static void +gdk_input_common_find_events(GdkWindow *window, + GdkDevicePrivate *gdkdev, + gint mask, + XEventClass *classes, + int *num_classes) +{ + gint i; + XEventClass class; + + i = 0; + /* We have to track press and release events in pairs to keep + track of button state correctly and implement grabbing */ + if (mask & GDK_BUTTON_PRESS_MASK || mask & GDK_BUTTON_RELEASE_MASK) + { + DeviceButtonPress (gdkdev->xdevice, gdkdev->buttonpress_type, + class); + if (class != 0) + classes[i++] = class; + DeviceButtonRelease (gdkdev->xdevice, gdkdev->buttonrelease_type, + class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_MASK) + { + DeviceMotionNotify (gdkdev->xdevice, gdkdev->motionnotify_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_POINTER_MOTION_HINT_MASK) + { + /* We'll get into trouble if the macros change, but at least we'll + know about it, and we avoid warnings now */ + DevicePointerMotionHint (gdkdev->xdevice, 0, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_IN_MASK) + { + ProximityIn (gdkdev->xdevice, gdkdev->proximityin_type, class); + if (class != 0) + classes[i++] = class; + } + if (mask & GDK_PROXIMITY_OUT_MASK) + { + ProximityOut (gdkdev->xdevice, gdkdev->proximityout_type, class); + if (class != 0) + classes[i++] = class; + } + + *num_classes = i; +} + +static void +gdk_input_common_select_events(GdkWindow *window, + GdkDevicePrivate *gdkdev) +{ + XEventClass classes[6]; + gint num_classes; + + if (gdkdev->info.mode == GDK_MODE_DISABLED) + gdk_input_common_find_events(window, gdkdev, 0, classes, &num_classes); + else + gdk_input_common_find_events(window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + classes, &num_classes); + + XSelectExtensionEvent (gdk_display, + GDK_WINDOW_XWINDOW(window), + classes, num_classes); +} + +gint +gdk_input_common_init(gint include_core) +{ + char **extensions; + XDeviceInfo *devices; + int num_devices; + int num_extensions, loop; + Display *display = gdk_display; + + /* Init global vars */ + gdk_window_get_geometry(NULL, /* use root window */ + NULL,NULL, + &gdk_input_root_width,&gdk_input_root_height, + NULL); + + /* Init XInput extension */ + + extensions = XListExtensions(display, &num_extensions); + for (loop = 0; loop < num_extensions && + (strcmp(extensions[loop], "XInputExtension") != 0); loop++); + XFreeExtensionList(extensions); + if (loop == num_extensions) /* XInput extension not found */ + return FALSE; + + gdk_input_devices = 0; + devices = XListInputDevices(display, &num_devices); + + for(loop=0; loopwindow; + + x_axis = gdkdev->axis_for_use[GDK_AXIS_X]; + y_axis = gdkdev->axis_for_use[GDK_AXIS_Y]; + pressure_axis = gdkdev->axis_for_use[GDK_AXIS_PRESSURE]; + xtilt_axis = gdkdev->axis_for_use[GDK_AXIS_XTILT]; + ytilt_axis = gdkdev->axis_for_use[GDK_AXIS_YTILT]; + + device_width = gdkdev->axes[x_axis].max_value - + gdkdev->axes[x_axis].min_value; + device_height = gdkdev->axes[y_axis].max_value - + gdkdev->axes[y_axis].min_value; + + if (gdkdev->info.mode == GDK_MODE_SCREEN) + { + x_scale = gdk_input_root_width / device_width; + y_scale = gdk_input_root_height / device_height; + + x_offset = - input_window->root_x; + y_offset = - input_window->root_y; + } + else /* GDK_MODE_WINDOW */ + { + double device_aspect = (device_height*gdkdev->axes[y_axis].resolution) / + (device_width*gdkdev->axes[x_axis].resolution); + + if (device_aspect * win_priv->width >= win_priv->height) + { + /* device taller than window */ + x_scale = win_priv->width / device_width; + y_scale = (x_scale * gdkdev->axes[x_axis].resolution) + / gdkdev->axes[y_axis].resolution; + + x_offset = 0; + y_offset = -(device_height * y_scale - + win_priv->height)/2; + } + else + { + /* window taller than device */ + y_scale = win_priv->height / device_height; + x_scale = (y_scale * gdkdev->axes[y_axis].resolution) + / gdkdev->axes[x_axis].resolution; + + y_offset = 0; + x_offset = - (device_width * x_scale - win_priv->width)/2; + } + } + + if (x) *x = x_offset + x_scale*axis_data[x_axis]; + if (y) *y = y_offset + y_scale*axis_data[y_axis]; + + if (pressure) + { + if (pressure_axis != -1) + *pressure = ((double)axis_data[pressure_axis] + - gdkdev->axes[pressure_axis].min_value) + / (gdkdev->axes[pressure_axis].max_value + - gdkdev->axes[pressure_axis].min_value); + else + *pressure = 0.5; + } + + if (xtilt) + { + if (xtilt_axis != -1) + { + *xtilt = 2. * (double)(axis_data[xtilt_axis] - + (gdkdev->axes[xtilt_axis].min_value + + gdkdev->axes[xtilt_axis].max_value)/2) / + (gdkdev->axes[xtilt_axis].max_value - + gdkdev->axes[xtilt_axis].min_value); + } + else *xtilt = 0; + } + + if (ytilt) + { + if (ytilt_axis != -1) + { + *ytilt = 2. * (double)(axis_data[ytilt_axis] - + (gdkdev->axes[ytilt_axis].min_value + + gdkdev->axes[ytilt_axis].max_value)/2) / + (gdkdev->axes[ytilt_axis].max_value - + gdkdev->axes[ytilt_axis].min_value); + } + else + *ytilt = 0; + } +} + +/* combine the state of the core device and the device state + into one - for now we do this in a simple-minded manner - + we just take the keyboard portion of the core device and + the button portion (all of?) the device state. + Any button remapping should go on here. */ +static guint +gdk_input_translate_state(guint state, guint device_state) +{ + return device_state | (state & 0xFF); +} + +static gint +gdk_input_common_other_event (GdkEvent *event, + XEvent *xevent, + GdkInputWindow *input_window, + GdkDevicePrivate *gdkdev) +{ + if ((xevent->type == gdkdev->buttonpress_type) || + (xevent->type == gdkdev->buttonrelease_type)) + { + XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *)(xevent); + + if (xdbe->type == gdkdev->buttonpress_type) + { + event->button.type = GDK_BUTTON_PRESS; + gdkdev->button_state |= 1 << xdbe->button; + } + else + { + event->button.type = GDK_BUTTON_RELEASE; + gdkdev->button_state &= ~(1 << xdbe->button); + } + event->button.window = input_window->window; + event->button.time = xdbe->time; + event->button.source = gdkdev->info.source; + event->button.deviceid = xdbe->deviceid; + + gdk_input_translate_coordinates (gdkdev,input_window, xdbe->axis_data, + &event->button.x,&event->button.y, + &event->button.pressure, + &event->button.xtilt, + &event->button.ytilt); + event->button.state = gdk_input_translate_state(xdbe->state,xdbe->device_state); + event->button.button = xdbe->button; + + return TRUE; + } + + if (xevent->type == gdkdev->motionnotify_type) + { + XDeviceMotionEvent *xdme = (XDeviceMotionEvent *)(xevent); + + gdk_input_translate_coordinates(gdkdev,input_window,xdme->axis_data, + &event->motion.x,&event->motion.y, + &event->motion.pressure, + &event->motion.xtilt, + &event->motion.ytilt); + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = input_window->window; + event->motion.time = xdme->time; + event->motion.deviceid = xdme->deviceid; + event->motion.state = gdk_input_translate_state(xdme->state, + xdme->device_state); + event->motion.source = gdkdev->info.source; + event->motion.deviceid = xdme->deviceid; + + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld device: %ld x,y: %f %f hint: %s\n", + xdme->window, + xdme->deviceid, + event->motion.x, event->motion.y, + (xevent->xmotion.is_hint) ? "true" : "false"); + + + return TRUE; + } + + if (xevent->type == gdkdev->proximityin_type || + xevent->type == gdkdev->proximityout_type) + { + XProximityNotifyEvent *xpne = (XProximityNotifyEvent *)(xevent); + + event->proximity.type = (xevent->type == gdkdev->proximityin_type)? + GDK_PROXIMITY_IN:GDK_PROXIMITY_OUT; + event->proximity.window = input_window->window; + event->proximity.time = xpne->time; + event->proximity.source = gdkdev->info.source; + event->proximity.deviceid = xpne->deviceid; + + return TRUE; + } + + return -1; /* wasn't one of our event types */ +} + +static void +gdk_input_common_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + int i; + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + for (i=GDK_AXIS_IGNORE;iaxis_for_use[i] = -1; + } + + for (i=0;iinfo.num_axes;i++) + { + gdkdev->info.axes[i] = axes[i]; + gdkdev->axis_for_use[axes[i]] = i; + } +} + +static GdkTimeCoord * +gdk_input_common_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + GdkTimeCoord *coords; + XDeviceTimeCoord *device_coords; + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + + int mode_return; + int axis_count_return; + int i; + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_val_if_fail (gdkdev != NULL, NULL); + g_return_val_if_fail (gdkdev->xdevice != NULL, NULL); + g_return_val_if_fail (input_window != NULL, NULL); + + device_coords = XGetDeviceMotionEvents (gdk_display, + gdkdev->xdevice, + start, stop, + nevents_return, &mode_return, + &axis_count_return); + + if (device_coords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + + for (i=0; i<*nevents_return; i++) + { + gdk_input_translate_coordinates (gdkdev, input_window, + device_coords[i].data, + &coords[i].x, &coords[i].y, + &coords[i].pressure, + &coords[i].xtilt, &coords[i].ytilt); + } + XFreeDeviceMotionEvents (device_coords); + + return coords; + } + else + return NULL; +} + +static void +gdk_input_common_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + GdkDevicePrivate *gdkdev; + GdkInputWindow *input_window; + XDeviceState *state; + XInputClass *input_class; + gint x_int, y_int; + gint i; + + /* we probably need to get the mask in any case */ + + if (deviceid == GDK_CORE_POINTER) + { + gdk_window_get_pointer (window, &x_int, &y_int, mask); + if (x) *x = x_int; + if (y) *y = y_int; + if (pressure) *pressure = 0.5; + if (xtilt) *xtilt = 0; + if (ytilt) *ytilt = 0; + } + else + { + if (mask) + gdk_window_get_pointer (window, NULL, NULL, mask); + + gdkdev = gdk_input_find_device (deviceid); + input_window = gdk_input_window_find (window); + + g_return_if_fail (gdkdev != NULL); + g_return_if_fail (gdkdev->xdevice != NULL); + g_return_if_fail (input_window != NULL); + + state = XQueryDeviceState (gdk_display, gdkdev->xdevice); + input_class = state->data; + for (i=0; inum_classes; i++) + { + switch (input_class->class) + { + case ValuatorClass: + gdk_input_translate_coordinates(gdkdev, input_window, + ((XValuatorState *)input_class)->valuators, + x, y, pressure, + xtilt, ytilt); + + + break; + case ButtonClass: + if (mask) + { + *mask &= ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | + GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | + GDK_BUTTON5_MASK); + for (i=0; i < ((XButtonState *)input_class)->num_buttons; i++) + { + if (((XButtonState *)input_class)->buttons[i]) + *mask |= GDK_BUTTON1_MASK << i; + } + } + break; + } + input_class = (XInputClass *)(((char *)input_class)+input_class->length); + } + } +} + +#endif diff --git a/gdk/x11/gdkinput-xfree.c b/gdk/x11/gdkinput-xfree.c new file mode 100644 index 000000000..f74249008 --- /dev/null +++ b/gdk/x11/gdkinput-xfree.c @@ -0,0 +1,368 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef XINPUT_XFREE + +/* forward declarations */ + +static gint gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode); +static void gdk_input_check_proximity(); +static void gdk_input_xfree_configure_event (XConfigureEvent *xevent, + GdkWindow *window); +static void gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window); +static gint gdk_input_xfree_enable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_disable_window(GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time); +static void gdk_input_xfree_ungrab_pointer (guint32 time); + +void +gdk_input_init(void) +{ + gdk_input_vtable.set_mode = gdk_input_xfree_set_mode; + gdk_input_vtable.set_axes = gdk_input_common_set_axes; + gdk_input_vtable.motion_events = gdk_input_common_motion_events; + gdk_input_vtable.get_pointer = gdk_input_common_get_pointer; + gdk_input_vtable.grab_pointer = gdk_input_xfree_grab_pointer; + gdk_input_vtable.ungrab_pointer = gdk_input_xfree_ungrab_pointer; + gdk_input_vtable.configure_event = gdk_input_xfree_configure_event; + gdk_input_vtable.enter_event = gdk_input_xfree_enter_event; + gdk_input_vtable.other_event = gdk_input_xfree_other_event; + gdk_input_vtable.window_none_event = NULL; + gdk_input_vtable.enable_window = gdk_input_xfree_enable_window; + gdk_input_vtable.disable_window = gdk_input_xfree_disable_window; + + gdk_input_ignore_core = FALSE; + gdk_input_common_init(FALSE); +} + +static gint +gdk_input_xfree_set_mode (guint32 deviceid, GdkInputMode mode) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + GdkInputMode old_mode; + GdkInputWindow *input_window; + + gdkdev = gdk_input_find_device(deviceid); + g_return_val_if_fail (gdkdev != NULL,FALSE); + old_mode = gdkdev->info.mode; + + if (gdkdev->info.mode == mode) + return TRUE; + + gdkdev->info.mode = mode; + + if (mode == GDK_MODE_WINDOW) + { + gdkdev->info.has_cursor = FALSE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_enable_window (input_window->window, gdkdev); + else + if (old_mode != GDK_MODE_DISABLED) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + else if (mode == GDK_MODE_SCREEN) + { + gdkdev->info.has_cursor = TRUE; + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + gdk_input_enable_window (((GdkInputWindow *)tmp_list->data)->window, + gdkdev); + } + else /* mode == GDK_MODE_DISABLED */ + { + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (old_mode != GDK_MODE_WINDOW || + input_window->mode != GDK_EXTENSION_EVENTS_CURSOR) + gdk_input_disable_window (input_window->window, gdkdev); + } + } + + return TRUE; + +} + +static void +gdk_input_check_proximity() +{ + gint new_proximity = 0; + GList *tmp_list = gdk_input_devices; + + while (tmp_list && !new_proximity) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.mode != GDK_MODE_DISABLED + && gdkdev->info.deviceid != GDK_CORE_POINTER + && gdkdev->xdevice) + { + XDeviceState *state = XQueryDeviceState(GDK_DISPLAY(), + gdkdev->xdevice); + XInputClass *xic; + int i; + + xic = state->data; + for (i=0; inum_classes; i++) + { + if (xic->class == ValuatorClass) + { + XValuatorState *xvs = (XValuatorState *)xic; + if ((xvs->mode & ProximityState) == InProximity) + { + new_proximity = TRUE; + } + break; + } + xic = (XInputClass *)((char *)xic + xic->length); + } + } + tmp_list = tmp_list->next; + } + + gdk_input_ignore_core = new_proximity; +} + +static void +gdk_input_xfree_configure_event (XConfigureEvent *xevent, GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static void +gdk_input_xfree_enter_event (XCrossingEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + gint root_x, root_y; + + input_window = gdk_input_window_find(window); + g_return_if_fail (window != NULL); + + gdk_input_check_proximity(); + + gdk_input_get_root_relative_geometry(GDK_DISPLAY(),GDK_WINDOW_XWINDOW(window), + &root_x, + &root_y, NULL, NULL); + + input_window->root_x = root_x; + input_window->root_y = root_y; +} + +static gint +gdk_input_xfree_other_event (GdkEvent *event, + XEvent *xevent, + GdkWindow *window) +{ + GdkInputWindow *input_window; + + GdkDevicePrivate *gdkdev; + gint return_val; + + input_window = gdk_input_window_find(window); + g_return_val_if_fail (window != NULL, -1); + + /* This is a sort of a hack, as there isn't any XDeviceAnyEvent - + but it's potentially faster than scanning through the types of + every device. If we were deceived, then it won't match any of + the types for the device anyways */ + gdkdev = gdk_input_find_device(((XDeviceButtonEvent *)xevent)->deviceid); + + if (!gdkdev) { + return -1; /* we don't handle it - not an XInput event */ + } + + /* FIXME: It would be nice if we could just get rid of the events + entirely, instead of having to ignore them */ + if (gdkdev->info.mode == GDK_MODE_DISABLED || + (gdkdev->info.mode == GDK_MODE_WINDOW + && input_window->mode == GDK_EXTENSION_EVENTS_CURSOR)) + return FALSE; + + if (!gdk_input_ignore_core) + gdk_input_check_proximity(); + + return_val = gdk_input_common_other_event (event, xevent, + input_window, gdkdev); + + if (return_val > 0 && event->type == GDK_PROXIMITY_OUT && + gdk_input_ignore_core) + gdk_input_check_proximity(); + + /* Do a passive button grab. We have to be careful not to release + an explicit grab, if any. Doubling the grab should be harmless, + but we check anyways. */ + + /* FIXME, finding the proper events here is going to be SLOW - but + we might have different sets for each window/device combination */ + + if (return_val> 0 && !input_window->grabbed) + { + if (event->type == GDK_BUTTON_PRESS) + { + XEventClass event_classes[6]; + gint num_classes; + + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, event->button.time); + } + else if (event->type == GDK_BUTTON_RELEASE) + XUngrabDevice( GDK_DISPLAY(), gdkdev->xdevice, event->button.time); + } + + return return_val; +} + +static gint +gdk_input_xfree_enable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + /* FIXME: watchout, gdkdev might be core pointer, never opened */ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_disable_window(GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + gdk_input_common_select_events (window, gdkdev); + return TRUE; +} + +static gint +gdk_input_xfree_grab_pointer (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + guint32 time) +{ + GdkInputWindow *input_window, *new_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + XEventClass event_classes[6]; + gint num_classes; + + tmp_list = gdk_input_windows; + new_window = NULL; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + return AlreadyGrabbed; + + if (input_window->window == window) + { + new_window = input_window; + break; + } + + tmp_list = tmp_list->next; + } + + g_return_if_fail (new_window == NULL); + + new_window->grabbed = TRUE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + gdk_input_common_find_events (window, gdkdev, + ((GdkWindowPrivate *)window)->extension_events, + event_classes, &num_classes); + + /* FIXME: we should do something on failure */ + XGrabDevice( GDK_DISPLAY(), gdkdev->xdevice, + GDK_WINDOW_XWINDOW (window), + TRUE, num_classes, event_classes, + GrabModeAsync, GrabModeAsync, time); + } + tmp_list = tmp_list->next; + } + + return Success; +} + +static void +gdk_input_xfree_ungrab_pointer (guint32 time) +{ + GdkInputWindow *input_window; + GdkDevicePrivate *gdkdev; + GList *tmp_list; + + tmp_list = gdk_input_windows; + while (tmp_list) + { + input_window = (GdkInputWindow *)tmp_list->data; + if (input_window->grabbed) + break; + tmp_list = tmp_list->next; + } + + if (tmp_list) /* we found a grabbed window */ + { + input_window->grabbed = FALSE; + + tmp_list = gdk_input_devices; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)tmp_list->data; + if (gdkdev->info.deviceid != GDK_CORE_POINTER && + gdkdev->xdevice && !gdkdev->button_state) + { + XUngrabDevice( gdk_display, gdkdev->xdevice, time); + } + tmp_list = tmp_list->next; + } + } +} + +#endif /* XINPUT_XFREE */ diff --git a/gdk/x11/gdkinput.c b/gdk/x11/gdkinput.c new file mode 100644 index 000000000..ad4b1fcc9 --- /dev/null +++ b/gdk/x11/gdkinput.c @@ -0,0 +1,324 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "../config.h" +#include "gdk.h" +#include "gdkx.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +/* Forward declarations */ + +static gint gdk_input_enable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static gint gdk_input_disable_window (GdkWindow *window, + GdkDevicePrivate *gdkdev); +static GdkInputWindow *gdk_input_window_find (GdkWindow *window); +static GdkDevicePrivate *gdk_input_find_device (guint32 id); + + +/* Incorporate the specific routines depending on compilation options */ + +static GdkAxisUse gdk_input_core_axes[] = { GDK_AXIS_X, GDK_AXIS_Y }; + +static GdkDeviceInfo gdk_input_core_info = +{ + GDK_CORE_POINTER, + "Core Pointer", + GDK_SOURCE_MOUSE, + GDK_MODE_SCREEN, + TRUE, + 2, + gdk_input_core_axes +}; + +/* Global variables */ + +GdkInputVTable gdk_input_vtable; +/* information about network port and host for gxid daemon */ +gchar *gdk_input_gxid_host; +gint gdk_input_gxid_port; +gint gdk_input_ignore_core; + +/* Local variables */ + +static GList *gdk_input_devices; +static GList *gdk_input_windows; + +#include "gdkinputnone.h" +#include "gdkinputcommon.h" +#include "gdkinputxfree.h" +#include "gdkinputgxi.h" + +GList * +gdk_input_list_devices () +{ + return gdk_input_devices; +} + +void +gdk_input_set_source (guint32 deviceid, GdkInputSource source) +{ + GdkDevicePrivate *gdkdev = gdk_input_find_device(deviceid); + g_return_if_fail (gdkdev != NULL); + + gdkdev->info.source = source; +} + +gint +gdk_input_set_mode (guint32 deviceid, GdkInputMode mode) +{ + if (deviceid == GDK_CORE_POINTER) + return FALSE; + + if (gdk_input_vtable.set_mode) + return gdk_input_vtable.set_mode(deviceid,mode); + else + return FALSE; +} + +void +gdk_input_set_axes (guint32 deviceid, GdkAxisUse *axes) +{ + if (deviceid != GDK_CORE_POINTER && gdk_input_vtable.set_axes) + gdk_input_vtable.set_axes (deviceid, axes); +} + +GdkTimeCoord * +gdk_input_motion_events (GdkWindow *window, + guint32 deviceid, + guint32 start, + guint32 stop, + gint *nevents_return) +{ + XTimeCoord *xcoords; + GdkTimeCoord *coords; + int i; + + if (deviceid == GDK_CORE_POINTER) + { + xcoords = XGetMotionEvents (gdk_display, + ((GdkWindowPrivate *)window)->xwindow, + start, stop, nevents_return); + if (xcoords) + { + coords = g_new (GdkTimeCoord, *nevents_return); + for (i=0; i<*nevents_return; i++) + { + coords[i].time = xcoords[i].time; + coords[i].x = xcoords[i].x; + coords[i].y = xcoords[i].y; + coords[i].pressure = 0.5; + coords[i].xtilt = 0.0; + coords[i].ytilt = 0.0; + } + + XFree(xcoords); + + return coords; + } + else + return NULL; + } + else + { + if (gdk_input_vtable.motion_events) + { + return gdk_input_vtable.motion_events(window, + deviceid, start, stop, + nevents_return); + } + else + { + *nevents_return = 0; + return NULL; + } + } +} + +static gint +gdk_input_enable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.enable_window) + return gdk_input_vtable.enable_window (window, gdkdev); + else + return TRUE; +} + +static gint +gdk_input_disable_window (GdkWindow *window, GdkDevicePrivate *gdkdev) +{ + if (gdk_input_vtable.disable_window) + return gdk_input_vtable.disable_window(window,gdkdev); + else + return TRUE; +} + + +static GdkInputWindow * +gdk_input_window_find(GdkWindow *window) +{ + GList *tmp_list; + + for (tmp_list=gdk_input_windows; tmp_list; tmp_list=tmp_list->next) + if (((GdkInputWindow *)(tmp_list->data))->window == window) + return (GdkInputWindow *)(tmp_list->data); + + return NULL; /* Not found */ +} + +/* FIXME: this routine currently needs to be called between creation + and the corresponding configure event (because it doesn't get the + root_relative_geometry). This should work with + gtk_window_set_extension_events, but will likely fail in other + cases */ + +void +gdk_input_set_extension_events (GdkWindow *window, gint mask, + GdkExtensionMode mode) +{ + GList *tmp_list; + GdkInputWindow *iw; + + g_return_if_fail (window != NULL); + + if (mode == GDK_EXTENSION_EVENTS_NONE) + mask = 0; + + if (mask != 0) + { + iw = g_new(GdkInputWindow,1); + + iw->window = window; + iw->mode = mode; + + iw->obscuring = NULL; + iw->num_obscuring = 0; + iw->grabbed = FALSE; + + gdk_input_windows = g_list_append(gdk_input_windows,iw); + ((GdkWindowPrivate *)window)->extension_events = mask; + + /* Add enter window events to the event mask */ + /* FIXME, this is not needed for XINPUT_NONE */ + gdk_window_set_events (window, + gdk_window_get_events (window) | + GDK_ENTER_NOTIFY_MASK); + } + else + { + iw = gdk_input_window_find (window); + if (iw) + { + gdk_input_windows = g_list_remove(gdk_input_windows,iw); + g_free(iw); + } + + ((GdkWindowPrivate *)window)->extension_events = 0; + } + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + GdkDevicePrivate *gdkdev = (GdkDevicePrivate *)(tmp_list->data); + + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + if (mask != 0 && gdkdev->info.mode != GDK_MODE_DISABLED + && (gdkdev->info.has_cursor || mode == GDK_EXTENSION_EVENTS_ALL)) + gdk_input_enable_window(window,gdkdev); + else + gdk_input_disable_window(window,gdkdev); + } + } +} + +void +gdk_input_window_destroy (GdkWindow *window) +{ + GdkInputWindow *input_window; + + input_window = gdk_input_window_find (window); + g_return_if_fail (input_window != NULL); + + gdk_input_windows = g_list_remove(gdk_input_windows,input_window); + g_free(input_window); +} + +void +gdk_input_exit (void) +{ + GList *tmp_list; + GdkDevicePrivate *gdkdev; + + for (tmp_list = gdk_input_devices; tmp_list; tmp_list = tmp_list->next) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid != GDK_CORE_POINTER) + { + gdk_input_set_mode(gdkdev->info.deviceid,GDK_MODE_DISABLED); + + g_free(gdkdev->info.name); +#ifndef XINPUT_NONE + g_free(gdkdev->axes); +#endif + g_free(gdkdev->info.axes); + g_free(gdkdev); + } + } + + g_list_free(gdk_input_devices); + + for (tmp_list = gdk_input_windows; tmp_list; tmp_list = tmp_list->next) + { + g_free(tmp_list->data); + } + g_list_free(gdk_input_windows); +} + +static GdkDevicePrivate * +gdk_input_find_device(guint32 id) +{ + GList *tmp_list = gdk_input_devices; + GdkDevicePrivate *gdkdev; + while (tmp_list) + { + gdkdev = (GdkDevicePrivate *)(tmp_list->data); + if (gdkdev->info.deviceid == id) + return gdkdev; + tmp_list = tmp_list->next; + } + return NULL; +} + +void +gdk_input_window_get_pointer (GdkWindow *window, + guint32 deviceid, + gdouble *x, + gdouble *y, + gdouble *pressure, + gdouble *xtilt, + gdouble *ytilt, + GdkModifierType *mask) +{ + if (gdk_input_vtable.get_pointer) + gdk_input_vtable.get_pointer (window, deviceid, x, y, pressure, + xtilt, ytilt, mask); +} diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c new file mode 100644 index 000000000..d5f85dd1e --- /dev/null +++ b/gdk/x11/gdkmain-x11.c @@ -0,0 +1,2897 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* HAVE_SYS_SELECT_H_ */ + +#define XLIB_ILLEGAL_ACCESS +#include +#include +#include +#include +#include +#include +#include "gdk.h" +#include "gdkprivate.h" +#include "gdkinput.h" + + +#ifndef X_GETTIMEOFDAY +#define X_GETTIMEOFDAY(tv) gettimeofday (tv, NULL) +#endif /* X_GETTIMEOFDAY */ + + +#define DOUBLE_CLICK_TIME 250 +#define TRIPLE_CLICK_TIME 500 +#define DOUBLE_CLICK_DIST 5 +#define TRIPLE_CLICK_DIST 5 + + +#ifndef NO_FD_SET +# define SELECT_MASK fd_set +#else +# ifndef _AIX + typedef long fd_mask; +# endif +# if defined(_IBMR2) +# define SELECT_MASK void +# else +# define SELECT_MASK int +# endif +#endif + + +typedef struct _GdkInput GdkInput; +typedef struct _GdkPredicate GdkPredicate; + +struct _GdkInput +{ + gint tag; + gint source; + GdkInputCondition condition; + GdkInputFunction function; + gpointer data; +}; + +struct _GdkPredicate +{ + GdkEventFunc func; + gpointer data; +}; + +/* + * Private function declarations + */ +static gint gdk_event_wait (void); +static gint gdk_event_translate (GdkEvent *event, + XEvent *xevent); +static Bool gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg); +static void gdk_synthesize_click (GdkEvent *event, + gint nclicks); + +static void gdk_dnd_drag_begin (GdkWindow *initial_window); +static void gdk_dnd_drag_enter (Window dest); +static void gdk_dnd_drag_leave (Window dest); +static void gdk_dnd_drag_end (Window dest, + GdkPoint coords); +static GdkAtom gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent); +static void gdk_print_atom (GdkAtom anatom); + +/* + * old junk from offix, we might use it though so leave it + */ +static Window gdk_drop_get_client_window (Display *dpy, + Window win); +static GdkWindow * gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y); +static void gdk_exit_func (void); +static int gdk_x_error (Display *display, + XErrorEvent *error); +static int gdk_x_io_error (Display *display); +static RETSIGTYPE gdk_signal (int signum); + + +/* Private variable declarations + */ +static int initialized = 0; /* 1 if the library is initialized, + * 0 otherwise. + */ +static int connection_number = 0; /* The file descriptor number of our + * connection to the X server. This + * is used so that we may determine + * when events are pending by using + * the "select" system call. + */ + +static gint received_destroy_notify = FALSE; /* Did we just receive a destroy notify + * event? If so, we need to actually + * destroy the window which received + * it now. + */ +static GdkWindow *window_to_destroy = NULL; /* If we previously received a destroy + * notify event then this is the window + * which received that event. + */ + +static struct timeval start; /* The time at which the library was + * last initialized. + */ +static struct timeval timer; /* Timeout interval to use in the call + * to "select". This is used in + * conjunction with "timerp" to create + * a maximum time to wait for an event + * to arrive. + */ +static struct timeval *timerp; /* The actual timer passed to "select" + * This may be NULL, in which case + * "select" will block until an event + * arrives. + */ +static guint32 timer_val; /* The timeout length as specified by + * the user in milliseconds. + */ +static GList *inputs; /* A list of the input file descriptors + * that we care about. Each list node + * contains a GdkInput struct that describes + * when we are interested in the specified + * file descriptor. That is, when it is + * available for read, write or has an + * exception pending. + */ +static guint32 button_click_time[2]; /* The last 2 button click times. Used + * to determine if the latest button click + * is part of a double or triple click. + */ +static GdkWindow *button_window[2]; /* The last 2 windows to receive button presses. + * Also used to determine if the latest button + * click is part of a double or triple click. + */ +static guint button_number[2]; /* The last 2 buttons to be pressed. + */ + +#define OTHER_XEVENT_BUFSIZE 4 +static XEvent other_xevent[OTHER_XEVENT_BUFSIZE]; /* XEvents passed along to user */ +static int other_xevent_i = 0; +static GList *putback_events = NULL; + +static gulong base_id; +static gint autorepeat; + + +/* + *-------------------------------------------------------------- + * gdk_init + * + * Initialize the library for use. + * + * Arguments: + * "argc" is the number of arguments. + * "argv" is an array of strings. + * + * Results: + * "argc" and "argv" are modified to reflect any arguments + * which were not handled. (Such arguments should either + * be handled by the application or dismissed). + * + * Side effects: + * The library is initialized. + * + *-------------------------------------------------------------- + */ + +void +gdk_init (int *argc, + char ***argv) +{ + XKeyboardState keyboard_state; + int synchronize; + int i, j, k; + XClassHint *class_hint; + int argc_orig = *argc; + char **argv_orig; + + argv_orig = malloc ((argc_orig + 1) * sizeof (char*)); + for (i = 0; i < argc_orig; i++) + argv_orig[i] = g_strdup ((*argv)[i]); + argv_orig[argc_orig] = NULL; + + X_GETTIMEOFDAY (&start); + + signal (SIGHUP, gdk_signal); + signal (SIGINT, gdk_signal); + signal (SIGQUIT, gdk_signal); + signal (SIGBUS, gdk_signal); + signal (SIGSEGV, gdk_signal); + signal (SIGPIPE, gdk_signal); + signal (SIGTERM, gdk_signal); + + gdk_display_name = NULL; + + XSetErrorHandler (gdk_x_error); + XSetIOErrorHandler (gdk_x_io_error); + + synchronize = FALSE; + + if (argc && argv) + { + if (*argc > 0) + gdk_progname = (*argv)[0]; + + for (i = 1; i < *argc;) + { + if (strcmp ("--display", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + + if ((i + 1) < *argc) + { + gdk_display_name = g_strdup ((*argv)[i + 1]); + (*argv)[i + 1] = NULL; + i += 1; + } + } + else if (strcmp ("--sync", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + synchronize = TRUE; + } + else if (strcmp ("--show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = TRUE; + } + else if (strcmp ("--no-show-events", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_show_events = FALSE; + } + else if (strcmp ("--no-xshm", (*argv)[i]) == 0) + { + (*argv)[i] = NULL; + gdk_use_xshm = FALSE; + } + else if (strcmp ("--debug-level", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_debug_level = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("-name", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progname = (*argv)[i]; + (*argv)[i] = NULL; + } + } + else if (strcmp ("-class", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_progclass = (*argv)[i]; + (*argv)[i] = NULL; + } + } +#ifdef XINPUT_GXI + else if (strcmp ("--gxid_host", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_input_gxid_host = ((*argv)[i]); + (*argv)[i] = NULL; + } + } + else if (strcmp ("--gxid_port", (*argv)[i]) == 0) + { + if ((i + 1) < *argc) + { + (*argv)[i++] = NULL; + gdk_input_gxid_port = atoi ((*argv)[i]); + (*argv)[i] = NULL; + } + } +#endif + i += 1; + } + + for (i = 1; i < *argc; i++) + { + for (k = i; k < *argc; k++) + if ((*argv)[k] != NULL) + break; + + if (k > i) + { + k -= i; + for (j = i + k; j < *argc; j++) + (*argv)[j-k] = (*argv)[j]; + *argc -= k; + } + } + } + else + { + gdk_progname = ""; + } + + gdk_display = XOpenDisplay (gdk_display_name); + if (!gdk_display) + g_error ("cannot open display: %s", XDisplayName (gdk_display_name)); + + /* This is really crappy. We have to look into the display structure + * to find the base resource id. This is only needed for recording + * and playback of events. + */ + /* base_id = RESOURCE_BASE; */ + base_id = 0; + if (gdk_show_events) + g_print ("base id: %lu\n", base_id); + + connection_number = ConnectionNumber (gdk_display); + if (gdk_debug_level >= 1) + g_print ("connection number: %d\n", connection_number); + + if (synchronize) + XSynchronize (gdk_display, True); + + gdk_screen = DefaultScreen (gdk_display); + gdk_root_window = RootWindow (gdk_display, gdk_screen); + + gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window, + 10, 10, 10, 10, 0, 0 , 0); + class_hint = XAllocClassHint(); + class_hint->res_name = gdk_progname; + class_hint->res_class = gdk_progclass; + XSetClassHint(gdk_display, gdk_leader_window, class_hint); + XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig); + XFree (class_hint); + + gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True); + gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True); + gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True); + gdk_wm_window_protocols[0] = gdk_wm_delete_window; + gdk_wm_window_protocols[1] = gdk_wm_take_focus; + gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False); + + gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE); + gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE); + gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE); + gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE); + gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE); + gdk_dnd.gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity); + gdk_dnd.gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart); + + XGetKeyboardControl (gdk_display, &keyboard_state); + autorepeat = keyboard_state.global_auto_repeat; + + timer.tv_sec = 0; + timer.tv_usec = 0; + timerp = NULL; + + button_click_time[0] = 0; + button_click_time[1] = 0; + button_window[0] = NULL; + button_window[1] = NULL; + button_number[0] = -1; + button_number[1] = -1; + + if (ATEXIT (gdk_exit_func)) + g_warning ("unable to register exit function"); + + gdk_visual_init (); + gdk_window_init (); + gdk_image_init (); + gdk_input_init (); + + initialized = 1; +} + +/* + *-------------------------------------------------------------- + * gdk_exit + * + * Restores the library to an un-itialized state and exits + * the program using the "exit" system call. + * + * Arguments: + * "errorcode" is the error value to pass to "exit". + * + * Results: + * Allocated structures are freed and the program exits + * cleanly. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_exit (int errorcode) +{ + /* de-initialisation is done by the gdk_exit_funct(), + no need to do this here (Alex J.) */ + exit (errorcode); +} + +/* + *-------------------------------------------------------------- + * gdk_set_locale + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gchar* +gdk_set_locale () +{ + if (!setlocale (LC_ALL,"")) + g_print ("locale not supported by C library\n"); + + if (!XSupportsLocale ()) + { + g_print ("locale not supported by Xlib, locale set to C\n"); + setlocale (LC_ALL, "C"); + } + + if (!XSetLocaleModifiers ("")) + { + g_print ("can not set locale modifiers\n"); + } + + return setlocale (LC_ALL,NULL); +} + +/* + *-------------------------------------------------------------- + * gdk_events_pending + * + * Returns the number of events pending on the queue. + * These events have already been read from the server + * connection. + * + * Arguments: + * + * Results: + * Returns the number of events on XLib's event queue. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_events_pending () +{ + return XPending (gdk_display); +} + +/* + *-------------------------------------------------------------- + * gdk_event_get + * + * Gets the next event. + * + * Arguments: + * "event" is used to hold the received event. + * If "event" is NULL an event is received as normal + * however it is not placed in "event" (and thus no + * error occurs). + * + * Results: + * Returns TRUE if an event was received that we care about + * and FALSE otherwise. This function will also return + * before an event is received if the timeout interval + * runs out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_event_get (GdkEvent *event, + GdkEventFunc pred, + gpointer data) +{ + GdkEvent *temp_event; + GdkPredicate event_pred; + GList *temp_list; + XEvent xevent; + + /* If the last event we received was a destroy notify + * event then we will actually destroy the "gdk" data + * structures now. We don't want to destroy them at the + * time of receiving the event since the main program + * may try to access them and may need to destroy user + * data that has been attached to the window + */ + if (received_destroy_notify) + { + if (gdk_show_events) + g_print ("destroying window:\twindow: %ld\n", + ((GdkWindowPrivate*) window_to_destroy)->xwindow - base_id); + + gdk_window_real_destroy (window_to_destroy); + received_destroy_notify = FALSE; + window_to_destroy = NULL; + } + + /* Initially we haven't received an event and want to + * return FALSE. If "event" is non-NULL, then initialize + * it to the nothing event. + */ + if (event) + { + event->any.type = GDK_NOTHING; + event->any.window = NULL; + event->any.send_event = FALSE; + } + + if (pred) + { + temp_list = putback_events; + while (temp_list) + { + temp_event = temp_list->data; + + if ((* pred) (temp_event, data)) + { + if (event) + *event = *temp_event; + putback_events = g_list_remove_link (putback_events, temp_list); + g_list_free (temp_list); + return TRUE; + } + + temp_list = temp_list->next; + } + + event_pred.func = pred; + event_pred.data = data; + + if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) &event_pred)) + if (event) + return gdk_event_translate (event, &xevent); + } + else + { + if (putback_events) + { + temp_event = putback_events->data; + *event = *temp_event; + + temp_list = putback_events; + putback_events = putback_events->next; + if (putback_events) + putback_events->prev = NULL; + + temp_list->next = NULL; + temp_list->prev = NULL; + g_list_free (temp_list); + g_free (temp_event); + + return TRUE; + } + + /* Wait for an event to occur or the timeout to elapse. + * If an event occurs "gdk_event_wait" will return TRUE. + * If the timeout elapses "gdk_event_wait" will return + * FALSE. + */ + if (gdk_event_wait ()) + { + /* If we get here we can rest assurred that an event + * has occurred. Read it. + */ + XNextEvent (gdk_display, &xevent); + + event->any.send_event = xevent.xany.send_event; + + /* If "event" non-NULL. + */ + if (event) + return gdk_event_translate (event, &xevent); + } + } + + return FALSE; +} + +void +gdk_event_put (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_if_fail (event != NULL); + + new_event = g_new (GdkEvent, 1); + *new_event = *event; + + putback_events = g_list_prepend (putback_events, new_event); +} + +/* + *-------------------------------------------------------------- + * gdk_event_copy + * + * Copy a event structure into new storage. + * + * Arguments: + * "event" is the event struct to copy. + * + * Results: + * A new event structure. Free it with gdk_event_free. + * + * Side effects: + * The reference count of the window in the event is increased. + * + *-------------------------------------------------------------- + */ + +static GMemChunk *event_chunk; + +GdkEvent* +gdk_event_copy (GdkEvent *event) +{ + GdkEvent *new_event; + + g_return_val_if_fail (event != NULL, NULL); + + if (event_chunk == NULL) + event_chunk = g_mem_chunk_new ("events", + sizeof (GdkEvent), + 4096, + G_ALLOC_AND_FREE); + + new_event = g_chunk_new (GdkEvent, event_chunk); + *new_event = *event; + gdk_window_ref (new_event->any.window); + return new_event; +} + +/* + *-------------------------------------------------------------- + * gdk_event_free + * + * Free a event structure obtained from gdk_event_copy. Do not use + * with other event structures. + * + * Arguments: + * "event" is the event struct to free. + * + * Results: + * + * Side effects: + * The reference count of the window in the event is decreased and + * might be freed, too. + * + *-------------------------------------------------------------- */ + +void +gdk_event_free (GdkEvent *event) +{ + g_assert (event_chunk != NULL); + g_return_if_fail (event != NULL); + + gdk_window_unref (event->any.window); + g_mem_chunk_free (event_chunk, event); +} + +/* + *-------------------------------------------------------------- + * gdk_set_debug_level + * + * Sets the debugging level. + * + * Arguments: + * "level" is the new debugging level. + * + * Results: + * + * Side effects: + * Other function calls to "gdk" use the debugging + * level to determine what kind of debugging information + * to print out. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_debug_level (int level) +{ + gdk_debug_level = level; +} + +/* + *-------------------------------------------------------------- + * gdk_set_show_events + * + * Turns on/off the showing of events. + * + * Arguments: + * "show_events" is a boolean describing whether or + * not to show the events gdk receives. + * + * Results: + * + * Side effects: + * When "show_events" is TRUE, calls to "gdk_event_get" + * will output debugging informatin regarding the event + * received to stdout. + * + *-------------------------------------------------------------- + */ + +void +gdk_set_show_events (int show_events) +{ + gdk_show_events = show_events; +} + +void +gdk_set_use_xshm (gint use_xshm) +{ + gdk_use_xshm = use_xshm; +} + +gint +gdk_get_debug_level () +{ + return gdk_debug_level; +} + +gint +gdk_get_show_events () +{ + return gdk_show_events; +} + +gint +gdk_get_use_xshm () +{ + return gdk_use_xshm; +} + +/* + *-------------------------------------------------------------- + * gdk_time_get + * + * Get the number of milliseconds since the library was + * initialized. + * + * Arguments: + * + * Results: + * The time since the library was initialized is returned. + * This time value is accurate to milliseconds even though + * a more accurate time down to the microsecond could be + * returned. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_time_get () +{ + struct timeval end; + struct timeval elapsed; + guint32 milliseconds; + + X_GETTIMEOFDAY (&end); + + if (start.tv_usec > end.tv_usec) + { + end.tv_usec += 1000000; + end.tv_sec--; + } + elapsed.tv_sec = end.tv_sec - start.tv_sec; + elapsed.tv_usec = end.tv_usec - start.tv_usec; + + milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000); + + return milliseconds; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_get + * + * Returns the current timer. + * + * Arguments: + * + * Results: + * Returns the current timer interval. This interval is + * in units of milliseconds. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +guint32 +gdk_timer_get () +{ + return timer_val; +} + +/* + *-------------------------------------------------------------- + * gdk_timer_set + * + * Sets the timer interval. + * + * Arguments: + * "milliseconds" is the new value for the timer. + * + * Results: + * + * Side effects: + * Calls to "gdk_event_get" will last for a maximum + * of time of "milliseconds". However, a value of 0 + * milliseconds will cause "gdk_event_get" to block + * indefinately until an event is received. + * + *-------------------------------------------------------------- + */ + +void +gdk_timer_set (guint32 milliseconds) +{ + timer_val = milliseconds; + timer.tv_sec = milliseconds / 1000; + timer.tv_usec = (milliseconds % 1000) * 1000; + +} + +void +gdk_timer_enable () +{ + timerp = &timer; +} + +void +gdk_timer_disable () +{ + timerp = NULL; +} + +gint +gdk_input_add (gint source, + GdkInputCondition condition, + GdkInputFunction function, + gpointer data) +{ + static gint next_tag = 1; + GList *list; + GdkInput *input; + gint tag; + + tag = 0; + list = inputs; + + while (list) + { + input = list->data; + list = list->next; + + if ((input->source == source) && (input->condition == condition)) + { + input->function = function; + input->data = data; + tag = input->tag; + } + } + + if (!tag) + { + input = g_new (GdkInput, 1); + input->tag = next_tag++; + input->source = source; + input->condition = condition; + input->function = function; + input->data = data; + tag = input->tag; + + inputs = g_list_prepend (inputs, input); + } + + return tag; +} + +void +gdk_input_remove (gint tag) +{ + GList *list; + GList *temp_list; + GdkInput *input; + + list = inputs; + while (list) + { + input = list->data; + + if (input->tag == tag) + { + temp_list = list; + + if (list->next) + list->next->prev = list->prev; + if (list->prev) + list->prev->next = list->next; + if (inputs == list) + inputs = list->next; + + temp_list->next = NULL; + temp_list->prev = NULL; + + g_free (temp_list->data); + g_list_free (temp_list); + break; + } + + list = list->next; + } +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_grab + * + * Grabs the pointer to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "event_mask" masks only interesting events + * "confine_to" limits the cursor movement to the specified window + * "cursor" changes the cursor for the duration of the grab + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_pointer_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_pointer_grab (GdkWindow * window, + gint owner_events, + GdkEventMask event_mask, + GdkWindow * confine_to, + GdkCursor * cursor, + guint32 time) +{ + /* From gdkwindow.c */ + extern int nevent_masks; + extern int event_mask_table[]; + + gint return_val; + GdkWindowPrivate *window_private; + GdkWindowPrivate *confine_to_private; + GdkCursorPrivate *cursor_private; + guint xevent_mask; + Window xwindow; + Window xconfine_to; + Cursor xcursor; + int i; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + confine_to_private = (GdkWindowPrivate*) confine_to; + cursor_private = (GdkCursorPrivate*) cursor; + + xwindow = window_private->xwindow; + + if (!confine_to) + xconfine_to = None; + else + xconfine_to = confine_to_private->xwindow; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + + xevent_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + if (((GdkWindowPrivate *)window)->extension_events && + gdk_input_vtable.grab_pointer) + return_val = gdk_input_vtable.grab_pointer (window, + owner_events, + event_mask, + confine_to, + time); + else + return_val = Success;; + + if (return_val == Success) + return_val = XGrabPointer (window_private->xdisplay, + xwindow, + owner_events, + xevent_mask, + GrabModeAsync, GrabModeAsync, + xconfine_to, + xcursor, + time); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_pointer_ungrab + * + * Releases any pointer grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_pointer_ungrab (guint32 time) +{ + if (gdk_input_vtable.ungrab_pointer) + gdk_input_vtable.ungrab_pointer (time); + + XUngrabPointer (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_grab + * + * Grabs the keyboard to a specific window + * + * Arguments: + * "window" is the window which will receive the grab + * "owner_events" specifies whether events will be reported as is, + * or relative to "window" + * "time" specifies the time + * + * Results: + * + * Side effects: + * requires a corresponding call to gdk_keyboard_ungrab + * + *-------------------------------------------------------------- + */ + +gint +gdk_keyboard_grab (GdkWindow * window, + gint owner_events, + guint32 time) +{ + GdkWindowPrivate *window_private; + Window xwindow; + + g_return_val_if_fail (window != NULL, 0); + + window_private = (GdkWindowPrivate*) window; + xwindow = window_private->xwindow; + + return XGrabKeyboard (window_private->xdisplay, + xwindow, + owner_events, + GrabModeAsync, GrabModeAsync, + time); +} + +/* + *-------------------------------------------------------------- + * gdk_keyboard_ungrab + * + * Releases any keyboard grab + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void +gdk_keyboard_ungrab (guint32 time) +{ + XUngrabKeyboard (gdk_display, time); +} + +/* + *-------------------------------------------------------------- + * gdk_screen_width + * + * Return the width of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_width () +{ + gint return_val; + + return_val = DisplayWidth (gdk_display, gdk_screen); + + return return_val; +} + +/* + *-------------------------------------------------------------- + * gdk_screen_height + * + * Return the height of the screen. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +gint +gdk_screen_height () +{ + gint return_val; + + return_val = DisplayHeight (gdk_display, gdk_screen); + + return return_val; +} + +void +gdk_key_repeat_disable () +{ + XAutoRepeatOff (gdk_display); +} + +void +gdk_key_repeat_restore () +{ + if (autorepeat) + XAutoRepeatOn (gdk_display); + else + XAutoRepeatOff (gdk_display); +} + + +/* + *-------------------------------------------------------------- + * gdk_flush + * + * Flushes the Xlib output buffer and then waits + * until all requests have been received and processed + * by the X server. The only real use for this function + * is in dealing with XShm. + * + * Arguments: + * + * Results: + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +void gdk_flush () +{ + XSync (gdk_display, False); +} + + +void +gdk_beep () +{ + XBell(gdk_display, 100); +} + + +/* + *-------------------------------------------------------------- + * gdk_event_wait + * + * Waits until an event occurs or the timer runs out. + * + * Arguments: + * + * Results: + * Returns TRUE if an event is ready to be read and FALSE + * if the timer ran out. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static gint +gdk_event_wait () +{ + GList *list; + GdkInput *input; + GdkInputCondition condition; + SELECT_MASK readfds; + SELECT_MASK writefds; + SELECT_MASK exceptfds; + int max_input; + int nfd; + + /* If there are no events pending we will wait for an event. + * The time we wait is dependant on the "timer". If no timer + * has been specified then we'll block until an event arrives. + * If a timer has been specified we'll block until an event + * arrives or the timer expires. (This is all done using the + * "select" system call). + */ + + if (XPending (gdk_display) == 0) + { + FD_ZERO (&readfds); + FD_ZERO (&writefds); + FD_ZERO (&exceptfds); + + FD_SET (connection_number, &readfds); + max_input = connection_number; + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + if (input->condition & GDK_INPUT_READ) + FD_SET (input->source, &readfds); + if (input->condition & GDK_INPUT_WRITE) + FD_SET (input->source, &writefds); + if (input->condition & GDK_INPUT_EXCEPTION) + FD_SET (input->source, &exceptfds); + + max_input = MAX (max_input, input->source); + } + + nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp); + + timerp = NULL; + timer_val = 0; + + if (nfd > 0) + { + if (FD_ISSET (connection_number, &readfds)) + { + if (XPending (gdk_display) == 0) + { + if (nfd == 1) + { + XNoOp (gdk_display); + XFlush (gdk_display); + } + return FALSE; + } + else + return TRUE; + } + + list = inputs; + while (list) + { + input = list->data; + list = list->next; + + condition = 0; + if (FD_ISSET (input->source, &readfds)) + condition |= GDK_INPUT_READ; + if (FD_ISSET (input->source, &writefds)) + condition |= GDK_INPUT_WRITE; + if (FD_ISSET (input->source, &exceptfds)) + condition |= GDK_INPUT_EXCEPTION; + + if (condition && input->function) + (* input->function) (input->data, input->source, condition); + } + } + } + else + return TRUE; + + return FALSE; +} + +static gint +gdk_event_translate (GdkEvent *event, + XEvent *xevent) +{ + + GdkWindow *window; + GdkWindowPrivate *window_private; + XComposeStatus compose; + int charcount; + char buf[16]; + gint return_val; + + /* Are static variables used for this purpose thread-safe? */ + static GdkPoint dnd_drag_start = {0,0}, + dnd_drag_oldpos = {0,0}; + static GdkRectangle dnd_drag_dropzone = {0,0,0,0}; + static gint dnd_drag_perhaps = 0; + static GdkWindowPrivate *real_sw = NULL; + static Window dnd_drag_curwin = None, dnd_drag_target = None; + + return_val = FALSE; + + /* Find the GdkWindow that this event occurred in. + * All events occur in some GdkWindow (otherwise, why + * would we be receiving them). It really is an error + * to receive an event for which we cannot find the + * corresponding GdkWindow. We handle events with window=None + * specially - they are generated by XFree86's XInput under + * some circumstances. + */ + + if ((xevent->xany.window == None) && + gdk_input_vtable.window_none_event) + { + return_val = gdk_input_vtable.window_none_event (event,xevent); + + if (return_val >= 0) /* was handled */ + return return_val; + else + return_val = FALSE; + } + + window = gdk_window_lookup (xevent->xany.window); + window_private = (GdkWindowPrivate *) window; + + /* We do a "manual" conversion of the XEvent to a + * GdkEvent. The structures are mostly the same so + * the conversion is fairly straightforward. We also + * optionally print debugging info regarding events + * received. + */ + /* Addendum: + * During drag & drop you get events where the pointer is + * in other windows. Need to just do finer-grained checking + */ + switch (xevent->type) + { + case KeyPress: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key press:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_PRESS; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case KeyRelease: + /* Lookup the string corresponding to the given keysym. + */ + charcount = XLookupString (&xevent->xkey, buf, 16, + (KeySym*) &event->key.keyval, + &compose); + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("key release:\t\twindow: %ld key: %12s %d\n", + xevent->xkey.window - base_id, + XKeysymToString (event->key.keyval), + event->key.keyval); + + event->key.type = GDK_KEY_RELEASE; + event->key.window = window; + event->key.time = xevent->xkey.time; + event->key.state = (GdkModifierType) xevent->xkey.state; + + return_val = !window_private->destroyed; + break; + + case ButtonPress: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button press[%d]:\t\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_PRESS; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) && + (event->button.window == button_window[1]) && + (event->button.button == button_number[1])) + { + gdk_synthesize_click (event, 3); + + button_click_time[1] = 0; + button_click_time[0] = 0; + button_window[1] = NULL; + button_window[0] = 0; + button_number[1] = -1; + button_number[0] = -1; + } + else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) && + (event->button.window == button_window[0]) && + (event->button.button == button_number[0])) + { + gdk_synthesize_click (event, 2); + + button_click_time[1] = button_click_time[0]; + button_click_time[0] = event->button.time; + button_window[1] = button_window[0]; + button_window[0] = event->button.window; + button_number[1] = button_number[0]; + button_number[0] = event->button.button; + } + else + { + button_click_time[1] = 0; + button_click_time[0] = event->button.time; + button_window[1] = NULL; + button_window[0] = event->button.window; + button_number[1] = -1; + button_number[0] = event->button.button; + } + if(window_private + && window_private->dnd_drag_enabled + && !dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + dnd_drag_perhaps = 1; + dnd_drag_start.x = xevent->xbutton.x_root; + dnd_drag_start.y = xevent->xbutton.y_root; + real_sw = window_private; + + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0; + + { + /* Set motion mask for first DnD'd window, since it + will be the one that is actually dragged */ + XWindowAttributes dnd_winattr; + XSetWindowAttributes dnd_setwinattr; + Status rv; + + /* We need to get motion events while the button is down, so + we can know whether to really start dragging or not... */ + XGetWindowAttributes(gdk_display, (Window)window_private->xwindow, + &dnd_winattr); + + window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask; + dnd_setwinattr.event_mask = + window_private->dnd_drag_eventmask = ButtonMotionMask; + XChangeWindowAttributes(gdk_display, window_private->xwindow, + CWEventMask, &dnd_setwinattr); + } + } + return_val = window_private?(!window_private->destroyed):FALSE; + break; + + case ButtonRelease: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("button release[%d]:\twindow: %ld x,y: %d %d button: %d\n", + window_private?window_private->dnd_drag_enabled:0, + xevent->xbutton.window - base_id, + xevent->xbutton.x, xevent->xbutton.y, + xevent->xbutton.button); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->button.type = GDK_BUTTON_RELEASE; + event->button.window = window; + event->button.time = xevent->xbutton.time; + event->button.x = xevent->xbutton.x; + event->button.y = xevent->xbutton.y; + event->button.pressure = 0.5; + event->button.xtilt = 0; + event->button.ytilt = 0; + event->button.state = (GdkModifierType) xevent->xbutton.state; + event->button.button = xevent->xbutton.button; + event->button.source = GDK_SOURCE_MOUSE; + event->button.deviceid = GDK_CORE_POINTER; + + if(dnd_drag_perhaps) + { + if(gdk_dnd.drag_really) + { + GdkPoint foo = {xevent->xbutton.x_root, + xevent->xbutton.y_root}; + XUngrabPointer(gdk_display, CurrentTime); + + if(dnd_drag_target != None) + gdk_dnd_drag_end(dnd_drag_target, foo); + gdk_dnd.drag_really = 0; + + if(gdk_dnd.drag_numwindows) + { + XSetWindowAttributes attrs; + /* Reset event mask to pre-drag value, assuming event_mask + doesn't change during drag */ + attrs.event_mask = real_sw->dnd_drag_savedeventmask; + XChangeWindowAttributes(gdk_display, real_sw->xwindow, + CWEventMask, &attrs); + } + + gdk_dnd.drag_numwindows = 0; + if(gdk_dnd.drag_startwindows) + { + g_free(gdk_dnd.drag_startwindows); + gdk_dnd.drag_startwindows = NULL; + } + + real_sw = NULL; + } + + dnd_drag_perhaps = 0; + dnd_drag_start.x = dnd_drag_start.y = 0; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_curwin = None; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case MotionNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("motion notify:\t\twindow: %ld x,y: %d %d hint: %s d:%d r%d\n", + xevent->xmotion.window - base_id, + xevent->xmotion.x, xevent->xmotion.y, + (xevent->xmotion.is_hint) ? "true" : "false", + dnd_drag_perhaps, gdk_dnd.drag_really); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_ignore_core) + break; + + event->motion.type = GDK_MOTION_NOTIFY; + event->motion.window = window; + event->motion.time = xevent->xmotion.time; + event->motion.x = xevent->xmotion.x; + event->motion.y = xevent->xmotion.y; + event->motion.pressure = 0.5; + event->motion.xtilt = 0; + event->motion.ytilt = 0; + event->motion.state = (GdkModifierType) xevent->xmotion.state; + event->motion.is_hint = xevent->xmotion.is_hint; + event->motion.source = GDK_SOURCE_MOUSE; + event->motion.deviceid = GDK_CORE_POINTER; + +#define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \ + && cy >= dnd_drag_dropzone.y \ + && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \ + && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height)) + + if(dnd_drag_perhaps && gdk_dnd.drag_really) + { + /* First, we have to find what window the motion was in... */ + /* XXX there has to be a better way to do this, perhaps with + XTranslateCoordinates or XQueryTree - I don't know how, + and this sort of works */ + Window curwin, childwin = gdk_root_window, rootwinret; + int x, y; + unsigned int mask; + while(childwin != None) + { + curwin = childwin; + XQueryPointer(gdk_display, curwin, &rootwinret, &childwin, + &x, &y, &x, &y, &mask); + } + if(curwin != dnd_drag_curwin) + { + /* We have left one window and entered another + (do leave & enter bits) */ + if(dnd_drag_curwin != real_sw->xwindow && dnd_drag_curwin != None) + gdk_dnd_drag_leave(dnd_drag_curwin); + dnd_drag_curwin = curwin; + gdk_dnd_drag_enter(dnd_drag_curwin); + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0; + dnd_drag_target = None; + XChangeActivePointerGrab(gdk_display, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragdefault, + CurrentTime); + } + else if(dnd_drag_dropzone.width > 0 + && dnd_drag_dropzone.height > 0) + { + /* Handle all that dropzone stuff - thanks John ;-) */ + if(dnd_drag_target != None + && IS_IN_ZONE(dnd_drag_oldpos.x, dnd_drag_oldpos.y) + && !IS_IN_ZONE(xevent->xmotion.x_root, + xevent->xmotion.y_root)) + { + /* We were in the drop zone and moved out */ + dnd_drag_target = None; + gdk_dnd_drag_leave(curwin); + } + else + { + /* We were outside drop zone but in the window + - have to send enter events */ + gdk_dnd_drag_enter(curwin); + dnd_drag_curwin = curwin; + dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0; + dnd_drag_target = None; + } + } else + dnd_drag_curwin = None; + return_val = FALSE; + } + else + return_val = window?(!window_private->destroyed):FALSE; + break; + + case EnterNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("enter notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, + xevent->xcrossing.subwindow - base_id); + + /* Tell XInput stuff about it if appropriate */ + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.enter_event) + gdk_input_vtable.enter_event (&xevent->xcrossing, window); + + event->crossing.type = GDK_ENTER_NOTIFY; + event->crossing.window = window; + + /* If the subwindow field of the XEvent is non-NULL, then + * lookup the corresponding GdkWindow. + */ + if (xevent->xcrossing.subwindow != None) + event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow); + else + event->crossing.subwindow = NULL; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + + if(dnd_drag_perhaps + && gdk_dnd.drag_really + && xevent->xcrossing.window == real_sw->xwindow) + { + gdk_dnd.drag_really = 0; + XUngrabPointer(gdk_display, CurrentTime); + } + + return_val = (window ? !window_private->destroyed : FALSE); + break; + + case LeaveNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("leave notify:\t\twindow: %ld detail: %d subwin: %ld\n", + xevent->xcrossing.window - base_id, + xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id); + + event->crossing.type = GDK_LEAVE_NOTIFY; + event->crossing.window = window; + + /* Translate the crossing detail into Gdk terms. + */ + switch (xevent->xcrossing.detail) + { + case NotifyInferior: + event->crossing.detail = GDK_NOTIFY_INFERIOR; + break; + case NotifyAncestor: + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + break; + case NotifyVirtual: + event->crossing.detail = GDK_NOTIFY_VIRTUAL; + break; + case NotifyNonlinear: + event->crossing.detail = GDK_NOTIFY_NONLINEAR; + break; + case NotifyNonlinearVirtual: + event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL; + break; + default: + event->crossing.detail = GDK_NOTIFY_UNKNOWN; + break; + } + if(dnd_drag_perhaps + && !gdk_dnd.drag_really) + { + gdk_dnd_drag_addwindow((GdkWindow *) real_sw); + gdk_dnd_drag_begin((GdkWindow *) real_sw); + XGrabPointer(gdk_display, real_sw->xwindow, False, + ButtonMotionMask | + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + GrabModeAsync, GrabModeAsync, gdk_root_window, + gdk_dnd.gdk_cursor_dragdefault, CurrentTime); + gdk_dnd.drag_really = 1; + } + return_val = window ? (!window_private->destroyed) : FALSE; + break; + + case FocusIn: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus in:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = TRUE; + + return_val = !window_private->destroyed; + break; + + case FocusOut: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("focus out:\t\twindow: %ld\n", + xevent->xfocus.window - base_id); + + event->focus_change.type = GDK_FOCUS_CHANGE; + event->focus_change.window = window; + event->focus_change.in = FALSE; + + return_val = !window_private->destroyed; + break; + + case KeymapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("keymap notify\n"); + + /* Not currently handled */ + break; + + case Expose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("expose:\t\twindow: %ld %d x,y: %d %d w,h: %d %d\n", + xevent->xexpose.window - base_id, xevent->xexpose.count, + xevent->xexpose.x, xevent->xexpose.y, + xevent->xexpose.width, xevent->xexpose.height); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xexpose.x; + event->expose.area.y = xevent->xexpose.y; + event->expose.area.width = xevent->xexpose.width; + event->expose.area.height = xevent->xexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case GraphicsExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("graphics expose:\tdrawable: %ld\n", + xevent->xgraphicsexpose.drawable - base_id); + + event->expose.type = GDK_EXPOSE; + event->expose.window = window; + event->expose.area.x = xevent->xgraphicsexpose.x; + event->expose.area.y = xevent->xgraphicsexpose.y; + event->expose.area.width = xevent->xgraphicsexpose.width; + event->expose.area.height = xevent->xgraphicsexpose.height; + event->expose.count = xevent->xexpose.count; + + return_val = !window_private->destroyed; + break; + + case NoExpose: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("no expose:\t\tdrawable: %ld\n", + xevent->xnoexpose.drawable - base_id); + + /* Not currently handled */ + break; + + case VisibilityNotify: + /* Print debugging info. + */ + if (gdk_show_events) + switch (xevent->xvisibility.state) + { + case VisibilityFullyObscured: + g_print ("visibility notify:\twindow: %ld none\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityPartiallyObscured: + g_print ("visibility notify:\twindow: %ld partial\n", + xevent->xvisibility.window - base_id); + break; + case VisibilityUnobscured: + g_print ("visibility notify:\twindow: %ld full\n", + xevent->xvisibility.window - base_id); + break; + } + + /* Not currently handled */ + break; + + case CreateNotify: + /* Not currently handled */ + break; + + case DestroyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("destroy notify:\twindow: %ld\n", + xevent->xdestroywindow.window - base_id); + + event->any.type = GDK_DESTROY; + event->any.window = window; + + /* Remeber which window received the destroy notify + * event so that we can destroy our associated + * data structures the next time the user asks + * us for an event. + */ + received_destroy_notify = TRUE; + window_to_destroy = window; + + return_val = !window_private->destroyed; + break; + + case UnmapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("unmap notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_UNMAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case MapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("map notify:\t\twindow: %ld\n", + xevent->xmap.window - base_id); + + event->any.type = GDK_MAP; + event->any.window = window; + + return_val = !window_private->destroyed; + break; + + case ReparentNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("reparent notify:\twindow: %ld\n", + xevent->xreparent.window - base_id); + + /* Not currently handled */ + break; + + case ConfigureNotify: + /* Print debugging info. + */ + while ((XPending(gdk_display) > 0) && + XCheckTypedWindowEvent(gdk_display, xevent->xany.window, + ConfigureNotify, xevent)) + /*XSync(gdk_display, 0)*/; + + if (gdk_show_events) + g_print ("configure notify:\twindow: %ld x,y: %d %d w,h: %d %d\n", + xevent->xconfigure.window - base_id, + xevent->xconfigure.x, xevent->xconfigure.y, + xevent->xconfigure.width, xevent->xconfigure.height); + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.configure_event) + gdk_input_vtable.configure_event (&xevent->xconfigure, window); + + if ((window_private->window_type != GDK_WINDOW_CHILD) && + ((window_private->width != xevent->xconfigure.width) || + (window_private->height != xevent->xconfigure.height))) + { + event->configure.type = GDK_CONFIGURE; + event->configure.window = window; + event->configure.x = xevent->xconfigure.x; + event->configure.y = xevent->xconfigure.y; + event->configure.width = xevent->xconfigure.width; + event->configure.height = xevent->xconfigure.height; + + window_private->x = xevent->xconfigure.x; + window_private->y = xevent->xconfigure.y; + window_private->width = xevent->xconfigure.width; + window_private->height = xevent->xconfigure.height; + if (window_private->resize_count > 1) + window_private->resize_count -= 1; + + return_val = !window_private->destroyed; + } + break; + + case PropertyNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("property notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->property.type = GDK_PROPERTY_NOTIFY; + event->property.window = window; + event->property.atom = xevent->xproperty.atom; + event->property.time = xevent->xproperty.time; + event->property.state = xevent->xproperty.state; + + return_val = !window_private->destroyed; + break; + + case SelectionClear: + if (gdk_show_events) + g_print ("selection clear:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_CLEAR; + event->selection.window = window; + event->selection.selection = xevent->xselectionclear.selection; + event->selection.time = xevent->xselectionclear.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionRequest: + if (gdk_show_events) + g_print ("selection request:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + event->selection.type = GDK_SELECTION_REQUEST; + event->selection.window = window; + event->selection.selection = xevent->xselectionrequest.selection; + event->selection.target = xevent->xselectionrequest.target; + event->selection.property = xevent->xselectionrequest.property; + event->selection.requestor = xevent->xselectionrequest.requestor; + event->selection.time = xevent->xselectionrequest.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case SelectionNotify: + if (gdk_show_events) + g_print ("selection notify:\twindow: %ld\n", + xevent->xproperty.window - base_id); + + + event->selection.type = GDK_SELECTION_NOTIFY; + event->selection.window = window; + event->selection.selection = xevent->xselection.selection; + event->selection.target = xevent->xselection.target; + event->selection.property = xevent->xselection.property; + event->selection.time = xevent->xselection.time; + + return_val = !((GdkWindowPrivate*) window)->destroyed; + break; + + case ColormapNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("colormap notify:\twindow: %ld\n", + xevent->xcolormap.window - base_id); + + /* Not currently handled */ + break; + + case ClientMessage: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("client message:\twindow: %ld\n", + xevent->xclient.window - base_id); + + /* Client messages are the means of the window manager + * communicating with a program. We'll first check to + * see if this is really the window manager talking + * to us. + */ + if (xevent->xclient.message_type == gdk_wm_protocols) + { + if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window) + { + /* The delete window request specifies a window + * to delete. We don't actually destroy the + * window because "it is only a request". (The + * window might contain vital data that the + * program does not want destroyed). Instead + * the event is passed along to the program, + * which should then destroy the window. + */ + + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("delete window:\t\twindow: %ld\n", + xevent->xclient.window - base_id); + + event->any.type = GDK_DELETE; + event->any.window = window; + + return_val = !window_private->destroyed; + } + else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus) + { + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter) + { + Atom reptype = 0; + + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + if (gdk_show_events) + g_print ("GDK_DROP_ENTER\n"); + return_val = FALSE; + + /* Now figure out if we really want this drop... + * If someone is trying funky clipboard stuff, ignore + */ + if (window_private + && window_private->dnd_drop_enabled + && event->dropenter.u.flags.sendreply + && (reptype = gdk_dnd_check_types (window, xevent))) + { + XEvent replyev; + + replyev.xclient.type = ClientMessage; + replyev.xclient.window = xevent->xclient.data.l[0]; + replyev.xclient.format = 32; + replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest; + replyev.xclient.data.l[0] = window_private->xwindow; + + event->dragrequest.u.allflags = 0; + event->dragrequest.u.flags.protocol_version = + DND_PROTOCOL_VERSION; + event->dragrequest.u.flags.willaccept = 1; + event->dragrequest.u.flags.delete_data = + (window_private->dnd_drop_destructive_op) ? 1 : 0; + + replyev.xclient.data.l[1] = event->dragrequest.u.allflags; + replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0; + replyev.xclient.data.l[4] = reptype; + + XSendEvent (gdk_display, replyev.xclient.window, + False, NoEventMask, &replyev); + + event->any.type = GDK_DROP_ENTER; + event->dropenter.requestor = replyev.xclient.window; + event->dropenter.u.allflags = xevent->xclient.data.l[1]; + } + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave) + { + if (gdk_show_events) + g_print ("GDK_DROP_LEAVE\n"); + if (window_private && window_private->dnd_drop_enabled) + { + event->dropleave.type = GDK_DROP_LEAVE; + event->dropleave.window = window; + event->dropleave.requestor = xevent->xclient.data.l[0]; + event->dropleave.u.allflags = xevent->xclient.data.l[1]; + return_val = TRUE; + } + else + return_val = FALSE; + } + else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest) + { + /* + * make sure to only handle requests from the window the cursor is + * over + */ + if (gdk_show_events) + g_print ("GDK_DRAG_REQUEST\n"); + event->dragrequest.u.allflags = xevent->xclient.data.l[1]; + return_val = FALSE; + + if (window && gdk_dnd.drag_really && + xevent->xclient.data.l[0] == dnd_drag_curwin && + event->dragrequest.u.flags.sendreply == 0) + { + /* Got request - do we need to ask user? */ + if (!event->dragrequest.u.flags.willaccept + && event->dragrequest.u.flags.senddata) + { + /* Yes we do :) */ + event->dragrequest.type = GDK_DRAG_REQUEST; + event->dragrequest.window = window; + event->dragrequest.requestor = xevent->xclient.data.l[0]; + event->dragrequest.isdrop = 0; + event->dragrequest.drop_coords.x = + event->dragrequest.drop_coords.y = 0; + return_val = TRUE; + } + else if (event->dragrequest.u.flags.willaccept) + { + window_private->dnd_drag_destructive_op = + event->dragrequest.u.flags.delete_data; + window_private->dnd_drag_accepted = 1; + window_private->dnd_drag_data_type = + xevent->xclient.data.l[4]; + + dnd_drag_target = dnd_drag_curwin; + XChangeActivePointerGrab (gdk_display, + ButtonMotionMask | + ButtonPressMask | + ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask, + gdk_dnd.gdk_cursor_dragok, + CurrentTime); + } + dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535; + dnd_drag_dropzone.y = + (xevent->xclient.data.l[2] >> 16) & 65535; + dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535; + dnd_drag_dropzone.height = + (xevent->xclient.data.l[3] >> 16) & 65535; + } + } + else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable) + { + gint tmp_int; Atom tmp_atom; + gulong tmp_long; + guchar *tmp_charptr; + gpointer tmp_ptr; + + if(gdk_show_events) + g_print("GDK_DROP_DATA_AVAIL\n"); + event->dropdataavailable.u.allflags = xevent->xclient.data.l[1]; + if(window + /* No preview of data ATM */ + && event->dropdataavailable.u.flags.isdrop) + { + event->dropdataavailable.type = GDK_DROP_DATA_AVAIL; + event->dropdataavailable.window = window; + event->dropdataavailable.requestor = xevent->xclient.data.l[0]; + event->dropdataavailable.data_type = + gdk_atom_name(xevent->xclient.data.l[2]); + if(XGetWindowProperty (gdk_display, + event->dropdataavailable.requestor, + xevent->xclient.data.l[2], + 0, LONG_MAX - 1, + False, XA_PRIMARY, &tmp_atom, + &tmp_int, + &event->dropdataavailable.data_numbytes, + &tmp_long, + &tmp_charptr) + != Success) + { + g_warning("XGetWindowProperty on %#x may have failed\n", + event->dropdataavailable.requestor); + event->dropdataavailable.data = NULL; + } + else + { + g_print("XGetWindowProperty got us %d bytes\n", + event->dropdataavailable.data_numbytes); + event->dropdataavailable.data = + g_malloc(event->dropdataavailable.data_numbytes); + memcpy(event->dropdataavailable.data, + tmp_charptr, event->dropdataavailable.data_numbytes); + XFree(tmp_charptr); + return_val = TRUE; + } + return_val = TRUE; + } + } else { + /* Send unknown ClientMessage's on to Gtk for it to use */ + event->client.type = GDK_CLIENT_EVENT; + event->client.window = window; + event->client.message_type = xevent->xclient.message_type; + event->client.data_format = xevent->xclient.format; + memcpy(&event->client.data, &xevent->xclient.data, + sizeof(event->client.data)); + return_val = TRUE; + } + return_val = return_val && !window_private->destroyed; + break; + + case MappingNotify: + /* Print debugging info. + */ + if (gdk_show_events) + g_print ("mapping notify\n"); + + /* Let XLib know that there is a new keyboard mapping. + */ + XRefreshKeyboardMapping (&xevent->xmapping); + break; + + default: + /* something else - (e.g., a Xinput event) */ + + if (window_private && + (window_private->extension_events != 0) && + gdk_input_vtable.other_event) + return_val = gdk_input_vtable.other_event(event, xevent, window); + + if (return_val < 0) /* not an XInput event, convert */ + { + event->other.type = GDK_OTHER_EVENT; + event->other.window = window; + event->other.xevent = &other_xevent[other_xevent_i]; + memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent)); + other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE; + return_val = TRUE; + } + + return_val = return_val && !window_private->destroyed; + break; + } + + return return_val; +} + +static Bool +gdk_event_get_type (Display *display, + XEvent *xevent, + XPointer arg) +{ + GdkEvent event; + GdkPredicate *pred; + + if (gdk_event_translate (&event, xevent)) + { + pred = (GdkPredicate*) arg; + return (* pred->func) (&event, pred->data); + } + + return FALSE; +} + +static void +gdk_synthesize_click (GdkEvent *event, + gint nclicks) +{ + GdkEvent temp_event; + + g_return_if_fail (event != NULL); + + temp_event = *event; + temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS; + + gdk_event_put (&temp_event); +} + +/* + *-------------------------------------------------------------- + * gdk_exit_func + * + * This is the "atexit" function that makes sure the + * library gets a chance to cleanup. + * + * Arguments: + * + * Results: + * + * Side effects: + * The library is un-initialized and the program exits. + * + *-------------------------------------------------------------- + */ + +static void +gdk_exit_func () +{ + if (initialized) + { + gdk_image_exit (); + gdk_input_exit (); + gdk_key_repeat_restore (); + + XCloseDisplay (gdk_display); + initialized = 0; + } +} + +/* + *-------------------------------------------------------------- + * gdk_x_error + * + * The X error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * "error" is the XErrorEvent that we are handling. + * + * Results: + * Either we were expecting some sort of error to occur, + * in which case we set the "gdk_error_code" flag, or this + * error was unexpected, in which case we will print an + * error message and exit. (Since trying to continue will + * most likely simply lead to more errors). + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_error (Display *display, + XErrorEvent *error) +{ + char buf[64]; + + if (gdk_error_warnings) + { + XGetErrorText (display, error->error_code, buf, 63); + g_error ("%s", buf); + } + + gdk_error_code = -1; + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_x_io_error + * + * The X I/O error handling routine. + * + * Arguments: + * "display" is the X display the error orignated from. + * + * Results: + * An X I/O error basically means we lost our connection + * to the X server. There is not much we can do to + * continue, so simply print an error message and exit. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static int +gdk_x_io_error (Display *display) +{ + g_error ("an x io error occurred"); + return 0; +} + +/* + *-------------------------------------------------------------- + * gdk_signal + * + * The signal handler. + * + * Arguments: + * "sig_num" is the number of the signal we received. + * + * Results: + * The signals we catch are all fatal. So we simply build + * up a nice little error message and print it and exit. + * If in the process of doing so another signal is received + * we notice that we are already exiting and simply kill + * our process. + * + * Side effects: + * + *-------------------------------------------------------------- + */ + +static RETSIGTYPE +gdk_signal (int sig_num) +{ + static int caught_fatal_sig = 0; + char *sig; + + if (caught_fatal_sig) + kill (getpid (), sig_num); + caught_fatal_sig = 1; + + switch (sig_num) + { + case SIGHUP: + sig = "sighup"; + break; + case SIGINT: + sig = "sigint"; + break; + case SIGQUIT: + sig = "sigquit"; + break; + case SIGBUS: + sig = "sigbus"; + break; + case SIGSEGV: + sig = "sigsegv"; + break; + case SIGPIPE: + sig = "sigpipe"; + break; + case SIGTERM: + sig = "sigterm"; + break; + default: + sig = "unknown signal"; + break; + } + + g_print ("\n** ERROR **: %s caught\n", sig); + gdk_exit (1); +} + +static void +gdk_dnd_drag_begin (GdkWindow *initial_window) +{ + GdkEventDragBegin tev; + tev.type = GDK_DRAG_BEGIN; + tev.window = initial_window; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + + gdk_event_put ((GdkEvent *) &tev); +} + +static void +gdk_dnd_drag_enter (Window dest) +{ + XEvent sev; + GdkEventDropEnter tev; + int i; + GdkWindowPrivate *wp; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeEnter; + sev.xclient.window = dest; + + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.u.flags.sendreply = 1; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_data_numtypesavail) + { + sev.xclient.data.l[0] = wp->xwindow; + tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0; + sev.xclient.data.l[1] = tev.u.allflags; + sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0]; + if (wp->dnd_drag_data_numtypesavail > 1) + { + sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1]; + if (wp->dnd_drag_data_numtypesavail > 2) + { + sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2]; + } + else + sev.xclient.data.l[4] = None; + } + else + sev.xclient.data.l[3] = sev.xclient.data.l[4] = None; + XSendEvent (gdk_display, dest, False, NoEventMask, &sev); + } + + } +} + +static void +gdk_dnd_drag_leave (Window dest) +{ + XEvent sev; + GdkEventDropLeave tev; + int i; + GdkWindowPrivate *wp; + + tev.u.allflags = 0; + + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + sev.xclient.type = ClientMessage; + sev.xclient.window = dest; + sev.xclient.format = 32; + sev.xclient.message_type = gdk_dnd.gdk_XdeLeave; + sev.xclient.data.l[1] = tev.u.allflags; + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + sev.xclient.data.l[0] = wp->xwindow; + XSendEvent(gdk_display, dest, False, NoEventMask, &sev); + wp->dnd_drag_accepted = 0; + } +} + +/* + * when a drop occurs, we go through the list of windows being dragged and + * tell them that it has occurred, so that they can set things up and reply + * to 'dest' window + */ +static void +gdk_dnd_drag_end (Window dest, + GdkPoint coords) +{ + GdkWindowPrivate *wp; + GdkEventDragRequest tev; + gchar *tmp_cptr; + int i; + + tev.type = GDK_DRAG_REQUEST; + tev.drop_coords = coords; + tev.requestor = dest; + tev.u.allflags = 0; + tev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tev.isdrop = 1; + + for (i = 0; i < gdk_dnd.drag_numwindows; i++) + { + wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i]; + if (wp->dnd_drag_accepted) + { + tev.window = (GdkWindow *) wp; + tev.u.flags.delete_data = wp->dnd_drag_destructive_op; + tev.data_type = + gdk_atom_name(wp->dnd_drag_data_type); + + gdk_event_put((GdkEvent *) &tev); + } + } +} + +static GdkAtom +gdk_dnd_check_types (GdkWindow *window, + XEvent *xevent) +{ + GdkWindowPrivate *wp = (GdkWindowPrivate *) window; + int i, j; + GdkEventDropEnter event; + + g_return_val_if_fail(window != NULL, 0); + g_return_val_if_fail(xevent != NULL, 0); + g_return_val_if_fail(xevent->type == ClientMessage, 0); + g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0); + + if(wp->dnd_drop_data_numtypesavail <= 0 || + !wp->dnd_drop_data_typesavail) + return 0; + + for (i = 2; i <= 4; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j]) + return xevent->xclient.data.l[i]; + } + } + + /* Now we get the extended type list if it's available */ + event.u.allflags = xevent->xclient.data.l[1]; + if (event.u.flags.extended_typelist) + { + Atom *exttypes, realtype; + gulong nitems, nbar; + gint realfmt; + + if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0], + gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1, + False, AnyPropertyType, &realtype, &realfmt, + &nitems, &nbar, (unsigned char **) &exttypes) + != Success) + return 0; + + if (realfmt != (sizeof(Atom) * 8)) + { + g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n", + realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]); + return 0; + } + + for (i = 0; i <= nitems; i++) + { + for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++) + { + if (exttypes[i] == wp->dnd_drop_data_typesavail[j]) + { + XFree (exttypes); + return exttypes[i]; + } + } + } + XFree (exttypes); + } + return 0; +} + +/* + * used for debugging only + */ +static void +gdk_print_atom (GdkAtom anatom) +{ + gchar *tmpstr = NULL; + tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)"; + g_print("Atom %lu has name %s\n", anatom, tmpstr); + if(tmpstr) + g_free(tmpstr); +} + +/* + * used only by below routine and itself + */ +static Window +getchildren (Display *dpy, + Window win, + Atom WM_STATE) +{ + Window root, parent, *children, inf = 0; + Atom type = None; + unsigned int nchildren, i; + int format; + unsigned long nitems, after; + unsigned char *data; + + if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0) + return 0; + + for (i = 0; !inf && (i < nchildren); i++) + { + XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, + &after, &data); + if (type != 0) + inf = children[i]; + } + + for (i = 0; !inf && (i < nchildren); i++) + inf = getchildren (dpy, children[i], WM_STATE); + + if (children != 0) + XFree ((char *) children); + + return inf; +} + +/* + * find a window with WM_STATE, else return win itself, as per ICCCM + * + * modification of the XmuClientWindow() routine from X11R6.3 + */ +Window +gdk_get_client_window (Display *dpy, + Window win) +{ + Atom WM_STATE; + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + Window inf; + + if (win == 0) + return DefaultRootWindow(dpy); + + if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0) + return win; + + XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &data); + if (type) + return win; + + inf = getchildren (dpy, win, WM_STATE); + + if (inf == 0) + return win; + else + return inf; +} + +static GdkWindow * +gdk_drop_get_real_window (GdkWindow *w, + guint16 *x, + guint16 *y) +{ + GdkWindow *retval = w; + GdkWindowPrivate *awin; + GList *children; + gint16 myx = *x, myy = *y; + + g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL); + + myx = *x; + myy = *y; + +descend: + for (children = gdk_window_get_children(retval); + children && children->next; + children = children->next) + { + awin = (GdkWindowPrivate *) children->data; + if ((myx >= awin->x) && (myy >= awin->y) + && (myx < (awin->x + awin->width)) + && (myy < (awin->y + awin->height))) + { + retval = (GdkWindow *) awin; + myx -= awin->x; + myy -= awin->y; + goto descend; + } + } + + *x = myx; + *y = myy; + + return retval; +} + +/* Sends a ClientMessage to all toplevel client windows */ +void +gdk_event_send_clientmessage_toall(GdkEvent *event) +{ + XEvent sev; + Window *ret_children, ret_root, ret_parent, curwin; + unsigned int ret_nchildren; + int i; + + g_return_if_fail(event != NULL); + + /* Set up our event to send, with the exception of its target window */ + sev.xclient.type = ClientMessage; + sev.xclient.display = gdk_display; + sev.xclient.format = event->client.data_format; + sev.xclient.serial = CurrentTime; + memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data)); + sev.xclient.message_type = event->client.message_type; + + /* OK, we're all set, now let's find some windows to send this to */ + if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent, + &ret_children, &ret_nchildren) != True) + return; + + /* foreach true child window of the root window, send an event to it */ + for(i = 0; i < ret_nchildren; i++) { + curwin = gdk_get_client_window(gdk_display, ret_children[i]); + sev.xclient.window = curwin; + XSendEvent(gdk_display, curwin, False, NoEventMask, &sev); + } + + XFree(ret_children); +} diff --git a/gdk/x11/gdkpixmap-x11.c b/gdk/x11/gdkpixmap-x11.c new file mode 100644 index 000000000..d2d96b6da --- /dev/null +++ b/gdk/x11/gdkpixmap-x11.c @@ -0,0 +1,657 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "../config.h" +#include +#include +#include +#include + +#include "gdk.h" +#include "gdkprivate.h" + +typedef struct +{ + gchar *color_string; + GdkColor color; + gint transparent; +} _GdkPixmapColor; + +GdkPixmap* +gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow, + width, height, depth); + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap * +gdk_bitmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreateBitmapFromData (private->xdisplay, + window_private->xwindow, + data, width, height); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkWindow *window, + gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (fg != NULL, NULL); + g_return_val_if_fail (bg != NULL, NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + if (depth == -1) + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + private = g_new (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + window_private = (GdkWindowPrivate*) window; + + private->parent = NULL; + private->xdisplay = window_private->xdisplay; + private->window_type = GDK_WINDOW_PIXMAP; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = FALSE; + + private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay, + window_private->xwindow, + data, width, height, + fg->pixel, bg->pixel, depth); + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +gint +gdk_pixmap_seek_string (FILE *infile, + const gchar *str, + gint skip_comments) +{ + char instr[1024]; + + while (!feof (infile)) + { + fscanf (infile, "%s", instr); + if (skip_comments == TRUE && strcmp (instr, "/*") == 0) + { + fscanf (infile, "%s", instr); + while (!feof (infile) && strcmp (instr, "*/") != 0) + fscanf (infile, "%s", instr); + fscanf(infile, "%s", instr); + } + if (strcmp (instr, str)==0) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_seek_char (FILE *infile, + gchar c) +{ + gchar b, oldb; + + while (!feof (infile)) + { + fscanf(infile, "%c", &b); + if (c != b && b == '/') + { + fscanf (infile, "%c", &b); + if (b == '*') + { + oldb = b; + while (!feof (infile) && !(oldb == '*' && b == '/')) + { + oldb = b; + fscanf (infile, "%c", &b); + } + fscanf (infile, "%c", &b); + } + } + if (c == b) + return TRUE; + } + + return FALSE; +} + +gint +gdk_pixmap_read_string (FILE *infile, + gchar **buffer, + int *buffer_size) +{ + gchar c; + gint cnt = 0; + + if ((*buffer) == NULL) + { + (*buffer_size) = 10 * sizeof (gchar); + (*buffer) = (gchar *) malloc (*buffer_size); + } + + do + fscanf (infile, "%c", &c); + while (!feof (infile) && c != '"'); + + if (c != '"') + return FALSE; + + while (!feof (infile)) + { + fscanf (infile, "%c", &c); + + if (cnt == (*buffer_size)) + { + (*buffer_size) *= 2; + (*buffer) = (gchar *) realloc ((*buffer), *buffer_size); + } + + if (c != '"') + (*buffer)[cnt++] = c; + else + { + (*buffer)[cnt++] = 0; + return TRUE; + } + } + + return FALSE; +} + +gchar* +gdk_pixmap_skip_whitespaces (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_skip_string (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) + index++; + + return &buffer[index]; +} + +gchar* +gdk_pixmap_extract_color (gchar *buffer) +{ + gint counter, finished = FALSE, numnames; + gchar *ptr = NULL, ch, temp[128]; + gchar color[128], *retcol; + + counter = 0; + while (ptr == NULL) + { + if (buffer[counter] == 'c') + { + ch = buffer[counter + 1]; + if (ch == 0x20 || ch == 0x09) + ptr = &buffer[counter + 1]; + } + else if (buffer[counter] == 0) + return NULL; + + counter++; + } + + if (ptr == NULL) + return NULL; + + ptr = gdk_pixmap_skip_whitespaces (ptr); + + if (ptr[0] == 0) + return NULL; + else if (ptr[0] == '#') + { + retcol = g_new(gchar, strlen (ptr) + 1); + strcpy (retcol, ptr); + return retcol; + } + + color[0] = 0; + numnames = 0; + + while (finished == FALSE) + { + sscanf (ptr, "%s", temp); + + if ((gint)ptr[0] == 0 || strcmp ("s", temp) == 0 || strcmp ("m", temp) == 0 || + strcmp ("g", temp) == 0 || strcmp ("g4", temp) == 0) + finished = TRUE; + else + { + if (numnames > 0) + strcat (color, " "); + strcat (color, temp); + ptr = gdk_pixmap_skip_string (ptr); + ptr = gdk_pixmap_skip_whitespaces (ptr); + numnames++; + } + } + + retcol = g_new(gchar, strlen (color) + 1); + strcpy (retcol, color); + return retcol; +} + + +GdkPixmap* +gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + FILE *infile = NULL; + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt; + gchar *buffer = NULL, *color_name = NULL, pixel_str[32]; + guint buffer_size = 0; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + infile = fopen (filename, "rb"); + if (infile != NULL) + { + if (gdk_pixmap_seek_string (infile, "XPM", FALSE) == TRUE) + { + if (gdk_pixmap_seek_char (infile,'{') == TRUE) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + gdk_pixmap_seek_char (infile, '"'); + fseek (infile, -1, SEEK_CUR); + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + gdk_pixmap_read_string (infile, &buffer, &buffer_size); + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + } + } + + fclose (infile); + free (buffer); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + } + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkColormap *colormap; + GdkVisual *visual; + GdkGC *gc; + GdkColor tmp_color; + gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt, i; + gchar *buffer, *color_name = NULL, pixel_str[32]; + _GdkPixmapColor *colors = NULL, *color = NULL; + gulong index; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + i = 0; + buffer = data[i++]; + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); + + colors = g_new(_GdkPixmapColor, num_cols); + + colormap = gdk_window_get_colormap (window); + visual = gdk_window_get_visual (window); + + if (transparent_color == NULL) + { + gdk_color_white (colormap, &tmp_color); + transparent_color = &tmp_color; + } + + for (cnt = 0; cnt < num_cols; cnt++) + { + buffer = data[i++]; + + colors[cnt].color_string = g_new(gchar, cpp + 1); + for (n = 0; n < cpp; n++) + colors[cnt].color_string[n] = buffer[n]; + colors[cnt].color_string[n] = 0; + colors[cnt].transparent = FALSE; + + if (color_name != NULL) + g_free (color_name); + + color_name = gdk_pixmap_extract_color (&buffer[cpp]); + + if (color_name != NULL) + { + if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + } + else + { + colors[cnt].color = *transparent_color; + colors[cnt].transparent = TRUE; + } + + gdk_color_alloc (colormap, &colors[cnt].color); + } + + index = 0; + image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); + + gc = NULL; + if (mask) + { + *mask = gdk_pixmap_new (window, width, height, 1); + gc = gdk_gc_new (*mask); + + gdk_color_black (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); + + gdk_color_white (colormap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); + } + + for (ycnt = 0; ycnt < height; ycnt++) + { + buffer = data[i++]; + + for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + { + strncpy (pixel_str, &buffer[n], cpp); + pixel_str[cpp] = 0; + color = NULL; + ns = 0; + + while (color == NULL) + { + if (strcmp (pixel_str, colors[ns].color_string) == 0) + color = &colors[ns]; + else + ns++; + } + + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); + + if (mask && color->transparent) + { + if (cnt < xcnt) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + cnt = xcnt + 1; + } + } + + if (mask && (cnt < xcnt)) + gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); + } + + if (mask) + gdk_gc_destroy (gc); + + pixmap = gdk_pixmap_new (window, width, height, visual->depth); + + gc = gdk_gc_new (pixmap); + gdk_gc_set_foreground (gc, transparent_color); + gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height); + gdk_gc_destroy (gc); + gdk_image_destroy (image); + + if (colors != NULL) + { + for (cnt = 0; cnt < num_cols; cnt++) + g_free (colors[cnt].color_string); + g_free (colors); + } + + return pixmap; +} + +void +gdk_pixmap_destroy (GdkPixmap *pixmap) +{ + GdkWindowPrivate *private; + + g_return_if_fail (pixmap != NULL); + + private = (GdkPixmapPrivate*) pixmap; + if (private->ref_count <= 0) + { + XFreePixmap (private->xdisplay, private->xwindow); + gdk_xid_table_remove (private->xwindow); + g_free (pixmap); + } + else + { + private->ref_count -= 1; + } +} diff --git a/gdk/x11/gdkproperty-x11.c b/gdk/x11/gdkproperty-x11.c new file mode 100644 index 000000000..35d8a50cf --- /dev/null +++ b/gdk/x11/gdkproperty-x11.c @@ -0,0 +1,194 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +GdkAtom +gdk_atom_intern (const gchar *atom_name, + gint only_if_exists) +{ + return XInternAtom (gdk_display, atom_name, only_if_exists); +} + +gchar * +gdk_atom_name (GdkAtom atom) +{ + gchar *t; + gchar *name; + + /* If this atom doesn't exist, we'll die with an X error unless + we take precautions */ + + gdk_error_warnings = 0; + t = XGetAtomName (gdk_display, atom); + gdk_error_warnings = 1; + + if (gdk_error_code == -1) + { + return NULL; + } + else + { + name = g_strdup (t); + XFree (t); + + return name; + } +} + +gint +gdk_property_get (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format_type, + gint *actual_length, + guchar **data) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + Atom ret_prop_type; + gint ret_format; + gulong ret_nitems; + gulong ret_bytes_after; + gulong ret_length; + guchar *ret_data; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XGetWindowProperty (xdisplay, xwindow, property, + offset, (length + 3) / 4, pdelete, + type, &ret_prop_type, &ret_format, + &ret_nitems, &ret_bytes_after, + &ret_data); + + if ((ret_prop_type == None) && (ret_format == 0)) + return FALSE; + + if (actual_property_type) + *actual_property_type = ret_prop_type; + if (actual_format_type) + *actual_format_type = ret_format; + + if (ret_prop_type != property) + { + XFree (ret_data); + return FALSE; + } + + /* FIXME: ignoring bytes_after could have very bad effects */ + + if (data) + { + switch (ret_format) + { + case 8: + ret_length = ret_nitems; + break; + case 16: + ret_length = 2 * ret_nitems; + break; + case 32: + ret_length = 4 * ret_nitems; + break; + default: + g_warning ("unknown property return format: %d", ret_format); + XFree (ret_data); + return FALSE; + } + + *data = g_new (guchar, ret_length); + memcpy (*data, ret_data, ret_length); + if (actual_length) + *actual_length = ret_length; + } + + XFree (ret_data); + + return TRUE; +} + +void +gdk_property_change (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + guchar *data, + gint nelements) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XChangeProperty (xdisplay, xwindow, property, type, + format, mode, data, nelements); +} + +void +gdk_property_delete (GdkWindow *window, + GdkAtom property) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (window) + { + private = (GdkWindowPrivate*) window; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = gdk_root_window; + } + + XDeleteProperty (xdisplay, xwindow, property); +} diff --git a/gdk/x11/gdkselection-x11.c b/gdk/x11/gdkselection-x11.c new file mode 100644 index 000000000..6bd425110 --- /dev/null +++ b/gdk/x11/gdkselection-x11.c @@ -0,0 +1,168 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +gint +gdk_selection_owner_set (GdkWindow *owner, + GdkAtom selection, + guint32 time, + gint send_event) +{ + GdkWindowPrivate *private; + Display *xdisplay; + Window xwindow; + + if (owner) + { + private = (GdkWindowPrivate*) owner; + xdisplay = private->xdisplay; + xwindow = private->xwindow; + } + else + { + xdisplay = gdk_display; + xwindow = None; + } + + XSetSelectionOwner (xdisplay, selection, xwindow, time); + + return (XGetSelectionOwner (xdisplay, selection) == xwindow); +} + +GdkWindow* +gdk_selection_owner_get (GdkAtom selection) +{ + Window xwindow; + + xwindow = XGetSelectionOwner (gdk_display, selection); + if (xwindow == None) + return NULL; + + return gdk_window_lookup (xwindow); +} + +void +gdk_selection_convert (GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GdkWindowPrivate *private; + + g_return_if_fail (requestor != NULL); + + private = (GdkWindowPrivate*) requestor; + + XConvertSelection (private->xdisplay, selection, target, + gdk_selection_property, private->xwindow, time); +} + +gint +gdk_selection_property_get (GdkWindow *requestor, + guchar **data, + GdkAtom *ret_type, + gint *ret_format) +{ + GdkWindowPrivate *private; + gulong nitems; + gulong nbytes; + gulong length; + GdkAtom prop_type; + gint prop_format; + guchar *t; + + g_return_val_if_fail (requestor != NULL, 0); + + /* If retrieved chunks are typically small, (and the ICCM says the + should be) it would be a win to try first with a buffer of + moderate length, to avoid two round trips to the server */ + + private = (GdkWindowPrivate*) requestor; + + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, 0, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (ret_type) + *ret_type = prop_type; + if (ret_format) + *ret_format = prop_format; + + if (prop_type == None) + { + *data = NULL; + return 0; + } + + XFree (t); + + /* Add on an extra byte to handle null termination. X guarantees + that t will be 1 longer than nbytes and null terminated */ + length = nbytes + 1; + + /* We can't delete the selection here, because it might be the INCR + protocol, in which case the client has to make sure they'll be + notified of PropertyChange events _before_ the property is deleted. + Otherwise there's no guarantee we'll win the race ... */ + XGetWindowProperty (private->xdisplay, private->xwindow, + gdk_selection_property, 0, (nbytes + 3) / 4, False, + AnyPropertyType, &prop_type, &prop_format, + &nitems, &nbytes, &t); + + if (prop_type != None) + { + *data = g_new (guchar, length); + memcpy (*data, t, length); + XFree (t); + return length-1; + } + else + { + *data = NULL; + return 0; + } +} + + +void +gdk_selection_send_notify (guint32 requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time) +{ + XSelectionEvent xevent; + + xevent.type = SelectionNotify; + xevent.serial = 0; + xevent.send_event = True; + xevent.display = gdk_display; + xevent.requestor = requestor; + xevent.selection = selection; + xevent.target = target; + xevent.property = property; + xevent.time = time; + + XSendEvent (gdk_display, requestor, False, NoEventMask, (XEvent*) &xevent); +} diff --git a/gdk/x11/gdkvisual-x11.c b/gdk/x11/gdkvisual-x11.c new file mode 100644 index 000000000..22acee6f1 --- /dev/null +++ b/gdk/x11/gdkvisual-x11.c @@ -0,0 +1,431 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk.h" +#include "gdkprivate.h" + + +static void gdk_visual_add (GdkVisual *visual); +static void gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec); +static guint gdk_visual_hash (Visual *key); +static gint gdk_visual_compare (Visual *a, + Visual *b); + + +static GdkVisualPrivate *system_visual; +static GdkVisualPrivate *visuals; +static gint nvisuals; + +static gint available_depths[4]; +static gint navailable_depths; + +static GdkVisualType available_types[6]; +static gint navailable_types; + +static char* visual_names[] = +{ + "static gray", + "grayscale", + "static color", + "pseudo color", + "true color", + "direct color", +}; + +static GHashTable *visual_hash = NULL; + +void +gdk_visual_init () +{ + static gint possible_depths[5] = { 32, 24, 16, 15, 8 }; + static GdkVisualType possible_types[6] = + { + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_PSEUDO_COLOR, + GDK_VISUAL_STATIC_COLOR, + GDK_VISUAL_GRAYSCALE, + GDK_VISUAL_STATIC_GRAY + }; + + static gint npossible_depths = 5; + static gint npossible_types = 6; + + XVisualInfo *visual_list; + XVisualInfo visual_template; + GdkVisualPrivate temp_visual; + Visual *default_xvisual; + int nxvisuals; + int i, j; + + visual_template.screen = gdk_screen; + visual_list = XGetVisualInfo (gdk_display, VisualScreenMask, &visual_template, &nxvisuals); + visuals = g_new (GdkVisualPrivate, nxvisuals); + + default_xvisual = DefaultVisual (gdk_display, gdk_screen); + + nvisuals = 0; + for (i = 0; i < nxvisuals; i++) + { + if (visual_list[i].depth >= 8) + { +#ifdef __cplusplus + switch (visual_list[i].c_class) +#else /* __cplusplus */ + switch (visual_list[i].class) +#endif /* __cplusplus */ + { + case StaticGray: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_GRAY; + break; + case GrayScale: + visuals[nvisuals].visual.type = GDK_VISUAL_GRAYSCALE; + break; + case StaticColor: + visuals[nvisuals].visual.type = GDK_VISUAL_STATIC_COLOR; + break; + case PseudoColor: + visuals[nvisuals].visual.type = GDK_VISUAL_PSEUDO_COLOR; + break; + case TrueColor: + visuals[nvisuals].visual.type = GDK_VISUAL_TRUE_COLOR; + break; + case DirectColor: + visuals[nvisuals].visual.type = GDK_VISUAL_DIRECT_COLOR; + break; + } + + visuals[nvisuals].visual.depth = visual_list[i].depth; + visuals[nvisuals].visual.byte_order = + (ImageByteOrder(gdk_display) == LSBFirst) ? + GDK_LSB_FIRST : GDK_MSB_FIRST; + visuals[nvisuals].visual.red_mask = visual_list[i].red_mask; + visuals[nvisuals].visual.green_mask = visual_list[i].green_mask; + visuals[nvisuals].visual.blue_mask = visual_list[i].blue_mask; + visuals[nvisuals].visual.colormap_size = visual_list[i].colormap_size; + visuals[nvisuals].visual.bits_per_rgb = visual_list[i].bits_per_rgb; + visuals[nvisuals].xvisual = visual_list[i].visual; + + if ((visuals[nvisuals].visual.type == GDK_VISUAL_TRUE_COLOR) || + (visuals[nvisuals].visual.type == GDK_VISUAL_DIRECT_COLOR)) + { + gdk_visual_decompose_mask (visuals[nvisuals].visual.red_mask, + &visuals[nvisuals].visual.red_shift, + &visuals[nvisuals].visual.red_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.green_mask, + &visuals[nvisuals].visual.green_shift, + &visuals[nvisuals].visual.green_prec); + + gdk_visual_decompose_mask (visuals[nvisuals].visual.blue_mask, + &visuals[nvisuals].visual.blue_shift, + &visuals[nvisuals].visual.blue_prec); + } + else + { + visuals[nvisuals].visual.red_mask = 0; + visuals[nvisuals].visual.red_shift = 0; + visuals[nvisuals].visual.red_prec = 0; + + visuals[nvisuals].visual.green_mask = 0; + visuals[nvisuals].visual.green_shift = 0; + visuals[nvisuals].visual.green_prec = 0; + + visuals[nvisuals].visual.blue_mask = 0; + visuals[nvisuals].visual.blue_shift = 0; + visuals[nvisuals].visual.blue_prec = 0; + } + + nvisuals += 1; + } + } + + XFree (visual_list); + + for (i = 0; i < nvisuals; i++) + { + for (j = i+1; j < nvisuals; j++) + { + if (visuals[j].visual.depth >= visuals[i].visual.depth) + { + if ((visuals[j].visual.depth == 8) && (visuals[i].visual.depth == 8)) + { + if (visuals[j].visual.type == GDK_VISUAL_PSEUDO_COLOR) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + else if ((visuals[i].visual.type != GDK_VISUAL_PSEUDO_COLOR) && + visuals[j].visual.type > visuals[i].visual.type) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + else if ((visuals[j].visual.depth > visuals[i].visual.depth) || + ((visuals[j].visual.depth == visuals[i].visual.depth) && + (visuals[j].visual.type > visuals[i].visual.type))) + { + temp_visual = visuals[j]; + visuals[j] = visuals[i]; + visuals[i] = temp_visual; + } + } + } + } + + for (i = 0; i < nvisuals; i++) + if (default_xvisual->visualid == visuals[i].xvisual->visualid) + { + system_visual = &visuals[i]; + break; + } + + if (gdk_debug_level >= 1) + for (i = 0; i < nvisuals; i++) + g_print ("visual: %s: %d\n", + visual_names[visuals[i].visual.type], + visuals[i].visual.depth); + + navailable_depths = 0; + for (i = 0; i < npossible_depths; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.depth == possible_depths[i]) + { + available_depths[navailable_depths++] = visuals[j].visual.depth; + break; + } + } + } + + if (navailable_depths == 0) + g_error ("unable to find a usable depth"); + + navailable_types = 0; + for (i = 0; i < npossible_types; i++) + { + for (j = 0; j < nvisuals; j++) + { + if (visuals[j].visual.type == possible_types[i]) + { + available_types[navailable_types++] = visuals[j].visual.type; + break; + } + } + } + + for (i = 0; i < nvisuals; i++) + gdk_visual_add ((GdkVisual*) &visuals[i]); + + if (npossible_types == 0) + g_error ("unable to find a usable visual type"); +} + +GdkVisual* +gdk_visual_ref (GdkVisual *visual) +{ + return visual; +} + +void +gdk_visual_unref (GdkVisual *visual) +{ + return; +} + +gint +gdk_visual_get_best_depth () +{ + return available_depths[0]; +} + +GdkVisualType +gdk_visual_get_best_type () +{ + return available_types[0]; +} + +GdkVisual* +gdk_visual_get_system () +{ + return ((GdkVisual*) system_visual); +} + +GdkVisual* +gdk_visual_get_best () +{ + return ((GdkVisual*) &(visuals[0])); +} + +GdkVisual* +gdk_visual_get_best_with_depth (gint depth) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (depth == visuals[i].visual.depth) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_type (GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if (visual_type == visuals[i].visual.type) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +GdkVisual* +gdk_visual_get_best_with_both (gint depth, + GdkVisualType visual_type) +{ + GdkVisual *return_val; + int i; + + return_val = NULL; + for (i = 0; i < nvisuals; i++) + if ((depth == visuals[i].visual.depth) && + (visual_type == visuals[i].visual.type)) + { + return_val = (GdkVisual*) &(visuals[i]); + break; + } + + return return_val; +} + +void +gdk_query_depths (gint **depths, + gint *count) +{ + *count = navailable_depths; + *depths = available_depths; +} + +void +gdk_query_visual_types (GdkVisualType **visual_types, + gint *count) +{ + *count = navailable_types; + *visual_types = available_types; +} + +void +gdk_query_visuals (GdkVisual **visual_return, + gint *count) +{ + *count = nvisuals; + *visual_return = (GdkVisual*) visuals; +} + + +GdkVisual* +gdk_visual_lookup (Visual *xvisual) +{ + GdkVisual *visual; + + if (!visual_hash) + return NULL; + + visual = g_hash_table_lookup (visual_hash, xvisual); + return visual; +} + +GdkVisual* +gdkx_visual_get (VisualID xvisualid) +{ + int i; + + for (i = 0; i < nvisuals; i++) + if (xvisualid == visuals[i].xvisual->visualid) + return (GdkVisual*) &visuals[i]; + + return NULL; +} + + +static void +gdk_visual_add (GdkVisual *visual) +{ + GdkVisualPrivate *private; + + if (!visual_hash) + visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash, + (GCompareFunc) gdk_visual_compare); + + private = (GdkVisualPrivate*) visual; + + g_hash_table_insert (visual_hash, private->xvisual, visual); +} + +static void +gdk_visual_decompose_mask (gulong mask, + gint *shift, + gint *prec) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) + { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) + { + (*prec)++; + mask >>= 1; + } +} + +static guint +gdk_visual_hash (Visual *key) +{ + return key->visualid; +} + +static gint +gdk_visual_compare (Visual *a, + Visual *b) +{ + return (a->visualid == b->visualid); +} diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c new file mode 100644 index 000000000..aef1367d9 --- /dev/null +++ b/gdk/x11/gdkwindow-x11.c @@ -0,0 +1,1358 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include "gdk.h" +#include "gdkinput.h" +#include "gdkprivate.h" +#include + +int nevent_masks = 16; +int event_mask_table[18] = +{ + ExposureMask, + PointerMotionMask, + PointerMotionHintMask, + ButtonMotionMask, + Button1MotionMask, + Button2MotionMask, + Button3MotionMask, + ButtonPressMask | OwnerGrabButtonMask, + ButtonReleaseMask | OwnerGrabButtonMask, + KeyPressMask, + KeyReleaseMask, + EnterWindowMask, + LeaveWindowMask, + FocusChangeMask, + StructureNotifyMask, + PropertyChangeMask, + 0, /* PROXIMITY_IN */ + 0 /* PROXIMTY_OUT */ +}; + + +void +gdk_window_init () +{ + XWindowAttributes xattributes; + unsigned int width; + unsigned int height; + unsigned int border_width; + unsigned int depth; + int x, y; + + XGetGeometry (gdk_display, gdk_root_window, &gdk_root_window, + &x, &y, &width, &height, &border_width, &depth); + XGetWindowAttributes (gdk_display, gdk_root_window, &xattributes); + + gdk_root_parent.xdisplay = gdk_display; + gdk_root_parent.xwindow = gdk_root_window; + gdk_root_parent.window_type = GDK_WINDOW_ROOT; + gdk_root_parent.window.user_data = NULL; +} + +GdkWindow* +gdk_window_new (GdkWindow *parent, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + GdkWindow *window; + GdkWindowPrivate *private; + GdkWindowPrivate *parent_private; + GdkVisual *visual; + GdkColormap *colormap; + Display *parent_display; + Window xparent; + Visual *xvisual; + XSetWindowAttributes xattributes; + long xattributes_mask; + XSizeHints size_hints; + XWMHints wm_hints; + XTextProperty text_property; + XClassHint *class_hint; + int x, y, depth; + unsigned int class; + char *title; + int i; + + g_return_val_if_fail (attributes != NULL, NULL); + + if (!parent) + parent = (GdkWindow*) &gdk_root_parent; + + parent_private = (GdkWindowPrivate*) parent; + xparent = parent_private->xwindow; + parent_display = parent_private->xdisplay; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + private->parent = parent; + private->xdisplay = parent_display; + private->destroyed = FALSE; + private->resize_count = 0; + private->ref_count = 1; + xattributes_mask = 0; + + if (attributes_mask & GDK_WA_X) + x = attributes->x; + else + x = 0; + + if (attributes_mask & GDK_WA_Y) + y = attributes->y; + else + y = 0; + + private->x = x; + private->y = y; + private->width = (attributes->width > 1) ? (attributes->width) : (1); + private->height = (attributes->height > 1) ? (attributes->height) : (1); + private->window_type = attributes->window_type; + private->extension_events = FALSE; + private->dnd_drag_data_type = None; + private->dnd_drag_data_typesavail = + private->dnd_drop_data_typesavail = NULL; + private->dnd_drop_enabled = private->dnd_drag_enabled = + private->dnd_drag_accepted = private->dnd_drag_datashow = + private->dnd_drop_data_numtypesavail = + private->dnd_drag_data_numtypesavail = 0; + private->dnd_drag_eventmask = private->dnd_drag_savedeventmask = 0; + + window->user_data = NULL; + + if (attributes_mask & GDK_WA_VISUAL) + visual = attributes->visual; + else + visual = gdk_visual_get_system (); + xvisual = ((GdkVisualPrivate*) visual)->xvisual; + + xattributes.event_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (attributes->event_mask & (1 << (i + 1))) + xattributes.event_mask |= event_mask_table[i]; + } + + if (xattributes.event_mask) + xattributes_mask |= CWEventMask; + + if (attributes->wclass == GDK_INPUT_OUTPUT) + { + class = InputOutput; + depth = visual->depth; + + if (attributes_mask & GDK_WA_COLORMAP) + colormap = attributes->colormap; + else + colormap = gdk_colormap_get_system (); + + xattributes.background_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes.border_pixel = BlackPixel (gdk_display, gdk_screen); + xattributes_mask |= CWBorderPixel | CWBackPixel; + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_CHILD: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + break; + + case GDK_WINDOW_DIALOG: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + break; + + case GDK_WINDOW_TEMP: + xattributes.colormap = ((GdkColormapPrivate*) colormap)->xcolormap; + xattributes_mask |= CWColormap; + + xparent = gdk_root_window; + + xattributes.save_under = True; + xattributes.override_redirect = True; + xattributes.cursor = None; + xattributes_mask |= CWSaveUnder | CWOverrideRedirect; + break; + case GDK_WINDOW_ROOT: + g_error ("cannot make windows of type GDK_WINDOW_ROOT"); + break; + case GDK_WINDOW_PIXMAP: + g_error ("cannot make windows of type GDK_WINDOW_PIXMAP (use gdk_pixmap_new)"); + break; + } + } + else + { + depth = 1; + class = InputOnly; + colormap = NULL; + } + + private->xwindow = XCreateWindow (private->xdisplay, xparent, + x, y, private->width, private->height, + 0, depth, class, xvisual, + xattributes_mask, &xattributes); + gdk_xid_table_insert (&private->xwindow, window); + + switch (private->window_type) + { + case GDK_WINDOW_DIALOG: + XSetTransientForHint (private->xdisplay, private->xwindow, xparent); + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_TEMP: + XSetWMProtocols (private->xdisplay, private->xwindow, gdk_wm_window_protocols, 2); + break; + case GDK_WINDOW_CHILD: + if ((attributes->wclass == GDK_INPUT_OUTPUT) && + (colormap != gdk_colormap_get_system ()) && + (colormap != gdk_window_get_colormap (gdk_window_get_toplevel (window)))) + { + g_print ("adding colormap window\n"); + gdk_window_add_colormap_windows (window); + } + break; + default: + break; + } + + size_hints.flags = PSize | PBaseSize; + size_hints.width = private->width; + size_hints.height = private->height; + size_hints.base_width = private->width; + size_hints.base_height = private->height; + + wm_hints.flags = InputHint | StateHint | WindowGroupHint; + wm_hints.window_group = gdk_leader_window; + wm_hints.input = True; + wm_hints.initial_state = NormalState; + + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); + XSetWMHints (private->xdisplay, private->xwindow, &wm_hints); + + if (attributes_mask & GDK_WA_TITLE) + title = attributes->title; + else + title = gdk_progname; + + if (XStringListToTextProperty (&title, 1, &text_property)) + { + XSetWMName (private->xdisplay, private->xwindow, &text_property); + XSetWMIconName (private->xdisplay, private->xwindow, &text_property); + XFree (text_property.value); + } + + if (attributes_mask & GDK_WA_WMCLASS) + { + class_hint = XAllocClassHint (); + class_hint->res_name = attributes->wmclass_name; + class_hint->res_class = attributes->wmclass_class; + XSetClassHint (private->xdisplay, private->xwindow, class_hint); + XFree (class_hint); + } + + gdk_window_set_cursor (window, ((attributes_mask & GDK_WA_CURSOR) ? + (attributes->cursor) : + NULL)); + + return window; +} + +GdkWindow * +gdk_window_foreign_new (guint32 anid) +{ + GdkWindow *window; + GdkWindowPrivate *private; + XWindowAttributes attrs; + + private = g_new (GdkWindowPrivate, 1); + window = (GdkWindow*) private; + + XGetWindowAttributes (gdk_display, anid, &attrs); + + private->parent = NULL; + private->xwindow = anid; + private->xdisplay = gdk_display; + private->x = attrs.x; + private->y = attrs.y; + private->width = attrs.width; + private->height = attrs.height; + private->resize_count = 0; + private->ref_count = 1; + if (anid == attrs.root) + private->window_type = GDK_WINDOW_ROOT; + else + private->window_type = GDK_WINDOW_TOPLEVEL; + /* the above is probably wrong, but it may not be worth the extra + X call to get it right */ + + private->destroyed = FALSE; + private->extension_events = 0; + + window->user_data = NULL; + + gdk_xid_table_insert (&private->xwindow, window); + + return window; +} + +void +gdk_window_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindowPrivate *temp_private; + GdkWindow *temp_window; + GList *children; + GList *tmp; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if(private->dnd_drag_data_numtypesavail > 0) + { + free(private->dnd_drag_data_typesavail); + private->dnd_drag_data_typesavail = NULL; + } + if(private->dnd_drop_data_numtypesavail > 0) + { + free(private->dnd_drop_data_typesavail); + private->dnd_drop_data_typesavail = NULL; + } + + switch (private->window_type) + { + case GDK_WINDOW_TOPLEVEL: + case GDK_WINDOW_CHILD: + case GDK_WINDOW_DIALOG: + case GDK_WINDOW_TEMP: + if (private->ref_count >= 1) + private->ref_count -= 1; + + if (!private->destroyed || (private->destroyed == 2)) + { + children = gdk_window_get_children (window); + tmp = children; + + while (tmp) + { + temp_window = tmp->data; + tmp = tmp->next; + + temp_private = (GdkWindowPrivate*) temp_window; + if (temp_private && !temp_private->destroyed) + /* Removes some nice coredumps... /David */ + { + temp_private->destroyed = 2; + temp_private->ref_count += 1; + gdk_window_destroy (temp_window); + } + } + + g_list_free (children); + + if (!private->destroyed) + XDestroyWindow (private->xdisplay, private->xwindow); + private->destroyed = TRUE; + } + break; + + case GDK_WINDOW_ROOT: + g_error ("attempted to destroy root window"); + break; + + case GDK_WINDOW_PIXMAP: + g_warning ("called gdk_window_destroy on a pixmap (use gdk_pixmap_destroy)"); + gdk_pixmap_destroy (window); + break; + } +} + +void +gdk_window_real_destroy (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (private->extension_events != 0) + gdk_input_window_destroy (window); + + if (private->ref_count == 0) + { + gdk_xid_table_remove (private->xwindow); + g_free (window); + } +} + +GdkWindow* +gdk_window_ref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count += 1; + return window; +} + +void +gdk_window_unref (GdkWindow *window) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + g_return_if_fail (window != NULL); + + private->ref_count -= 1; + if (private->ref_count == 0) + gdk_window_real_destroy (window); +} + +void +gdk_window_show (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + { + XRaiseWindow (private->xdisplay, private->xwindow); + XMapWindow (private->xdisplay, private->xwindow); + } +} + +void +gdk_window_hide (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + if (!private->destroyed) + XUnmapWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_move (GdkWindow *window, + gint x, + gint y) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XMoveWindow (private->xdisplay, private->xwindow, x, y); + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->x = x; + private->y = y; + } +} + +void +gdk_window_resize (GdkWindow *window, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed && + ((private->resize_count > 0) || + (private->width != (guint16) width) || + (private->height != (guint16) height))) + { + XResizeWindow (private->xdisplay, private->xwindow, width, height); + private->resize_count += 1; + + if (private->window_type == GDK_WINDOW_CHILD) + { + private->width = width; + private->height = height; + } + } +} + +void +gdk_window_move_resize (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + private = (GdkWindowPrivate*) window; + XMoveResizeWindow (private->xdisplay, private->xwindow, x, y, width, height); + + if (!private->destroyed && + (private->window_type == GDK_WINDOW_CHILD)) + { + private->x = x; + private->y = y; + private->width = width; + private->height = height; + } +} + +void +gdk_window_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *parent_private; + + g_return_if_fail (window != NULL); + + if (!new_parent) + new_parent = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + parent_private = (GdkWindowPrivate*) new_parent; + + XReparentWindow (window_private->xdisplay, + window_private->xwindow, + parent_private->xwindow, + x, y); +} + +void +gdk_window_clear (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + XClearWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_clear_area (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, False); +} + +void +gdk_window_clear_area_e (GdkWindow *window, + gint x, + gint y, + gint width, + gint height) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XClearArea (private->xdisplay, private->xwindow, + x, y, width, height, True); +} + +void +gdk_window_copy_area (GdkWindow *window, + GdkGC *gc, + gint x, + gint y, + GdkWindow *source_window, + gint source_x, + gint source_y, + gint width, + gint height) +{ + GdkWindowPrivate *src_private; + GdkWindowPrivate *dest_private; + GdkGCPrivate *gc_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (gc != NULL); + + if (source_window == NULL) + source_window = window; + + src_private = (GdkWindowPrivate*) source_window; + dest_private = (GdkWindowPrivate*) window; + gc_private = (GdkGCPrivate*) gc; + + if (!src_private->destroyed && !dest_private->destroyed) + { + XCopyArea (dest_private->xdisplay, src_private->xwindow, dest_private->xwindow, + gc_private->xgc, + source_x, source_y, + width, height, + x, y); + } +} + +void +gdk_window_raise (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XRaiseWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_lower (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + + if (!private->destroyed) + XLowerWindow (private->xdisplay, private->xwindow); +} + +void +gdk_window_set_user_data (GdkWindow *window, + gpointer user_data) +{ + g_return_if_fail (window != NULL); + + window->user_data = user_data; +} + +void +gdk_window_set_hints (GdkWindow *window, + gint x, + gint y, + gint min_width, + gint min_height, + gint max_width, + gint max_height, + gint flags) +{ + GdkWindowPrivate *private; + XSizeHints size_hints; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + size_hints.flags = 0; + + if (flags & GDK_HINT_POS) + { + size_hints.flags |= PPosition; + size_hints.x = x; + size_hints.y = y; + } + + if (flags & GDK_HINT_MIN_SIZE) + { + size_hints.flags |= PMinSize; + size_hints.min_width = min_width; + size_hints.min_height = min_height; + } + + if (flags & GDK_HINT_MAX_SIZE) + { + size_hints.flags |= PMaxSize; + size_hints.max_width = max_width; + size_hints.max_height = max_height; + } + + if (flags) + XSetWMNormalHints (private->xdisplay, private->xwindow, &size_hints); +} + +void +gdk_window_set_title (GdkWindow *window, + const gchar *title) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XStoreName (private->xdisplay, private->xwindow, title); + XSetIconName (private->xdisplay, private->xwindow, title); +} + +void +gdk_window_set_background (GdkWindow *window, + GdkColor *color) +{ + GdkWindowPrivate *private; + + g_return_if_fail (window != NULL); + + private = (GdkWindowPrivate*) window; + XSetWindowBackground (private->xdisplay, private->xwindow, color->pixel); +} + +void +gdk_window_set_back_pixmap (GdkWindow *window, + GdkPixmap *pixmap, + gint parent_relative) +{ + GdkWindowPrivate *window_private; + GdkPixmapPrivate *pixmap_private; + Pixmap xpixmap; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkPixmapPrivate*) pixmap; + + if (pixmap) + xpixmap = pixmap_private->xwindow; + else + xpixmap = None; + + if (parent_relative) + xpixmap = ParentRelative; + + XSetWindowBackgroundPixmap (window_private->xdisplay, window_private->xwindow, xpixmap); +} + +void +gdk_window_set_cursor (GdkWindow *window, + GdkCursor *cursor) +{ + GdkWindowPrivate *window_private; + GdkCursorPrivate *cursor_private; + Cursor xcursor; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + cursor_private = (GdkCursorPrivate*) cursor; + + if (!cursor) + xcursor = None; + else + xcursor = cursor_private->xcursor; + + XDefineCursor (window_private->xdisplay, window_private->xwindow, xcursor); +} + +void +gdk_window_set_colormap (GdkWindow *window, + GdkColormap *colormap) +{ + GdkWindowPrivate *window_private; + GdkColormapPrivate *colormap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (colormap != NULL); + + window_private = (GdkWindowPrivate*) window; + colormap_private = (GdkColormapPrivate*) colormap; + + XSetWindowColormap (window_private->xdisplay, + window_private->xwindow, + colormap_private->xcolormap); + + if (window_private->window_type != GDK_WINDOW_TOPLEVEL) + gdk_window_add_colormap_windows (window); +} + +void +gdk_window_get_user_data (GdkWindow *window, + gpointer *data) +{ + g_return_if_fail (window != NULL); + + *data = window->user_data; +} + +void +gdk_window_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height, + gint *depth) +{ + GdkWindowPrivate *window_private; + Window root; + gint tx; + gint ty; + guint twidth; + guint theight; + guint tborder_width; + guint tdepth; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + + XGetGeometry (window_private->xdisplay, window_private->xwindow, + &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth); + + if (x) + *x = tx; + if (y) + *y = ty; + if (width) + *width = twidth; + if (height) + *height = theight; + if (depth) + *depth = tdepth; +} + +void +gdk_window_get_position (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (x) + *x = window_private->x; + if (y) + *y = window_private->y; +} + +void +gdk_window_get_size (GdkWindow *window, + gint *width, + gint *height) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate*) window; + + if (width) + *width = window_private->width; + if (height) + *height = window_private->height; +} + + +GdkVisual* +gdk_window_get_visual (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + while (window_private && (window_private->window_type == GDK_WINDOW_PIXMAP)) + window_private = (GdkWindowPrivate*) window_private->parent; + + if (window_private) + { + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_visual_lookup (window_attributes.visual); + } + + return NULL; +} + +GdkColormap* +gdk_window_get_colormap (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + XWindowAttributes window_attributes; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate*) window; + + XGetWindowAttributes (window_private->xdisplay, + window_private->xwindow, + &window_attributes); + + return gdk_colormap_lookup (window_attributes.colormap); +} + +GdkWindowType +gdk_window_get_type (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, (GdkWindowType) -1); + + window_private = (GdkWindowPrivate*) window; + return window_private->window_type; +} + +gint +gdk_window_get_origin (GdkWindow *window, + gint *x, + gint *y) +{ + GdkWindowPrivate *private; + gint return_val; + Window child; + gint tx, ty; + + g_return_val_if_fail (window != NULL, 0); + + private = (GdkWindowPrivate*) window; + + return_val = XTranslateCoordinates (private->xdisplay, + private->xwindow, + gdk_root_window, + 0, 0, &tx, &ty, + &child); + + if (x) + *x = tx; + if (y) + *y = ty; + + return return_val; +} + +GdkWindow* +gdk_window_get_pointer (GdkWindow *window, + gint *x, + gint *y, + GdkModifierType *mask) +{ + GdkWindowPrivate *private; + GdkWindow *return_val; + Window root; + Window child; + int rootx, rooty; + int winx, winy; + unsigned int xmask; + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + private = (GdkWindowPrivate*) window; + + return_val = NULL; + if (XQueryPointer (private->xdisplay, private->xwindow, &root, &child, + &rootx, &rooty, &winx, &winy, &xmask)) + { + if (x) *x = winx; + if (y) *y = winy; + if (mask) *mask = xmask; + + if (child) + return_val = gdk_window_lookup (child); + } + + return return_val; +} + +GdkWindow* +gdk_window_get_parent (GdkWindow *window) +{ + g_return_val_if_fail (window != NULL, NULL); + + return ((GdkWindowPrivate*) window)->parent; +} + +GdkWindow* +gdk_window_get_toplevel (GdkWindow *window) +{ + GdkWindowPrivate *private; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + while (private->window_type == GDK_WINDOW_CHILD) + { + window = ((GdkWindowPrivate*) window)->parent; + private = (GdkWindowPrivate*) window; + } + + return window; +} + +GList* +gdk_window_get_children (GdkWindow *window) +{ + GdkWindowPrivate *private; + GdkWindow *child; + GList *children; + Window root; + Window parent; + Window *xchildren; + unsigned int nchildren; + unsigned int i; + + g_return_val_if_fail (window != NULL, NULL); + + private = (GdkWindowPrivate*) window; + + XQueryTree (private->xdisplay, private->xwindow, + &root, &parent, &xchildren, &nchildren); + + children = NULL; + + if (nchildren > 0) + { + for (i = 0; i < nchildren; i++) + { + child = gdk_window_lookup (xchildren[i]); + if (child) + children = g_list_prepend (children, child); + } + + XFree (xchildren); + } + + return children; +} + +GdkEventMask +gdk_window_get_events (GdkWindow *window) +{ + XWindowAttributes attrs; + GdkEventMask event_mask; + int i; + + XGetWindowAttributes (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + &attrs); + + event_mask = 0; + for (i = 0; i < nevent_masks; i++) + { + if (attrs.your_event_mask & event_mask_table[i]) + event_mask |= 1 << (i + 1); + } + + return event_mask; +} + +void +gdk_window_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + long xevent_mask; + int i; + + xevent_mask = StructureNotifyMask; + for (i = 0; i < nevent_masks; i++) + { + if (event_mask & (1 << (i + 1))) + xevent_mask |= event_mask_table[i]; + } + + XSelectInput (gdk_display, ((GdkWindowPrivate *)window)->xwindow, + xevent_mask); +} + +void +gdk_window_add_colormap_windows (GdkWindow *window) +{ + GdkWindow *toplevel; + GdkWindowPrivate *toplevel_private; + GdkWindowPrivate *window_private; + Window *old_windows; + Window *new_windows; + int i, count; + + g_return_if_fail (window != NULL); + + toplevel = gdk_window_get_toplevel (window); + toplevel_private = (GdkWindowPrivate*) toplevel; + window_private = (GdkWindowPrivate*) window; + + if (!XGetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + &old_windows, &count)) + { + old_windows = NULL; + count = 0; + } + + for (i = 0; i < count; i++) + if (old_windows[i] == window_private->xwindow) + return; + + new_windows = g_new (Window, count + 1); + + for (i = 0; i < count; i++) + new_windows[i] = old_windows[i]; + new_windows[count] = window_private->xwindow; + + XSetWMColormapWindows (toplevel_private->xdisplay, + toplevel_private->xwindow, + new_windows, count + 1); + + g_free (new_windows); + if (old_windows) + XFree (old_windows); +} + +/* + * This needs the X11 shape extension. + * If not available, simply remove the call to + * XShapeCombineMask. Shaped windows will look + * ugly, but programs still work. Stefan Wille + */ +void +gdk_window_shape_combine_mask (GdkWindow *window, + GdkBitmap *mask, + gint x, gint y) +{ + GdkWindowPrivate *window_private; + GdkWindowPrivate *pixmap_private; + + g_return_if_fail (window != NULL); + g_return_if_fail (mask != NULL); + + window_private = (GdkWindowPrivate*) window; + pixmap_private = (GdkWindowPrivate*) mask; + + XShapeCombineMask (window_private->xdisplay, + window_private->xwindow, + ShapeBounding, + x, y, /* offset */ + (Pixmap)pixmap_private->xwindow, + ShapeSet); +} + +void +gdk_dnd_drag_addwindow (GdkWindow *window) +{ + GdkWindowPrivate *window_private; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + if (window_private->dnd_drag_enabled == 1 && gdk_dnd.drag_really == 0) + { + gdk_dnd.drag_numwindows++; + gdk_dnd.drag_startwindows = g_realloc (gdk_dnd.drag_startwindows, + gdk_dnd.drag_numwindows + * sizeof(GdkWindow *)); + gdk_dnd.drag_startwindows[gdk_dnd.drag_numwindows - 1] = window; + window_private->dnd_drag_accepted = 0; + } + else + g_warning ("dnd_really is 1 or drag is not enabled! can't addwindow\n"); +} + +void +gdk_window_dnd_drag_set (GdkWindow *window, + guint8 drag_enable, + gchar **typelist, + guint numtypes) +{ + GdkWindowPrivate *window_private; + int i, wasset = 0; + + g_return_if_fail (window != NULL); + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drag_enabled = drag_enable ? 1 : 0; + + if (drag_enable) + { + g_return_if_fail(typelist != NULL); + + if (window_private->dnd_drag_data_numtypesavail > 3) + wasset = 1; + window_private->dnd_drag_data_numtypesavail = numtypes; + + window_private->dnd_drag_data_typesavail = + g_realloc (window_private->dnd_drag_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + { + /* Allow blanket use of ALL to get anything... */ + if (strcmp (typelist[i], "ALL")) + window_private->dnd_drag_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + else + window_private->dnd_drag_data_typesavail[i] = None; + } + + /* + * set our extended type list if we need to + */ + if (numtypes > 3) + gdk_property_change(window, gdk_dnd.gdk_XdeTypelist, + XA_PRIMARY, 32, GDK_PROP_MODE_REPLACE, + (guchar *)(window_private->dnd_drag_data_typesavail + + (sizeof(GdkAtom) * 3)), + (numtypes - 3) * sizeof(GdkAtom)); + else if (wasset) + gdk_property_delete (window, gdk_dnd.gdk_XdeTypelist); + } + else + { + free (window_private->dnd_drag_data_typesavail); + window_private->dnd_drag_data_typesavail = NULL; + window_private->dnd_drag_data_numtypesavail = 0; + } +} + +void +gdk_window_dnd_drop_set (GdkWindow *window, + guint8 drop_enable, + gchar **typelist, + guint numtypes, + guint8 destructive_op) +{ + GdkWindowPrivate *window_private; + int i; + + g_return_if_fail (window != NULL); + + window_private = (GdkWindowPrivate *) window; + + window_private->dnd_drop_enabled = drop_enable ? 1 : 0; + if (drop_enable) + { + g_return_if_fail(typelist != NULL); + + window_private->dnd_drop_data_numtypesavail = numtypes; + + window_private->dnd_drop_data_typesavail = + g_realloc (window_private->dnd_drop_data_typesavail, + (numtypes + 1) * sizeof (GdkAtom)); + + for (i = 0; i < numtypes; i++) + window_private->dnd_drop_data_typesavail[i] = + gdk_atom_intern (typelist[i], FALSE); + + window_private->dnd_drop_destructive_op = destructive_op; + } +} + +/* + * This is used to reply to a GDK_DRAG_REQUEST event + * (which may be generated by XdeRequest or a confirmed drop... + */ +void +gdk_window_dnd_data_set (GdkWindow *window, + GdkEvent *event, + gpointer data, + gulong data_numbytes) +{ + GdkWindowPrivate *window_private; + XEvent sev; + GdkEventDropDataAvailable tmp_ev; + gchar *tmp; + + g_return_if_fail (window != NULL); + g_return_if_fail (event != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (data_numbytes > 0); + g_return_if_fail (event->type == GDK_DRAG_REQUEST); + + g_free (event->dragrequest.data_type); + event->dragrequest.data_type = NULL; + + window_private = (GdkWindowPrivate *) window; + g_return_if_fail (window_private->dnd_drag_accepted != 0); + + /* We set the property on our window... */ + gdk_property_change (window, window_private->dnd_drag_data_type, + XA_PRIMARY, 8, GDK_PROP_MODE_REPLACE, data, + data_numbytes); + tmp = gdk_atom_name(window_private->dnd_drag_data_type); + g_print("DnD type %s on window %ld\n", tmp, window_private->xwindow); + g_free(tmp); + + /* + * Then we send the event to tell the receiving window that the + * drop has happened + */ + tmp_ev.u.allflags = 0; + tmp_ev.u.flags.protocol_version = DND_PROTOCOL_VERSION; + tmp_ev.u.flags.isdrop = event->dragrequest.isdrop; + + sev.xclient.type = ClientMessage; + sev.xclient.format = 32; + sev.xclient.window = event->dragrequest.requestor; + sev.xclient.message_type = gdk_dnd.gdk_XdeDataAvailable; + sev.xclient.data.l[0] = window_private->xwindow; + sev.xclient.data.l[1] = tmp_ev.u.allflags; + sev.xclient.data.l[2] = window_private->dnd_drag_data_type; + + if (event->dragrequest.isdrop) + sev.xclient.data.l[3] = event->dragrequest.drop_coords.x + + (event->dragrequest.drop_coords.y << 16); + else + sev.xclient.data.l[3] = 0; + + sev.xclient.data.l[4] = 0; + + XSendEvent (gdk_display, event->dragrequest.requestor, False, + NoEventMask, &sev); +} diff --git a/gdk/x11/gdkx.h b/gdk/x11/gdkx.h new file mode 100644 index 000000000..cb8e33b44 --- /dev/null +++ b/gdk/x11/gdkx.h @@ -0,0 +1,48 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GDK_X_H__ +#define __GDK_X_H__ + +#include + + +#define GDK_ROOT_WINDOW() gdk_root_window +#define GDK_ROOT_PARENT() &gdk_root_parent +#define GDK_DISPLAY() gdk_display +#define GDK_WINDOW_XDISPLAY(win) (((GdkWindowPrivate*) win)->xdisplay) +#define GDK_WINDOW_XWINDOW(win) (((GdkWindowPrivate*) win)->xwindow) +#define GDK_IMAGE_XDISPLAY(image) (((GdkImagePrivate*) image)->xdisplay) +#define GDK_IMAGE_XIMAGE(image) (((GdkImagePrivate*) image)->ximage) +#define GDK_GC_XDISPLAY(gc) (((GdkGCPrivate*) gc)->xdisplay) +#define GDK_GC_XGC(gc) (((GdkGCPrivate*) gc)->xgc) +#define GDK_COLORMAP_XDISPLAY(cmap) (((GdkColormapPrivate*) cmap)->xdisplay) +#define GDK_COLORMAP_XCOLORMAP(cmap) (((GdkColormapPrivate*) cmap)->xcolormap) +#define GDK_VISUAL_XVISUAL(vis) (((GdkVisualPrivate*) vis)->xvisual) +#define GDK_FONT_XDISPLAY(font) (((GdkFontPrivate*) font)->xdisplay) +#define GDK_FONT_XFONT(font) (((GdkFontPrivate*) font)->xfont) + + +GdkVisual* gdkx_visual_get (VisualID xvisualid); +GdkColormap* gdkx_colormap_get (Colormap xcolormap); +/* Utility function in gdk.c - not sure where it belongs, but it's + needed in more than one place, so make it public */ +Window gdk_get_client_window (Display *dpy, + Window win); + + +#endif /* __GDK_X_H__ */ diff --git a/gdk/x11/gdkxid.c b/gdk/x11/gdkxid.c new file mode 100644 index 000000000..7ee6075c5 --- /dev/null +++ b/gdk/x11/gdkxid.c @@ -0,0 +1,74 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gdkprivate.h" + + +static guint gdk_xid_hash (XID *xid); +static gint gdk_xid_compare (XID *a, + XID *b); + + +GHashTable *xid_ht = NULL; + + +void +gdk_xid_table_insert (XID *xid, + gpointer data) +{ + g_return_if_fail (xid != NULL); + + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_insert (xid_ht, xid, data); +} + +void +gdk_xid_table_remove (XID xid) +{ + if (!xid_ht) + xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash, + (GCompareFunc) gdk_xid_compare); + + g_hash_table_remove (xid_ht, &xid); +} + +gpointer +gdk_xid_table_lookup (XID xid) +{ + gpointer data; + + data = g_hash_table_lookup (xid_ht, &xid); + + return data; +} + + +static guint +gdk_xid_hash (XID *xid) +{ + return *xid; +} + +static gint +gdk_xid_compare (XID *a, + XID *b) +{ + return (*a == *b); +} diff --git a/gdk/x11/gxid.c b/gdk/x11/gxid.c new file mode 100644 index 000000000..219c08bfe --- /dev/null +++ b/gdk/x11/gxid.c @@ -0,0 +1,844 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gxid_proto.h" + +/* #define DEBUG_CLIENTS */ +/* #define DEBUG_EVENTS */ + +char *program_name; +Display *dpy; +Window root_window; /* default root window of dpy */ +int port = 0; /* port to listen on */ +int socket_fd = 0; /* file descriptor of socket */ +typedef struct GxidWindow_ GxidWindow; + +typedef struct GxidDevice_ GxidDevice; +struct GxidDevice_ { + XID id; + int exclusive; + int ispointer; + + XDevice *xdevice; + int motionnotify_type; + int changenotify_type; +}; + +struct GxidWindow_ { + Window xwindow; + /* Immediate child of root that is ancestor of window */ + Window root_child; + int num_devices; + GxidDevice **devices; +}; + +GxidDevice **devices = NULL; +int num_devices = 0; +GxidWindow **windows = NULL; +int num_windows = 0; + +void +handler(int signal) +{ + fprintf(stderr,"%s: dying on signal %d\n",program_name,signal); + if (socket_fd) + close(socket_fd); + exit(1); +} + +void +init_socket() +{ + struct sockaddr_in sin; + + socket_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if (socket_fd < 0) + { + fprintf (stderr, "%s: error getting socket\n", + program_name); + exit(1); + } + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = INADDR_ANY; + + if (bind(socket_fd,(struct sockaddr *)(&sin), + sizeof(struct sockaddr_in)) < 0) + { + fprintf (stderr,"%s: cannot bind to port %d\n", + program_name,port); + exit(1); + } + + if (listen(socket_fd,5) < 0) + { + fprintf (stderr,"%s: error listening on socket\n", + program_name); + exit(1); + }; +} + +#define NUM_EVENTC 2 +static void +enable_device(GxidDevice *dev) +{ + XEventClass xevc[NUM_EVENTC]; + int num_eventc = NUM_EVENTC; + int i,j; + + if (!dev->xdevice) + { + if (dev->ispointer) return; + + dev->xdevice = XOpenDevice(dpy, dev->id); + if (!dev->xdevice) return; + + DeviceMotionNotify (dev->xdevice, dev->motionnotify_type, + xevc[0]); + ChangeDeviceNotify (dev->xdevice, dev->changenotify_type, + xevc[1]); + + /* compress out zero event classes */ + for (i=0,j=0;iispointer) + old_pointer = devices[i]; + else + if (!new_pointer && !devices[i]->exclusive) + new_pointer = devices[i]; + } + + if (!old_pointer || !new_pointer) + return 0; + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Switching core from %ld to %ld\n", + old_pointer->id,new_pointer->id); +#endif + result = XChangePointerDevice(dpy,new_pointer->xdevice, 0, 1); + if (result != Success) + { + fprintf(stderr,"gxid: Error %d switching core from %ld to %ld\n", + result, old_pointer->id, new_pointer->id); + } + else + { + new_pointer->ispointer = 1; + old_pointer->ispointer = 0; + if (!old_pointer->xdevice) + enable_device(old_pointer); + } + + return 1; +} + +void +disable_device(GxidDevice *dev) +{ + if (dev->xdevice) + { + if (dev->ispointer) + return; + XCloseDevice(dpy,dev->xdevice); + dev->xdevice = 0; + } +} + +GxidDevice * +init_device(XDeviceInfo *xdevice) +{ + GxidDevice *dev = (GxidDevice *)malloc(sizeof(GxidDevice)); + XAnyClassPtr class; + int num_axes, i; + + dev->id = xdevice->id; + dev->exclusive = 0; + dev->xdevice = NULL; + + dev->ispointer = (xdevice->use == IsXPointer); + + /* step through the classes */ + + num_axes = 0; + class = xdevice->inputclassinfo; + for (i=0;inum_classes;i++) + { + if (class->class == ValuatorClass) + { + XValuatorInfo *xvi = (XValuatorInfo *)class; + num_axes = xvi->num_axes; + } + class = (XAnyClassPtr)(((char *)class) + class->length); + } + + /* return NULL if insufficient axes */ + if (num_axes < 2) + { + free((void *)dev); + return NULL; + } + + if (!dev->ispointer) + enable_device(dev); + return dev; +} + +void +init_xinput() +{ + char **extensions; + XDeviceInfo *xdevices; + int num_xdevices; + int num_extensions; + int i; + + extensions = XListExtensions(dpy, &num_extensions); + for (i = 0; i < num_extensions && + (strcmp(extensions[i], "XInputExtension") != 0); i++); + XFreeExtensionList(extensions); + if (i == num_extensions) /* XInput extension not found */ + { + fprintf(stderr,"XInput extension not found\n"); + exit(1); + } + + xdevices = XListInputDevices(dpy, &num_xdevices); + devices = (GxidDevice **)malloc(num_xdevices * sizeof(GxidDevice *)); + + num_devices = 0; + for(i=0; idevice); + XID winid = ntohl(msg->window); + int exclusive = ntohl(msg->exclusive); + GxidDevice *device = NULL; + GxidWindow *window = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld claimed (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;iid == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + if (device->exclusive) + { + /* already in use */ + fprintf(stderr, + "%s: Device %ld already claimed in exclusive mode\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + if (exclusive) + { + for (i=0;inum_devices;j++) + if (windows[i]->devices[j]->id == devid) + { + /* already in use */ + fprintf(stderr, + "%s: Can't establish exclusive use of device %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + } + if (device->ispointer) + if (!switch_core_pointer()) + { + fprintf(stderr, + "%s: Can't free up core pointer %ld\n", + program_name,devid); + return GXID_RETURN_ERROR; + } + + device->exclusive = 1; + disable_device(device); + XSelectInput(dpy,winid,StructureNotifyMask); + } + else /* !exclusive */ + { + /* FIXME: this is a bit improper. We probably should do this only + when a window is first claimed. But we might be fooled if + an old client died without releasing it's windows. So until + we look for client-window closings, do it here + + (We do look for closings now...) + */ + + XSelectInput(dpy,winid,EnterWindowMask|StructureNotifyMask); + } + + for (i=0;ixwindow == winid) + { + window = windows[i]; + break; + } + } + + /* Create window structure if no devices have been previously + claimed on it */ + if (!window) + { + num_windows++; + windows = (GxidWindow **)realloc(windows, + sizeof(GxidWindow*)*num_windows); + window = (GxidWindow *)malloc(sizeof(GxidWindow)); + windows[num_windows-1] = window; + + window->xwindow = winid; + window->root_child = gxi_find_root_child(dpy,winid); + window->num_devices = 0; + window->devices = 0; + } + + + for (i=0;inum_devices;i++) + { + if (window->devices[i] == device) + return GXID_RETURN_OK; + } + + window->num_devices++; + window->devices = (GxidDevice **)realloc(window->devices, + sizeof(GxidDevice*)*num_devices); + /* we need add the device to the window */ + window->devices[i] = device; + + return GXID_RETURN_OK; +} + +int +handle_release_device(GxidReleaseDevice *msg) +{ + int i,j; + XID devid = ntohl(msg->device); + XID winid = ntohl(msg->window); + + GxidDevice *device = NULL; + +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released (window 0x%lx)\n",devid,winid); +#endif + + for (i=0;iid == devid) + { + device = devices[i]; + break; + } + } + if (!device) + { + fprintf(stderr,"%s: Unknown device id %ld\n",program_name,devid); + return GXID_RETURN_ERROR; + } + + for (i=0;ixwindow == winid) + for (j=0;jnum_devices;j++) + if (w->devices[j]->id == devid) + { + if (jnum_devices-1) + w->devices[j] = w->devices[w->num_devices-1]; + w->num_devices--; + + if (w->num_devices == 0) + { + if (iexclusive) + { + device->exclusive = 0; + enable_device(device); + } + return GXID_RETURN_OK; + } + } + + /* device/window combination not found */ + fprintf(stderr, + "%s: Device %ld not claimed for window 0x%lx\n", + program_name,devid,winid); + return GXID_RETURN_ERROR; +} + +void +handle_connection() +{ + GxidMessage msg; + GxidU32 type; + int length; + GxidI32 retval; + + int conn_fd; + struct sockaddr_in sin; + int sin_length; + int count; + + sin_length = sizeof(struct sockaddr_in); + conn_fd = accept(socket_fd,(struct sockaddr *)&sin,&sin_length); + if (conn_fd < 0) + { + fprintf(stderr,"%s: Error accepting connection\n", + program_name); + exit(1); + } + + /* read type and length of message */ + + count = read(conn_fd,(char *)&msg,2*sizeof(GxidU32)); + if (count != 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message header\n", + program_name); + close(conn_fd); + return; + } + type = ntohl(msg.any.type); + length = ntohl(msg.any.length); + + /* read rest of message */ + + if (length > sizeof(GxidMessage)) + { + fprintf(stderr,"%s: Bad message length\n", + program_name); + close(conn_fd); + return; + } + + count = read(conn_fd,2*sizeof(GxidU32) + (char *)&msg, + length - 2*sizeof(GxidU32)); + if (count != length - 2*sizeof(GxidU32)) + { + fprintf(stderr,"%s: Error reading message body\n", + program_name); + close(conn_fd); + return; + } + + switch (type) + { + case GXID_CLAIM_DEVICE: + retval = handle_claim_device((GxidClaimDevice *)&msg); + break; + case GXID_RELEASE_DEVICE: + retval = handle_release_device((GxidReleaseDevice *)&msg); + break; + default: + fprintf(stderr,"%s: Unknown message type: %ld (ignoring)\n", + program_name,type); + close(conn_fd); + return; + } + + count = write(conn_fd,&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"%s: Error writing return code\n", + program_name); + } + + close(conn_fd); +} + +void +handle_motion_notify(XDeviceMotionEvent *event) +{ + int i,j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + Window w, root, child; + int root_x, root_y, x, y, mask; + + for (j=0;jispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + + if (new_device && !new_device->exclusive && !new_device->ispointer) + { + /* make sure we aren't stealing the pointer back from a slow + client */ + child = root_window; + do + { + w = child; + /* FIXME: this fails disasterously if child vanishes between + calls. (Which is prone to happening since we get events + on root just as the client exits) */ + + XQueryPointer(dpy,w,&root,&child,&root_x,&root_y, + &x,&y,&mask); + } + while (child != None); + + for (i=0;ixwindow == w) + for (j=0;jnum_devices;j++) + if (windows[i]->devices[j] == new_device) + return; + + /* FIXME: do something smarter with axes */ + XChangePointerDevice(dpy,new_device->xdevice, 0, 1); + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_change_notify(XChangeDeviceNotifyEvent *event) +{ + int j; + GxidDevice *old_device = NULL; + GxidDevice *new_device = NULL; + + + for (j=0;jispointer) + old_device = devices[j]; + if (devices[j]->id == event->deviceid) + new_device = devices[j]; + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: ChangeNotify event; old = %ld; new = %ld\n", + old_device->id, new_device->id); +#endif + + if (old_device != new_device) + { + new_device->ispointer = 1; + + old_device->ispointer = 0; + if (!old_device->xdevice) + enable_device(old_device); + } +} + +void +handle_enter_notify(XEnterWindowEvent *event, GxidWindow *window) +{ + int i; + GxidDevice *old_pointer = NULL; + for (i=0;iispointer) + { + old_pointer = devices[i]; + break; + } + } + +#ifdef DEBUG_EVENTS + fprintf(stderr,"gxid: Enter event; oldpointer = %ld\n", + old_pointer->id); +#endif + + if (old_pointer) + for (i=0;inum_devices;i++) + { + if (window->devices[i] == old_pointer) + { + switch_core_pointer(); + break; + } + } +} + +void +handle_destroy_notify(XDestroyWindowEvent *event) +{ + int i,j; + + for (i=0;ixwindow == event->window) + { + GxidWindow *w = windows[i]; + + for (j=0;jnum_devices;j++) + { +#ifdef DEBUG_CLIENTS + fprintf(stderr,"device %ld released on destruction of window 0x%lx.\n", + w->devices[j]->id,w->xwindow); +#endif + + if (w->devices[j]->exclusive) + { + w->devices[j]->exclusive = 0; + enable_device(devices[j]); + } + } + + if (idevices) + free((void *)w->devices); + free((void *)w); + /* FIXME: should we deselect input? But what + what if window is already destroyed */ + + return; + } +} + +void +handle_xevent() +{ + int i; + XEvent event; + + XNextEvent (dpy, &event); + +#ifdef DEBUG_EVENTS + fprintf(stderr,"Event - type = %d; window = 0x%lx\n", + event.type,event.xany.window); +#endif + + if (event.type == ConfigureNotify) + { +#ifdef DEBUG_EVENTS + XConfigureEvent *xce = (XConfigureEvent *)&event; + fprintf(stderr," configureNotify: window = 0x%lx\n",xce->window); +#endif + } + else if (event.type == EnterNotify) + { + /* pointer entered a claimed window */ + for (i=0;ixwindow) + handle_enter_notify((XEnterWindowEvent *)&event,windows[i]); + } + } + else if (event.type == DestroyNotify) + { + /* A claimed window was destroyed */ + for (i=0;ixwindow) + handle_destroy_notify((XDestroyWindowEvent *)&event); + } + } + else + for (i=0;imotionnotify_type) + { + handle_motion_notify((XDeviceMotionEvent *)&event); + break; + } + else if (event.type == devices[i]->changenotify_type) + { + handle_change_notify((XChangeDeviceNotifyEvent *)&event); + break; + } + } +} + +void +usage() +{ + fprintf(stderr,"Usage: %s [-d display] [-p --gxid-port port]\n", + program_name); + exit(1); +} + +int +main(int argc, char **argv) +{ + int i; + char *display_name = NULL; + fd_set readfds; + + program_name = argv[0]; + + for (i=1;i= argc) usage(); + display_name = argv[i]; + } + else if (!strcmp(argv[i],"--gxid-port") || + !strcmp(argv[i],"-p")) + { + if (++i >= argc) usage(); + port = atoi(argv[i]); + break; + } + else + usage(); + } + + if (!port) + { + char *t = getenv("GXID_PORT"); + if (t) + port = atoi(t); + else + port = 6951; + } + /* set up a signal handler so we can clean up if killed */ + + signal(SIGTERM,handler); + signal(SIGINT,handler); + + /* initialize the X connection */ + + dpy = XOpenDisplay (display_name); + if (!dpy) + { + fprintf (stderr, "%s: unable to open display '%s'\n", + program_name, XDisplayName (display_name)); + exit (1); + } + + root_window = DefaultRootWindow(dpy); + + /* We'll want to do this in the future if we are to support + gxid monitoring visibility information for clients */ +#if 0 + XSelectInput(dpy,root_window,SubstructureNotifyMask); +#endif + init_xinput(); + + /* set up our server connection */ + + init_socket(); + + /* main loop */ + + if (XPending(dpy)) /* this seems necessary to get things + in sync */ + handle_xevent(); + while (1) + { + + FD_ZERO(&readfds); + FD_SET(ConnectionNumber(dpy),&readfds); + FD_SET(socket_fd,&readfds); + + if (select(8*sizeof(readfds),&readfds, + (fd_set *)0,(fd_set *)0, (struct timeval *)0) < 0) + { + fprintf(stderr,"Error in select\n"); + exit(1); + } + + if (FD_ISSET(socket_fd,&readfds)) + handle_connection(socket_fd); + + while (XPending(dpy)) + handle_xevent(); + } + + XCloseDisplay (dpy); + exit (0); +} diff --git a/gdk/x11/gxid_lib.c b/gdk/x11/gxid_lib.c new file mode 100644 index 000000000..357b76451 --- /dev/null +++ b/gdk/x11/gxid_lib.c @@ -0,0 +1,116 @@ +/* + * gxid version 0.3 + * + * Copyright 1997 Owen Taylor +*/ + +#include "../config.h" + +#ifdef XINPUT_GXI + +#include +#include +#include +#include +#include +#include +#include + +#include "gxid_lib.h" + +/* handles mechanics of communicating with a client */ +static int +gxid_send_message(char *host, int port, GxidMessage *msg) +{ + int socket_fd; + struct sockaddr_in sin; + int count; + GxidI32 retval; + struct hostent *he; + + if (!port) port = 6951; + + if (!host || strcmp(host,"localhost") ) + { + /* looking it up as localhost can be _SLOW_ on ppp systems */ + /* FIXME: Could localhost be anything other than loopback? */ + host = "127.0.0.1"; + } + + he = gethostbyname(host); + if (!he) + { + fprintf(stderr,"gxid_lib: error looking up %s\n",host); + return GXID_RETURN_ERROR; + } + + sin.sin_family = he->h_addrtype; + sin.sin_port = htons(port); + memcpy(&sin.sin_addr,he->h_addr_list[0],he->h_length); + + socket_fd = socket(AF_INET,SOCK_STREAM,0); + if (socket_fd < 0) + { + fprintf(stderr,"gxid_lib: can't get socket"); + return GXID_RETURN_ERROR; + } + + if (connect(socket_fd, (struct sockaddr *)&sin, + sizeof sin) < 0) + { + fprintf(stderr,"gxid_lib: can't connect to %s:%d\n",host,port); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + count = write(socket_fd,(char *)msg,ntohl(msg->any.length)); + if (count != ntohl(msg->any.length)) + { + fprintf(stderr,"gxid_lib: error writing"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + /* now read the return code */ + count = read(socket_fd,(char *)&retval,sizeof(GxidI32)); + if (count != sizeof(GxidI32)) + { + fprintf(stderr,"gxid_lib: error reading return code"); + close(socket_fd); + return GXID_RETURN_ERROR; + } + + close (socket_fd); + return ntohl(retval); +} + +/* claim a device. If exclusive, device is claimed exclusively */ +int +gxid_claim_device(char *host, int port, GxidU32 device, GxidU32 window, + int exclusive) +{ + GxidClaimDevice msg; + msg.type = htonl(GXID_CLAIM_DEVICE); + msg.length = htonl(sizeof(GxidClaimDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + msg.exclusive = htonl(exclusive); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +/* release a device/window pair */ +int +gxid_release_device(char *host, int port, GxidU32 device, GxidU32 window) +{ + GxidReleaseDevice msg; + msg.type = htonl(GXID_RELEASE_DEVICE); + msg.length = htonl(sizeof(GxidReleaseDevice)); + msg.device = htonl(device); + msg.window = htonl(window); + + return gxid_send_message(host,port,(GxidMessage *)&msg); +} + +#endif /* XINPUT_GXI */ + diff --git a/gdk/x11/gxid_lib.h b/gdk/x11/gxid_lib.h new file mode 100644 index 000000000..6a7103bbe --- /dev/null +++ b/gdk/x11/gxid_lib.h @@ -0,0 +1,6 @@ +#include "gxid_proto.h" + +int gxid_claim_device(char *host, int port, + GxidU32 device, GxidU32 window, int exclusive); +int gxid_release_device(char *host, int port, GxidU32 device, + GxidU32 window); diff --git a/gdk/x11/gxid_proto.h b/gdk/x11/gxid_proto.h new file mode 100644 index 000000000..24959b806 --- /dev/null +++ b/gdk/x11/gxid_proto.h @@ -0,0 +1,39 @@ +#define GXID_CLAIM_DEVICE 1 +#define GXID_RELEASE_DEVICE 2 + +#define GXID_RETURN_OK 0 +#define GXID_RETURN_ERROR -1 + +typedef struct GxidClaimDevice_ GxidClaimDevice; +typedef struct GxidReleaseDevice_ GxidReleaseDevice; +typedef struct GxidMessageAny_ GxidMessageAny; +typedef union GxidMessage_ GxidMessage; + +typedef unsigned long GxidU32; +typedef long GxidI32; + +struct GxidClaimDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; + GxidU32 exclusive; +}; + +struct GxidReleaseDevice_ { + GxidU32 type; + GxidU32 length; + GxidU32 device; + GxidU32 window; +}; + +struct GxidMessageAny_ { + GxidU32 type; + GxidU32 length; +}; + +union GxidMessage_ { + GxidMessageAny any; + GxidClaimDevice claim; + GxidReleaseDevice release; +}; diff --git a/glib/.cvsignore b/glib/.cvsignore new file mode 100644 index 000000000..e0d0bd21d --- /dev/null +++ b/glib/.cvsignore @@ -0,0 +1,11 @@ +*.lo +config.log +libtool +config.status +stamp-h +Makefile +.deps +_libs +libglib.la +testglib +glibconfig.h diff --git a/glib/AUTHORS b/glib/AUTHORS new file mode 100644 index 000000000..67f4e5617 --- /dev/null +++ b/glib/AUTHORS @@ -0,0 +1 @@ +Peter Mattis (petm@xcf.berkeley.edu) diff --git a/glib/COPYING b/glib/COPYING new file mode 100644 index 000000000..e69de29bb diff --git a/glib/ChangeLog b/glib/ChangeLog new file mode 100644 index 000000000..b119426ca --- /dev/null +++ b/glib/ChangeLog @@ -0,0 +1,10 @@ +Tue Dec 17 13:14:07 1996 Peter Mattis + + * glib.h: Changed 'g_return_if_fail' and 'g_return_val_if_fail' to + not call 'g_string' but to simply stringify the + expression. Calling 'g_string' causes the expression to be + expanded which is undesired. + +Sun Dec 1 01:30:48 1996 Peter Mattis + + * Started ChangeLog diff --git a/glib/INSTALL b/glib/INSTALL new file mode 100644 index 000000000..e69de29bb diff --git a/glib/Makefile.am b/glib/Makefile.am new file mode 100644 index 000000000..18afb93a5 --- /dev/null +++ b/glib/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to produce Makefile.in + +lib_LTLIBRARIES = libglib.la + +libglib_la_SOURCES = \ + garray.c \ + gcache.c \ + gerror.c \ + ghash.c \ + glist.c \ + gmem.c \ + gprimes.c \ + gslist.c \ + gtimer.c \ + gtree.c \ + gutils.c \ + gstring.c + +include_HEADERS = \ + glib.h \ + glibconfig.h + +libglib_la_LDFLAGS = -version-info 1:0:0 + +INCLUDES = + +noinst_PROGRAMS = testglib +testglib_LDADD = $(top_builddir)/libglib.la + +.PHONY: files release + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done + +release: + $(MAKE) dist distdir=$(PACKAGE)`date +"%y%m%d"` diff --git a/glib/NEWS b/glib/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/glib/README b/glib/README new file mode 100644 index 000000000..e69de29bb diff --git a/glib/acconfig.h b/glib/acconfig.h new file mode 100644 index 000000000..48ca75f8d --- /dev/null +++ b/glib/acconfig.h @@ -0,0 +1,62 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* acconfig.h + This file is in the public domain. + + Descriptive text for the C preprocessor macros that + the distributed Autoconf macros can define. + No software package will use all of them; autoheader copies the ones + your configure.in uses into your configuration header file templates. + + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). Although this order + can split up related entries, it makes it easier to check whether + a given entry is in the file. + + Leave the following blank line there!! Autoheader needs it. */ + + +/* Other stuff */ +#undef HAVE_DOPRNT +#undef HAVE_FLOAT_H +#undef HAVE_LIMITS_H +#undef HAVE_LONG_DOUBLE +#undef HAVE_SYS_SELECT_H +#undef HAVE_STRERROR +#undef HAVE_STRSIGNAL +#undef HAVE_VALUES_H +#undef HAVE_VPRINTF + +#undef NO_FD_SET +#undef NO_SYS_ERRLIST +#undef NO_SYS_SIGLIST + +#undef SIZEOF_CHAR +#undef SIZEOF_SHORT +#undef SIZEOF_LONG +#undef SIZEOF_INT +#undef SIZEOF_VOID_P + +/* #undef PACKAGE */ +/* #undef VERSION */ + + +/* Leave that blank line there!! Autoheader needs it. + If you're adding to this file, keep in mind: + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). */ diff --git a/glib/aclocal.m4 b/glib/aclocal.m4 new file mode 100644 index 000000000..9f99ab8e7 --- /dev/null +++ b/glib/aclocal.m4 @@ -0,0 +1,395 @@ +dnl aclocal.m4 generated automatically by aclocal 1.2 + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AM_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") +AC_DEFINE_UNQUOTED(VERSION, "$VERSION")) +AM_SANITY_CHECK +AC_ARG_PROGRAM +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_PROG_MAKE_SET]) + + +# serial 1 + +AC_DEFUN(AM_PROG_INSTALL, +[AC_REQUIRE([AC_PROG_INSTALL]) +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' +AC_SUBST(INSTALL_SCRIPT)dnl +]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$@" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +# serial 17 AM_PROG_LIBTOOL +AC_DEFUN(AM_PROG_LIBTOOL, +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_RANLIB]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AM_PROG_LD]) +AC_REQUIRE([AM_PROG_NM]) +AC_REQUIRE([AC_PROG_LN_S]) + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL) + +dnl Allow the --disable-shared flag to stop us from building shared libs. +AC_ARG_ENABLE(shared, +[ --enable-shared build shared libraries [default=yes]], +[if test "$enableval" = no; then + libtool_enable_shared=no +else + libtool_enable_shared=yes +fi]) +test -n "$libtool_enable_shared" && enable_shared="$libtool_enable_shared" +libtool_shared= +test "$enable_shared" = no && libtool_shared=" --disable-shared" + +dnl Allow the --disable-static flag to stop us from building static libs. +AC_ARG_ENABLE(static, +[ --enable-static build static libraries [default=yes]], +[if test "$enableval" = no; then + libtool_enable_static=no +else + libtool_enable_static=yes +fi]) +test -n "$libtool_enable_static" && enable_static="$libtool_enable_static" +libtool_static= +test "$enable_static" = no && libtool_static=" --disable-static" + +libtool_flags="$libtool_shared$libtool_static" +test "$silent" = yes && libtool_flags="$libtool_flags --silent" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +[case "$host" in +*-*-irix6*) + ac_save_CFLAGS="$CFLAGS" + flag_passed=no + for f in -32 -64 -n32 ABI -cckr -mips1 -mips2 -mips3 -mips4; do + case "$f" in + ABI) + test -n "$SGI_ABI" && flag_passed=yes + if test "$flag_passed" = no && test "$ac_cv_prog_gcc" = yes; then + # Choose the ABI flag according to GCC's specs. + if $CC -dumpspecs 2>&1 | sed '/^\*link:$/,/^$/!d' | egrep -e '[ ]-32' >/dev/null; then + LD="${LD-ld} -32" + else + LD="${LD-ld} -n32" + fi + fi + ;; + + *) + if echo " $CC $CFLAGS " | egrep -e "[ ]$f[ ]" > /dev/null; then + flag_passed=yes + LD="${LD-ld} $f" + fi + ;; + esac + done + CFLAGS="$ac_save_CFLAGS" + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + CFLAGS="$CFLAGS -belf" + ;; +esac] + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ +|| AC_MSG_ERROR([libtool configure failed]) +]) + +# AM_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN(AM_PROG_LD, +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC]) +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_SUBST(LD) +AM_PROG_LD_GNU +]) + +AC_DEFUN(AM_PROG_LD_GNU, +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +]) + +# AM_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN(AM_PROG_NM, +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(ac_cv_path_NM, +[case "$NM" in +/*) + ac_cv_path_NM="$NM" # Let the user override the test with a path. + ;; +*) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb $PATH /bin; do + test -z "$ac_dir" && dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + if ($ac_dir/nm -B /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + else + ac_cv_path_NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm + ;; +esac]) +NM="$ac_cv_path_NM" +AC_MSG_RESULT([$NM]) +AC_SUBST(NM) +]) + +# Add --enable-maintainer-mode option to configure. +# From Jim Meyering + +# serial 1 + +AC_DEFUN(AM_MAINTAINER_MODE, +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT($USE_MAINTAINER_MODE) + if test $USE_MAINTAINER_MODE = yes; then + MAINT= + else + MAINT='#M#' + fi + AC_SUBST(MAINT)dnl +] +) + + +# serial 1 + +# @defmac AC_PROG_CC_STDC +# @maindex PROG_CC_STDC +# @ovindex CC +# If the C compiler in not in ANSI C mode by default, try to add an option +# to output variable @code{CC} to make it so. This macro tries various +# options that select ANSI C on some system or another. It considers the +# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and +# handles function prototypes correctly. +# +# If you use this macro, you should check after calling it whether the C +# compiler has been set to accept ANSI C; if not, the shell variable +# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source +# code in ANSI C, you can make an un-ANSIfied copy of it by using the +# program @code{ansi2knr}, which comes with Ghostscript. +# @end defmac + +AC_DEFUN(AM_PROG_CC_STDC, +[AC_REQUIRE([AC_PROG_CC]) +AC_BEFORE([$0], [AC_C_INLINE]) +AC_BEFORE([$0], [AC_C_CONST]) +AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C) +AC_CACHE_VAL(am_cv_prog_cc_stdc, +[am_cv_prog_cc_stdc=no +ac_save_CC="$CC" +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + AC_TRY_COMPILE( +[#if !defined(__STDC__) || __STDC__ != 1 +choke me +#endif +/* DYNIX/ptx V4.1.3 can't compile sys/stat.h with -Xc -D__EXTENSIONS__. */ +#ifdef _SEQUENT_ +# include +# include +#endif +], [ +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);};], +[am_cv_prog_cc_stdc="$ac_arg"; break]) +done +CC="$ac_save_CC" +]) +if test -z "$am_cv_prog_cc_stdc"; then + AC_MSG_RESULT([none needed]) +else + AC_MSG_RESULT($am_cv_prog_cc_stdc) +fi +case "x$am_cv_prog_cc_stdc" in + x|xno) ;; + *) CC="$CC $am_cv_prog_cc_stdc" ;; +esac +]) + diff --git a/glib/config.guess b/glib/config.guess new file mode 100755 index 000000000..413ed41c0 --- /dev/null +++ b/glib/config.guess @@ -0,0 +1,883 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[3478]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;; + 9000/8?? ) HP_ARCH=hppa1.0 ;; + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo i386-pc-cygwin32 + exit 0 ;; + i*:MINGW*:*) + echo i386-pc-mingw32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin32 + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c </dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >dummy.c < +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/glib/config.sub b/glib/config.sub new file mode 100755 index 000000000..213a6d47d --- /dev/null +++ b/glib/config.sub @@ -0,0 +1,954 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 \ + | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[3456]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[3456]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[3456]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[3456]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[3456]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[3456]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + np1) + basic_machine=np1-gould + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5) + basic_machine=i586-intel + ;; + pentiumpro | p6) + basic_machine=i686-intel + ;; + pentium-* | p5-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + k5) + # We don't have specific support for AMD's K5 yet, so just call it a Pentium + basic_machine=i586-amd + ;; + nexen) + # We don't have specific support for Nexgen yet, so just call it a Pentium + basic_machine=i586-nexgen + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-ibm) + os=-aix + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/glib/configure b/glib/configure new file mode 100755 index 000000000..becb1c703 --- /dev/null +++ b/glib/configure @@ -0,0 +1,2921 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-gnu-ld assume the C compiler uses GNU ld [default=no]" +ac_help="$ac_help + --enable-shared build shared libraries [default=yes]" +ac_help="$ac_help + --enable-static build static libraries [default=yes]" +ac_help="$ac_help + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer" +ac_help="$ac_help + --enable-debug turn on debugging [default=no]" +ac_help="$ac_help + --enable-ansi turn on strict ansi [default=no]" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.12" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=glib.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:566: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + + +PACKAGE=glib + +VERSION=971109 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:635: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +missing_dir=`cd $ac_aux_dir && pwd` +echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 +echo "configure:682: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:695: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:708: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:721: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:734: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:747: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +# Specify a configuration file + + + + + +# Make sure we can run config.sub. +if $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:786: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`$ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:809: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:838: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:867: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:915: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:949: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:954: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:978: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + elif test $ac_cv_prog_cc_g = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + + +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6 +echo "configure:1018: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld""... $ac_c" 1>&6 +echo "configure:1036: checking for GNU ld" >&5 +else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 +echo "configure:1039: checking for non-GNU ld" >&5 +fi +if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$ac_cv_path_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; } + +echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6 +echo "configure:1075: checking if the linker ($LD) is GNU ld" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gnu_ld'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gnu_ld" 1>&6 + + +echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6 +echo "configure:1091: checking for BSD-compatible nm" >&5 +if eval "test \"`echo '$''{'ac_cv_path_NM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$NM" in +/*) + ac_cv_path_NM="$NM" # Let the user override the test with a path. + ;; +*) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb $PATH /bin; do + test -z "$ac_dir" && dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + if ($ac_dir/nm -B /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + else + ac_cv_path_NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm + ;; +esac +fi + +NM="$ac_cv_path_NM" +echo "$ac_t""$NM" 1>&6 + + +echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:1126: checking whether ln -s works" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi +fi +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + + + + + + + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + if test "$enableval" = no; then + libtool_enable_shared=no +else + libtool_enable_shared=yes +fi +fi + +test -n "$libtool_enable_shared" && enable_shared="$libtool_enable_shared" +libtool_shared= +test "$enable_shared" = no && libtool_shared=" --disable-shared" + +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + if test "$enableval" = no; then + libtool_enable_static=no +else + libtool_enable_static=yes +fi +fi + +test -n "$libtool_enable_static" && enable_static="$libtool_enable_static" +libtool_static= +test "$enable_static" = no && libtool_static=" --disable-static" + +libtool_flags="$libtool_shared$libtool_static" +test "$silent" = yes && libtool_flags="$libtool_flags --silent" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case "$host" in +*-*-irix6*) + ac_save_CFLAGS="$CFLAGS" + flag_passed=no + for f in -32 -64 -n32 ABI -cckr -mips1 -mips2 -mips3 -mips4; do + case "$f" in + ABI) + test -n "$SGI_ABI" && flag_passed=yes + if test "$flag_passed" = no && test "$ac_cv_prog_gcc" = yes; then + # Choose the ABI flag according to GCC's specs. + if $CC -dumpspecs 2>&1 | sed '/^\*link:$/,/^$/!d' | egrep -e '[ ]-32' >/dev/null; then + LD="${LD-ld} -32" + else + LD="${LD-ld} -n32" + fi + fi + ;; + + *) + if echo " $CC $CFLAGS " | egrep -e "[ ]$f[ ]" > /dev/null; then + flag_passed=yes + LD="${LD-ld} $f" + fi + ;; + esac + done + CFLAGS="$ac_save_CFLAGS" + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + CFLAGS="$CFLAGS -belf" + ;; +esac + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ +|| { echo "configure: error: libtool configure failed" 1>&2; exit 1; } + + +echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 +echo "configure:1236: checking whether to enable maintainer-specific portions of Makefiles" >&5 + # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval="$enable_maintainer_mode" + USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6 + if test $USE_MAINTAINER_MODE = yes; then + MAINT= + else + MAINT='#M#' + fi + + + + +# Make sure we can run config.sub. +if $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:1261: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`$ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`$ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + + +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + if eval "test x$enable_debug = xyes"; then + DEBUGFLAG="-g" +fi +fi + + +# Check whether --enable-ansi or --disable-ansi was given. +if test "${enable_ansi+set}" = set; then + enableval="$enable_ansi" + : +else + enable_ansi=no +fi + + +if test -n "$DEBUGFLAG"; then + CFLAGS="$DEBUGFLAG" +fi + +# Checks for programs. +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1308: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1337: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1385: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1419: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1424: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1448: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + elif test $ac_cv_prog_cc_g = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + + + + +echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6 +echo "configure:1479: checking for ${CC-cc} option to accept ANSI C" >&5 +if eval "test \"`echo '$''{'am_cv_prog_cc_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + am_cv_prog_cc_stdc=no +ac_save_CC="$CC" +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + cat > conftest.$ac_ext < +# include +#endif + +int main() { + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +; return 0; } +EOF +if { (eval echo configure:1513: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + am_cv_prog_cc_stdc="$ac_arg"; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done +CC="$ac_save_CC" + +fi + +if test -z "$am_cv_prog_cc_stdc"; then + echo "$ac_t""none needed" 1>&6 +else + echo "$ac_t""$am_cv_prog_cc_stdc" 1>&6 +fi +case "x$am_cv_prog_cc_stdc" in + x|xno) ;; + *) CC="$CC $am_cv_prog_cc_stdc" ;; +esac + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1547: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +if eval "test x$GCC = xyes"; then + test `echo "$CFLAGS" | grep "\-Wall" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -Wall" + fi + + if eval "test x$enable_ansi = xyes"; then + test `echo "$CFLAGS" | grep "\-ansi" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -ansi" + fi + + test `echo "$CFLAGS" | grep "\-pedantic" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -pedantic" + fi + fi +fi + +# Checks for header files. +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1618: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1639: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1656: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1679: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1692: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1759: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + + +# Checks for library functions. +echo $ac_n "checking for vprintf""... $ac_c" 1>&6 +echo "configure:1785: checking for vprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vprintf(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vprintf) || defined (__stub___vprintf) +choke me +#else +vprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1813: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_vprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_func_vprintf" != yes; then +echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 +echo "configure:1837: checking for _doprnt" >&5 +if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +_doprnt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1865: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func__doprnt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func__doprnt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DOPRNT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +fi + + +echo $ac_n "checking size of char""... $ac_c" 1>&6 +echo "configure:1891: checking size of char" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_char'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(char)); + exit(0); +} +EOF +if { (eval echo configure:1910: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_char=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_char=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_char" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1930: checking size of short" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(short)); + exit(0); +} +EOF +if { (eval echo configure:1949: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_short=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_short=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_short" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1969: checking size of long" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(long)); + exit(0); +} +EOF +if { (eval echo configure:1988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_long=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_long=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_long" 1>&6 +cat >> confdefs.h <&6 +echo "configure:2008: checking size of int" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(int)); + exit(0); +} +EOF +if { (eval echo configure:2027: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_int=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_int=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_int" 1>&6 +cat >> confdefs.h <&6 +echo "configure:2047: checking size of void *" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_void_p'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(void *)); + exit(0); +} +EOF +if { (eval echo configure:2066: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_void_p=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_void_p=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_void_p" 1>&6 +cat >> confdefs.h <&6 +echo "configure:2087: checking for long double" >&5 +if eval "test \"`echo '$''{'ac_cv_c_long_double'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$GCC" = yes; then + ac_cv_c_long_double=yes +else +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_c_long_double=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_long_double=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_long_double" 1>&6 +if test $ac_cv_c_long_double = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_LONG_DOUBLE 1 +EOF + +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2130: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2184: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for inline""... $ac_c" 1>&6 +echo "configure:2205: checking for inline" >&5 +if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_inline=$ac_kw; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done + +fi + +echo "$ac_t""$ac_cv_c_inline" 1>&6 +case "$ac_cv_c_inline" in + inline | yes) ;; + no) cat >> confdefs.h <<\EOF +#define inline +EOF + ;; + *) cat >> confdefs.h <&6 +echo "configure:2249: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2259: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <> confdefs.h <<\EOF +#define HAVE_FLOAT_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in limits.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2292: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2302: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <> confdefs.h <<\EOF +#define HAVE_LIMITS_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in values.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2335: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2345: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <> confdefs.h <<\EOF +#define HAVE_VALUES_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +# Check for strerror and strsignal functions +for ac_func in strerror strsignal +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2379: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2407: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +# Check for sys_errlist +echo $ac_n "checking sys_errlist""... $ac_c" 1>&6 +echo "configure:2434: checking sys_errlist" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + glib_ok=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + glib_ok=no +fi +rm -f conftest* +echo "$ac_t""$glib_ok" 1>&6 +if test $glib_ok = no; then + cat >> confdefs.h <<\EOF +#define NO_SYS_ERRLIST 1 +EOF + +fi + +# Check for sys_siglist +echo $ac_n "checking sys_siglist""... $ac_c" 1>&6 +echo "configure:2467: checking sys_siglist" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + glib_ok=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + glib_ok=no +fi +rm -f conftest* +echo "$ac_t""$glib_ok" 1>&6 +if test $glib_ok = no; then + cat >> confdefs.h <<\EOF +#define NO_SYS_SIGLIST 1 +EOF + +fi + +# Check for sys/select.h + +echo $ac_n "checking fd_set and sys/select""... $ac_c" 1>&6 +echo "configure:2500: checking fd_set and sys/select" >&5 +cat > conftest.$ac_ext < +int main() { +fd_set readMask, writeMask; +; return 0; } +EOF +if { (eval echo configure:2509: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + gtk_ok=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + gtk_ok=no +fi +rm -f conftest* +if test $gtk_ok = no; then + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "fd_mask" >/dev/null 2>&1; then + rm -rf conftest* + gtk_ok=yes +fi +rm -f conftest* + + if test $gtk_ok = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_SELECT_H 1 +EOF + + fi +fi +echo "$ac_t""$gtk_ok" 1>&6 +if test $gtk_ok = no; then + cat >> confdefs.h <<\EOF +#define NO_FD_SET 1 +EOF + +fi + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.12" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile glibconfig.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@RANLIB@%$RANLIB%g +s%@CC@%$CC%g +s%@LD@%$LD%g +s%@NM@%$NM%g +s%@LN_S@%$LN_S%g +s%@LIBTOOL@%$LIBTOOL%g +s%@MAINT@%$MAINT%g +s%@CPP@%$CPP%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/glib/configure.in b/glib/configure.in new file mode 100644 index 000000000..d97b441bc --- /dev/null +++ b/glib/configure.in @@ -0,0 +1,116 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT(glib.h) + +dnl Initialize automake stuff +AM_INIT_AUTOMAKE(glib, 971109) + +# Specify a configuration file +AM_CONFIG_HEADER(glibconfig.h) + +dnl Initialize libtool +AM_PROG_LIBTOOL + +dnl Initialize maintainer mode +AM_MAINTAINER_MODE + +AC_CANONICAL_HOST + +AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging [default=no]], +if eval "test x$enable_debug = xyes"; then + DEBUGFLAG="-g" +fi) + +AC_ARG_ENABLE(ansi, [ --enable-ansi turn on strict ansi [default=no]], + , enable_ansi=no) + +if test -n "$DEBUGFLAG"; then + CFLAGS="$DEBUGFLAG" +fi + +# Checks for programs. +AC_PROG_CC +AM_PROG_CC_STDC +AC_PROG_INSTALL + +if eval "test x$GCC = xyes"; then + test `echo "$CFLAGS" | grep "\-Wall" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -Wall" + fi + + if eval "test x$enable_ansi = xyes"; then + test `echo "$CFLAGS" | grep "\-ansi" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -ansi" + fi + + test `echo "$CFLAGS" | grep "\-pedantic" > /dev/null 2> /dev/null` + if test ! $?; then + CFLAGS="$CFLAGS -pedantic" + fi + fi +fi + +# Checks for header files. +AC_HEADER_STDC + +# Checks for library functions. +AC_FUNC_VPRINTF + +AC_CHECK_SIZEOF(char) +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(void *) + +AC_C_LONG_DOUBLE +AC_C_CONST +AC_C_INLINE + +AC_CHECK_HEADERS(float.h, AC_DEFINE(HAVE_FLOAT_H)) +AC_CHECK_HEADERS(limits.h, AC_DEFINE(HAVE_LIMITS_H)) +AC_CHECK_HEADERS(values.h, AC_DEFINE(HAVE_VALUES_H)) + +# Check for strerror and strsignal functions +AC_CHECK_FUNCS(strerror strsignal) + +# Check for sys_errlist +AC_MSG_CHECKING(sys_errlist) +AC_TRY_LINK(, [ +extern char *sys_errlist[]; +extern int sys_nerr; +sys_errlist[sys_nerr-1][0] = 0; +], glib_ok=yes, glib_ok=no) +AC_MSG_RESULT($glib_ok) +if test $glib_ok = no; then + AC_DEFINE(NO_SYS_ERRLIST) +fi + +# Check for sys_siglist +AC_MSG_CHECKING(sys_siglist) +AC_TRY_LINK(, [ +extern char *sys_siglist[]; +sys_siglist[1][0] = 0; +], glib_ok=yes, glib_ok=no) +AC_MSG_RESULT($glib_ok) +if test $glib_ok = no; then + AC_DEFINE(NO_SYS_SIGLIST) +fi + +# Check for sys/select.h + +AC_MSG_CHECKING([fd_set and sys/select]) +AC_TRY_COMPILE([#include ], + [fd_set readMask, writeMask;], gtk_ok=yes, gtk_ok=no) +if test $gtk_ok = no; then + AC_HEADER_EGREP(fd_mask, sys/select.h, gtk_ok=yes) + if test $gtk_ok = yes; then + AC_DEFINE(HAVE_SYS_SELECT_H) + fi +fi +AC_MSG_RESULT($gtk_ok) +if test $gtk_ok = no; then + AC_DEFINE(NO_FD_SET) +fi + +AC_OUTPUT(Makefile) diff --git a/glib/garray.c b/glib/garray.c new file mode 100644 index 000000000..370084843 --- /dev/null +++ b/glib/garray.c @@ -0,0 +1,142 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "glib.h" + + +#define MIN_ARRAY_SIZE 16 + + +typedef struct _GRealArray GRealArray; + +struct _GRealArray +{ + guint8 *data; + guint len; + guint alloc; + guint zero_terminated; +}; + + +static gint g_nearest_pow (gint num); +static void g_array_maybe_expand (GRealArray *array, + gint len); + + +static GMemChunk *array_mem_chunk = NULL; + + +GArray* +g_array_new (zero_terminated) +{ + GRealArray *array; + + if (!array_mem_chunk) + array_mem_chunk = g_mem_chunk_new ("array mem chunk", + sizeof (GRealArray), + 1024, G_ALLOC_AND_FREE); + + array = g_chunk_new (GRealArray, array_mem_chunk); + + array->data = NULL; + array->len = 0; + array->alloc = 0; + array->zero_terminated = (zero_terminated ? 1 : 0); + + return (GArray*) array; +} + +void +g_array_free (GArray *array, + gint free_segment) +{ + if (free_segment) + g_free (array->data); + + g_mem_chunk_free (array_mem_chunk, array); +} + +GArray* +g_rarray_append (GArray *array, + gpointer data, + gint size) +{ + g_array_maybe_expand ((GRealArray*) array, size); + + memcpy (array->data + array->len, data, size); + + array->len += size; + + return array; +} + +GArray* +g_rarray_prepend (GArray *array, + gpointer data, + gint size) +{ + g_array_maybe_expand ((GRealArray*) array, size); + + memmove (array->data + size, array->data, array->len); + memcpy (array->data, data, size); + + array->len += size; + + return array; +} + +GArray* +g_rarray_truncate (GArray *array, + gint length, + gint size) +{ + if (array->data) + memset (array->data + length * size, 0, size); + array->len = length; + return array; +} + + +static gint +g_nearest_pow (gint num) +{ + gint n = 1; + + while (n < num) + n <<= 1; + + return n; +} + +static void +g_array_maybe_expand (GRealArray *array, + gint len) +{ + guint old_alloc; + + if ((array->len + len) > array->alloc) + { + old_alloc = array->alloc; + + array->alloc = g_nearest_pow (array->len + array->zero_terminated + len); + array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE); + array->data = g_realloc (array->data, array->alloc); + + memset (array->data + old_alloc, 0, array->alloc - old_alloc); + } +} diff --git a/glib/gcache.c b/glib/gcache.c new file mode 100644 index 000000000..b12121995 --- /dev/null +++ b/glib/gcache.c @@ -0,0 +1,211 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "glib.h" + + +typedef struct _GCacheNode GCacheNode; +typedef struct _GRealCache GRealCache; + +struct _GCacheNode +{ + /* A reference counted node */ + gpointer value; + gint ref_count; +}; + +struct _GRealCache +{ + /* Called to create a value from a key */ + GCacheNewFunc value_new_func; + + /* Called to destroy a value */ + GCacheDestroyFunc value_destroy_func; + + /* Called to duplicate a key */ + GCacheDupFunc key_dup_func; + + /* Called to destroy a key */ + GCacheDestroyFunc key_destroy_func; + + /* Associates keys with nodes */ + GHashTable *key_table; + + /* Associates nodes with keys */ + GHashTable *value_table; +}; + + +static GCacheNode* g_cache_node_new (gpointer value); +static void g_cache_node_destroy (GCacheNode *node); + + +static GMemChunk *node_mem_chunk = NULL; + + +GCache* +g_cache_new (GCacheNewFunc value_new_func, + GCacheDestroyFunc value_destroy_func, + GCacheDupFunc key_dup_func, + GCacheDestroyFunc key_destroy_func, + GHashFunc hash_key_func, + GHashFunc hash_value_func, + GCompareFunc key_compare_func) +{ + GRealCache *cache; + + g_return_val_if_fail (value_new_func != NULL, NULL); + g_return_val_if_fail (value_destroy_func != NULL, NULL); + g_return_val_if_fail (key_dup_func != NULL, NULL); + g_return_val_if_fail (key_destroy_func != NULL, NULL); + g_return_val_if_fail (hash_key_func != NULL, NULL); + g_return_val_if_fail (hash_value_func != NULL, NULL); + g_return_val_if_fail (key_compare_func != NULL, NULL); + + cache = g_new (GRealCache, 1); + cache->value_new_func = value_new_func; + cache->value_destroy_func = value_destroy_func; + cache->key_dup_func = key_dup_func; + cache->key_destroy_func = key_destroy_func; + cache->key_table = g_hash_table_new (hash_key_func, key_compare_func); + cache->value_table = g_hash_table_new (hash_value_func, NULL); + + return (GCache*) cache; +} + +void +g_cache_destroy (GCache *cache) +{ + GRealCache *rcache; + + g_return_if_fail (cache != NULL); + + rcache = (GRealCache*) cache; + g_hash_table_destroy (rcache->key_table); + g_hash_table_destroy (rcache->value_table); + g_free (rcache); +} + +gpointer +g_cache_insert (GCache *cache, + gpointer key) +{ + GRealCache *rcache; + GCacheNode *node; + gpointer value; + + g_return_val_if_fail (cache != NULL, NULL); + + rcache = (GRealCache*) cache; + + node = g_hash_table_lookup (rcache->key_table, key); + if (node) + { + node->ref_count += 1; + return node->value; + } + + key = (* rcache->key_dup_func) (key); + value = (* rcache->value_new_func) (key); + node = g_cache_node_new (value); + + g_hash_table_insert (rcache->key_table, key, node); + g_hash_table_insert (rcache->value_table, value, key); + + return node->value; +} + +void +g_cache_remove (GCache *cache, + gpointer value) +{ + GRealCache *rcache; + GCacheNode *node; + gpointer key; + + g_return_if_fail (cache != NULL); + + rcache = (GRealCache*) cache; + + key = g_hash_table_lookup (rcache->value_table, value); + node = g_hash_table_lookup (rcache->key_table, key); + + node->ref_count -= 1; + if (node->ref_count == 0) + { + g_hash_table_remove (rcache->value_table, value); + g_hash_table_remove (rcache->key_table, key); + + (* rcache->key_destroy_func) (key); + (* rcache->value_destroy_func) (node->value); + g_cache_node_destroy (node); + } +} + +void +g_cache_key_foreach (GCache *cache, + GHFunc func, + gpointer user_data) +{ + GRealCache *rcache; + + g_return_if_fail (cache != NULL); + g_return_if_fail (func != NULL); + + rcache = (GRealCache*) cache; + + g_hash_table_foreach (rcache->value_table, func, user_data); +} + +void +g_cache_value_foreach (GCache *cache, + GHFunc func, + gpointer user_data) +{ + GRealCache *rcache; + + g_return_if_fail (cache != NULL); + g_return_if_fail (func != NULL); + + rcache = (GRealCache*) cache; + + g_hash_table_foreach (rcache->key_table, func, user_data); +} + + +static GCacheNode* +g_cache_node_new (gpointer value) +{ + GCacheNode *node; + + if (!node_mem_chunk) + node_mem_chunk = g_mem_chunk_new ("cache node mem chunk", sizeof (GCacheNode), + 1024, G_ALLOC_AND_FREE); + + node = g_chunk_new (GCacheNode, node_mem_chunk); + + node->value = value; + node->ref_count = 1; + + return node; +} + +static void +g_cache_node_destroy (GCacheNode *node) +{ + g_mem_chunk_free (node_mem_chunk, node); +} diff --git a/glib/gerror.c b/glib/gerror.c new file mode 100644 index 000000000..96e1013e9 --- /dev/null +++ b/glib/gerror.c @@ -0,0 +1,256 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include "glib.h" + +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* HAVE_SYS_SELECT_H */ + +#ifdef STDC_HEADERS +#include /* for bzero on BSD systems */ +#endif + +#define INTERACTIVE 0 +#define STACK_TRACE 1 + + +#ifndef NO_FD_SET +# define SELECT_MASK fd_set +#else +# ifndef _AIX + typedef long fd_mask; +# endif +# if defined(_IBMR2) +# define SELECT_MASK void +# else +# define SELECT_MASK int +# endif +#endif + + +static int do_query (char *prompt); +static void debug (char *progname, int method); +static void stack_trace (char **); +static void stack_trace_sigchld (int); + + +static int stack_trace_done; + +void +g_debug (char *progname) +{ + char buf[32]; + + fprintf (stdout, "[n]othing, [e]xit, [s]tack trace, [a]ttach to process: "); + fflush (stdout); + + fgets (buf, 32, stdin); + if (strcmp (buf, "n\n") == 0) + return; + else if (strcmp (buf, "s\n") == 0) + debug (progname, STACK_TRACE); + else if (strcmp (buf, "a\n") == 0) + debug (progname, INTERACTIVE); + else + exit (0); +} + +void +g_attach_process (char *progname, int query) +{ + if (!query || do_query ("attach to process")) + debug (progname, INTERACTIVE); +} + +void +g_stack_trace (char *progname, int query) +{ + if (!query || do_query ("print stack trace")) + debug (progname, STACK_TRACE); +} + +static int +do_query (char *prompt) +{ + char buf[32]; + + fprintf (stdout, "%s (y/n) ", prompt); + fflush (stdout); + + fgets (buf, 32, stdin); + if ((strcmp (buf, "yes\n") == 0) || + (strcmp (buf, "y\n") == 0) || + (strcmp (buf, "YES\n") == 0) || + (strcmp (buf, "Y\n") == 0)) + return TRUE; + + return FALSE; +} + +static void +debug (char *progname, + int method) +{ + pid_t pid; + char buf[16]; + char *args[4] = { "gdb", NULL, NULL, NULL }; + volatile int x; + + sprintf (buf, "%d", (int) getpid ()); + + args[1] = progname; + args[2] = buf; + + switch (method) + { + case INTERACTIVE: + fprintf (stdout, "pid: %s\n", buf); + break; + case STACK_TRACE: + pid = fork (); + if (pid == 0) + { + stack_trace (args); + _exit (0); + } + else if (pid == (pid_t) -1) + { + perror ("could not fork"); + return; + } + break; + } + + x = 1; + while (x) + ; +} + +static void +stack_trace (char **args) +{ + pid_t pid; + int in_fd[2]; + int out_fd[2]; + SELECT_MASK fdset; + SELECT_MASK readset; + struct timeval tv; + int sel, index, state; + char buffer[256]; + char c; + + stack_trace_done = 0; + signal (SIGCHLD, stack_trace_sigchld); + + if ((pipe (in_fd) == -1) || (pipe (out_fd) == -1)) + { + perror ("could open pipe"); + _exit (0); + } + + pid = fork (); + if (pid == 0) + { + close (0); dup (in_fd[0]); /* set the stdin to the in pipe */ + close (1); dup (out_fd[1]); /* set the stdout to the out pipe */ + close (2); dup (out_fd[1]); /* set the stderr to the out pipe */ + + execvp (args[0], args); /* exec gdb */ + perror ("exec failed"); + _exit (0); + } + else if (pid == (pid_t) -1) + { + perror ("could not fork"); + _exit (0); + } + + FD_ZERO (&fdset); + FD_SET (out_fd[0], &fdset); + + write (in_fd[1], "backtrace\n", 10); + write (in_fd[1], "p x = 0\n", 8); + write (in_fd[1], "quit\n", 5); + + index = 0; + state = 0; + + while (1) + { + readset = fdset; + tv.tv_sec = 1; + tv.tv_usec = 0; + + sel = select (FD_SETSIZE, &readset, NULL, NULL, &tv); + if (sel == -1) + break; + + if ((sel > 0) && (FD_ISSET (out_fd[0], &readset))) + { + if (read (out_fd[0], &c, 1)) + { + switch (state) + { + case 0: + if (c == '#') + { + state = 1; + index = 0; + buffer[index++] = c; + } + break; + case 1: + buffer[index++] = c; + if ((c == '\n') || (c == '\r')) + { + buffer[index] = 0; + fprintf (stdout, "%s", buffer); + state = 0; + index = 0; + } + break; + default: + break; + } + } + } + else if (stack_trace_done) + break; + } + + close (in_fd[0]); + close (in_fd[1]); + close (out_fd[0]); + close (out_fd[1]); + _exit (0); +} + +static void +stack_trace_sigchld (int signum) +{ + stack_trace_done = 1; +} diff --git a/glib/ghash.c b/glib/ghash.c new file mode 100644 index 000000000..ed736d4cb --- /dev/null +++ b/glib/ghash.c @@ -0,0 +1,418 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "glib.h" + + +#define HASH_TABLE_MIN_SIZE 11 +#define HASH_TABLE_MAX_SIZE 13845163 + + +typedef struct _GHashNode GHashNode; +typedef struct _GRealHashTable GRealHashTable; + +struct _GHashNode +{ + gpointer key; + gpointer value; + GHashNode *next; +}; + +struct _GRealHashTable +{ + gint size; + gint nnodes; + gint frozen; + GHashNode **nodes; + GHashFunc hash_func; + GCompareFunc key_compare_func; +}; + + +static void g_hash_table_resize (GHashTable *hash_table); +static gint g_hash_closest_prime (gint num); +static GHashNode* g_hash_node_new (gpointer key, + gpointer value); +static void g_hash_node_destroy (GHashNode *hash_node); +static void g_hash_nodes_destroy (GHashNode *hash_node); + + +extern gint g_primes[]; +extern gint g_nprimes; + +static GMemChunk *node_mem_chunk = NULL; +static GHashNode *node_free_list = NULL; + + +GHashTable* +g_hash_table_new (GHashFunc hash_func, + GCompareFunc key_compare_func) +{ + GRealHashTable *hash_table; + + g_return_val_if_fail (hash_func != NULL, NULL); + + hash_table = g_new (GRealHashTable, 1); + hash_table->size = 0; + hash_table->nnodes = 0; + hash_table->frozen = FALSE; + hash_table->nodes = NULL; + hash_table->hash_func = hash_func; + hash_table->key_compare_func = key_compare_func; + + return ((GHashTable*) hash_table); +} + +void +g_hash_table_destroy (GHashTable *hash_table) +{ + GRealHashTable *rhash_table; + gint i; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + + for (i = 0; i < rhash_table->size; i++) + g_hash_nodes_destroy (rhash_table->nodes[i]); + + if (rhash_table->nodes) + g_free (rhash_table->nodes); + g_free (rhash_table); + } +} + +void +g_hash_table_insert (GHashTable *hash_table, + gpointer key, + gpointer value) +{ + GRealHashTable *rhash_table; + GHashNode *node; + guint hash_val; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + + if (rhash_table->size == 0) + g_hash_table_resize (hash_table); + + hash_val = (* rhash_table->hash_func) (key) % rhash_table->size; + + node = rhash_table->nodes[hash_val]; + while (node) + { + if ((rhash_table->key_compare_func && + (* rhash_table->key_compare_func) (node->key, key)) || + (node->key == key)) + { + node->value = value; + return; + } + node = node->next; + } + + node = g_hash_node_new (key, value); + node->next = rhash_table->nodes[hash_val]; + rhash_table->nodes[hash_val] = node; + + rhash_table->nnodes += 1; + g_hash_table_resize (hash_table); + } +} + +void +g_hash_table_remove (GHashTable *hash_table, + gpointer key) +{ + GRealHashTable *rhash_table; + GHashNode *node; + GHashNode *prev; + guint hash_val; + + rhash_table = (GRealHashTable*) hash_table; + if (hash_table && rhash_table->size) + { + hash_val = (* rhash_table->hash_func) (key) % rhash_table->size; + + prev = NULL; + node = rhash_table->nodes[hash_val]; + + while (node) + { + if ((rhash_table->key_compare_func && + (* rhash_table->key_compare_func) (node->key, key)) || + (node->key == key)) + { + if (prev) + prev->next = node->next; + if (node == rhash_table->nodes[hash_val]) + rhash_table->nodes[hash_val] = node->next; + + g_hash_node_destroy (node); + + rhash_table->nnodes -= 1; + g_hash_table_resize (hash_table); + break; + } + + prev = node; + node = node->next; + } + } +} + +gpointer +g_hash_table_lookup (GHashTable *hash_table, + const gpointer key) +{ + GRealHashTable *rhash_table; + GHashNode *node; + guint hash_val; + + rhash_table = (GRealHashTable*) hash_table; + if (hash_table && rhash_table->size) + { + hash_val = (* rhash_table->hash_func) (key) % rhash_table->size; + + node = rhash_table->nodes[hash_val]; + + /* Hash table lookup needs to be fast. + * We therefore remove the extra conditional of testing + * whether to call the key_compare_func or not from + * the inner loop. + */ + if (rhash_table->key_compare_func) + { + while (node) + { + if ((* rhash_table->key_compare_func) (node->key, key)) + return node->value; + node = node->next; + } + } + else + { + while (node) + { + if (node->key == key) + return node->value; + node = node->next; + } + } + } + + return NULL; +} + +void +g_hash_table_freeze (GHashTable *hash_table) +{ + GRealHashTable *rhash_table; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + rhash_table->frozen = TRUE; + } +} + +void +g_hash_table_thaw (GHashTable *hash_table) +{ + GRealHashTable *rhash_table; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + rhash_table->frozen = FALSE; + + g_hash_table_resize (hash_table); + } +} + +void +g_hash_table_foreach (GHashTable *hash_table, + GHFunc func, + gpointer user_data) +{ + GRealHashTable *rhash_table; + GHashNode *node; + gint i; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + + for (i = 0; i < rhash_table->size; i++) + { + node = rhash_table->nodes[i]; + + while (node) + { + (* func) (node->key, node->value, user_data); + node = node->next; + } + } + } +} + + +static void +g_hash_table_resize (GHashTable *hash_table) +{ + GRealHashTable *rhash_table; + GHashNode **new_nodes; + GHashNode *node; + GHashNode *next; + gfloat nodes_per_list; + guint hash_val; + gint new_size; + gint need_resize; + gint i; + + if (hash_table) + { + rhash_table = (GRealHashTable*) hash_table; + + if (rhash_table->size == 0) + { + rhash_table->size = HASH_TABLE_MIN_SIZE; + rhash_table->nodes = g_new (GHashNode*, rhash_table->size); + + for (i = 0; i < rhash_table->size; i++) + rhash_table->nodes[i] = NULL; + } + else if (!rhash_table->frozen) + { + need_resize = FALSE; + nodes_per_list = (gfloat) rhash_table->nnodes / (gfloat) rhash_table->size; + + if (nodes_per_list < 0.3) + { + if (rhash_table->size > HASH_TABLE_MIN_SIZE) + need_resize = TRUE; + } + else if (nodes_per_list > 3.0) + { + if (rhash_table->size < HASH_TABLE_MAX_SIZE) + need_resize = TRUE; + } + + if (need_resize) + { + new_size = g_hash_closest_prime (rhash_table->nnodes); + if (new_size < HASH_TABLE_MIN_SIZE) + new_size = HASH_TABLE_MIN_SIZE; + else if (new_size > HASH_TABLE_MAX_SIZE) + new_size = HASH_TABLE_MAX_SIZE; + + new_nodes = g_new (GHashNode*, new_size); + + for (i = 0; i < new_size; i++) + new_nodes[i] = NULL; + + for (i = 0; i < rhash_table->size; i++) + { + node = rhash_table->nodes[i]; + + while (node) + { + next = node->next; + + hash_val = (* rhash_table->hash_func) (node->key) % new_size; + node->next = new_nodes[hash_val]; + new_nodes[hash_val] = node; + + node = next; + } + } + + g_free (rhash_table->nodes); + + rhash_table->nodes = new_nodes; + rhash_table->size = new_size; + } + } + } +} + +static gint +g_hash_closest_prime (gint num) +{ + gint i; + + for (i = 0; i < g_nprimes; i++) + if ((g_primes[i] - num) > 0) + return g_primes[i]; + + return g_primes[g_nprimes - 1]; +} + +static GHashNode* +g_hash_node_new (gpointer key, + gpointer value) +{ + GHashNode *hash_node; + + if (node_free_list) + { + hash_node = node_free_list; + node_free_list = node_free_list->next; + } + else + { + if (!node_mem_chunk) + node_mem_chunk = g_mem_chunk_new ("hash node mem chunk", + sizeof (GHashNode), + 1024, G_ALLOC_ONLY); + + hash_node = g_chunk_new (GHashNode, node_mem_chunk); + } + + hash_node->key = key; + hash_node->value = value; + hash_node->next = NULL; + + return hash_node; +} + +static void +g_hash_node_destroy (GHashNode *hash_node) +{ + if (hash_node) + { + hash_node->next = node_free_list; + node_free_list = hash_node; + } +} + +static void +g_hash_nodes_destroy (GHashNode *hash_node) +{ + GHashNode *node; + + if (hash_node) + { + node = hash_node; + while (node->next) + node = node->next; + node->next = node_free_list; + node_free_list = hash_node; + } +} diff --git a/glib/glib.h b/glib/glib.h new file mode 100644 index 000000000..9af5fa1bb --- /dev/null +++ b/glib/glib.h @@ -0,0 +1,674 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __G_LIB_H__ +#define __G_LIB_H__ + + +#include + +#ifdef USE_DMALLOC +#include "dmalloc.h" +#endif + + +/* glib provides definitions for the extrema of many + * of the standard types. These are: + * G_MINFLOAT + * G_MAXFLOAT + * G_MINDOUBLE + * G_MAXDOUBLE + * G_MINSHORT + * G_MAXSHORT + * G_MININT + * G_MAXINT + * G_MINLONG + * G_MAXLONG + */ + +#ifdef HAVE_FLOAT_H + +#include + +#define G_MINFLOAT FLT_MIN +#define G_MAXFLOAT FLT_MAX +#define G_MINDOUBLE DBL_MIN +#define G_MAXDOUBLE DBL_MAX + +#elif HAVE_VALUES_H + +#include + +#define G_MINFLOAT MINFLOAT +#define G_MAXFLOAT MAXFLOAT +#define G_MINDOUBLE MINDOUBLE +#define G_MAXDOUBLE MAXDOUBLE + +#endif /* HAVE_VALUES_H */ + + +#ifdef HAVE_LIMITS_H + +#include + +#define G_MINSHORT SHRT_MIN +#define G_MAXSHORT SHRT_MAX +#define G_MININT INT_MIN +#define G_MAXINT INT_MAX +#define G_MINLONG LONG_MIN +#define G_MAXLONG LONG_MAX + +#elif HAVE_VALUES_H + +#ifdef HAVE_FLOAT_H +#include +#endif /* HAVE_FLOAT_H */ + +#define G_MINSHORT MINSHORT +#define G_MAXSHORT MAXSHORT +#define G_MININT MININT +#define G_MAXINT MAXINT +#define G_MINLONG MINLONG +#define G_MAXLONG MAXLONG + +#endif /* HAVE_VALUES_H */ + + +/* Provide definitions for some commonly used macros. + * These are only provided if they haven't already + * been defined. It is assumed that if they are already + * defined then the current definition is correct. + */ + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ + +#ifndef NULL +#define NULL ((void*) 0) +#endif /* NULL */ + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif /* MAX */ + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* MIN */ + +#ifndef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) +#endif /* ABS */ + +#ifndef CLAMP +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#endif /* CLAMP */ + +#ifndef ATEXIT +#define ATEXIT(proc) (atexit (proc)) +#endif /* ATEXIT */ + + +/* Provide macros for easily allocating memory. The macros + * will cast the allocated memory to the specified type + * in order to avoid compiler warnings. (Makes the code neater). + */ + +#ifdef __DMALLOC_H__ + +#define g_new(type,count) ALLOC(type,count) +#define g_new0(type,count) CALLOC(type,count) + +#else /* __DMALLOC_H__ */ + +#define g_new(type, count) \ + ((type *) g_malloc ((unsigned) sizeof (type) * (count))) +#define g_new0(type, count) \ + ((type *) g_malloc0 ((unsigned) sizeof (type) * (count))) +#endif /* __DMALLOC_H__ */ + +#define g_chunk_new(type, chunk) \ + ((type *) g_mem_chunk_alloc (chunk)) + + +/* Provide macros for error handling. The "assert" macros will + * exit on failur. The "return" macros will exit the current + * function. Two different definitions are given for the macros + * in order to support gcc's __PRETTY_FUNCTION__ capability. + */ + +#define g_string(x) #x + +#ifdef __GNUC__ + +#define g_assert(expr) \ + if (!(expr)) \ + g_error ("file %s: line %d (%s): \"%s\"", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr) + +#define g_assert_not_reached() \ + g_error ("file %s: line %d (%s): \"should not be reached\"", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__) + +#define g_return_if_fail(expr) \ + if (!(expr)) \ + { \ + g_warning ("file %s: line %d (%s): \"%s\"", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr); \ + return; \ + } + +#define g_return_val_if_fail(expr,val) \ + if (!(expr)) \ + { \ + g_warning ("file %s: line %d (%s): \"%s\"", \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + #expr); \ + return val; \ + } + +#else /* __GNUC__ */ + +#define g_assert(expr) \ + if (!(expr)) \ + g_error ("file %s: line %d: \"%s\"", \ + __FILE__, \ + __LINE__, \ + #expr) + +#define g_assert_not_reached() \ + g_error ("file %s: line %d: \"should not be reached\"", \ + __FILE__, \ + __LINE__) + +#define g_return_if_fail(expr) \ + if (!(expr)) \ + { \ + g_warning ("file %s: line %d: \"%s\"", \ + __FILE__, \ + __LINE__, \ + #expr); \ + return; \ + } + +#define g_return_val_if_fail(expr, val) \ + if (!(expr)) \ + { \ + g_warning ("file %s: line %d: \"%s\"", \ + __FILE__, \ + __LINE__, \ + #expr); \ + return val; \ + } + +#endif /* __GNUC__ */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Provide type definitions for commonly used types. + * These are useful because a "gint8" can be adjusted + * to be 1 byte (8 bits) on all platforms. Similarly and + * more importantly, "gint32" can be adjusted to be + * 4 bytes (32 bits) on all platforms. + */ + +typedef char gchar; +typedef short gshort; +typedef long glong; +typedef int gint; +typedef char gboolean; + +typedef unsigned char guchar; +typedef unsigned short gushort; +typedef unsigned long gulong; +typedef unsigned int guint; + +typedef float gfloat; +typedef double gdouble; + +#ifdef HAVE_LONG_DOUBLE +typedef long double gldouble; +#else /* HAVE_LONG_DOUBLE */ +typedef double gldouble; +#endif /* HAVE_LONG_DOUBLE */ + +typedef void* gpointer; + +#if (SIZEOF_CHAR == 1) +typedef signed char gint8; +typedef unsigned char guint8; +#endif /* SIZEOF_CHAR */ + + +#if (SIZEOF_SHORT == 2) +typedef signed short gint16; +typedef unsigned short guint16; +#endif /* SIZEOF_SHORT */ + + +#if (SIZEOF_INT == 4) +typedef signed int gint32; +typedef unsigned int guint32; +#elif (SIZEOF_LONG == 4) +typedef signed long gint32; +typedef unsigned long guint32; +#endif /* SIZEOF_INT */ + + +typedef struct _GList GList; +typedef struct _GSList GSList; +typedef struct _GHashTable GHashTable; +typedef struct _GCache GCache; +typedef struct _GTree GTree; +typedef struct _GTimer GTimer; +typedef struct _GMemChunk GMemChunk; +typedef struct _GListAllocator GListAllocator; +typedef struct _GStringChunk GStringChunk; +typedef struct _GString GString; +typedef struct _GArray GArray; + +typedef void (*GFunc) (gpointer data, gpointer user_data); +typedef void (*GHFunc) (gpointer key, gpointer value, gpointer user_data); +typedef guint (*GHashFunc) (gpointer key); +typedef gint (*GCompareFunc) (gpointer a, gpointer b); +typedef gpointer (*GCacheNewFunc) (gpointer key); +typedef gpointer (*GCacheDupFunc) (gpointer value); +typedef void (*GCacheDestroyFunc) (gpointer value); +typedef gint (*GTraverseFunc) (gpointer key, + gpointer value, + gpointer data); +typedef gint (*GSearchFunc) (gpointer key, + gpointer data); +typedef void (*GErrorFunc) (gchar *str); +typedef void (*GWarningFunc) (gchar *str); +typedef void (*GPrintFunc) (gchar *str); + + +struct _GList +{ + gpointer data; + GList *next; + GList *prev; +}; + +struct _GSList +{ + gpointer data; + GSList *next; +}; + +struct _GString +{ + gchar *str; + gint len; +}; + +struct _GArray +{ + gchar *data; + guint len; +}; + +struct _GHashTable { gint dummy; }; +struct _GCache { gint dummy; }; +struct _GTree { gint dummy; }; +struct _GTimer { gint dummy; }; +struct _GMemChunk { gint dummy; }; +struct _GListAllocator { gint dummy; }; +struct _GStringChunk { gint dummy; }; + +typedef enum +{ + G_IN_ORDER, + G_PRE_ORDER, + G_POST_ORDER +} GTraverseType; + +/* Doubly linked lists + */ +GList* g_list_alloc (void); +void g_list_free (GList *list); +void g_list_free_1 (GList *list); +GList* g_list_append (GList *list, + gpointer data); +GList* g_list_prepend (GList *list, + gpointer data); +GList* g_list_insert (GList *list, + gpointer data, + gint position); +GList* g_list_remove (GList *list, + gpointer data); +GList* g_list_remove_link (GList *list, + GList *link); +GList* g_list_reverse (GList *list); +GList* g_list_nth (GList *list, + gint n); +GList* g_list_find (GList *list, + gpointer data); +GList* g_list_last (GList *list); +GList* g_list_first (GList *list); +gint g_list_length (GList *list); +void g_list_foreach (GList *list, + GFunc func, + gpointer user_data); + + +/* Singly linked lists + */ +GSList* g_slist_alloc (void); +void g_slist_free (GSList *list); +void g_slist_free_1 (GSList *list); +GSList* g_slist_append (GSList *list, + gpointer data); +GSList* g_slist_prepend (GSList *list, + gpointer data); +GSList* g_slist_insert (GSList *list, + gpointer data, + gint position); +GSList* g_slist_remove (GSList *list, + gpointer data); +GSList* g_slist_remove_link (GSList *list, + GSList *link); +GSList* g_slist_reverse (GSList *list); +GSList* g_slist_nth (GSList *list, + gint n); +GSList* g_slist_find (GSList *list, + gpointer data); +GSList* g_slist_last (GSList *list); +gint g_slist_length (GSList *list); +void g_slist_foreach (GSList *list, + GFunc func, + gpointer user_data); + + +/* List Allocators + */ +GListAllocator* g_list_allocator_new (void); +void g_list_allocator_free (GListAllocator* allocator); +GListAllocator* g_slist_set_allocator (GListAllocator* allocator); +GListAllocator* g_list_set_allocator (GListAllocator* allocator); + + +/* Hash tables + */ +GHashTable* g_hash_table_new (GHashFunc hash_func, + GCompareFunc key_compare_func); +void g_hash_table_destroy (GHashTable *hash_table); +void g_hash_table_insert (GHashTable *hash_table, + gpointer key, + gpointer value); +void g_hash_table_remove (GHashTable *hash_table, + gpointer key); +gpointer g_hash_table_lookup (GHashTable *hash_table, + const gpointer key); +void g_hash_table_freeze (GHashTable *hash_table); +void g_hash_table_thaw (GHashTable *hash_table); +void g_hash_table_foreach (GHashTable *hash_table, + GHFunc func, + gpointer user_data); + + +/* Caches + */ +GCache* g_cache_new (GCacheNewFunc value_new_func, + GCacheDestroyFunc value_destroy_func, + GCacheDupFunc key_dup_func, + GCacheDestroyFunc key_destroy_func, + GHashFunc hash_key_func, + GHashFunc hash_value_func, + GCompareFunc key_compare_func); +void g_cache_destroy (GCache *cache); +gpointer g_cache_insert (GCache *cache, + gpointer key); +void g_cache_remove (GCache *cache, + gpointer value); +void g_cache_key_foreach (GCache *cache, + GHFunc func, + gpointer user_data); +void g_cache_value_foreach (GCache *cache, + GHFunc func, + gpointer user_data); + + +/* Trees + */ +GTree* g_tree_new (GCompareFunc key_compare_func); +void g_tree_destroy (GTree *tree); +void g_tree_insert (GTree *tree, + gpointer key, + gpointer value); +void g_tree_remove (GTree *tree, + gpointer key); +gpointer g_tree_lookup (GTree *tree, + gpointer key); +void g_tree_traverse (GTree *tree, + GTraverseFunc traverse_func, + GTraverseType traverse_type, + gpointer data); +gpointer g_tree_search (GTree *tree, + GSearchFunc search_func, + gpointer data); +gint g_tree_height (GTree *tree); +gint g_tree_nnodes (GTree *tree); + + +/* Memory + */ + +#ifdef USE_DMALLOC + +#define g_malloc(size) (gpointer) MALLOC(size) +#define g_malloc0(size) (gpointer) CALLOC(char,size) +#define g_realloc(mem,size) (gpointer) REALLOC(mem,char,size) +#define g_free(mem) FREE(mem) + +#else /* USE_DMALLOC */ + +gpointer g_malloc (gulong size); +gpointer g_malloc0 (gulong size); +gpointer g_realloc (gpointer mem, + gulong size); +void g_free (gpointer mem); + +#endif /* USE_DMALLOC */ + +void g_mem_profile (void); +void g_mem_check (gpointer mem); + + +/* "g_mem_chunk_new" creates a new memory chunk. + * Memory chunks are used to allocate pieces of memory which are + * always the same size. Lists are a good example of such a data type. + * The memory chunk allocates and frees blocks of memory as needed. + * Just be sure to call "g_mem_chunk_free" and not "g_free" on data + * allocated in a mem chunk. ("g_free" will most likely cause a seg + * fault...somewhere). + * + * Oh yeah, GMemChunk is an opaque data type. (You don't really + * want to know what's going on inside do you?) + */ + +/* ALLOC_ONLY MemChunk's can only allocate memory. The free operation + * is interpreted as a no op. ALLOC_ONLY MemChunk's save 4 bytes per + * atom. (They are also useful for lists which use MemChunk to allocate + * memory but are also part of the MemChunk implementation). + * ALLOC_AND_FREE MemChunk's can allocate and free memory. + */ + +#define G_ALLOC_ONLY 1 +#define G_ALLOC_AND_FREE 2 + +GMemChunk* g_mem_chunk_new (gchar *name, + gint atom_size, + gulong area_size, + gint type); +void g_mem_chunk_destroy (GMemChunk *mem_chunk); +gpointer g_mem_chunk_alloc (GMemChunk *mem_chunk); +void g_mem_chunk_free (GMemChunk *mem_chunk, + gpointer mem); +void g_mem_chunk_clean (GMemChunk *mem_chunk); +void g_mem_chunk_reset (GMemChunk *mem_chunk); +void g_mem_chunk_print (GMemChunk *mem_chunk); +void g_mem_chunk_info (void); + +/* Ah yes...we have a "g_blow_chunks" function. + * "g_blow_chunks" simply compresses all the chunks. This operation + * consists of freeing every memory area that should be freed (but + * which we haven't gotten around to doing yet). And, no, + * "g_blow_chunks" doesn't follow the naming scheme, but it is a + * much better name than "g_mem_chunk_clean_all" or something + * similar. + */ +void g_blow_chunks (void); + + +/* Timer + */ +GTimer* g_timer_new (void); +void g_timer_destroy (GTimer *timer); +void g_timer_start (GTimer *timer); +void g_timer_stop (GTimer *timer); +void g_timer_reset (GTimer *timer); +gdouble g_timer_elapsed (GTimer *timer, + gulong *microseconds); + + +/* Output + */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +void g_error (gchar *format, ...) __attribute__ ((format (printf, 1, 2))); +void g_warning (gchar *format, ...) __attribute__ ((format (printf, 1, 2))); +void g_message (gchar *format, ...) __attribute__ ((format (printf, 1, 2))); +void g_print (gchar *format, ...) __attribute__ ((format (printf, 1, 2))); +#else +void g_error (gchar *format, ...); +void g_warning (gchar *format, ...); +void g_message (gchar *format, ...); +void g_print (gchar *format, ...); +#endif + +/* Utility functions + */ +gchar* g_strdup (const gchar *str); +gchar* g_strerror (gint errnum); +gchar* g_strsignal (gint signum); + + +/* Errors + */ +GErrorFunc g_set_error_handler (GErrorFunc func); +GWarningFunc g_set_warning_handler (GWarningFunc func); +GPrintFunc g_set_message_handler (GPrintFunc func); +GPrintFunc g_set_print_handler (GPrintFunc func); + +void g_debug (char *progname); +void g_attach_process (char *progname, int query); +void g_stack_trace (char *progname, int query); + + +/* String Chunks + */ +GStringChunk* g_string_chunk_new (gint size); +void g_string_chunk_free (GStringChunk *chunk); +gchar* g_string_chunk_insert (GStringChunk *chunk, + gchar* string); +gchar* g_string_chunk_insert_const (GStringChunk *chunk, + gchar* string); + +/* Strings + */ +GString* g_string_new (gchar *init); +void g_string_free (GString *string, + gint free_segment); +GString* g_string_assign (GString *lval, + gchar *rval); +GString* g_string_truncate (GString *string, + gint len); +GString* g_string_append (GString *string, + gchar *val); +GString* g_string_append_c (GString *string, + gchar c); +GString* g_string_prepend (GString *string, + gchar *val); +GString* g_string_prepend_c (GString *string, + gchar c); +void g_string_sprintf (GString *string, + gchar *fmt, + ...); +void g_string_sprintfa (GString *string, + gchar *fmt, + ...); + +/* Resizable arrays + */ +#define g_array_append_val(array,type,val) \ + g_rarray_append (array, (gpointer) &val, sizeof (type)) +#define g_array_append_vals(array,type,vals,nvals) \ + g_rarray_append (array, (gpointer) vals, sizeof (type) * nvals) +#define g_array_prepend_val(array,type,val) \ + g_rarray_prepend (array, (gpointer) &val, sizeof (type)) +#define g_array_prepend_vals(array,type,vals,nvals) \ + g_rarray_prepend (array, (gpointer) vals, sizeof (type) * nvals) +#define g_array_truncate(array,type,length) \ + g_rarray_truncate (array, length, sizeof (type)) +#define g_array_index(array,type,index) \ + ((type*) array->data)[index] + +GArray* g_array_new (gint zero_terminated); +void g_array_free (GArray *array, + gint free_segment); +GArray* g_rarray_append (GArray *array, + gpointer data, + gint size); +GArray* g_rarray_prepend (GArray *array, + gpointer data, + gint size); +GArray* g_rarray_truncate (GArray *array, + gint length, + gint size); + + +/* Hash Functions + */ +gint g_string_equal (gpointer v, + gpointer v2); +guint g_string_hash (gpointer v); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __G_LIB_H__ */ diff --git a/glib/glibconfig.h.in b/glib/glibconfig.h.in new file mode 100644 index 000000000..7a7655952 --- /dev/null +++ b/glib/glibconfig.h.in @@ -0,0 +1,67 @@ +/* glibconfig.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if the `long double' type works. */ +#undef HAVE_LONG_DOUBLE + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Other stuff */ +#undef HAVE_DOPRNT +#undef HAVE_FLOAT_H +#undef HAVE_LIMITS_H +#undef HAVE_LONG_DOUBLE +#undef HAVE_SYS_SELECT_H +#undef HAVE_STRERROR +#undef HAVE_STRSIGNAL +#undef HAVE_VALUES_H +#undef HAVE_VPRINTF + +#undef NO_FD_SET +#undef NO_SYS_ERRLIST +#undef NO_SYS_SIGLIST + +/* #undef PACKAGE */ +/* #undef VERSION */ + +/* The number of bytes in a char. */ +#undef SIZEOF_CHAR + +/* The number of bytes in a int. */ +#undef SIZEOF_INT + +/* The number of bytes in a long. */ +#undef SIZEOF_LONG + +/* The number of bytes in a short. */ +#undef SIZEOF_SHORT + +/* The number of bytes in a void *. */ +#undef SIZEOF_VOID_P + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strsignal function. */ +#undef HAVE_STRSIGNAL + +/* Define if you have the header file. */ +#undef HAVE_FLOAT_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_VALUES_H diff --git a/glib/glist.c b/glib/glist.c new file mode 100644 index 000000000..f5a31d743 --- /dev/null +++ b/glib/glist.c @@ -0,0 +1,349 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "glib.h" + + +typedef struct _GRealListAllocator GRealListAllocator; + +struct _GRealListAllocator +{ + GMemChunk *list_mem_chunk; + GList *free_list; +}; + + +static GRealListAllocator *default_allocator = NULL; +static GRealListAllocator *current_allocator = NULL; + + +GListAllocator* +g_list_allocator_new () +{ + GRealListAllocator* allocator = g_new (GRealListAllocator, 1); + + allocator->list_mem_chunk = NULL; + allocator->free_list = NULL; + + return (GListAllocator*) allocator; +} + +void +g_list_allocator_free (GListAllocator* fallocator) +{ + GRealListAllocator* allocator = (GRealListAllocator *) fallocator; + + if (allocator && allocator->list_mem_chunk) + g_mem_chunk_destroy (allocator->list_mem_chunk); + if (allocator) + g_free (allocator); +} + +GListAllocator* +g_list_set_allocator (GListAllocator* fallocator) +{ + GRealListAllocator* allocator = (GRealListAllocator *) fallocator; + GRealListAllocator* old_allocator = current_allocator; + + if (allocator) + current_allocator = allocator; + else + { + if (!default_allocator) + default_allocator = (GRealListAllocator*) g_list_allocator_new (); + current_allocator = default_allocator; + } + + if (!current_allocator->list_mem_chunk) + current_allocator->list_mem_chunk = g_mem_chunk_new ("list mem chunk", + sizeof (GList), + 1024, + G_ALLOC_ONLY); + + return (GListAllocator*) (old_allocator == default_allocator ? NULL : old_allocator); +} + + +GList* +g_list_alloc () +{ + GList *new_list; + + g_list_set_allocator (NULL); + if (current_allocator->free_list) + { + new_list = current_allocator->free_list; + current_allocator->free_list = current_allocator->free_list->next; + } + else + { + new_list = g_chunk_new (GList, current_allocator->list_mem_chunk); + } + + new_list->data = NULL; + new_list->next = NULL; + new_list->prev = NULL; + + return new_list; +} + +void +g_list_free (GList *list) +{ + GList *last; + + if (list) + { + last = g_list_last (list); + last->next = current_allocator->free_list; + current_allocator->free_list = list; + } +} + +void +g_list_free_1 (GList *list) +{ + if (list) + { + list->next = current_allocator->free_list; + current_allocator->free_list = list; + } +} + +GList* +g_list_append (GList *list, + gpointer data) +{ + GList *new_list; + GList *last; + + new_list = g_list_alloc (); + new_list->data = data; + + if (!list) + { + list = new_list; + } + else + { + last = g_list_last (list); + g_assert (last != NULL); + last->next = new_list; + new_list->prev = last; + } + + return list; +} + +GList* +g_list_prepend (GList *list, + gpointer data) +{ + GList *new_list; + + new_list = g_list_alloc (); + new_list->data = data; + + if (list) + { + if (list->prev) + list->prev->next = new_list; + new_list->prev = list->prev; + list->prev = new_list; + } + new_list->next = list; + + return new_list; +} + +GList* +g_list_insert (GList *list, + gpointer data, + gint position) +{ + GList *new_list; + GList *tmp_list; + + if (position < 0) + return g_list_append (list, data); + else if (position == 0) + return g_list_prepend (list, data); + + tmp_list = g_list_nth (list, position); + if (!tmp_list) + return g_list_append (list, data); + + new_list = g_list_alloc (); + new_list->data = data; + + if (tmp_list->prev) + tmp_list->prev->next = new_list; + new_list->next = tmp_list; + new_list->prev = tmp_list->prev; + tmp_list->prev = new_list; + + if (tmp_list == list) + list = new_list; + + return list; +} + +GList* +g_list_remove (GList *list, + gpointer data) +{ + GList *tmp; + + tmp = list; + while (tmp) + { + if (tmp->data == data) + { + if (tmp->prev) + tmp->prev->next = tmp->next; + if (tmp->next) + tmp->next->prev = tmp->prev; + + if (list == tmp) + list = list->next; + + tmp->next = NULL; + tmp->prev = NULL; + g_list_free (tmp); + + break; + } + + tmp = tmp->next; + } + return list; +} + +GList* +g_list_remove_link (GList *list, + GList *link) +{ + if (link) + { + if (link->prev) + link->prev->next = link->next; + if (link->next) + link->next->prev = link->prev; + + if (link == list) + list = list->next; + + link->next = NULL; + link->prev = NULL; + } + + return list; +} + +GList* +g_list_reverse (GList *list) +{ + GList *tmp; + GList *last; + + last = NULL; + while (list) + { + last = list; + tmp = list->next; + list->next = list->prev; + list->prev = tmp; + list = tmp; + } + + return last; +} + +GList* +g_list_nth (GList *list, + gint n) +{ + while ((n-- > 0) && list) + list = list->next; + + return list; +} + +GList* +g_list_find (GList *list, + gpointer data) +{ + while (list) + { + if (list->data == data) + break; + list = list->next; + } + + return list; +} + +GList* +g_list_last (GList *list) +{ + if (list) + { + while (list->next) + list = list->next; + } + + return list; +} + +GList* +g_list_first (GList *list) +{ + if (list) + { + while (list->prev) + list = list->prev; + } + + return list; +} + +gint +g_list_length (GList *list) +{ + gint length; + + length = 0; + while (list) + { + length++; + list = list->next; + } + + return length; +} + +void +g_list_foreach (GList *list, + GFunc func, + gpointer user_data) +{ + while (list) + { + (*func) (list->data, user_data); + list = list->next; + } +} diff --git a/glib/gmem.c b/glib/gmem.c new file mode 100644 index 000000000..35dfdaba3 --- /dev/null +++ b/glib/gmem.c @@ -0,0 +1,824 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "glib.h" + + +/* #define MEM_PROFILE */ +/* #define MEM_CHECK */ + + +#define MAX_MEM_AREA 65536L +#define MEM_AREA_SIZE 4L + +#if SIZEOF_VOID_P > SIZEOF_LONG +#define MEM_ALIGN SIZEOF_VOID_P +#else +#define MEM_ALIGN SIZEOF_LONG +#endif + + +typedef struct _GFreeAtom GFreeAtom; +typedef struct _GMemArea GMemArea; +typedef struct _GRealMemChunk GRealMemChunk; + +struct _GFreeAtom +{ + GFreeAtom *next; +}; + +struct _GMemArea +{ + GMemArea *next; /* the next mem area */ + GMemArea *prev; /* the previous mem area */ + gulong index; /* the current index into the "mem" array */ + gulong free; /* the number of free bytes in this mem area */ + gulong allocated; /* the number of atoms allocated from this area */ + gulong mark; /* is this mem area marked for deletion */ + gchar mem[MEM_AREA_SIZE]; /* the mem array from which atoms get allocated + * the actual size of this array is determined by + * the mem chunk "area_size". ANSI says that it + * must be declared to be the maximum size it + * can possibly be (even though the actual size + * may be less). + */ +}; + +struct _GRealMemChunk +{ + gchar *name; /* name of this MemChunk...used for debugging output */ + gint type; /* the type of MemChunk: ALLOC_ONLY or ALLOC_AND_FREE */ + gint num_mem_areas; /* the number of memory areas */ + gint num_marked_areas; /* the number of areas marked for deletion */ + guint atom_size; /* the size of an atom */ + gulong area_size; /* the size of a memory area */ + GMemArea *mem_area; /* the current memory area */ + GMemArea *mem_areas; /* a list of all the mem areas owned by this chunk */ + GMemArea *free_mem_area; /* the free area...which is about to be destroyed */ + GFreeAtom *free_atoms; /* the free atoms list */ + GTree *mem_tree; /* tree of mem areas sorted by memory address */ + GRealMemChunk *next; /* pointer to the next chunk */ + GRealMemChunk *prev; /* pointer to the previous chunk */ +}; + + +static gulong g_mem_chunk_compute_size (gulong size); +static gint g_mem_chunk_area_compare (GMemArea *a, + GMemArea *b); +static gint g_mem_chunk_area_search (GMemArea *a, + gchar *addr); + + +static GRealMemChunk *mem_chunks = NULL; + +#ifdef MEM_PROFILE +static gulong allocations[4096] = { 0 }; +static gulong allocated_mem = 0; +static gulong freed_mem = 0; +#endif /* MEM_PROFILE */ + + +#ifndef USE_DMALLOC + +gpointer +g_malloc (gulong size) +{ + gpointer p; + + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + gulong *t; +#endif /* MEM_PROFILE || MEM_CHECK */ + + + if (size == 0) + return NULL; + + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size += SIZEOF_LONG; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#ifdef MEM_CHECK + size += SIZEOF_LONG; +#endif /* MEM_CHECK */ + + + p = (gpointer) malloc (size); + if (!p) + g_error ("could not allocate %ld bytes", size); + + +#ifdef MEM_CHECK + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = 0; +#endif /* MEM_CHECK */ + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = size; + +#ifdef MEM_PROFILE + if (size <= 4095) + allocations[size-1] += 1; + else + allocations[4095] += 1; + allocated_mem += size; +#endif /* MEM_PROFILE */ +#endif /* MEM_PROFILE || MEM_CHECK */ + + + return p; +} + +gpointer +g_malloc0 (gulong size) +{ + gpointer p; + + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + gulong *t; +#endif /* MEM_PROFILE || MEM_CHECK */ + + + if (size == 0) + return NULL; + + +#ifdef MEM_PROFILE + size += SIZEOF_LONG; +#endif /* MEM_PROFILE */ + +#ifdef MEM_CHECK + size += SIZEOF_LONG; +#endif /* MEM_CHECK */ + + + p = (gpointer) calloc (size, 1); + if (!p) + g_error ("could not allocate %ld bytes", size); + + +#ifdef MEM_CHECK + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = 0; +#endif /* MEM_CHECK */ + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = size; + +#ifdef MEM_PROFILE + if (size <= 4095) + allocations[size-1] += 1; + else + allocations[4095] += 1; + allocated_mem += size; +#endif /* MEM_PROFILE */ +#endif /* MEM_PROFILE */ + + + return p; +} + +gpointer +g_realloc (gpointer mem, + gulong size) +{ + gpointer p; + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + gulong *t; +#endif /* MEM_PROFILE || MEM_CHECK */ + + + if (size == 0) + return NULL; + + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size += SIZEOF_LONG; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#ifdef MEM_CHECK + size += SIZEOF_LONG; +#endif /* MEM_CHECK */ + + + if (!mem) + p = (gpointer) malloc (size); + else + { +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + t = (gulong*) ((guchar*) mem - SIZEOF_LONG); +#ifdef MEM_PROFILE + freed_mem += *t; +#endif /* MEM_PROFILE */ + mem = t; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#ifdef MEM_CHECK + t = (gulong*) ((guchar*) mem - SIZEOF_LONG); + if (*t >= 1) + g_warning ("trying to realloc freed memory\n"); + mem = t; +#endif /* MEM_CHECK */ + + p = (gpointer) realloc (mem, size); + } + + if (!p) + g_error ("could not reallocate %ld bytes", size); + + +#ifdef MEM_CHECK + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = 0; +#endif /* MEM_CHECK */ + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + size -= SIZEOF_LONG; + + t = p; + p = ((guchar*) p + SIZEOF_LONG); + *t = size; + +#ifdef MEM_PROFILE + if (size <= 4095) + allocations[size-1] += 1; + else + allocations[4095] += 1; + allocated_mem += size; +#endif /* MEM_PROFILE */ +#endif /* MEM_PROFILE || MEM_CHECK */ + + + return p; +} + +void +g_free (gpointer mem) +{ + if (mem) + { +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + gulong *t; + gulong size; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#if defined(MEM_PROFILE) || defined(MEM_CHECK) + t = (gulong*) ((guchar*) mem - SIZEOF_LONG); + size = *t; +#ifdef MEM_PROFILE + freed_mem += size; +#endif /* MEM_PROFILE */ + mem = t; +#endif /* MEM_PROFILE || MEM_CHECK */ + +#ifdef MEM_CHECK + t = (gulong*) ((guchar*) mem - SIZEOF_LONG); + if (*t >= 1) + g_warning ("freeing previously freed memory\n"); + *t += 1; + mem = t; + + memset ((guchar*) mem + 8, 0, size); +#else /* MEM_CHECK */ + free (mem); +#endif /* MEM_CHECK */ + } +} + +#endif /* ! USE_DMALLOC */ + + +void +g_mem_profile () +{ +#ifdef MEM_PROFILE + gint i; + + for (i = 0; i < 4095; i++) + if (allocations[i] > 0) + g_print ("%lu allocations of %d bytes\n", allocations[i], i + 1); + + if (allocations[4095] > 0) + g_print ("%lu allocations of greater than 4095 bytes\n", allocations[4095]); + g_print ("%lu bytes allocated\n", allocated_mem); + g_print ("%lu bytes freed\n", freed_mem); + g_print ("%lu bytes in use\n", allocated_mem - freed_mem); +#endif /* MEM_PROFILE */ +} + +void +g_mem_check (gpointer mem) +{ +#ifdef MEM_CHECK + gulong *t; + + t = (gulong*) ((guchar*) mem - SIZEOF_LONG - SIZEOF_LONG); + + if (*t >= 1) + g_warning ("mem: 0x%08x has been freed: %lu\n", (gulong) mem, *t); +#endif /* MEM_CHECK */ +} + +GMemChunk* +g_mem_chunk_new (gchar *name, + gint atom_size, + gulong area_size, + gint type) +{ + GRealMemChunk *mem_chunk; + gulong rarea_size; + + mem_chunk = g_new (struct _GRealMemChunk, 1); + mem_chunk->name = name; + mem_chunk->type = type; + mem_chunk->num_mem_areas = 0; + mem_chunk->num_marked_areas = 0; + mem_chunk->mem_area = NULL; + mem_chunk->free_mem_area = NULL; + mem_chunk->free_atoms = NULL; + mem_chunk->mem_tree = NULL; + mem_chunk->mem_areas = NULL; + mem_chunk->atom_size = atom_size; + + if (mem_chunk->type == G_ALLOC_AND_FREE) + mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); + + if (mem_chunk->atom_size % MEM_ALIGN) + mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN); + + mem_chunk->area_size = area_size; + if (mem_chunk->area_size > MAX_MEM_AREA) + mem_chunk->area_size = MAX_MEM_AREA; + while (mem_chunk->area_size < mem_chunk->atom_size) + mem_chunk->area_size *= 2; + + rarea_size = mem_chunk->area_size + sizeof (GMemArea) - MEM_AREA_SIZE; + rarea_size = g_mem_chunk_compute_size (rarea_size); + mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE); + + /* + mem_chunk->area_size -= (sizeof (GMemArea) - MEM_AREA_SIZE); + if (mem_chunk->area_size < mem_chunk->atom_size) + { + mem_chunk->area_size = (mem_chunk->area_size + sizeof (GMemArea) - MEM_AREA_SIZE) * 2; + mem_chunk->area_size -= (sizeof (GMemArea) - MEM_AREA_SIZE); + } + + if (mem_chunk->area_size % mem_chunk->atom_size) + mem_chunk->area_size += mem_chunk->atom_size - (mem_chunk->area_size % mem_chunk->atom_size); + */ + + mem_chunk->next = mem_chunks; + mem_chunk->prev = NULL; + if (mem_chunks) + mem_chunks->prev = mem_chunk; + mem_chunks = mem_chunk; + + return ((GMemChunk*) mem_chunk); +} + +void +g_mem_chunk_destroy (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *mem_areas; + GMemArea *temp_area; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + mem_areas = rmem_chunk->mem_areas; + while (mem_areas) + { + temp_area = mem_areas; + mem_areas = mem_areas->next; + g_free (temp_area); + } + + if (rmem_chunk->next) + rmem_chunk->next->prev = rmem_chunk->prev; + if (rmem_chunk->prev) + rmem_chunk->prev->next = rmem_chunk->next; + + if (rmem_chunk == mem_chunks) + mem_chunks = mem_chunks->next; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + g_tree_destroy (rmem_chunk->mem_tree); + + g_free (rmem_chunk); +} + +gpointer +g_mem_chunk_alloc (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *temp_area; + gpointer mem; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + while (rmem_chunk->free_atoms) + { + /* Get the first piece of memory on the "free_atoms" list. + * We can go ahead and destroy the list node we used to keep + * track of it with and to update the "free_atoms" list to + * point to its next element. + */ + mem = rmem_chunk->free_atoms; + rmem_chunk->free_atoms = rmem_chunk->free_atoms->next; + + /* Determine which area this piece of memory is allocated from */ + temp_area = g_tree_search (rmem_chunk->mem_tree, + (GSearchFunc) g_mem_chunk_area_search, + mem); + + /* If the area has been marked, then it is being destroyed. + * (ie marked to be destroyed). + * We check to see if all of the segments on the free list that + * reference this area have been removed. This occurs when + * the ammount of free memory is less than the allocatable size. + * If the chunk should be freed, then we place it in the "free_mem_area". + * This is so we make sure not to free the mem area here and then + * allocate it again a few lines down. + * If we don't allocate a chunk a few lines down then the "free_mem_area" + * will be freed. + * If there is already a "free_mem_area" then we'll just free this mem area. + */ + if (temp_area->mark) + { + /* Update the "free" memory available in that area */ + temp_area->free += rmem_chunk->atom_size; + + if (temp_area->free == rmem_chunk->area_size) + { + if (temp_area == rmem_chunk->mem_area) + rmem_chunk->mem_area = NULL; + + if (rmem_chunk->free_mem_area) + { + rmem_chunk->num_mem_areas -= 1; + rmem_chunk->num_marked_areas -= 1; + + if (temp_area->next) + temp_area->next->prev = temp_area->prev; + if (temp_area->prev) + temp_area->prev->next = temp_area->next; + if (temp_area == rmem_chunk->mem_areas) + rmem_chunk->mem_areas = rmem_chunk->mem_areas->next; + if (temp_area == rmem_chunk->mem_area) + rmem_chunk->mem_area = NULL; + + g_free (temp_area); + } + else + rmem_chunk->free_mem_area = temp_area; + } + } + else + { + /* Update the number of allocated atoms count. + */ + temp_area->allocated += 1; + + /* The area wasn't marked...return the memory + */ + goto outa_here; + } + } + + /* If there isn't a current mem area or the current mem area is out of space + * then allocate a new mem area. We'll first check and see if we can use + * the "free_mem_area". Otherwise we'll just malloc the mem area. + */ + if ((!rmem_chunk->mem_area) || + ((rmem_chunk->mem_area->index + rmem_chunk->atom_size) > rmem_chunk->area_size)) + { + if (rmem_chunk->free_mem_area) + { + rmem_chunk->mem_area = rmem_chunk->free_mem_area; + rmem_chunk->free_mem_area = NULL; + } + else + { + rmem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) - + MEM_AREA_SIZE + + rmem_chunk->area_size); + + rmem_chunk->num_mem_areas += 1; + rmem_chunk->mem_area->next = rmem_chunk->mem_areas; + rmem_chunk->mem_area->prev = NULL; + + if (rmem_chunk->mem_areas) + rmem_chunk->mem_areas->prev = rmem_chunk->mem_area; + rmem_chunk->mem_areas = rmem_chunk->mem_area; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + g_tree_insert (rmem_chunk->mem_tree, rmem_chunk->mem_area, rmem_chunk->mem_area); + } + + rmem_chunk->mem_area->index = 0; + rmem_chunk->mem_area->free = rmem_chunk->area_size; + rmem_chunk->mem_area->allocated = 0; + rmem_chunk->mem_area->mark = 0; + } + else if (rmem_chunk->free_mem_area) + { + rmem_chunk->num_mem_areas -= 1; + + if (rmem_chunk->free_mem_area->next) + rmem_chunk->free_mem_area->next->prev = rmem_chunk->free_mem_area->prev; + if (rmem_chunk->free_mem_area->prev) + rmem_chunk->free_mem_area->prev->next = rmem_chunk->free_mem_area->next; + if (rmem_chunk->free_mem_area == rmem_chunk->mem_areas) + rmem_chunk->mem_areas = rmem_chunk->mem_areas->next; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + g_tree_remove (rmem_chunk->mem_tree, rmem_chunk->free_mem_area); + + g_free (rmem_chunk->free_mem_area); + rmem_chunk->free_mem_area = NULL; + } + + /* Get the memory and modify the state variables appropriately. + */ + mem = (gpointer) &rmem_chunk->mem_area->mem[rmem_chunk->mem_area->index]; + rmem_chunk->mem_area->index += rmem_chunk->atom_size; + rmem_chunk->mem_area->free -= rmem_chunk->atom_size; + rmem_chunk->mem_area->allocated += 1; + +outa_here: + return mem; +} + +void +g_mem_chunk_free (GMemChunk *mem_chunk, + gpointer mem) +{ + GRealMemChunk *rmem_chunk; + GMemArea *temp_area; + GFreeAtom *free_atom; + + g_assert (mem_chunk != NULL); + g_assert (mem != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + /* Don't do anything if this is an ALLOC_ONLY chunk + */ + if (rmem_chunk->type == G_ALLOC_AND_FREE) + { + /* Place the memory on the "free_atoms" list + */ + free_atom = (GFreeAtom*) mem; + free_atom->next = rmem_chunk->free_atoms; + rmem_chunk->free_atoms = free_atom; + + temp_area = g_tree_search (rmem_chunk->mem_tree, + (GSearchFunc) g_mem_chunk_area_search, + mem); + + temp_area->allocated -= 1; + + if (temp_area->allocated == 0) + { + temp_area->mark = 1; + rmem_chunk->num_marked_areas += 1; + + g_mem_chunk_clean (mem_chunk); + } + } +} + +void +g_mem_chunk_clean (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *mem_area; + GFreeAtom *prev_free_atom; + GFreeAtom *temp_free_atom; + gpointer mem; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + { + prev_free_atom = NULL; + temp_free_atom = rmem_chunk->free_atoms; + + while (temp_free_atom) + { + mem = (gpointer) temp_free_atom; + + mem_area = g_tree_search (rmem_chunk->mem_tree, + (GSearchFunc) g_mem_chunk_area_search, + mem); + + /* If this mem area is marked for destruction then delete the + * area and list node and decrement the free mem. + */ + if (mem_area->mark) + { + if (prev_free_atom) + prev_free_atom->next = temp_free_atom->next; + else + rmem_chunk->free_atoms = temp_free_atom->next; + temp_free_atom = temp_free_atom->next; + + mem_area->free += rmem_chunk->atom_size; + if (mem_area->free == rmem_chunk->area_size) + { + rmem_chunk->num_mem_areas -= 1; + rmem_chunk->num_marked_areas -= 1; + + if (mem_area->next) + mem_area->next->prev = mem_area->prev; + if (mem_area->prev) + mem_area->prev->next = mem_area->next; + if (mem_area == rmem_chunk->mem_areas) + rmem_chunk->mem_areas = rmem_chunk->mem_areas->next; + if (mem_area == rmem_chunk->mem_area) + rmem_chunk->mem_area = NULL; + + if (rmem_chunk->type == G_ALLOC_AND_FREE) + g_tree_remove (rmem_chunk->mem_tree, mem_area); + g_free (mem_area); + } + } + else + { + prev_free_atom = temp_free_atom; + temp_free_atom = temp_free_atom->next; + } + } + } +} + +void +g_mem_chunk_reset (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *mem_areas; + GMemArea *temp_area; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + + mem_areas = rmem_chunk->mem_areas; + rmem_chunk->num_mem_areas = 0; + rmem_chunk->mem_areas = NULL; + rmem_chunk->mem_area = NULL; + + while (mem_areas) + { + temp_area = mem_areas; + mem_areas = mem_areas->next; + g_free (temp_area); + } + + rmem_chunk->free_atoms = NULL; + + if (rmem_chunk->mem_tree) + g_tree_destroy (rmem_chunk->mem_tree); + rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare); +} + +void +g_mem_chunk_print (GMemChunk *mem_chunk) +{ + GRealMemChunk *rmem_chunk; + GMemArea *mem_areas; + gulong mem; + + g_assert (mem_chunk != NULL); + + rmem_chunk = (GRealMemChunk*) mem_chunk; + mem_areas = rmem_chunk->mem_areas; + mem = 0; + + while (mem_areas) + { + mem += rmem_chunk->area_size - mem_areas->free; + mem_areas = mem_areas->next; + } + + g_print ("%s: %ld bytes using %d mem areas", rmem_chunk->name, mem, rmem_chunk->num_mem_areas); +} + +void +g_mem_chunk_info () +{ + GRealMemChunk *mem_chunk; + gint count; + + count = 0; + mem_chunk = mem_chunks; + while (mem_chunk) + { + count += 1; + mem_chunk = mem_chunk->next; + } + + g_print ("%d mem chunks", count); + + mem_chunk = mem_chunks; + while (mem_chunk) + { + g_mem_chunk_print ((GMemChunk*) mem_chunk); + mem_chunk = mem_chunk->next; + } +} + +void +g_blow_chunks () +{ + GRealMemChunk *mem_chunk; + + mem_chunk = mem_chunks; + while (mem_chunk) + { + g_mem_chunk_clean ((GMemChunk*) mem_chunk); + mem_chunk = mem_chunk->next; + } +} + + +static gulong +g_mem_chunk_compute_size (gulong size) +{ + gulong power_of_2; + gulong lower, upper; + + power_of_2 = 16; + while (power_of_2 < size) + power_of_2 <<= 1; + + lower = power_of_2 >> 1; + upper = power_of_2; + + if ((size - lower) < (upper - size)) + return lower; + return upper; +} + +static gint +g_mem_chunk_area_compare (GMemArea *a, + GMemArea *b) +{ + return (a->mem - b->mem); +} + +static gint +g_mem_chunk_area_search (GMemArea *a, + gchar *addr) +{ + if (a->mem <= addr) + { + if (addr < &a->mem[a->index]) + return 0; + return 1; + } + return -1; +} diff --git a/glib/gprimes.c b/glib/gprimes.c new file mode 100644 index 000000000..8887c0e66 --- /dev/null +++ b/glib/gprimes.c @@ -0,0 +1,61 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "glib.h" + + +gint g_primes[] = +{ + 11, + 15, + 23, + 35, + 49, + 73, + 109, + 163, + 251, + 367, + 557, + 823, + 1237, + 1861, + 2777, + 4177, + 6247, + 9371, + 14057, + 21089, + 31627, + 47431, + 71143, + 106721, + 160073, + 240101, + 360163, + 540217, + 810343, + 1215497, + 1823231, + 2734867, + 4102283, + 6153409, + 9230113, + 13845163, +}; + +gint g_nprimes = sizeof (g_primes) / sizeof (g_primes[0]); diff --git a/glib/gslist.c b/glib/gslist.c new file mode 100644 index 000000000..e09198522 --- /dev/null +++ b/glib/gslist.c @@ -0,0 +1,324 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "glib.h" + + +typedef struct _GRealListAllocator GRealListAllocator; + +struct _GRealListAllocator +{ + GMemChunk *list_mem_chunk; + GSList *free_list; +}; + + +static GRealListAllocator *default_allocator = NULL; +static GRealListAllocator *current_allocator = NULL; + +GListAllocator* +g_slist_set_allocator (GListAllocator* fallocator) +{ + GRealListAllocator* allocator = (GRealListAllocator *) fallocator; + GRealListAllocator* old_allocator = current_allocator; + + if (allocator) + current_allocator = allocator; + else + { + if (!default_allocator) + default_allocator = (GRealListAllocator*) g_list_allocator_new (); + current_allocator = default_allocator; + } + + if (!current_allocator->list_mem_chunk) + current_allocator->list_mem_chunk = g_mem_chunk_new ("slist mem chunk", + sizeof (GSList), + 1024, + G_ALLOC_ONLY); + + return (GListAllocator*) (old_allocator == default_allocator ? NULL : old_allocator); +} + + +GSList* +g_slist_alloc () +{ + GSList *new_list; + + g_slist_set_allocator (NULL); + if (current_allocator->free_list) + { + new_list = current_allocator->free_list; + current_allocator->free_list = current_allocator->free_list->next; + } + else + { + new_list = g_chunk_new (GSList, current_allocator->list_mem_chunk); + } + + new_list->data = NULL; + new_list->next = NULL; + + return new_list; +} + +void +g_slist_free (GSList *list) +{ + GSList *last; + + if (list) + { + last = g_slist_last (list); + last->next = current_allocator->free_list; + current_allocator->free_list = list; + } +} + +void +g_slist_free_1 (GSList *list) +{ + if (list) + { + list->next = current_allocator->free_list; + current_allocator->free_list = list; + } +} + +GSList* +g_slist_append (GSList *list, + gpointer data) +{ + GSList *new_list; + GSList *last; + + new_list = g_slist_alloc (); + new_list->data = data; + + if (!list) + { + list = new_list; + } + else + { + last = g_slist_last (list); + g_assert (last != NULL); + last->next = new_list; + } + + return list; +} + +GSList* +g_slist_prepend (GSList *list, + gpointer data) +{ + GSList *new_list; + + new_list = g_slist_alloc (); + new_list->data = data; + new_list->next = list; + + return new_list; +} + +GSList* +g_slist_insert (GSList *list, + gpointer data, + gint position) +{ + GSList *prev_list; + GSList *tmp_list; + GSList *new_list; + + prev_list = NULL; + tmp_list = list; + + while (tmp_list && (position-- > 0)) + { + prev_list = tmp_list; + tmp_list = tmp_list->next; + } + + if (!tmp_list && !prev_list) + return list; + + new_list = g_slist_alloc (); + + if (!prev_list) + { + new_list->next = list; + list = new_list; + } + else + { + new_list->next = prev_list->next; + prev_list->next = new_list; + } + + return list; +} + +GSList* +g_slist_remove (GSList *list, + gpointer data) +{ + GSList *tmp; + GSList *prev; + + prev = NULL; + tmp = list; + + while (tmp) + { + if (tmp->data == data) + { + if (prev) + prev->next = tmp->next; + if (list == tmp) + list = list->next; + + tmp->next = NULL; + g_slist_free (tmp); + + break; + } + + prev = tmp; + tmp = tmp->next; + } + + return list; +} + +GSList* +g_slist_remove_link (GSList *list, + GSList *link) +{ + GSList *tmp; + GSList *prev; + + prev = NULL; + tmp = list; + + while (tmp) + { + if (tmp == link) + { + if (prev) + prev->next = tmp->next; + if (list == tmp) + list = list->next; + + tmp->next = NULL; + break; + } + + prev = tmp; + tmp = tmp->next; + } + + return list; +} + +GSList* +g_slist_reverse (GSList *list) +{ + GSList *tmp; + GSList *prev; + GSList *last; + + last = NULL; + prev = NULL; + + while (list) + { + last = list; + + tmp = list->next; + list->next = prev; + + prev = list; + list = tmp; + } + + return last; +} + +GSList* +g_slist_nth (GSList *list, + gint n) +{ + while ((n-- > 0) && list) + list = list->next; + + return list; +} + +GSList* +g_slist_find (GSList *list, + gpointer data) +{ + while (list) + { + if (list->data == data) + break; + list = list->next; + } + + return list; +} + +GSList* +g_slist_last (GSList *list) +{ + if (list) + { + while (list->next) + list = list->next; + } + + return list; +} + +gint +g_slist_length (GSList *list) +{ + gint length; + + length = 0; + while (list) + { + length++; + list = list->next; + } + + return length; +} + +void +g_slist_foreach (GSList *list, + GFunc func, + gpointer user_data) +{ + while (list) + { + (*func) (list->data, user_data); + list = list->next; + } +} diff --git a/glib/gstring.c b/glib/gstring.c new file mode 100644 index 000000000..457d47ebc --- /dev/null +++ b/glib/gstring.c @@ -0,0 +1,487 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include + + +typedef struct _GRealStringChunk GRealStringChunk; +typedef struct _GRealString GRealString; + +struct _GRealStringChunk +{ + GHashTable *const_table; + GSList *storage_list; + gint storage_next; + gint this_size; + gint default_size; +}; + +struct _GRealString +{ + gchar *str; + gint len; + gint alloc; +}; + + +static GMemChunk *string_mem_chunk = NULL; + +/* Hash Functions. + */ + +/* Pete, you may have these elsewhere. */ +gint +g_string_equal(gpointer v, gpointer v2) +{ + return strcmp ((gchar*) v, (gchar*)v2) == 0; +} + +/* a char* hash function from ASU */ +guint +g_string_hash(gpointer v) +{ + char *s = (char*)v; + char *p; + guint h=0, g; + + for(p = s; *p != '\0'; p += 1) { + h = ( h << 4 ) + *p; + if ( ( g = h & 0xf0000000 ) ) { + h = h ^ (g >> 24); + h = h ^ g; + } + } + + return h /* % M */; +} + + +/* String Chunks. + */ + +GStringChunk* +g_string_chunk_new (gint default_size) +{ + GRealStringChunk *new_chunk = g_new (GRealStringChunk, 1); + gint size = 1; + + while (size < default_size) + size <<= 1; + + new_chunk->const_table = NULL; + new_chunk->storage_list = NULL; + new_chunk->storage_next = size; + new_chunk->default_size = size; + new_chunk->this_size = size; + + return (GStringChunk*) new_chunk; +} + +void +g_string_chunk_free (GStringChunk *fchunk) +{ + GRealStringChunk *chunk = (GRealStringChunk*) fchunk; + GSList *tmp_list; + + if (chunk->storage_list) + { + GListAllocator *tmp_allocator = g_slist_set_allocator (NULL); + + for (tmp_list = chunk->storage_list; tmp_list; tmp_list = tmp_list->next) + g_free (tmp_list->data); + + g_slist_free (chunk->storage_list); + + g_slist_set_allocator (tmp_allocator); + } + + if (chunk->const_table) + g_hash_table_destroy (chunk->const_table); + + g_free (chunk); +} + +gchar* +g_string_chunk_insert (GStringChunk *fchunk, + gchar* string) +{ + GRealStringChunk *chunk = (GRealStringChunk*) fchunk; + gint len = strlen (string); + char* pos; + + if ((chunk->storage_next + len + 1) > chunk->this_size) + { + GListAllocator *tmp_allocator = g_slist_set_allocator (NULL); + gint new_size = chunk->default_size; + + while (new_size < len+1) + new_size <<= 1; + + chunk->storage_list = g_slist_prepend (chunk->storage_list, + g_new (char, new_size)); + + chunk->this_size = new_size; + chunk->storage_next = 0; + + g_slist_set_allocator (tmp_allocator); + } + + pos = ((char*)chunk->storage_list->data) + chunk->storage_next; + + strcpy (pos, string); + + chunk->storage_next += len + 1; + + return pos; +} + +gchar* +g_string_chunk_insert_const (GStringChunk *fchunk, + gchar* string) +{ + GRealStringChunk *chunk = (GRealStringChunk*) fchunk; + char* lookup; + + if (!chunk->const_table) + chunk->const_table = g_hash_table_new (g_string_hash, g_string_equal); + + lookup = (char*) g_hash_table_lookup (chunk->const_table, string); + + if (!lookup) + { + lookup = g_string_chunk_insert (fchunk, string); + g_hash_table_insert (chunk->const_table, lookup, lookup); + } + + return lookup; +} + +/* Strings. + */ +static gint +nearest_pow (gint num) +{ + gint n = 1; + + while (n < num) + n <<= 1; + + return n; +} + +static void +g_string_maybe_expand (GRealString* string, gint len) +{ + if (string->len + len >= string->alloc) + { + string->alloc = nearest_pow (string->len + len + 1); + string->str = g_realloc (string->str, string->alloc); + } +} + +GString* +g_string_new (gchar *init) +{ + GRealString *string; + + if (!string_mem_chunk) + string_mem_chunk = g_mem_chunk_new ("string mem chunk", + sizeof (GRealString), + 1024, G_ALLOC_AND_FREE); + + string = g_chunk_new (GRealString, string_mem_chunk); + + string->alloc = 2; + string->len = 0; + string->str = g_new0(char, 2); + + if (init) + g_string_append ((GString*)string, init); + + return (GString*) string; +} + +void +g_string_free (GString *string, gint free_segment) +{ + if (free_segment) + g_free (string->str); + + g_mem_chunk_free (string_mem_chunk, string); +} + +GString* +g_string_assign (GString *lval, + char *rval) +{ + g_string_truncate (lval, 0); + g_string_append (lval, rval); + + return lval; +} + +GString* +g_string_truncate (GString* fstring, gint len) +{ + GRealString *string = (GRealString*)fstring; + + string->len = len; + + string->str[len] = 0; + + return fstring; +} + +GString* +g_string_append (GString *fstring, gchar *val) +{ + GRealString *string = (GRealString*)fstring; + int len = strlen (val); + + g_string_maybe_expand (string, len); + + strcpy (string->str + string->len, val); + + string->len += len; + + return fstring; +} + +GString* +g_string_append_c (GString *fstring, char c) +{ + GRealString *string = (GRealString*)fstring; + + g_string_maybe_expand (string, 1); + + string->str[string->len++] = c; + string->str[string->len] = 0; + + return fstring; +} + +GString* +g_string_prepend (GString *fstring, gchar *val) +{ + GRealString *string = (GRealString*)fstring; + gint len = strlen (val); + + g_string_maybe_expand (string, len); + + memmove (string->str, string->str + len, string->len); + + strncpy (string->str, val, len); + + string->len += len; + + string->str[string->len] = 0; + + return fstring; +} + +GString* +g_string_prepend_c (GString *fstring, char c) +{ + GRealString *string = (GRealString*)fstring; + + g_string_maybe_expand (string, 1); + + memmove (string->str, string->str + 1, string->len); + + string->str[0] = c; + + string->len += 1; + + string->str[string->len] = 0; + + return fstring; +} + +static int +get_length_upper_bound (gchar* fmt, va_list *args) +{ + int len = 0; + int short_int; + int long_int; + int done; + + while (*fmt) + { + char c = *fmt++; + + short_int = FALSE; + long_int = FALSE; + + if (c == '%') + { + done = FALSE; + while (*fmt && !done) + { + switch (*fmt++) + { + case '*': + len += va_arg(*args, int); + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + fmt -= 1; + len += strtol (fmt, &fmt, 10); + break; + case 'h': + short_int = TRUE; + break; + case 'l': + long_int = TRUE; + break; + + /* I ignore 'q' and 'L', they're not portable anyway. */ + + case 's': + len += strlen (va_arg (*args, char *)); + done = TRUE; + break; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (long_int) + (void)va_arg (*args, long); + else if (short_int) + (void)va_arg (*args, int); + else + (void)va_arg (*args, int); + len += 32; + done = TRUE; + break; + case 'D': + case 'O': + case 'U': + (void)va_arg (*args, long); + len += 32; + done = TRUE; + break; + case 'e': + case 'E': + case 'f': + case 'g': + (void)va_arg (*args, double); + len += 32; + done = TRUE; + break; + case 'c': + (void)va_arg (*args, int); + len += 1; + done = TRUE; + break; + case 'p': + case 'n': + (void)va_arg (*args, void*); + len += 32; + done = TRUE; + break; + case '%': + len += 1; + done = TRUE; + break; + default: + break; + } + } + } + else + len += 1; + } + + return len; +} + +char* +g_vsprintf (gchar *fmt, + va_list *args, + va_list *args2) +{ + static gchar *buf = NULL; + static gint alloc = 0; + + gint len = get_length_upper_bound (fmt, args); + + if (len >= alloc) + { + if (buf) + g_free (buf); + + alloc = nearest_pow (MAX(len + 1, 1024)); + + buf = g_new (char, alloc); + } + + vsprintf (buf, fmt, *args2); + + return buf; +} + +static void +g_string_sprintfa_int (GString *string, + gchar *fmt, + va_list *args, + va_list *args2) +{ + g_string_append (string, g_vsprintf (fmt, args, args2)); +} + +void +g_string_sprintf (GString *string, gchar *fmt, ...) +{ + va_list args, args2; + + va_start(args, fmt); + va_start(args2, fmt); + + g_string_truncate (string, 0); + + g_string_sprintfa_int (string, fmt, &args, &args2); + + va_end(args); + va_end(args2); +} + +void +g_string_sprintfa (GString *string, gchar *fmt, ...) +{ + va_list args, args2; + + va_start(args, fmt); + va_start(args2, fmt); + + g_string_sprintfa_int (string, fmt, &args, &args2); + + va_end(args); + va_end(args2); +} diff --git a/glib/gtimer.c b/glib/gtimer.c new file mode 100644 index 000000000..c3b720df9 --- /dev/null +++ b/glib/gtimer.c @@ -0,0 +1,119 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "glib.h" + + +typedef struct _GRealTimer GRealTimer; + +struct _GRealTimer +{ + struct timeval start; + struct timeval end; + gint active; +}; + + +GTimer* +g_timer_new () +{ + GRealTimer *timer; + + timer = g_new (GRealTimer, 1); + timer->active = TRUE; + + gettimeofday (&timer->start, NULL); + + return ((GTimer*) timer); +} + +void +g_timer_destroy (GTimer *timer) +{ + g_assert (timer != NULL); + + g_free (timer); +} + +void +g_timer_start (GTimer *timer) +{ + GRealTimer *rtimer; + + g_assert (timer != NULL); + + rtimer = (GRealTimer*) timer; + gettimeofday (&rtimer->start, NULL); + rtimer->active = 1; +} + +void +g_timer_stop (GTimer *timer) +{ + GRealTimer *rtimer; + + g_assert (timer != NULL); + + rtimer = (GRealTimer*) timer; + gettimeofday (&rtimer->end, NULL); + rtimer->active = 0; +} + +void +g_timer_reset (GTimer *timer) +{ + GRealTimer *rtimer; + + g_assert (timer != NULL); + + rtimer = (GRealTimer*) timer; + gettimeofday (&rtimer->start, NULL); +} + +gdouble +g_timer_elapsed (GTimer *timer, + gulong *microseconds) +{ + GRealTimer *rtimer; + struct timeval elapsed; + gdouble total; + + g_assert (timer != NULL); + + rtimer = (GRealTimer*) timer; + + if (rtimer->active) + gettimeofday (&rtimer->end, NULL); + + if (rtimer->start.tv_usec > rtimer->end.tv_usec) + { + rtimer->end.tv_usec += 1000000; + rtimer->end.tv_sec--; + } + + elapsed.tv_usec = rtimer->end.tv_usec - rtimer->start.tv_usec; + elapsed.tv_sec = rtimer->end.tv_sec - rtimer->start.tv_sec; + + total = elapsed.tv_sec + ((gdouble) elapsed.tv_usec / 1e6); + + if (microseconds) + *microseconds = elapsed.tv_usec; + + return total; +} diff --git a/glib/gtree.c b/glib/gtree.c new file mode 100644 index 000000000..61a32a409 --- /dev/null +++ b/glib/gtree.c @@ -0,0 +1,718 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "glib.h" + + +typedef struct _GRealTree GRealTree; +typedef struct _GTreeNode GTreeNode; + +struct _GRealTree +{ + GTreeNode *root; + GCompareFunc key_compare; +}; + +struct _GTreeNode +{ + gint balance; /* height (left) - height (right) */ + GTreeNode *left; /* left subtree */ + GTreeNode *right; /* right subtree */ + gpointer key; /* key for this node */ + gpointer value; /* value stored at this node */ +}; + + +static GTreeNode* g_tree_node_new (gpointer key, + gpointer value); +static void g_tree_node_destroy (GTreeNode *node); +static GTreeNode* g_tree_node_insert (GTreeNode *node, + GCompareFunc compare, + gpointer key, + gpointer value, + gint *inserted); +static GTreeNode* g_tree_node_remove (GTreeNode *node, + GCompareFunc compare, + gpointer key); +static GTreeNode* g_tree_node_balance (GTreeNode *node); +static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node, + GTreeNode **leftmost); +static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node, + gint old_balance); +static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node, + gint old_balance); +static gpointer g_tree_node_lookup (GTreeNode *node, + GCompareFunc compare, + gpointer key); +static gint g_tree_node_count (GTreeNode *node); +static gint g_tree_node_pre_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data); +static gint g_tree_node_in_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data); +static gint g_tree_node_post_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data); +static gpointer g_tree_node_search (GTreeNode *node, + GSearchFunc search_func, + gpointer data); +static gint g_tree_node_height (GTreeNode *node); +static GTreeNode* g_tree_node_rotate_left (GTreeNode *node); +static GTreeNode* g_tree_node_rotate_right (GTreeNode *node); +static void g_tree_node_check (GTreeNode *node); + + +static GMemChunk *node_mem_chunk = NULL; +static GSList *node_free_list = NULL; + + +GTree* +g_tree_new (GCompareFunc key_compare_func) +{ + GRealTree *rtree; + + rtree = g_new (GRealTree, 1); + rtree->root = NULL; + rtree->key_compare = key_compare_func; + + return (GTree*) rtree; +} + +void +g_tree_destroy (GTree *tree) +{ + GRealTree *rtree; + + g_return_if_fail (tree != NULL); + + rtree = (GRealTree*) tree; + + g_tree_node_destroy (rtree->root); + g_free (rtree); +} + +void +g_tree_insert (GTree *tree, + gpointer key, + gpointer value) +{ + GRealTree *rtree; + gint inserted; + + g_return_if_fail (tree != NULL); + + rtree = (GRealTree*) tree; + + inserted = FALSE; + rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare, + key, value, &inserted); +} + +void +g_tree_remove (GTree *tree, + gpointer key) +{ + GRealTree *rtree; + + g_return_if_fail (tree != NULL); + + rtree = (GRealTree*) tree; + + rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key); +} + +gpointer +g_tree_lookup (GTree *tree, + gpointer key) +{ + GRealTree *rtree; + + g_return_val_if_fail (tree != NULL, NULL); + + rtree = (GRealTree*) tree; + + return g_tree_node_lookup (rtree->root, rtree->key_compare, key); +} + +void +g_tree_traverse (GTree *tree, + GTraverseFunc traverse_func, + GTraverseType traverse_type, + gpointer data) +{ + GRealTree *rtree; + + g_return_if_fail (tree != NULL); + + rtree = (GRealTree*) tree; + + g_return_if_fail (rtree->root != NULL); + + switch (traverse_type) + { + case G_PRE_ORDER: + g_tree_node_pre_order (rtree->root, traverse_func, data); + break; + + case G_IN_ORDER: + g_tree_node_in_order (rtree->root, traverse_func, data); + break; + + case G_POST_ORDER: + g_tree_node_post_order (rtree->root, traverse_func, data); + break; + } +} + +gpointer +g_tree_search (GTree *tree, + GSearchFunc search_func, + gpointer data) +{ + GRealTree *rtree; + + g_return_val_if_fail (tree != NULL, NULL); + + rtree = (GRealTree*) tree; + + if (rtree->root) + return g_tree_node_search (rtree->root, search_func, data); + return NULL; +} + +gint +g_tree_height (GTree *tree) +{ + GRealTree *rtree; + + g_return_val_if_fail (tree != NULL, 0); + + rtree = (GRealTree*) tree; + + if (rtree->root) + return g_tree_node_height (rtree->root); + return 0; +} + +gint +g_tree_nnodes (GTree *tree) +{ + GRealTree *rtree; + + g_return_val_if_fail (tree != NULL, 0); + + rtree = (GRealTree*) tree; + + if (rtree->root) + return g_tree_node_count (rtree->root); + return 0; +} + + +static GTreeNode* +g_tree_node_new (gpointer key, + gpointer value) +{ + GTreeNode *node; + GSList *tmp_list; + + if (node_free_list) + { + tmp_list = node_free_list; + node_free_list = node_free_list->next; + + node = tmp_list->data; + + { + GListAllocator *tmp_allocator = g_list_set_allocator (NULL); + g_slist_free_1 (tmp_list); + g_list_set_allocator (tmp_allocator); + } + } + else + { + if (!node_mem_chunk) + node_mem_chunk = g_mem_chunk_new ("tree node mem chunk", sizeof (GTreeNode), 1024, G_ALLOC_ONLY); + + node = g_chunk_new (GTreeNode, node_mem_chunk); + } + + node->balance = 0; + node->left = NULL; + node->right = NULL; + node->key = key; + node->value = value; + + return node; +} + +static void +g_tree_node_destroy (GTreeNode *node) +{ + if (node) + { + node_free_list = g_slist_prepend (node_free_list, node); + g_tree_node_destroy (node->right); + g_tree_node_destroy (node->left); + } +} + +static GTreeNode* +g_tree_node_insert (GTreeNode *node, + GCompareFunc compare, + gpointer key, + gpointer value, + gint *inserted) +{ + gint old_balance; + gint cmp; + + if (!node) + { + *inserted = TRUE; + return g_tree_node_new (key, value); + } + + cmp = (* compare) (key, node->key); + if (cmp == 0) + { + *inserted = FALSE; + node->value = value; + return node; + } + + if (cmp < 0) + { + if (node->left) + { + old_balance = node->left->balance; + node->left = g_tree_node_insert (node->left, compare, key, value, inserted); + + if ((old_balance != node->left->balance) && node->left->balance) + node->balance -= 1; + } + else + { + *inserted = TRUE; + node->left = g_tree_node_new (key, value); + node->balance -= 1; + } + } + else if (cmp > 0) + { + if (node->right) + { + old_balance = node->right->balance; + node->right = g_tree_node_insert (node->right, compare, key, value, inserted); + + if ((old_balance != node->right->balance) && node->right->balance) + node->balance += 1; + } + else + { + *inserted = TRUE; + node->right = g_tree_node_new (key, value); + node->balance += 1; + } + } + + if (*inserted) + { + if ((node->balance < -1) || (node->balance > 1)) + node = g_tree_node_balance (node); + } + + return node; +} + +static GTreeNode* +g_tree_node_remove (GTreeNode *node, + GCompareFunc compare, + gpointer key) +{ + GTreeNode *garbage; + GTreeNode *new_root; + gint old_balance; + gint cmp; + + if (!node) + return NULL; + + cmp = (* compare) (key, node->key); + if (cmp == 0) + { + garbage = node; + + if (!node->right) + { + node = node->left; + } + else + { + old_balance = node->right->balance; + node->right = g_tree_node_remove_leftmost (node->right, &new_root); + new_root->left = node->left; + new_root->right = node->right; + new_root->balance = node->balance; + node = g_tree_node_restore_right_balance (new_root, old_balance); + } + + node_free_list = g_slist_prepend (node_free_list, garbage); + } + else if (cmp < 0) + { + if (node->left) + { + old_balance = node->left->balance; + node->left = g_tree_node_remove (node->left, compare, key); + node = g_tree_node_restore_left_balance (node, old_balance); + } + } + else if (cmp > 0) + { + if (node->right) + { + old_balance = node->right->balance; + node->right = g_tree_node_remove (node->right, compare, key); + node = g_tree_node_restore_right_balance (node, old_balance); + } + } + + return node; +} + +static GTreeNode* +g_tree_node_balance (GTreeNode *node) +{ + if (node->balance < -1) + { + if (node->left->balance > 0) + node->left = g_tree_node_rotate_left (node->left); + node = g_tree_node_rotate_right (node); + } + else if (node->balance > 1) + { + if (node->right->balance < 0) + node->right = g_tree_node_rotate_right (node->right); + node = g_tree_node_rotate_left (node); + } + + return node; +} + +static GTreeNode* +g_tree_node_remove_leftmost (GTreeNode *node, + GTreeNode **leftmost) +{ + gint old_balance; + + if (!node->left) + { + *leftmost = node; + return node->right; + } + + old_balance = node->left->balance; + node->left = g_tree_node_remove_leftmost (node->left, leftmost); + return g_tree_node_restore_left_balance (node, old_balance); +} + +static GTreeNode* +g_tree_node_restore_left_balance (GTreeNode *node, + gint old_balance) +{ + if (!node->left) + node->balance += 1; + else if ((node->left->balance != old_balance) && + (node->left->balance == 0)) + node->balance += 1; + + if (node->balance > 1) + return g_tree_node_balance (node); + return node; +} + +static GTreeNode* +g_tree_node_restore_right_balance (GTreeNode *node, + gint old_balance) +{ + if (!node->right) + node->balance -= 1; + else if ((node->right->balance != old_balance) && + (node->right->balance == 0)) + node->balance -= 1; + + if (node->balance < -1) + return g_tree_node_balance (node); + return node; +} + +static gpointer +g_tree_node_lookup (GTreeNode *node, + GCompareFunc compare, + gpointer key) +{ + gint cmp; + + if (!node) + return NULL; + + cmp = (* compare) (key, node->key); + if (cmp == 0) + return node->value; + + if (cmp < 0) + { + if (node->left) + return g_tree_node_lookup (node->left, compare, key); + } + else if (cmp > 0) + { + if (node->right) + return g_tree_node_lookup (node->right, compare, key); + } + + return NULL; +} + +static gint +g_tree_node_count (GTreeNode *node) +{ + gint count; + + count = 1; + if (node->left) + count += g_tree_node_count (node->left); + if (node->right) + count += g_tree_node_count (node->right); + + return count; +} + +static gint +g_tree_node_pre_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data) +{ + if ((*traverse_func) (node->key, node->value, data)) + return TRUE; + if (node->left) + { + if (g_tree_node_pre_order (node->left, traverse_func, data)) + return TRUE; + } + if (node->right) + { + if (g_tree_node_pre_order (node->right, traverse_func, data)) + return TRUE; + } + + return FALSE; +} + +static gint +g_tree_node_in_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data) +{ + if (node->left) + { + if (g_tree_node_in_order (node->left, traverse_func, data)) + return TRUE; + } + if ((*traverse_func) (node->key, node->value, data)) + return TRUE; + if (node->right) + { + if (g_tree_node_in_order (node->right, traverse_func, data)) + return TRUE; + } + + return FALSE; +} + +static gint +g_tree_node_post_order (GTreeNode *node, + GTraverseFunc traverse_func, + gpointer data) +{ + if (node->left) + { + if (g_tree_node_post_order (node->left, traverse_func, data)) + return TRUE; + } + if (node->right) + { + if (g_tree_node_post_order (node->right, traverse_func, data)) + return TRUE; + } + if ((*traverse_func) (node->key, node->value, data)) + return TRUE; + + return FALSE; +} + +static gpointer +g_tree_node_search (GTreeNode *node, + GSearchFunc search_func, + gpointer data) +{ + gint dir; + + if (!node) + return NULL; + + do { + dir = (* search_func) (node->key, data); + if (dir == 0) + return node->value; + + if (dir < 0) + node = node->left; + else if (dir > 0) + node = node->right; + } while (node && (dir != 0)); + + return NULL; +} + +static gint +g_tree_node_height (GTreeNode *node) +{ + gint left_height; + gint right_height; + + if (node) + { + left_height = 0; + right_height = 0; + + if (node->left) + left_height = g_tree_node_height (node->left); + + if (node->right) + right_height = g_tree_node_height (node->right); + + return MAX (left_height, right_height) + 1; + } + + return 0; +} + +static GTreeNode* +g_tree_node_rotate_left (GTreeNode *node) +{ + GTreeNode *left; + GTreeNode *right; + gint a_bal; + gint b_bal; + + left = node->left; + right = node->right; + + node->right = right->left; + right->left = node; + + a_bal = node->balance; + b_bal = right->balance; + + if (b_bal <= 0) + { + if (a_bal >= 1) + right->balance = b_bal - 1; + else + right->balance = a_bal + b_bal - 2; + node->balance = a_bal - 1; + } + else + { + if (a_bal <= b_bal) + right->balance = a_bal - 2; + else + right->balance = b_bal - 1; + node->balance = a_bal - b_bal - 1; + } + + return right; +} + +static GTreeNode* +g_tree_node_rotate_right (GTreeNode *node) +{ + GTreeNode *left; + GTreeNode *right; + gint a_bal; + gint b_bal; + + left = node->left; + right = node->right; + + node->left = left->right; + left->right = node; + + a_bal = node->balance; + b_bal = left->balance; + + if (b_bal <= 0) + { + if (b_bal > a_bal) + left->balance = b_bal + 1; + else + left->balance = a_bal + 2; + node->balance = a_bal - b_bal + 1; + } + else + { + if (a_bal <= -1) + left->balance = b_bal + 1; + else + left->balance = a_bal + b_bal + 2; + node->balance = a_bal + 1; + } + + return left; +} + +static void +g_tree_node_check (GTreeNode *node) +{ + gint left_height; + gint right_height; + gint balance; + + if (node) + { + left_height = 0; + right_height = 0; + + if (node->left) + left_height = g_tree_node_height (node->left); + if (node->right) + right_height = g_tree_node_height (node->right); + + balance = right_height - left_height; + if (balance != node->balance) + g_print ("g_tree_node_check: failed: %d ( %d )\n", + balance, node->balance); + + if (node->left) + g_tree_node_check (node->left); + if (node->right) + g_tree_node_check (node->right); + } +} diff --git a/glib/gutils.c b/glib/gutils.c new file mode 100644 index 000000000..c15332817 --- /dev/null +++ b/glib/gutils.c @@ -0,0 +1,732 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "glib.h" + + +static GErrorFunc error_func = NULL; +static GWarningFunc warning_func = NULL; +static GPrintFunc message_func = NULL; +static GPrintFunc print_func = NULL; + +extern char* g_vsprintf (gchar *fmt, va_list *args, va_list *args2); + +gchar* +g_strdup (const gchar *str) +{ + gchar *new_str; + + new_str = NULL; + if (str) + { + new_str = g_new (char, strlen (str) + 1); + strcpy (new_str, str); + } + + return new_str; +} + +gchar* +g_strerror (gint errnum) +{ + static char msg[64]; + +#ifdef HAVE_STRERROR + return strerror (errnum); +#elif NO_SYS_ERRLIST + switch (errnum) + { +#ifdef E2BIG + case E2BIG: return "argument list too long"; +#endif +#ifdef EACCES + case EACCES: return "permission denied"; +#endif +#ifdef EADDRINUSE + case EADDRINUSE: return "address already in use"; +#endif +#ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return "can't assign requested address"; +#endif +#ifdef EADV + case EADV: return "advertise error"; +#endif +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return "address family not supported by protocol family"; +#endif +#ifdef EAGAIN + case EAGAIN: return "no more processes"; +#endif +#ifdef EALIGN + case EALIGN: return "EALIGN"; +#endif +#ifdef EALREADY + case EALREADY: return "operation already in progress"; +#endif +#ifdef EBADE + case EBADE: return "bad exchange descriptor"; +#endif +#ifdef EBADF + case EBADF: return "bad file number"; +#endif +#ifdef EBADFD + case EBADFD: return "file descriptor in bad state"; +#endif +#ifdef EBADMSG + case EBADMSG: return "not a data message"; +#endif +#ifdef EBADR + case EBADR: return "bad request descriptor"; +#endif +#ifdef EBADRPC + case EBADRPC: return "RPC structure is bad"; +#endif +#ifdef EBADRQC + case EBADRQC: return "bad request code"; +#endif +#ifdef EBADSLT + case EBADSLT: return "invalid slot"; +#endif +#ifdef EBFONT + case EBFONT: return "bad font file format"; +#endif +#ifdef EBUSY + case EBUSY: return "mount device busy"; +#endif +#ifdef ECHILD + case ECHILD: return "no children"; +#endif +#ifdef ECHRNG + case ECHRNG: return "channel number out of range"; +#endif +#ifdef ECOMM + case ECOMM: return "communication error on send"; +#endif +#ifdef ECONNABORTED + case ECONNABORTED: return "software caused connection abort"; +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: return "connection refused"; +#endif +#ifdef ECONNRESET + case ECONNRESET: return "connection reset by peer"; +#endif +#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK)) + case EDEADLK: return "resource deadlock avoided"; +#endif +#ifdef EDEADLOCK + case EDEADLOCK: return "resource deadlock avoided"; +#endif +#ifdef EDESTADDRREQ + case EDESTADDRREQ: return "destination address required"; +#endif +#ifdef EDIRTY + case EDIRTY: return "mounting a dirty fs w/o force"; +#endif +#ifdef EDOM + case EDOM: return "math argument out of range"; +#endif +#ifdef EDOTDOT + case EDOTDOT: return "cross mount point"; +#endif +#ifdef EDQUOT + case EDQUOT: return "disk quota exceeded"; +#endif +#ifdef EDUPPKG + case EDUPPKG: return "duplicate package name"; +#endif +#ifdef EEXIST + case EEXIST: return "file already exists"; +#endif +#ifdef EFAULT + case EFAULT: return "bad address in system call argument"; +#endif +#ifdef EFBIG + case EFBIG: return "file too large"; +#endif +#ifdef EHOSTDOWN + case EHOSTDOWN: return "host is down"; +#endif +#ifdef EHOSTUNREACH + case EHOSTUNREACH: return "host is unreachable"; +#endif +#ifdef EIDRM + case EIDRM: return "identifier removed"; +#endif +#ifdef EINIT + case EINIT: return "initialization error"; +#endif +#ifdef EINPROGRESS + case EINPROGRESS: return "operation now in progress"; +#endif +#ifdef EINTR + case EINTR: return "interrupted system call"; +#endif +#ifdef EINVAL + case EINVAL: return "invalid argument"; +#endif +#ifdef EIO + case EIO: return "I/O error"; +#endif +#ifdef EISCONN + case EISCONN: return "socket is already connected"; +#endif +#ifdef EISDIR + case EISDIR: return "illegal operation on a directory"; +#endif +#ifdef EISNAME + case EISNAM: return "is a name file"; +#endif +#ifdef ELBIN + case ELBIN: return "ELBIN"; +#endif +#ifdef EL2HLT + case EL2HLT: return "level 2 halted"; +#endif +#ifdef EL2NSYNC + case EL2NSYNC: return "level 2 not synchronized"; +#endif +#ifdef EL3HLT + case EL3HLT: return "level 3 halted"; +#endif +#ifdef EL3RST + case EL3RST: return "level 3 reset"; +#endif +#ifdef ELIBACC + case ELIBACC: return "can not access a needed shared library"; +#endif +#ifdef ELIBBAD + case ELIBBAD: return "accessing a corrupted shared library"; +#endif +#ifdef ELIBEXEC + case ELIBEXEC: return "can not exec a shared library directly"; +#endif +#ifdef ELIBMAX + case ELIBMAX: return "attempting to link in more shared libraries than system limit"; +#endif +#ifdef ELIBSCN + case ELIBSCN: return ".lib section in a.out corrupted"; +#endif +#ifdef ELNRNG + case ELNRNG: return "link number out of range"; +#endif +#ifdef ELOOP + case ELOOP: return "too many levels of symbolic links"; +#endif +#ifdef EMFILE + case EMFILE: return "too many open files"; +#endif +#ifdef EMLINK + case EMLINK: return "too many links"; +#endif +#ifdef EMSGSIZE + case EMSGSIZE: return "message too long"; +#endif +#ifdef EMULTIHOP + case EMULTIHOP: return "multihop attempted"; +#endif +#ifdef ENAMETOOLONG + case ENAMETOOLONG: return "file name too long"; +#endif +#ifdef ENAVAIL + case ENAVAIL: return "not available"; +#endif +#ifdef ENET + case ENET: return "ENET"; +#endif +#ifdef ENETDOWN + case ENETDOWN: return "network is down"; +#endif +#ifdef ENETRESET + case ENETRESET: return "network dropped connection on reset"; +#endif +#ifdef ENETUNREACH + case ENETUNREACH: return "network is unreachable"; +#endif +#ifdef ENFILE + case ENFILE: return "file table overflow"; +#endif +#ifdef ENOANO + case ENOANO: return "anode table overflow"; +#endif +#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR)) + case ENOBUFS: return "no buffer space available"; +#endif +#ifdef ENOCSI + case ENOCSI: return "no CSI structure available"; +#endif +#ifdef ENODATA + case ENODATA: return "no data available"; +#endif +#ifdef ENODEV + case ENODEV: return "no such device"; +#endif +#ifdef ENOENT + case ENOENT: return "no such file or directory"; +#endif +#ifdef ENOEXEC + case ENOEXEC: return "exec format error"; +#endif +#ifdef ENOLCK + case ENOLCK: return "no locks available"; +#endif +#ifdef ENOLINK + case ENOLINK: return "link has be severed"; +#endif +#ifdef ENOMEM + case ENOMEM: return "not enough memory"; +#endif +#ifdef ENOMSG + case ENOMSG: return "no message of desired type"; +#endif +#ifdef ENONET + case ENONET: return "machine is not on the network"; +#endif +#ifdef ENOPKG + case ENOPKG: return "package not installed"; +#endif +#ifdef ENOPROTOOPT + case ENOPROTOOPT: return "bad proocol option"; +#endif +#ifdef ENOSPC + case ENOSPC: return "no space left on device"; +#endif +#ifdef ENOSR + case ENOSR: return "out of stream resources"; +#endif +#ifdef ENOSTR + case ENOSTR: return "not a stream device"; +#endif +#ifdef ENOSYM + case ENOSYM: return "unresolved symbol name"; +#endif +#ifdef ENOSYS + case ENOSYS: return "function not implemented"; +#endif +#ifdef ENOTBLK + case ENOTBLK: return "block device required"; +#endif +#ifdef ENOTCONN + case ENOTCONN: return "socket is not connected"; +#endif +#ifdef ENOTDIR + case ENOTDIR: return "not a directory"; +#endif +#ifdef ENOTEMPTY + case ENOTEMPTY: return "directory not empty"; +#endif +#ifdef ENOTNAM + case ENOTNAM: return "not a name file"; +#endif +#ifdef ENOTSOCK + case ENOTSOCK: return "socket operation on non-socket"; +#endif +#ifdef ENOTTY + case ENOTTY: return "inappropriate device for ioctl"; +#endif +#ifdef ENOTUNIQ + case ENOTUNIQ: return "name not unique on network"; +#endif +#ifdef ENXIO + case ENXIO: return "no such device or address"; +#endif +#ifdef EOPNOTSUPP + case EOPNOTSUPP: return "operation not supported on socket"; +#endif +#ifdef EPERM + case EPERM: return "not owner"; +#endif +#ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return "protocol family not supported"; +#endif +#ifdef EPIPE + case EPIPE: return "broken pipe"; +#endif +#ifdef EPROCLIM + case EPROCLIM: return "too many processes"; +#endif +#ifdef EPROCUNAVAIL + case EPROCUNAVAIL: return "bad procedure for program"; +#endif +#ifdef EPROGMISMATCH + case EPROGMISMATCH: return "program version wrong"; +#endif +#ifdef EPROGUNAVAIL + case EPROGUNAVAIL: return "RPC program not available"; +#endif +#ifdef EPROTO + case EPROTO: return "protocol error"; +#endif +#ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return "protocol not suppored"; +#endif +#ifdef EPROTOTYPE + case EPROTOTYPE: return "protocol wrong type for socket"; +#endif +#ifdef ERANGE + case ERANGE: return "math result unrepresentable"; +#endif +#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED)) + case EREFUSED: return "EREFUSED"; +#endif +#ifdef EREMCHG + case EREMCHG: return "remote address changed"; +#endif +#ifdef EREMDEV + case EREMDEV: return "remote device"; +#endif +#ifdef EREMOTE + case EREMOTE: return "pathname hit remote file system"; +#endif +#ifdef EREMOTEIO + case EREMOTEIO: return "remote i/o error"; +#endif +#ifdef EREMOTERELEASE + case EREMOTERELEASE: return "EREMOTERELEASE"; +#endif +#ifdef EROFS + case EROFS: return "read-only file system"; +#endif +#ifdef ERPCMISMATCH + case ERPCMISMATCH: return "RPC version is wrong"; +#endif +#ifdef ERREMOTE + case ERREMOTE: return "object is remote"; +#endif +#ifdef ESHUTDOWN + case ESHUTDOWN: return "can't send afer socket shutdown"; +#endif +#ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return "socket type not supported"; +#endif +#ifdef ESPIPE + case ESPIPE: return "invalid seek"; +#endif +#ifdef ESRCH + case ESRCH: return "no such process"; +#endif +#ifdef ESRMNT + case ESRMNT: return "srmount error"; +#endif +#ifdef ESTALE + case ESTALE: return "stale remote file handle"; +#endif +#ifdef ESUCCESS + case ESUCCESS: return "Error 0"; +#endif +#ifdef ETIME + case ETIME: return "timer expired"; +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: return "connection timed out"; +#endif +#ifdef ETOOMANYREFS + case ETOOMANYREFS: return "too many references: can't splice"; +#endif +#ifdef ETXTBSY + case ETXTBSY: return "text file or pseudo-device busy"; +#endif +#ifdef EUCLEAN + case EUCLEAN: return "structure needs cleaning"; +#endif +#ifdef EUNATCH + case EUNATCH: return "protocol driver not attached"; +#endif +#ifdef EUSERS + case EUSERS: return "too many users"; +#endif +#ifdef EVERSION + case EVERSION: return "version mismatch"; +#endif +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: return "operation would block"; +#endif +#ifdef EXDEV + case EXDEV: return "cross-domain link"; +#endif +#ifdef EXFULL + case EXFULL: return "message tables full"; +#endif + } +#else /* NO_SYS_ERRLIST */ + extern int sys_nerr; + extern char *sys_errlist[]; + + if ((errnum > 0) && (errnum <= sys_nerr)) + return sys_errlist [errnum]; +#endif /* NO_SYS_ERRLIST */ + + sprintf (msg, "unknown error (%d)", errnum); + return msg; +} + +gchar* +g_strsignal (gint signum) +{ + static char msg[64]; + +#ifdef HAVE_STRSIGNAL + extern char *strsignal (int sig); + return strsignal (signum); +#elif NO_SYS_SIGLIST + switch (signum) + { +#ifdef SIGHUP + case SIGHUP: return "Hangup"; +#endif +#ifdef SIGINT + case SIGINT: return "Interrupt"; +#endif +#ifdef SIGQUIT + case SIGQUIT: return "Quit"; +#endif +#ifdef SIGILL + case SIGILL: "Illegal instruction"; +#endif +#ifdef SIGTRAP + case SIGTRAP: "Trace/breakpoint trap"; +#endif +#ifdef SIGABRT + case SIGABRT: "IOT trap/Abort"; +#endif +#ifdef SIGBUS + case SIGBUS: "Bus error"; +#endif +#ifdef SIGFPE + case SIGFPE: "Floating point exception"; +#endif +#ifdef SIGKILL + case SIGKILL: "Killed"; +#endif +#ifdef SIGUSR1 + case SIGUSR1: "User defined signal 1"; +#endif +#ifdef SIGSEGV + case SIGSEGV: "Segmentation fault"; +#endif +#ifdef SIGUSR2 + case SIGUSR2: "User defined signal 2"; +#endif +#ifdef SIGPIPE + case SIGPIPE: "Broken pipe"; +#endif +#ifdef SIGALRM + case SIGALRM: "Alarm clock"; +#endif +#ifdef SIGTERM + case SIGTERM: "Terminated"; +#endif +#ifdef SIGSTKFLT + case SIGSTKFLT: "Stack fault"; +#endif +#ifdef SIGCHLD + case SIGCHLD: "Child exited"; +#endif +#ifdef SIGCONT + case SIGCONT: "Continued"; +#endif +#ifdef SIGSTOP + case SIGSTOP: "Stopped (signal)"; +#endif +#ifdef SIGTSTP + case SIGTSTP: "Stopped"; +#endif +#ifdef SIGTTIN + case SIGTTIN: "Stopped (tty input)"; +#endif +#ifdef SIGTTOU + case SIGTTOU: "Stopped (tty output)"; +#endif +#ifdef SIGURG + case SIGURG: "Urgent condition"; +#endif +#ifdef SIGXCPU + case SIGXCPU: "CPU time limit exceeded"; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: "File size limit exceeded"; +#endif +#ifdef SIGVTALRM + case SIGVTALRM: "Virtual time alarm"; +#endif +#ifdef SIGPROF + case SIGPROF: "Profile signal"; +#endif +#ifdef SIGWINCH + case SIGWINCH: "Window size changed"; +#endif +#ifdef SIGIO + case SIGIO: "Possible I/O"; +#endif +#ifdef SIGPWR + case SIGPWR: "Power failure"; +#endif +#ifdef SIGUNUSED + case SIGUNUSED: return "Unused signal"; +#endif + } +#else /* NO_SYS_SIGLIST */ + extern char *sys_siglist[]; + return sys_siglist [signum]; +#endif /* NO_SYS_SIGLIST */ + + sprintf (msg, "unknown signal (%d)", signum); + return msg; +} + +void +g_error (gchar *format, ...) +{ + va_list args, args2; + char *buf; + + va_start (args, format); + va_start (args2, format); + buf = g_vsprintf (format, &args, &args2); + va_end (args); + va_end (args2); + + if (error_func) + { + (* error_func) (buf); + } + else + { + fputs ("\n** ERROR **: ", stderr); + fputs (buf, stderr); + fputc ('\n', stderr); + } + + abort (); +} + +void +g_warning (gchar *format, ...) +{ + va_list args, args2; + char *buf; + + va_start (args, format); + va_start (args2, format); + buf = g_vsprintf (format, &args, &args2); + va_end (args); + va_end (args2); + + if (warning_func) + { + (* warning_func) (buf); + } + else + { + fputs ("\n** WARNING **: ", stderr); + fputs (buf, stderr); + fputc ('\n', stderr); + } +} + +void +g_message (gchar *format, ...) +{ + va_list args, args2; + char *buf; + + va_start (args, format); + va_start (args2, format); + buf = g_vsprintf (format, &args, &args2); + va_end (args); + va_end (args2); + + if (message_func) + { + (* message_func) (buf); + } + else + { + fputs ("message: ", stdout); + fputs (buf, stdout); + fputc ('\n', stdout); + } +} + +void +g_print (gchar *format, ...) +{ + va_list args, args2; + char *buf; + + va_start (args, format); + va_start (args2, format); + buf = g_vsprintf (format, &args, &args2); + va_end (args); + va_end (args2); + + if (print_func) + { + (* print_func) (buf); + } + else + { + fputs (buf, stdout); + } +} + +GErrorFunc +g_set_error_handler (GErrorFunc func) +{ + GErrorFunc old_error_func; + + old_error_func = error_func; + error_func = func; + + return old_error_func; +} + +GWarningFunc +g_set_warning_handler (GWarningFunc func) +{ + GWarningFunc old_warning_func; + + old_warning_func = warning_func; + warning_func = func; + + return old_warning_func; +} + +GPrintFunc +g_set_message_handler (GPrintFunc func) +{ + GPrintFunc old_message_func; + + old_message_func = message_func; + message_func = func; + + return old_message_func; +} + +GPrintFunc +g_set_print_handler (GPrintFunc func) +{ + GPrintFunc old_print_func; + + old_print_func = print_func; + print_func = func; + + return old_print_func; +} diff --git a/glib/install-sh b/glib/install-sh new file mode 100755 index 000000000..89fc9b098 --- /dev/null +++ b/glib/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/glib/ltconfig b/glib/ltconfig new file mode 100755 index 000000000..e9d3a8379 --- /dev/null +++ b/glib/ltconfig @@ -0,0 +1,1415 @@ +#! /bin/sh + +# ltconfig - Create a system-specific libtool. +# Generated automatically from ltconfig.in by configure. +# Copyright (C) 1996, 1997, Free Software Foundation, Inc. +# Gordon Matzigkeit , 1996 +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A lot of this script is taken from autoconf-2.10. + +# The name of this program. +progname=`echo "$0" | sed 's%^.*/%%'` + +# Constants: +PROGRAM=ltconfig +PACKAGE=libtool +VERSION=1.0f +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5' +rm="rm -f" + +help="Try \`$progname --help' for more information." + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([\\"$\\\\]\)/\\\1/g' + +# Same as above, but don't quote variable references. +double_quote_subst='s/\([\\"\\\\]\)/\\\1/g' + +# Global variables: +can_build_shared=yes +enable_shared=yes +# All known linkers require a `.a' archive for static linking. +enable_static=yes +ltmain= +silent= +srcdir= +ac_config_guess= +ac_config_sub= +host= +nonopt= +verify_host=yes +with_gcc=no +with_gnu_ld=no + +old_AR="$AR" +old_CC="$CC" +old_CFLAGS="$CFLAGS" +old_CPPFLAGS="$CPPFLAGS" +old_LD="$LD" +old_LN_S="$LN_S" +old_NM="$NM" +old_RANLIB="$RANLIB" + +# Parse the command line options. +args= +prev= +for option +do + case "$option" in + -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval "$prev=\$option" + prev= + continue + fi + + case "$option" in + --help) cat <&2 + echo "$help" 1>&2 + exit 1 + ;; + + *) + if test -z "$ltmain"; then + ltmain="$option" + elif test -z "$host"; then +# FIXME This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 +# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then +# echo "$progname: warning \`$option' is not a valid host type" 1>&2 +# fi + host="$option" + else + echo "$progname: too many arguments" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac +done + +if test -z "$ltmain"; then + echo "$progname: you must specify a LTMAIN file" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +if test -f "$ltmain"; then : +else + echo "$progname: warning: \`$ltmain' does not exist" 1>&2 +fi + +# Quote any args containing shell metacharacters. +ltconfig_args= +for arg +do + case "$arg" in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ltconfig_args="$ltconfig_args '$arg'" ;; + *) ltconfig_args="$ltconfig_args $arg" ;; + esac +done + +# A relevant subset of AC_INIT. + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 5 compiler messages saved in config.log +# 6 checking for... messages and results +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>>./config.log + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + +if test -z "$srcdir"; then + # Assume the source directory is the same one as the path to ltmain.sh. + srcdir=`echo "$ltmain" | sed 's%/[^/]*$%%'` + test "$srcdir" = "$ltmain" && srcdir=. +fi + +trap "$rm conftest*; exit 1" 1 2 15 +if test "$verify_host" = yes; then + # Check for config.guess and config.sub. + ac_aux_dir= + for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/config.guess; then + ac_aux_dir=$ac_dir + break + fi + done + if test -z "$ac_aux_dir"; then + echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 + echo "$help" 1>&2 + exit 1 + fi + ac_config_guess=$ac_aux_dir/config.guess + ac_config_sub=$ac_aux_dir/config.sub + + # Make sure we can run config.sub. + if $ac_config_sub sun4 >/dev/null 2>&1; then : + else + echo "$progname: cannot run $ac_config_sub" 1>&2 + echo "$help" 1>&2 + exit 1 + fi + + echo $ac_n "checking host system type""... $ac_c" 1>&6 + + host_alias=$host + case "$host_alias" in + "") + if host_alias=`$ac_config_guess`; then : + else + echo "$progname: cannot guess host type; you must specify one" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac + host=`$ac_config_sub $host_alias` + echo "$ac_t$host" 1>&6 + + # Make sure the host verified. + test -z "$host" && exit 1 + +elif test -z "$host"; then + echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 + echo "$help" 1>&2 + exit 1 +else + host_alias=$host +fi + +# Transform *-*-linux* to *-*-linux-gnu*, to support old configure scripts. +case "$host" in +*-*-linux-gnu*) ;; +*-*-linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +case "$host_os" in +aix*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "${COLLECT_NAMES+set}" != set; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR cru $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' + +# Set a sane default for `AR'. +test -z "$AR" && AR=ar + +# If RANLIB is not set, then run the test. +if test "${RANLIB+set}" != "set"; then + result=no + + echo $ac_n "checking for ranlib... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/ranlib; then + RANLIB="ranlib" + result="ranlib" + break + fi + done + IFS="$save_ifs" + + echo "$ac_t$result" 1>&6 +fi + +if test -n "$RANLIB"; then + old_archive_cmds="$old_archive_cmds;\$RANLIB \$oldlib" + old_postinstall_cmds="$old_postinstall_cmds;\$RANLIB \$oldlib" +fi + +# Check to see if we are using GCC. +if test "$with_gcc" != yes || test -z "$CC"; then + # If CC is not set, then try to find GCC or a usable CC. + if test -z "$CC"; then + echo $ac_n "checking for gcc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + IFS="$save_ifs" + test -z "$dir" && dir=. + if test -f $dir/gcc; then + CC="gcc" + break + fi + done + IFS="$save_ifs" + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + fi + + # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". + if test -z "$CC"; then + echo $ac_n "checking for cc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + cc_rejected=no + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/cc; then + if test "$dir/cc" = "/usr/ucb/cc"; then + cc_rejected=yes + continue + fi + CC="cc" + break + fi + done + IFS="$save_ifs" + if test $cc_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same name, so the bogon will be chosen + # first if we set CC to just the name; use the full file name. + shift + set dummy "$dir/cc" "$@" + shift + CC="$@" + fi + fi + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$CC"; then + echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 + exit 1 + fi + fi + + # Now see if the compiler is really GCC. + with_gcc=no + echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 + echo "$progname:394: checking whether we are using GNU C" >&5 + + $rm conftest.c + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + with_gcc=yes + fi + $rm conftest.c + echo "$ac_t$with_gcc" 1>&6 +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 +pic_flag= +profile_flag_pattern= +special_shlib_compile_flags= +wl= +link_static_flag= +no_builtin_flag= + +if test "$with_gcc" = yes; then + profile_flag_pattern='-pg?' + wl='-Wl,' + link_static_flag='-static' + no_builtin_flag=' -fno-builtin' + + case "$host_os" in + aix3* | aix4* | irix5* | irix6* | osf3* | osf4*) + # PIC is the default for these OSes. + ;; + os2*) + # We can build DLLs from non-PIC. + ;; + *) + pic_flag='-fPIC' + ;; + esac +else + # PORTME Check for PIC flags for the system compiler. + case "$host_os" in + aix3* | aix4*) + # All AIX code is PIC. + link_static_flag='-bnso -bI:/lib/syscalls.exp' + ;; + + hpux9* | hpux10*) + # Is there a better link_static_flag that works with the bundled CC? + wl='-Wl,' + link_static_flag='${wl}-a ${wl}archive' + pic_flag='+Z' + ;; + + irix5* | irix6*) + wl='-Wl,' + link_static_flag='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + os2*) + # We can build DLLs from non-PIC. + ;; + + osf3* | osf4*) + # All OSF/1 code is PIC. + wl='-Wl,' + link_static_flag='-non_shared' + ;; + + sco3.2v5*) + pic_flag='-Kpic' + link_static_flag='-dn' + special_shlib_compile_flags='-belf' + ;; + + solaris2*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + sunos4*) + pic_flag='-PIC' + link_static_flag='-Bstatic' + wl='-Qoption ld ' + ;; + + uts4*) + pic_flag='-pic' + link_static_flag='-Bstatic' + ;; + + *) + can_build_shared=no + ;; + esac +fi + +if test -n "$pic_flag"; then + echo "$ac_t$pic_flag" 1>&6 + + # Check to make sure the pic_flag actually works. + echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 + $rm conftest* + echo > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $pic_flag -DPIC" + echo "$progname:507: checking if $compiler PIC flag $pic_flag works" >&5 + if { (eval echo $progname:508: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + + # On HP-UX, the stripped-down bundled CC doesn't accept +Z, but also + # reports no error. So, we need to grep stderr for (Bundled). + if grep '(Bundled)' conftest.err >/dev/null; then + echo "$ac_t"no 1>&6 + can_build_shared=no + pic_flag= + else + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + can_build_shared=no + pic_flag= + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + echo "$ac_t"none 1>&6 +fi + +# Check for any special shared library compilation flags. +if test -n "$special_shlib_compile_flags"; then + echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : + else + echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 + can_build_shared=no + fi +fi + +echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 +$rm conftest* +echo 'main(){return(0);}' > conftest.c +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $link_static_flag" +echo "$progname:550: checking if $compiler static flag $link_static_flag works" >&5 +if { (eval echo $progname:551: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + echo "$ac_t$link_static_flag" 1>&6 +else + echo "$ac_t"none 1>&6 + link_static_flag= +fi +LDFLAGS="$save_LDFLAGS" +$rm conftest* + +if test -z "$LN_S"; then + # Check to see if we can use ln -s, or we need hard links. + echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 + $rm conftestdata + if ln -s X conftestdata 2>/dev/null; then + $rm conftestdata + LN_S="ln -s" + else + LN_S=ln + fi + if test "$LN_S" = "ln -s"; then + echo "$ac_t"yes 1>&6 + else + echo "$ac_t"no 1>&6 + fi +fi + +# Make sure LD is an absolute path. +if test -z "$LD"; then + ac_prog=ld + if test "$with_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 + echo "$progname:583: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + /*) + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac + elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld... $ac_c" 1>&6 + echo "$progname:601: checking for GNU ld" >&5 + else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 + echo "$progname:604: checking for non-GNU ld" >&5 + fi + + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog"; then + LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" + fi + + if test -n "$LD"; then + echo "$ac_t$LD" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$LD"; then + echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 + exit 1 + fi +fi + +# Check to see if it really is or isn't GNU ld. +echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 +# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + with_gnu_ld=yes +else + with_gnu_ld=no +fi +echo "$ac_t$with_gnu_ld" 1>&6 + +# See if the linker supports building shared libraries. +echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 + +allow_undefined_flag= +archive_cmds= +old_archive_from_new_cmds= +export_dynamic_flag_spec= +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_runpath_var=no +hardcode_shlibpath_var=unsupported +runpath_var= + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # See if GNU ld supports shared libraries. + + case "$host_os" in + sunos4*) + ld_shlibs=yes + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + archive_cmds='$CC -shared ${wl}-soname $wl$soname -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath $wl$libdir' + export_dynamic_flag_spec='${wl}-export-dynamic' + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case "$host_os" in + aix3*) + allow_undefined_flag=unsupported + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '"'s/.* //'"' > $lib.exp;$LD -o $objdir/$soname$libobjs -bE:$lib.exp -T512 -H512 -bM:SRE$deplibs;$AR cru $lib $objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$with_gcc" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4*) + allow_undefined_flag=unsupported + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '"'s/.* //'"' > $lib.exp;$CC -o $objdir/$soname$libobjs ${wl}-bE:$lib.exp ${wl}-bM:SRE ${wl}-bnoentry$deplibs;$AR cru $lib $objdir/$soname' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # doesn't break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib$libobjs$deplibs /usr/lib/c++rt0.o' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 don't have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib$libobjs$deplibs' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3, at last, uses gcc -shared to do shared libraries. + freebsd3*) + archive_cmds='$CC -shared -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + archive_cmds='$rm $objdir/$soname;$LD -b +s +b $install_libdir -o $objdir/$soname$libobjs$deplibs;mv $objdir/$soname $lib' + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + hpux10*) + archive_cmds='$LD -b +h $soname +s +b $install_libdir -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + + irix5* | irix6*) + archive_cmds='$LD -shared -o $lib -soname $soname -set_version $verstring$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + ;; + + netbsd*) + # Tested with NetBSD 1.2 ld + archive_cmds='$LD -Bshareable -o $lib$libobjs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + openbsd*) + archive_cmds='$LD -Bshareable -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def;echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def;echo DATA >> $objdir/$libname.def;echo " SINGLE NONSHARED" >> $objdir/$libname.def;echo EXPORTS >> $objdir/$libname.def;emxexp$libobjs >> $objdir/$libname.def;$CC -Zdll -Zcrtdll -o $lib$libobjs $objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' + ;; + + osf3* | osf4*) + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} -o $lib -soname $soname -set_version $verstring$libobjs$deplibs' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + sco3.2v5*) + archive_cmds='$LD -G -o $lib$libobjs$deplibs' + hardcode_direct=yes + ;; + + solaris2*) + archive_cmds='$LD -G -z text -h $soname -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bstatic -o $lib$libobjs' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib$libobjs$deplibs' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=no + hardcode_minus_L=no + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + can_build_shared=no + ;; + esac +fi +echo "$ac_t$ld_shlibs" 1>&6 + +if test -z "$NM"; then + echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 + case "$NM" in + /*) ;; # Let the user override the test with a path. + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in /usr/ucb $PATH /bin; do + test -z "$ac_dir" && dir=. + if test -f $ac_dir/nm; then + # Check to see if the nm accepts a BSD-compat flag. + if ($ac_dir/nm -B /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + NM="$ac_dir/nm -B" + elif ($ac_dir/nm -p /dev/null 2>&1; exit 0) | grep /dev/null >/dev/null; then + NM="$ac_dir/nm -p" + else + NM="$ac_dir/nm" + fi + break + fi + done + IFS="$ac_save_ifs" + test -z "$NM" && NM=nm + ;; + esac + echo "$ac_t$NM" 1>&6 +fi + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRSTU]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \1' + +# Define system-specific variables. +case "$host_os" in +aix*) + symcode='[BCDTU]' + ;; +solaris2*) + symcode='[BDTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[ABCDGISTUW]' +fi + +# Write the raw and C identifiers. +global_symbol_pipe="sed -n -e 's/^.* $symcode $sympat$/$symxfrm/p'" + +# Check to see that the pipe works correctly. +pipe_works=no +$rm conftest* +cat > conftest.c <&5 +if { (eval echo $progname:901: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.o; then + # Now try to grab the symbols. + nlist=conftest.nm + if { echo "$progname:904: eval \"$NM conftest.o | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.o | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + wcout=`wc "$nlist" 2>/dev/null` + count=`echo "$wcout" | sed 's/^[ ]*\([0-9][0-9]*\).*$/\1/'` + (test "$count" -ge 0) 2>/dev/null || count=-1 + else + rm -f "$nlist"T + count=-1 + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.c +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + sed 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> conftest.c + + cat <> conftest.c +#if defined (__STDC__) && __STDC__ +# define __ptr_t void * +#else +# define __ptr_t char * +#endif + +/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */ +int dld_preloaded_symbol_count = $count; + +/* The mapping between symbol names and symbols. */ +struct { + char *name; + __ptr_t address; +} +dld_preloaded_symbols[] = +{ +EOF + sed 's/^\(.*\) \(.*\)$/ {"\1", \&\2},/' < "$nlist" >> conftest.c + cat <<\EOF >> conftest.c + {0}, +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.o conftestm.o + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS='conftestm.o' + CFLAGS="$CFLAGS$no_builtin_flag" + if { (eval echo $progname:962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + pipe_works=yes + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + LIBS="$save_LIBS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $global_symbol_pipe" >&5 + fi +else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 +fi +$rm conftest* + +# Don't use the global_symbol_pipe unless it works. +echo "$ac_t$pipe_works" 1>&6 +test "$pipe_works" = yes || global_symbol_pipe= + +# Check hardcoding attributes. +echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test "$hardcode_runpath_var" = yes; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && \ + test "$hardcode_minus_L" != no && \ + test "$hardcode_shlibpath_var" != no; then + + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +elif test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" != yes; then + # We can't hardcode anything. + hardcode_action=unsupported +else + # We can only hardcode existing directories. + hardcode_action=relink +fi +echo "$ac_t$hardcode_action" 1>&6 +test "$hardcode_action" = unsupported && can_build_shared=no + + +reload_flag= +reload_cmds='$LD$reload_flag -o $output$reload_objs' +echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 +# PORTME Some linker may need a different reload flag. +reload_flag='-r' +echo "$ac_t$reload_flag" +test -n "$reload_flag" && reload_flag=" $reload_flag" + +# PORTME Fill in your ld.so characteristics +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +finish_cmds= +shlibpath_var= +version_type=none +dynamic_linker="$host_os ld.so" + +echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 +case "$host_os" in +aix3* | aix4*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='$libname.so.$major' + ;; + +freebsd2* | freebsd3*) + version_type=sunos + library_names_spec='$libname.so.$versuffix $libname.so' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +gnu*) + version_type=sunos + library_names_spec='$libname.so.$versuffix' + shlibpath_var=LD_LIBRARY_PATH + ;; + +hpux9* | hpux10*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + shlibpath_var=SHLIB_PATH + library_names_spec='$libname.sl.$versuffix $libname.sl.$major $libname.sl' + soname_spec='$libname.sl.$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +irix5* | irix6*) + version_type=osf + soname_spec='$libname.so' + library_names_spec='$libname.so.$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + + if test -f /lib/ld.so.1; then + dynamic_linker='GNU ld.so' + else + # Only the GNU ld.so supports shared libraries on MkLinux. + case "$host_cpu" in + powerpc*) dynamic_linker=no ;; + *) dynamic_linker='Linux ld.so' ;; + esac + fi + ;; + +netbsd* | openbsd*) + version_type=sunos + library_names_spec='$libname.so.$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + version_type=none + libname_spec='$name' + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4*) + version_type=osf + soname_spec='$libname.so' + library_names_spec='$libname.so.$versuffix $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sco3.2v5*) + version_type=osf + soname_spec='$libname.so.$major' + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris2*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname.so.$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +uts4*) + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$ac_t$dynamic_linker" +test "$dynamic_linker" = no && can_build_shared=no + +# FIXME add checks for striplib and old_striplib here. +# strip -x works for most platforms, though not for static libraries on NetBSD +# HP-UX requires "-r" for library stripping +striplib= +old_striplib= + +# Report the final consequences. +echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 + +echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds;\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +esac + +echo "$ac_t$enable_shared" 1>&6 + +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes + +echo "checking whether to build static libraries... $enable_static" 1>&6 + +echo $ac_n "checking for objdir... $ac_c" 1>&6 +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +echo "$ac_t$objdir" 1>&6 + +# Now quote all the things that may contain metacharacters. +for var in old_CC old_CFLAGS old_CPPFLAGS old_LD old_NM old_RANLIB \ + old_LN_S AR CC LD LN_S NM reload_flag reload_cmds wl pic_flag \ + link_static_flag no_builtin_flag export_dynamic_flag_spec \ + profile_flag_pattern libname_spec library_names_spec soname_spec RANLIB \ + old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + archive_cmds postinstall_cmds \ + allow_undefined_flag finish_cmds global_symbol_pipe \ + striplib old_striplib \ + hardcode_libdir_flag_spec hardcode_libdir_separator; do + + case "$var" in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | archive_cmds | postinstall_cmds | finish_cmds) + # Double-quote double-evaled strings. + eval "$var=\`echo \"\$$var\" | sed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\"\`" + ;; + *) + eval "$var=\`echo \"\$$var\" | sed \"\$sed_quote_subst\"\`" + ;; + esac +done + +ofile=libtool +trap "$rm $ofile; exit 1" 1 2 15 +echo creating $ofile +$rm $ofile +cat < $ofile +#! /bin/sh + +# libtool - Provide generalized library-building support services. +# +# Generated automatically by $PROGRAM - GNU $PACKAGE $VERSION +# This program was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# CC="$old_CC" CFLAGS="$old_CFLAGS" CPPFLAGS="$old_CPPFLAGS" \\ +# LD="$old_LD" NM="$old_NM" RANLIB="$old_RANLIB" LN_S="$old_LN_S" \\ +# $0$ltconfig_args +# +# Compiler and other test output produced by $progname, useful for +# debugging $progname, is in ./config.log if it exists. + +# The version of $progname that generated this script. +LTCONFIG_VERSION="$VERSION" + +# Shell to use when invoking shell scripts. +SHELL=${CONFIG_SHELL-/bin/sh} + +# Whether or not to build libtool libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build old-style libraries. +build_old_libs=$enable_static + +# The host system. +host_alias="$host_alias" +host="$host" + +# The archiver. +AR="$AR" + +# The default C compiler. +CC="$CC" + +# The linker used to build libraries. +LD="$LD" + +# Whether we need hard or soft links. +LN_S="$LN_S" + +# A BSD-compatible nm program. +NM="$NM" + +# The name of the directory that contains temporary libtool files. +objdir="$objdir" + +# How to create reloadable object files. +reload_flag="$reload_flag" +reload_cmds="$reload_cmds" + +# How to pass a linker flag through the compiler. +wl="$wl" + +# Additional compiler flags for building library objects. +pic_flag="$pic_flag" + +# Compiler flag to prevent dynamic linking. +link_static_flag="$link_static_flag" + +# Compiler flag to turn off builtin functions. +no_builtin_flag="$no_builtin_flag" + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec="$export_dynamic_flag_spec" + +# Pattern to match compiler flags for creating libNAME_p libraries: +profile_flag_pattern="$profile_flag_pattern" + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec="$libname_spec" + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec="$library_names_spec" + +# The coded name of the library, if different from the real name. +soname_spec="$soname_spec" + +# Commands used to build and install an old-style archive. +RANLIB="$RANLIB" +old_archive_cmds="$old_archive_cmds" +old_postinstall_cmds="$old_postinstall_cmds" + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds="$old_archive_from_new_cmds" + +# Commands used to build and install a shared archive. +archive_cmds="$archive_cmds" +postinstall_cmds="$postinstall_cmds" + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag="$allow_undefined_flag" + +# Commands used to finish a libtool library installation in a directory. +finish_cmds="$finish_cmds" + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe="$global_symbol_pipe" + +# How to strip a library file. +striplib="$striplib" +old_striplib="$old_striplib" + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec="$hardcode_libdir_flag_spec" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="$hardcode_libdir_separator" + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using RUNPATH_VAR=DIR during linking hardcodes DIR into the +# resulting binary. +hardcode_runpath_var=$hardcode_runpath_var + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +EOF + +case "$host_os" in +aix*) + cat <<\EOF >> $ofile +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "${COLLECT_NAMES+set}" != set; then + COLLECT_NAMES= + export COLLECT_NAMES +fi + +EOF + ;; +esac + +# Detect if we are using a relative or absolute path to ltmain.sh. +case "$ltmain" in +/*) cat <> $ofile +# Execute the libtool backend. +. $ltmain +EOF + ;; +*) cat <> $ofile +# Find the path to this script. +thisdir=\`echo "\$0" | sed -e 's%/[^/]*\$%%'\` +test "X\$0" = "X\$thisdir" && thisdir=. + +# Execute the libtool backend. +. \$thisdir/$ltmain +EOF + ;; +esac + +echo 'exit 1' >> $ofile + +chmod +x $ofile +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/glib/ltmain.sh b/glib/ltmain.sh new file mode 100644 index 000000000..cb46c8498 --- /dev/null +++ b/glib/ltmain.sh @@ -0,0 +1,2372 @@ +# ltmain.sh - Provide generalized library-building support services. +# Generated automatically from ltmain.in by configure. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +#FIXME: echo=echo +echo='printf %s\n' +if test "X`$echo '\t'`" = 'X\t'; then : +else + # The Solaris and AIX default echo program unquotes backslashes. + # This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # So, we emulate echo with printf '%s\n' + echo='printf %s\n' + if test "X`$echo '\t'`" = 'X\t'; then : + else + # Oops. We have no working printf. Try to find a not-so-buggy echo. + echo=echo + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}:" + save_PATH="$PATH" + PATH="$PATH":/usr/ucb + for dir in $PATH; do + if test -f $dir/echo && test "X`$dir/echo '\t'`" = 'X\t'; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + PATH="$save_PATH" + fi +fi + +# The name of this program. +progname=`$echo "$0" | sed 's%^.*/%%'` + +# Constants. +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.0f + +default_mode= +help="Try \`$progname --help' for more information." +magic="%%%MAGIC variable%%%" +mkdir="mkdir" +mv="mv -f" +rm="rm -f" + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([\\"$\\\\]\)/\\\1/g' + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = set; then LANG=C; export LANG; fi + +if test "$LTCONFIG_VERSION" != "$VERSION"; then + $echo "$progname: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + $echo "$progname: not configured to build any kind of library" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case "$arg" in + -*=*) optarg=`$echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + execute_dlfiles) + eval "$prev=\"\$$prev \$arg\"" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case "$arg" in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION" + exit 0 + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$progname: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$progname: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case "$nonopt" in + *cc | *++) + mode=link + for arg + do + case "$arg" in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx) + mode=execute + ;; + *install*|cp) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$progname: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$progname: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$progname: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case "$mode" in + # libtool compile mode + compile) + progname="$progname: compile" + # Get the compilation command and the source file. + base_compile= + lastarg= + srcfile="$nonopt" + suppress_output= + + for arg + do + # The only flag that cannot be specified is the output filename. + if test "X$arg" = "X-o"; then + $echo "$progname: you cannot specify the output filename with \`-o'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "$lastarg" | sed "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly in scan + # sets, so we specify it separately. + case "$lastarg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + # Get the name of the library object. + libobj=`$echo "$srcfile" | sed -e 's%^.*/%%'` + + # Recognize several different file suffixes. + xform='[cCFSfm]' + case "$libobj" in + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "$libobj" | sed -e "s/\.$xform$/.lo/"` + + case "$libobj" in + *.lo) obj=`$echo "$libobj" | sed -e 's/\.lo$/.o/'` ;; + *) + $echo "$progname: cannot determine name of library object from \`$srcfile'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$progname: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + $run $rm $obj $libobj + trap "$run $rm $obj $libobj; exit 1" 1 2 15 + else + $run $rm $libobj + trap "$run $rm $libobj; exit 1" 1 2 15 + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + # All platforms use -DPIC, to notify preprocessed assembler code. + $show "$base_compile$pic_flag -DPIC $srcfile" + if $run eval "$base_compile\$pic_flag -DPIC \$srcfile"; then : + else + test -n "$obj" && $run $rm $obj + exit 1 + fi + + # If we have no pic_flag, then copy the object into place and finish. + if test -z "$pic_flag"; then + $show "$LN_S $obj $libobj" + $run $LN_S $obj $libobj + exit $? + fi + + # Just move the object, then go on to compile the next one + $show "$mv $obj $libobj" + $run $mv $obj $libobj || exit 1 + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + # Suppress compiler output if we already did a PIC compilation. + $show "$base_compile $srcfile$suppress_output" + if $run eval "$base_compile \$srcfile$suppress_output"; then : + else + $run $rm $obj $libobj + exit 1 + fi + fi + + # Create an invalid libtool object if no PIC, so that we don't accidentally + # link it into a program. + if test "$build_libtool_libs" != yes; then + $show "$echo timestamp > $libobj" + $run eval "\$echo timestamp > \$libobj" || exit $? + fi + + exit 0 + ;; + + # libtool link mode + link) + progname="$progname: link" + CC="$nonopt" + allow_undefined=no + compile_command="$CC" + finalize_command="$CC" + + compile_shlibpath= + finalize_shlibpath= + deplibs= + dlfiles= + dlprefiles= + export_dynamic=no + hardcode_libdirs= + libobjs= + link_against_libtool_libs= + ltlibs= + objs= + prev= + prevarg= + rpath= + perm_rpath= + temp_rpath= + vinfo= + + # We need to know -static, to get the right output filenames. + for arg + do + case "$arg" in + -all-static | -static) + if test "X$arg" = "X-all-static" && test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + $echo "$progname: warning: complete static linking is impossible in this configuration" 1>&2 + fi + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + for arg + do + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case "$prev" in + dlfiles|dlprefiles) + case "$arg" in + *.la | *.lo) ;; # We handle these cases below. + *) + dlprefiles="$dlprefiles $arg" + test "$prev" = dlfiles && dlfiles="$dlfiles $arg" + prev= + ;; + esac + ;; + rpath) + rpath="$rpath $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi + + prevarg="$arg" + + case "$arg" in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + allow_undefined=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + if test "$export_dynamic" != yes; then + export_dynamic=yes + if test -n "$export_dynamic_flag_spec"; then + arg=`eval \\$echo "$export_dynamic_flag_spec"` + else + arg= + fi + + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + fi + ;; + + -L*) + dir=`$echo "$arg" | sed 's%^-L\(.*\)$%\1%'` + case "$dir" in + /*) + # Add the corresponding hardcode_libdir_flag, if it is not identical. + ;; + *) + $echo "$progname: \`-L$dir' cannot specify a relative directory" 1>&2 + exit 1 + ;; + esac + deplibs="$deplibs $arg" + ;; + + -l*) deplibs="$deplibs $arg" ;; + + -o) prev=output ;; + + -rpath) + prev=rpath + continue + ;; + + -static) + # If we have no pic_flag, then this is the same as -all-static. + if test -z "$pic_flag" && test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + + *.o | *.a) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A library object. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test "$build_libtool_libs" = yes; then + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "$arg" | sed 's/\.lo$/\.o/'` + prev= + fi + libobjs="$libobjs $arg" + ;; + + *.la) + # A libtool-controlled library. + + dlname= + libdir= + library_names= + old_library= + + # Check to see that this really is a libtool archive. + if egrep '^# Generated by ltmain.sh' $arg >/dev/null 2>&1; then : + else + $echo "$progname: \`$arg' is not a valid libtool archive" 1>&2 + exit 1 + fi + + # If there is no directory component, then add one. + case "$arg" in + */*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$libdir"; then + $echo "$progname: \`$arg' contains no -rpath information" 1>&2 + exit 1 + fi + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + + if test -z "$linklib"; then + $echo "$progname: cannot find name of link library for \`$arg'" 1>&2 + exit 1 + fi + + # Find the relevant object directory and library name. + name=`$echo "$arg" | sed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` + dir=`$echo "$arg" | sed 's%/[^/]*$%%'` + if test "X$dir" = "X$arg"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + + # This library was specified with -dlopen. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test -z "$dlname"; then + # If there is no dlname, we need to preload. + prev=dlprefiles + else + # We should not create a dependency on this library. + prev= + continue + fi + fi + + # The library was specified with -dlpreopen. + if test "$prev" = dlprefiles; then + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + dlprefiles="$dlprefiles $dir/$old_library" + else + dlprefiles="$dlprefiles $dir/$linklib" + fi + prev= + fi + + if test "$build_libtool_libs" = yes && test -n "$library_names"; then + link_against_libtool_libs="$link_against_libtool_libs $arg" + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # This is the magic to use -rpath. + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + # Put the magic libdir with the hardcode flag. + hardcode_libdirs="$libdir" + libdir="@HARDCODE_LIBDIRS@" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + libdir= + fi + fi + + if test -n "$libdir"; then + flag=`eval \\$echo \"$hardcode_libdir_flag_spec\"` + + compile_command="$compile_command $flag" + finalize_command="$finalize_command $flag" + fi + elif test "$hardcode_runpath_var" = yes; then + # Do the same for the permanent run path. + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + + + case "$hardcode_action" in + immediate) + if test "$hardcode_direct" = no; then + compile_command="$compile_command $dir/$linklib" + elif test "$hardcode_minus_L" = no; then + compile_command="$compile_command -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = no; then + compile_shlibpath="$compile_shlibpath$dir:" + compile_command="$compile_command -l$name" + fi + ;; + + relink) + # We need an absolute path. + case "$dir" in + /*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$progname: cannot determine absolute directory name of \`$dir'" 1>&2 + exit 1 + fi + dir="$absdir" + ;; + esac + + if test "$hardcode_direct" = yes; then + compile_command="$compile_command $dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + compile_command="$compile_command -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + compile_shlibpath="$compile_shlibpath$dir:" + compile_command="$compile_command -l$name" + fi + ;; + + *) + $echo "$progname: \`$hardcode_action' is an unknown hardcode action" 1>&2 + exit 1 + ;; + esac + + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + finalize_command="$finalize_command $libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + finalize_command="$finalize_command -L$libdir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + finalize_shlibpath="$finalize_shlibpath$libdir:" + finalize_command="$finalize_command -l$name" + else + # We can't seem to hardcode it, guess we'll fake it. + finalize_command="$finalize_command -L$libdir -l$name" + fi + else + # Transform directly to old archives if we don't build new libraries. + if test -n "$pic_flag" && test -z "$old_library"; then + $echo "$progname: cannot find static library for \`$arg'" 1>&2 + exit 1 + fi + + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_command="$compile_command $dir/$linklib" + finalize_command="$finalize_command $dir/$linklib" + else + compile_command="$compile_command -L$dir -l$name" + finalize_command="$finalize_command -L$dir -l$name" + fi + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + esac + + # Now actually substitute the argument into the commands. + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + done + + if test -n "$prev"; then + $echo "$progname: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + oldlib= + oldobjs= + case "$output" in + "") + $echo "$progname: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + */*) + $echo "$progname: output file \`$output' must have no directory components" 1>&2 + exit 1 + ;; + + *.la) + # Make sure we only generate libraries of the form `libNAME.la'. + case "$output" in + lib*) ;; + *) + $echo "$progname: libtool library \`$arg' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + name=`$echo "$output" | sed -e 's/\.la$//' -e 's/^lib//'` + libname=`eval \\$echo \"$libname_spec\"` + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + current=0 + revision=0 + age=0 + + if test -n "$objs"; then + $echo "$progname: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 + exit 1 + fi + + # How the heck are we supposed to write a wrapper for a shared library? + if test -n "$link_against_libtool_libs"; then + $echo "$progname: libtool library \`$output' may not depend on uninstalled libraries:$link_against_libtool_libs" 1>&2 + exit 1 + fi + + # Add libc to deplibs on all systems. + deplibs="$deplibs -lc" + + if test -n "$dlfiles$dlprefiles"; then + $echo "$progname: warning: \`-dlopen' is ignored while creating libtool libraries" 1>&2 + # Nullify the symbol file. + compile_command=`$echo "$compile_command" | sed "s% @SYMFILE@%%"` + finalize_command=`$echo "$finalize_command" | sed "s% @SYMFILE@%%"` + fi + + if test -z "$rpath"; then + $echo "$progname: you must specify an installation directory with \`-rpath'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$progname: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + # Parse the version information argument. + IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' + set dummy $vinfo + IFS="$save_ifs" + + if test -n "$5"; then + $echo "$progname: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + test -n "$2" && current="$2" + test -n "$3" && revision="$3" + test -n "$4" && age="$4" + + # Check that each of the things are valid numbers. + case "$current" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$progname: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$revision" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$progname: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$age" in + 0 | [1-9] | [1-9][0-9]*) ;; + *) + $echo "$progname: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$progname: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$progname: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + version_vars="version_type current age revision" + case "$version_type" in + none) ;; + + linux) + version_vars="$version_vars major versuffix" + major=`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + version_vars="$version_vars versuffix verstring" + major=`expr $current - $age` + versuffix="$current.$age.$revision" + verstring="$versuffix" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + version_vars="$version_vars major versuffix" + major="$current" + versuffix="$current.$revision" + ;; + + *) + $echo "$progname: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Create the output directory, or remove our outputs if we need to. + if test -d $objdir; then + $show "$rm $objdir/$output $objdir/$libname.*" + $run $rm $objdir/$output $objdir/$libname.* + else + $show "$mkdir $objdir" + $run $mkdir $objdir + status=$? + if test $status -eq 0 || test -d $objdir; then : + else + exit $status + fi + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$progname: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Clear the flag. + allow_undefined_flag= + fi + + if test "$build_libtool_libs" = yes; then + # Get the real and link names of the library. + library_names=`eval \\$echo \"$library_names_spec\"` + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + soname=`eval \\$echo \"$soname_spec\"` + else + soname="$realname" + fi + + lib="$objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are PIC. + test -z "$pic_flag" && libobjs=`$echo "$libobjs " | sed -e 's/\.lo /.o /g' -e 's/ $//g'` + + # Do each of the archive commands. + cmds=`eval \\$echo \"$archive_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Create links to the real library. + for link in $linknames; do + $show "(cd $objdir && $LN_S $realname $link)" + $run eval '(cd $objdir && $LN_S $realname $link)' || exit $? + done + + # If -export-dynamic was specified, set the dlname. + if test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + *.lo | *.o) + if test -n "$link_against_libtool_libs"; then + $echo "$progname: error: cannot link libtool libraries into reloadable objects" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$progname: warning: \`-l' and \`-L' are ignored while creating objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles"; then + $echo "$progname: warning: \`-dlopen' is ignored while creating objects" 1>&2 + # Nullify the symbol file. + compile_command=`$echo "$compile_command" | sed "s% @SYMFILE@%%"` + finalize_command=`$echo "$finalize_command" | sed "s% @SYMFILE@%%"` + fi + + if test -n "$rpath"; then + $echo "$progname: warning: \`-rpath' is ignored while creating objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$progname: warning: \`-version-info' is ignored while creating objects" 1>&2 + fi + + case "$output" in + *.lo) + if test -n "$objs"; then + $echo "$progname: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "$output" | sed 's/\.lo$/.o/'` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Create the old-style object. + reload_objs="$objs"`$echo "$libobjs " | sed -e 's/[^ ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'` + + output="$obj" + cmds=`eval \\$echo \"$reload_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + test -z "$libobj" && exit 0 + + if test "$build_libtool_libs" != yes; then + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "$echo timestamp > $libobj" + $run eval "\$echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs" + output="$libobj" + cmds=`eval \\$echo \"$reload_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show "$LN_S $obj $libobj" + $run $LN_S $obj $libobj || exit 1 + fi + + exit 0 + ;; + + *) + if test -n "$vinfo"; then + $echo "$progname: warning: \`-version-info' is ignored while linking programs" 1>&2 + fi + + if test -n "$rpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + # Put the magic libdir with the hardcode flag. + hardcode_libdirs="$libdir" + libdir="@HARDCODE_LIBDIRS@" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + libdir= + fi + fi + + if test -n "$libdir"; then + flag=`eval \\$echo \"$hardcode_libdir_flag_spec\"` + + compile_command="$compile_command $flag" + finalize_command="$finalize_command $flag" + fi + elif test "$hardcode_runpath_var" = yes; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + fi + + # Substitute the hardcoded libdirs into the compile commands. + if test -n "$hardcode_libdir_separator"; then + compile_command=`$echo "$compile_command" | sed "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"` + finalize_command=`$echo "$finalize_command" | sed "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"` + fi + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "$compile_command " | sed -e 's/\.lo /.o /g' -e 's/ $//'` + finalize_command=`$echo "$finalize_command " | sed -e 's/\.lo /.o /g' -e 's/ $//'` + fi + + if test "$export_dynamic" = yes && test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${output}S.c" + else + dlsyms= + fi + + if test -n "$dlsyms"; then + # Add our own program objects to the preloaded list. + dlprefiles=`$echo "$objs$dlprefiles " | sed -e 's/\.lo /.o /g' -e 's/ $//'` + + # Discover the nlist of each of the dlfiles. + nlist="$objdir/${output}.nm" + + if test -d $objdir; then + $show "$rm $nlist ${nlist}T" + $run $rm "$nlist" "${nlist}T" + else + $show "$mkdir $objdir" + $run $mkdir $objdir + status=$? + if test $status -eq 0 || test -d $objdir; then : + else + exit $status + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + # Parse the name list into a source file. + $show "creating $objdir/$dlsyms" + if test -z "$run"; then + # Make sure we at least have an empty file. + test -f "$nlist" || : > "$nlist" + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + wcout=`wc "$nlist" 2>/dev/null` + count=`$echo "$wcout" | sed 's/^[ ]*\([0-9][0-9]*\).*$/\1/'` + (test "$count" -ge 0) 2>/dev/null || count=-1 + else + $rm "$nlist"T + count=-1 + fi + + case "$dlsyms" in + "") ;; + *.c) + cat < "$objdir/$dlsyms" +/* $dlsyms - symbol resolution table for \`$output' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define dld_preloaded_symbol_count some_other_symbol +#define dld_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */ +EOF + if test -f "$nlist"; then + sed -e 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> "$objdir/$dlsyms" + else + $echo '/* NONE */' >> "$objdir/$dlsyms" +EOF + fi + + cat <> "$objdir/$dlsyms" + +#undef dld_preloaded_symbol_count +#undef dld_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define __ptr_t void * +#else +# define __ptr_t char * +#endif + +/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */ +int dld_preloaded_symbol_count = $count; + +/* The mapping between symbol names and symbols. */ +struct { + char *name; + __ptr_t address; +} +dld_preloaded_symbols[] = +{ +EOF + + if test -f "$nlist"; then + sed 's/^\(.*\) \(.*\)$/ {"\1", \&\2},/' < "$nlist" >> "$objdir/$dlsyms" + fi + + cat <<\EOF >> "$objdir/$dlsyms" + {0}, +}; + +#ifdef __cplusplus +} +#endif +EOF + ;; + + *) + echo "$progname: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + fi + + # Now compile the dynamic symbol file. + $show "(cd $objdir && $CC -c$no_builtin_flag \"$dlsyms\")" + $run eval '(cd $objdir && $CC -c$no_builtin_flag "$dlsyms")' || exit $? + + # Transform the symbol file into the correct name. + compile_command=`$echo "$compile_command" | sed "s%@SYMFILE@%$objdir/${output}S.o%"` + finalize_command=`$echo "$finalize_command" | sed "s%@SYMFILE@%$objdir/${output}S.o%"` + elif test "$export_dynamic" != yes; then + test -n "$dlfiles$dlprefiles" && $echo "$progname: warning: \`-dlopen' and \`-dlpreopen' are ignored without \`-export-dynamic'" 1>&2 + else + # We keep going just in case the user didn't refer to + # dld_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + $echo "$progname: not configured to extract global symbols from dlpreopened files" 1>&2 + + # Nullify the symbol file. + compile_command=`$echo "$compile_command" | sed "s% @SYMFILE@%%"` + finalize_command=`$echo "$finalize_command" | sed "s% @SYMFILE@%%"` + fi + + if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "$compile_command" | sed 's%@OUTPUT@%'"$output"'%g'` + finalize_command=`$echo "$finalize_command" | sed 's%@OUTPUT@%'"$output"'%g'` + + # We have no uninstalled library dependencies, so finalize right now. + $show "$compile_command" + $run eval "$compile_command" + exit $? + fi + + # Replace the output file specification. + compile_command=`$echo "$compile_command" | sed 's%@OUTPUT@%'"$objdir/$output"'%g'` + finalize_command=`$echo "$finalize_command" | sed 's%@OUTPUT@%'"$objdir/$output"'T%g'` + + # Create the binary in the object directory, then wrap it. + if test -d $objdir; then : + else + $show "$mkdir $objdir" + $run $mkdir $objdir || exit $? + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case "$dir" in + /*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + # Delete the old output file. + $run $rm $output + + if test -n "$compile_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_command="$runpath_var=\"$rpath\$$runpath_var\" $compile_command" + finalize_command="$runpath_var=\"$rpath\$$runpath_var\" $finalize_command" + fi + + case "$hardcode_action" in + relink) + # AGH! Flame the AIX and HP-UX people for me, will ya? + $echo "$progname: warning: using a buggy system linker" 1>&2 + $echo "$progname: relinking will be required before \`$output' can be installed" 1>&2 + ;; + esac + + $show "$compile_command" + $run eval "$compile_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the finalize command for shipping. + finalize_command=`$echo "$finalize_command" | sed "$sed_quote_subst"` + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + cat > $output < //p'\` + while test -n "\$file"; do + destdir=\`\$echo "\$file" | sed 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test "x\$destdir" != "x\$file"; then + case "\$destdir" in + /*) thisdir="\$destdir" ;; + *) thisdir="\$thisdir/\$destdir" ;; + esac + fi + + file=\`\$echo "\$file" | sed 's%^.*/%%'\` + file=\`ls -ld "\$thisdir/\$file" | sed -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd "\$thisdir" && pwd\` + test -n "\$absdir" && thisdir="\$absdir" + + progdir="\$thisdir/$objdir" + program='$output' + + if test -f "\$progdir/\$program"; then +EOF + + # Export our shlibpath_var if we have one. + if test -n "$shlibpath_var" && test -n "$temp_rpath"; then + cat >> $output <> $output <&2 + \$echo "This script is just a wrapper for \$program." 1>&2 + \$echo "See the $PACKAGE documentation for more information." 1>&2 + exit 1 + fi +fi +EOF + chmod +x $output + fi + exit 0 + ;; + esac + + + # See if we need to build an old-fashioned archive. + if test "$build_old_libs" = "yes"; then + # Now set the variables for building old libraries. + oldlib="$objdir/$libname.a" + + # Transform .lo files to .o files. + oldobjs="$objs"`$echo "$libobjs " | sed -e 's/[^ ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'` + + if test -d "$objdir"; then + $show "$rm $oldlib" + $run $rm $oldlib + else + $show "$mkdir $objdir" + $run $mkdir $objdir + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=`eval \\$echo \"$old_archive_from_new_cmds\"` + else + cmds=`eval \\$echo \"$old_archive_cmds\"` + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Now create the libtool archive. + case "$output" in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.a" + + $show "creating $output" + + # Only create the output if not a dry run. + if test -z "$run"; then + cat > $output <\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir= + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case "$arg" in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$progname: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$progname: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$progname: no file or destination specified" 1>&2 + else + $echo "$progname: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "$dest" | sed 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test -n "$isdir"; then + destdir="$dest" + destname= + else + destdir=`$echo "$dest" | sed 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "$dest" | sed 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$progname: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case "$destdir" in + /*) ;; + *) + for file in $files; do + case "$file" in + *.lo) ;; + *) + $echo "$progname: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case "$file" in + *.a) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then : + else + $echo "$progname: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir="`$echo "$file" | sed 's%/[^/]*$%%'`/" + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$realname $destdir/$realname" + $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? + test "X$dlname" = "X$realname" && dlname= + + # Support stripping libraries. + if test -n "$stripme"; then + if test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run $striplib $destdir/$realname || exit $? + else + $echo "$progname: warning: no library stripping program" 1>&2 + fi + fi + + if test $# -gt 0; then + # Delete the old symlinks. + rmcmd="$rm" + for linkname + do + rmcmd="$rmcmd $destdir/$linkname" + done + $show "$rmcmd" + $run $rmcmd + + # ... and create new ones. + for linkname + do + test "X$dlname" = "X$linkname" && dlname= + $show "(cd $destdir && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $LN_S $realname $linkname)" + done + fi + + if test -n "$dlname"; then + # Install the dynamically-loadable library. + $show "$install_prog $dir/$dlname $destdir/$dlname" + $run eval "$install_prog $dir/$dlname $destdir/$dlname" || exit $? + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=`eval \\$echo \"$postinstall_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "$file" | sed 's%^.*/%%'` + $show "$install_prog $file $destdir/$name" + $run eval "$install_prog $file $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "$file" | sed 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case "$destfile" in + *.lo) + staticdest=`$echo "$destfile" | sed 's/\.lo$/\.o/'` + ;; + *.o) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$progname: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "$file" | sed 's/\.lo$/\.o/'` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Do a test to see if this is really a libtool program. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then + link_against_libtool_libs= + finalize_command= + + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Check the variables that should have been set. + if test -z "$link_against_libtool_libs" || test -z "$finalize_command"; then + $echo "$progname: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $link_against_libtool_libs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case "$lib" in + */*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/`$echo "$lib" | sed 's%^.*/%%g'`" + if test -z "$libdir"; then + $echo "$progname: warning: \`$lib' contains no -rpath information" 1>&2 + elif test -f "$libfile"; then : + else + $echo "$progname: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + if test "$hardcode_action" = relink; then + if test "$finalize" = yes; then + $echo "$progname: warning: relinking \`$file' on behalf of your buggy system linker" 1>&2 + $show "$finalize_command" + if $run eval "$finalize_command"; then : + else + $echo "$progname: error: relink \`$file' with the above command before installing it" 1>&2 + continue + fi + file="$objdir/$file"T + else + $echo "$progname: warning: cannot relink \`$file' on behalf of your buggy system linker" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "$file" | sed "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + $show "$install_prog$stripme $file $dest" + $run eval "$install_prog\$stripme \$file \$dest" || exit $? + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "$file" | sed 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + # Support stripping libraries. + if test -n "$stripme"; then + if test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run $old_striplib $oldlib || exit $? + else + $echo "$progname: warning: no static library stripping program" 1>&2 + fi + fi + + # Do each command in the postinstall commands. + cmds=`eval \\$echo \"$old_postinstall_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$progname: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec $SHELL $0 --finish$current_libdirs + exit 1 + fi + + exit 0 + ;; + + # libtool finish mode + finish) + progname="$progname: finish" + libdirs="$nonopt" + + if test -n "$finish_cmds" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + # Do each command in the postinstall commands. + cmds=`eval \\$echo \"$finish_cmds\"` + IFS="${IFS= }"; save_ifs="$IFS"; IFS=';' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + done + fi + + $echo "To link against installed libraries in LIBDIR, users may have to:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to their \`$shlibpath_var' environment variable" + fi + $echo " - use the \`-LLIBDIR' linker flag" + exit 0 + ;; + + # libtool execute mode + execute) + progname="$progname: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$progname: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test -f "$file"; then : + else + $echo "$progname: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case "$file" in + *.la) + # Check to see that this really is a libtool archive. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then : + else + $echo "$progname: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$progname: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "$file" | sed 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$progname: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "$file" | sed 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$progname: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case "$file" in + -*) ;; + *) + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then + # If there is no directory component, then add one. + case "$file" in + */*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "$file" | sed "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + + # Now actually exec the command. + eval "exec \$cmd$args" + + $echo "$progname: cannot exec \$cmd$args" + exit 1 + else + # Display what would be done. + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool uninstall mode + uninstall) + progname="$progname: uninstall" + rm="$nonopt" + files= + + for arg + do + case "$arg" in + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$progname: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + for file in $files; do + dir=`$echo "$file" | sed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + name=`$echo "$file" | sed -e 's%^.*/%%'` + + rmfiles="$file" + + case "$name" in + *.la) + # Possibly a libtool archive, so verify it. + if egrep '^# Generated by ltmain.sh' $file >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $dir/$n" + test "X$n" = "X$dlname" && dlname= + done + test -n "$dlname" && rmfiles="$rmfiles $dir/$dlname" + test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" + + # FIXME: should reinstall the best remaining shared library. + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "$name" | sed 's/\.lo$/\.o/'` + rmfiles="$rmfiles $dir/$oldobj" + fi + ;; + esac + + $show "$rm $rmfiles" + $run $rm $rmfiles + done + exit 0 + ;; + + "") + $echo "$progname: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + $echo "$progname: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 +fi # test -z "$show_help" + +# We need to display help for each of the modes. +case "$mode" in +"") cat <&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +$echo +$echo "Try \`$progname --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/glib/missing b/glib/missing new file mode 100755 index 000000000..e4b838ca9 --- /dev/null +++ b/glib/missing @@ -0,0 +1,134 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program 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. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison touch file \`y.tab.c' + makeinfo touch the output file + yacc touch file \`y.tab.c'" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + touch config.h.in + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print \ + | sed 's/^\(.*\).am$/touch \1.in/' \ + | sh + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + your modified any \`.y' file. For being effective, your + modifications might require the \`Bison' package. Grab it from + any GNU archive site." + touch y.tab.c + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/glib/mkinstalldirs b/glib/mkinstalldirs new file mode 100755 index 000000000..fef1eb941 --- /dev/null +++ b/glib/mkinstalldirs @@ -0,0 +1,36 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? + fi + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/glib/stamp-h.in b/glib/stamp-h.in new file mode 100644 index 000000000..9788f7023 --- /dev/null +++ b/glib/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/glib/testglib.c b/glib/testglib.c new file mode 100644 index 000000000..4357b2364 --- /dev/null +++ b/glib/testglib.c @@ -0,0 +1,296 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "glib.h" + +int array[10000]; + +void +my_hash_callback (gpointer key, + gpointer value, + gpointer user_data) +{ + int *d = value; + *d = 1; +} + +guint +my_hash (gpointer key) +{ + return (guint) *((gint*) key); +} + +gint +my_hash_compare (gpointer a, + gpointer b) +{ + return *((gint*) a) == *((gint*) b); +} + +gint +my_compare (gpointer a, + gpointer b) +{ + char *cha = a; + char *chb = b; + + return *cha - *chb; +} + +gint +my_traverse (gpointer key, + gpointer value, + gpointer data) +{ + char *ch = key; + g_print ("%c ", *ch); + return FALSE; +} + +int +main (int argc, + char *argv[]) +{ + GList *list, *t; + GSList *slist, *st; + GHashTable *hash_table; + GMemChunk *mem_chunk; + GStringChunk *string_chunk; + GTimer *timer; + gint nums[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + gchar *mem[10000], *tmp_string, *tmp_string_2; + gint i, j; + GArray *garray; + GString *string1, *string2; + GTree *tree; + char chars[62]; + + g_print ("checking size of gint8...%d (should be 1)\n", sizeof (gint8)); + g_print ("checking size of gint16...%d (should be 2)\n", sizeof (gint16)); + g_print ("checking size of gint32...%d (should be 4)\n", sizeof (gint32)); + + g_print ("checking doubly linked lists..."); + + list = NULL; + for (i = 0; i < 10; i++) + list = g_list_append (list, &nums[i]); + list = g_list_reverse (list); + + for (i = 0; i < 10; i++) + { + t = g_list_nth (list, i); + if (*((gint*) t->data) != (9 - i)) + g_error ("failed"); + } + + g_list_free (list); + + g_print ("ok\n"); + + + g_print ("checking singly linked lists..."); + + slist = NULL; + for (i = 0; i < 10; i++) + slist = g_slist_append (slist, &nums[i]); + slist = g_slist_reverse (slist); + + for (i = 0; i < 10; i++) + { + st = g_slist_nth (slist, i); + if (*((gint*) st->data) != (9 - i)) + g_error ("failed"); + } + + g_slist_free (slist); + + g_print ("ok\n"); + + + g_print ("checking trees...\n"); + + tree = g_tree_new (my_compare); + i = 0; + for (j = 0; j < 10; j++, i++) + { + chars[i] = '0' + j; + g_tree_insert (tree, &chars[i], &chars[i]); + } + for (j = 0; j < 26; j++, i++) + { + chars[i] = 'A' + j; + g_tree_insert (tree, &chars[i], &chars[i]); + } + for (j = 0; j < 26; j++, i++) + { + chars[i] = 'a' + j; + g_tree_insert (tree, &chars[i], &chars[i]); + } + + g_print ("tree height: %d\n", g_tree_height (tree)); + g_print ("tree nnodes: %d\n", g_tree_nnodes (tree)); + + g_print ("tree: "); + g_tree_traverse (tree, my_traverse, G_IN_ORDER, NULL); + g_print ("\n"); + + for (i = 0; i < 10; i++) + g_tree_remove (tree, &chars[i]); + + g_print ("tree height: %d\n", g_tree_height (tree)); + g_print ("tree nnodes: %d\n", g_tree_nnodes (tree)); + + g_print ("tree: "); + g_tree_traverse (tree, my_traverse, G_IN_ORDER, NULL); + g_print ("\n"); + + g_print ("ok\n"); + + + g_print ("checking mem chunks..."); + + mem_chunk = g_mem_chunk_new ("test mem chunk", 50, 100, G_ALLOC_AND_FREE); + + for (i = 0; i < 10000; i++) + { + mem[i] = g_chunk_new (gchar, mem_chunk); + + for (j = 0; j < 50; j++) + mem[i][j] = i * j; + } + + for (i = 0; i < 10000; i++) + { + g_mem_chunk_free (mem_chunk, mem[i]); + } + + g_print ("ok\n"); + + + g_print ("checking hash tables..."); + + hash_table = g_hash_table_new (my_hash, my_hash_compare); + for (i = 0; i < 10000; i++) + { + array[i] = i; + g_hash_table_insert (hash_table, &array[i], &array[i]); + } + g_hash_table_foreach (hash_table, my_hash_callback, NULL); + + for (i = 0; i < 10000; i++) + if (array[i] == 0) + g_print ("%d\n", i); + + for (i = 0; i < 10000; i++) + g_hash_table_remove (hash_table, &array[i]); + + g_hash_table_destroy (hash_table); + + g_print ("ok\n"); + + + g_print ("checking string chunks..."); + + string_chunk = g_string_chunk_new (1024); + + for (i = 0; i < 100000; i ++) + { + tmp_string = g_string_chunk_insert (string_chunk, "hi pete"); + + if (strcmp ("hi pete", tmp_string) != 0) + g_error ("string chunks are broken.\n"); + } + + tmp_string_2 = g_string_chunk_insert_const (string_chunk, tmp_string); + + g_assert (tmp_string_2 != tmp_string && + strcmp(tmp_string_2, tmp_string) == 0); + + tmp_string = g_string_chunk_insert_const (string_chunk, tmp_string); + + g_assert (tmp_string_2 == tmp_string); + + g_string_chunk_free (string_chunk); + + g_print ("ok\n"); + + + g_print ("checking arrays..."); + + garray = g_array_new (FALSE); + for (i = 0; i < 10000; i++) + g_array_append_val (garray, gint, i); + + for (i = 0; i < 10000; i++) + if (g_array_index (garray, gint, i) != i) + g_print ("uh oh: %d ( %d )\n", g_array_index (garray, gint, i), i); + + g_array_free (garray, TRUE); + + garray = g_array_new (FALSE); + for (i = 0; i < 10000; i++) + g_array_prepend_val (garray, gint, i); + + for (i = 0; i < 10000; i++) + if (g_array_index (garray, gint, i) != (10000 - i - 1)) + g_print ("uh oh: %d ( %d )\n", g_array_index (garray, gint, i), 10000 - i - 1); + + g_array_free (garray, TRUE); + + g_print ("ok\n"); + + + g_print ("checking strings..."); + + string1 = g_string_new ("hi pete!"); + string2 = g_string_new (""); + + g_assert (strcmp ("hi pete!", string1->str) == 0); + + for (i = 0; i < 10000; i++) + g_string_append_c (string1, 'a'+(i%26)); + + g_string_sprintf (string2, "%s|%0100d|%s|%s|%0*d|%*.*f|%10000.10000f", + "this pete guy sure is a wuss, like he's the number ", + 1, + " wuss. everyone agrees.\n", + string1->str, + 10, 666, 15, 15, 666.666666666, 666.666666666); + + g_print ("ok\n"); + + g_print ("checking timers...\n"); + + timer = g_timer_new (); + g_print (" spinning for 3 seconds...\n"); + + g_timer_start (timer); + while (g_timer_elapsed (timer, NULL) < 3) + ; + + g_timer_stop (timer); + g_timer_destroy (timer); + + g_print ("ok\n"); + + /* g_debug (argv[0]); */ + + + return 0; +} diff --git a/gtk+.prj b/gtk+.prj new file mode 100644 index 000000000..2c16fecaf --- /dev/null +++ b/gtk+.prj @@ -0,0 +1,334 @@ +;; -*- Lisp -*- +(Created-By-Prcs-Version 1 1 0) +(Project-Description "") +(Project-Version gtk+ 0 16) +(Parent-Version gtk+ 0 15) +(Descends-From -*- -*- -*-) +(Version-Log "") +(New-Version-Log "") +(Checkin-Time "Wed, 19 Feb 1997 15:49:10 -0800") +(Checkin-Login pmattis) +(Populate-Ignore ("\\.o$" "\\.a$" "^core$" "^.*/core$" + ".*.deps/.*" "\\.dvi$" "\\.aux$" "\\.log" + "Makefile$" "config.cache$" "config.log$" + "configure$" "gconfig.h$" "stamp-h$")) +(Files +;; This is a comment. Fill in files here. +;; For example: (prcs/checkout.cc ()) + +; Files added by populate at Thu, 21 Nov 1996 16:48:40 -0800: + + (docs/texinfo.tex (gtk+/1_texinfo.te 1.1 644)) + (docs/gtk.texi (gtk+/2_gtk.texi 1.5 644)) + (docs/gdk.texi (gtk+/3_gdk.texi 1.2 644)) + (docs/Makefile.in (gtk+/4_Makefile.i 1.5 644)) + (docs/Makefile.am (gtk+/5_Makefile.a 1.2 644)) + (gtk/testgtk.c (gtk+/6_testgtk.c 1.14 644)) + (gtk/gtkwindow.h (gtk+/7_gtkwindow. 1.6 644)) + (gtk/gtkwindow.c (gtk+/8_gtkwindow. 1.10 644)) + (gtk/gtkwidget.h (gtk+/9_gtkwidget. 1.8 644)) + (gtk/gtkwidget.c (gtk+/10_gtkwidget. 1.14 644)) + (gtk/gtkvseparator.h (gtk+/11_gtkvsepara 1.3 644)) + (gtk/gtkvseparator.c (gtk+/12_gtkvsepara 1.5 644)) + (gtk/gtkvscrollbar.h (gtk+/13_gtkvscroll 1.3 644)) + (gtk/gtkvscrollbar.c (gtk+/14_gtkvscroll 1.5 644)) + (gtk/gtkvscale.h (gtk+/15_gtkvscale. 1.2 644)) + (gtk/gtkvscale.c (gtk+/16_gtkvscale. 1.7 644)) + (gtk/gtkvruler.h (gtk+/17_gtkvruler. 1.4 644)) + (gtk/gtkvruler.c (gtk+/18_gtkvruler. 1.7 644)) + (gtk/gtkviewport.h (gtk+/19_gtkviewpor 1.3 644)) + (gtk/gtkviewport.c (gtk+/20_gtkviewpor 1.6 644)) + (gtk/gtkvbox.h (gtk+/21_gtkvbox.h 1.2 644)) + (gtk/gtkvbox.c (gtk+/22_gtkvbox.c 1.5 644)) + (gtk/gtktypeutils.h (gtk+/23_gtktypeuti 1.4 644)) + (gtk/gtktypeutils.c (gtk+/24_gtktypeuti 1.6 644)) + (gtk/gtktreeitem.h (gtk+/25_gtktreeite 1.3 644)) + (gtk/gtktreeitem.c (gtk+/26_gtktreeite 1.4 644)) + (gtk/gtktree.h (gtk+/27_gtktree.h 1.3 644)) + (gtk/gtktree.c (gtk+/28_gtktree.c 1.4 644)) + (gtk/gtktogglebutton.h (gtk+/29_gtktoggleb 1.5 644)) + (gtk/gtktogglebutton.c (gtk+/30_gtktoggleb 1.8 644)) + (gtk/gtktable.h (gtk+/31_gtktable.h 1.2 644)) + (gtk/gtktable.c (gtk+/32_gtktable.c 1.8 644)) + (gtk/gtkstyle.h (gtk+/33_gtkstyle.h 1.3 644)) + (gtk/gtkstyle.c (gtk+/34_gtkstyle.c 1.7 644)) + (gtk/gtksignal.h (gtk+/35_gtksignal. 1.7 644)) + (gtk/gtksignal.c (gtk+/36_gtksignal. 1.9 644)) + (gtk/gtkseparator.h (gtk+/37_gtkseparat 1.2 644)) + (gtk/gtkseparator.c (gtk+/38_gtkseparat 1.4 644)) + (gtk/gtkscrolledwindow.h (gtk+/39_gtkscrolle 1.2 644)) + (gtk/gtkscrolledwindow.c (gtk+/40_gtkscrolle 1.8 644)) + (gtk/gtkscrollbar.h (gtk+/41_gtkscrollb 1.2 644)) + (gtk/gtkscrollbar.c (gtk+/42_gtkscrollb 1.4 644)) + (gtk/gtkscale.h (gtk+/43_gtkscale.h 1.4 644)) + (gtk/gtkscale.c (gtk+/44_gtkscale.c 1.7 644)) + (gtk/gtkruler.h (gtk+/45_gtkruler.h 1.5 644)) + (gtk/gtkruler.c (gtk+/46_gtkruler.c 1.8 644)) + (gtk/gtkrc.h (gtk+/47_gtkrc.h 1.3 644)) + (gtk/gtkrc.c (gtk+/48_gtkrc.c 1.4 644)) + (gtk/gtkrange.h (gtk+/49_gtkrange.h 1.4 644)) + (gtk/gtkrange.c (gtk+/50_gtkrange.c 1.6 644)) + (gtk/gtkradiobutton.h (gtk+/51_gtkradiobu 1.3 644)) + (gtk/gtkradiobutton.c (gtk+/b/0_gtkradiobutton.c 1.7 644)) + (gtk/gtkpixmap.h (gtk+/b/1_gtkpixmap. 1.3 644)) + (gtk/gtkpixmap.c (gtk+/b/2_gtkpixmap. 1.5 644)) + (gtk/gtkoptionmenu.h (gtk+/b/3_gtkoptionm 1.5 644)) + (gtk/gtkoptionmenu.c (gtk+/b/4_gtkoptionm 1.7 644)) + (gtk/gtkobject.h (gtk+/b/5_gtkobject. 1.6 644)) + (gtk/gtkobject.c (gtk+/b/6_gtkobject. 1.9 644)) + (gtk/gtkmisc.h (gtk+/b/7_gtkmisc.h 1.2 644)) + (gtk/gtkmisc.c (gtk+/b/8_gtkmisc.c 1.4 644)) + (gtk/gtkmenushell.h (gtk+/b/9_gtkmenushe 1.5 644)) + (gtk/gtkmenushell.c (gtk+/b/10_gtkmenushe 1.8 644)) + (gtk/gtkmenuitem.h (gtk+/b/11_gtkmenuite 1.6 644)) + (gtk/gtkmenuitem.c (gtk+/b/12_gtkmenuite 1.8 644)) + (gtk/gtkmenubar.h (gtk+/b/13_gtkmenubar 1.4 644)) + (gtk/gtkmenubar.c (gtk+/b/14_gtkmenubar 1.7 644)) + (gtk/gtkmenu.h (gtk+/b/15_gtkmenu.h 1.5 644)) + (gtk/gtkmenu.c (gtk+/b/16_gtkmenu.c 1.8 644)) + (gtk/gtkmain.h (gtk+/b/17_gtkmain.h 1.4 644)) + (gtk/gtkmain.c (gtk+/b/18_gtkmain.c 1.11 644)) + (gtk/gtklistitem.h (gtk+/b/19_gtklistite 1.3 644)) + (gtk/gtklistitem.c (gtk+/b/20_gtklistite 1.9 644)) + (gtk/gtklist.h (gtk+/b/21_gtklist.h 1.5 644)) + (gtk/gtklist.c (gtk+/b/22_gtklist.c 1.10 644)) + (gtk/gtklabel.h (gtk+/b/23_gtklabel.h 1.2 644)) + (gtk/gtklabel.c (gtk+/b/24_gtklabel.c 1.7 644)) + (gtk/gtkitem.h (gtk+/b/25_gtkitem.h 1.3 644)) + (gtk/gtkitem.c (gtk+/b/26_gtkitem.c 1.7 644)) + (gtk/gtkimage.h (gtk+/b/27_gtkimage.h 1.2 644)) + (gtk/gtkimage.c (gtk+/b/28_gtkimage.c 1.4 644)) + (gtk/gtkhseparator.h (gtk+/b/29_gtkhsepara 1.2 644)) + (gtk/gtkhseparator.c (gtk+/b/30_gtkhsepara 1.4 644)) + (gtk/gtkhscrollbar.h (gtk+/b/31_gtkhscroll 1.2 644)) + (gtk/gtkhscrollbar.c (gtk+/b/32_gtkhscroll 1.4 644)) + (gtk/gtkhscale.h (gtk+/b/33_gtkhscale. 1.2 644)) + (gtk/gtkhscale.c (gtk+/b/34_gtkhscale. 1.7 644)) + (gtk/gtkhruler.h (gtk+/b/35_gtkhruler. 1.4 644)) + (gtk/gtkhruler.c (gtk+/b/36_gtkhruler. 1.7 644)) + (gtk/gtkhbox.h (gtk+/b/37_gtkhbox.h 1.2 644)) + (gtk/gtkhbox.c (gtk+/b/38_gtkhbox.c 1.5 644)) + (gtk/gtkgc.h (gtk+/b/39_gtkgc.h 1.3 644)) + (gtk/gtkgc.c (gtk+/b/40_gtkgc.c 1.5 644)) + (gtk/gtkframe.h (gtk+/b/41_gtkframe.h 1.2 644)) + (gtk/gtkframe.c (gtk+/b/42_gtkframe.c 1.5 644)) + (gtk/gtkenums.h (gtk+/b/45_gtkenums.h 1.6 644)) + (gtk/gtkentry.h (gtk+/b/46_gtkentry.h 1.5 644)) + (gtk/gtkentry.c (gtk+/b/47_gtkentry.c 1.9 644)) + (gtk/gtkdrawingarea.h (gtk+/b/48_gtkdrawing 1.4 644)) + (gtk/gtkdrawingarea.c (gtk+/b/49_gtkdrawing 1.6 644)) + (gtk/gtkdata.h (gtk+/b/50_gtkdata.h 1.2 644)) + (gtk/gtkdata.c (gtk+/b/51_gtkdata.c 1.7 644)) + (gtk/gtkcontainer.h (gtk+/c/0_gtkcontainer.h 1.6 644)) + (gtk/gtkcontainer.c (gtk+/c/1_gtkcontain 1.10 644)) + (gtk/gtkcheckbutton.h (gtk+/c/2_gtkcheckbu 1.3 644)) + (gtk/gtkcheckbutton.c (gtk+/c/3_gtkcheckbu 1.6 644)) + (gtk/gtkbutton.h (gtk+/c/4_gtkbutton. 1.4 644)) + (gtk/gtkbutton.c (gtk+/c/5_gtkbutton. 1.9 644)) + (gtk/gtkbox.h (gtk+/c/6_gtkbox.h 1.2 644)) + (gtk/gtkbox.c (gtk+/c/7_gtkbox.c 1.5 644)) + (gtk/gtkbin.h (gtk+/c/8_gtkbin.h 1.2 644)) + (gtk/gtkbin.c (gtk+/c/9_gtkbin.c 1.6 644)) + (gtk/gtkarrow.h (gtk+/c/10_gtkarrow.h 1.2 644)) + (gtk/gtkarrow.c (gtk+/c/11_gtkarrow.c 1.4 644)) + (gtk/gtkalignment.h (gtk+/c/12_gtkalignme 1.2 644)) + (gtk/gtkalignment.c (gtk+/c/13_gtkalignme 1.5 644)) + (gtk/gtkadjustment.h (gtk+/c/14_gtkadjustm 1.3 644)) + (gtk/gtkadjustment.c (gtk+/c/15_gtkadjustm 1.7 644)) + (gtk/gtkaccelerator.h (gtk+/c/16_gtkacceler 1.4 644)) + (gtk/gtkaccelerator.c (gtk+/c/17_gtkacceler 1.4 644)) + (gtk/gtk.h (gtk+/c/18_gtk.h 1.7 644)) + (gtk/fnmatch.h (gtk+/c/19_fnmatch.h 1.1 644)) + (gtk/fnmatch.c (gtk+/c/20_fnmatch.c 1.1 644)) + (TODO (gtk+/c/21_TODO 1.13 644)) + (gtk/Makefile.in (gtk+/c/22_Makefile.i 1.10 644)) + (gtk/Makefile.am (gtk+/c/23_Makefile.a 1.10 644)) + (gdk/makekeysyms.sed (gtk+/c/24_makekeysym 1.1 644)) + (gdk/makekeysyms (gtk+/c/25_makekeysym 1.1 755)) + (gdk/makecursors.sed (gtk+/c/26_makecursor 1.1 644)) + (gdk/makecursors (gtk+/c/27_makecursor 1.1 755)) + (gdk/gdkx.h (gtk+/c/28_gdkx.h 1.2 644)) + (gdk/gdkwindow.c (gtk+/c/29_gdkwindow. 1.8 644)) + (gdk/gdkvisual.c (gtk+/c/30_gdkvisual. 1.2 644)) + (gdk/gdktypes.h (gtk+/c/31_gdktypes.h 1.6 644)) + (gdk/gdkrectangle.c (gtk+/c/32_gdkrectang 1.3 644)) + (gdk/gdkprivate.h (gtk+/c/33_gdkprivate 1.4 644)) + (gdk/gdkpixmap.c (gtk+/c/34_gdkpixmap. 1.6 644)) + (gdk/gdkkeysyms.h (gtk+/c/35_gdkkeysyms 1.2 644)) + (gdk/gdkimage.c (gtk+/c/36_gdkimage.c 1.4 644)) + (gdk/gdkglobals.c (gtk+/c/37_gdkglobals 1.3 644)) + (gdk/gdkgc.c (gtk+/c/38_gdkgc.c 1.6 644)) + (gdk/gdkfont.c (gtk+/c/39_gdkfont.c 1.4 644)) + (gdk/gdkdraw.c (gtk+/c/40_gdkdraw.c 1.4 644)) + (gdk/gdkcursors.h (gtk+/c/41_gdkcursors 1.3 644)) + (gdk/gdkcursor.c (gtk+/c/42_gdkcursor. 1.3 644)) + (gdk/gdkcolor.c (gtk+/c/43_gdkcolor.c 1.4 644)) + (gdk/gdk.h (gtk+/c/44_gdk.h 1.6 644)) + (gdk/gdk.c (gtk+/c/45_gdk.c 1.8 644)) + (gdk/Makefile.in (gtk+/c/46_Makefile.i 1.7 644)) + (gdk/Makefile.am (gtk+/c/47_Makefile.a 1.7 644)) + (glib/testglib.c (gtk+/c/48_testglib.c 1.8 644)) + (glib/stamp-h.in (gtk+/c/49_stamp-h.in 1.1 644)) + (glib/mkinstalldirs (gtk+/c/50_mkinstalld 1.1 755)) + (glib/install-sh (gtk+/c/51_install-sh 1.1 755)) + (glib/gutils.c (gtk+/d/0_gutils.c 1.3 644)) + (glib/gtimer.c (gtk+/d/1_gtimer.c 1.2 644)) + (glib/gslist.c (gtk+/d/2_gslist.c 1.6 644)) + (glib/gprimes.c (gtk+/d/3_gprimes.c 1.2 644)) + (glib/gmem.c (gtk+/d/4_gmem.c 1.9 644)) + (glib/glist.c (gtk+/d/5_glist.c 1.4 644)) + (glib/glib.h (gtk+/d/6_glib.h 1.8 644)) + (glib/ghash.c (gtk+/d/7_ghash.c 1.5 644)) + (glib/gerror.c (gtk+/d/8_gerror.c 1.4 644)) + (glib/gconfig.h.in (gtk+/d/9_gconfig.h. 1.3 644)) + (glib/gconfig.h (gtk+/d/10_gconfig.h 1.6 644)) + (glib/gcache.c (gtk+/d/11_gcache.c 1.6 644)) + (glib/configure.in (gtk+/d/12_configure. 1.4 644)) + (glib/configure (gtk+/d/13_configure 1.4 755)) + (glib/config.sub (gtk+/d/14_config.sub 1.2 755)) + (glib/config.guess (gtk+/d/15_config.gue 1.2 755)) + (glib/aclocal.m4 (gtk+/d/16_aclocal.m4 1.4 644)) + (glib/acconfig.h (gtk+/d/17_acconfig.h 1.3 644)) + (glib/README (gtk+/d/18_README 1.1 644)) + (glib/NEWS (gtk+/d/19_NEWS 1.1 644)) + (glib/Makefile.in (gtk+/d/20_Makefile.i 1.7 644)) + (glib/Makefile.am (gtk+/d/21_Makefile.a 1.7 644)) + (glib/INSTALL (gtk+/d/22_INSTALL 1.1 644)) + (glib/ChangeLog (gtk+/d/23_ChangeLog 1.2 644)) + (glib/COPYING (gtk+/d/24_COPYING 1.1 644)) + (glib/AUTHORS (gtk+/d/25_AUTHORS 1.2 644)) + (stamp-h.in (gtk+/d/26_stamp-h.in 1.1 644)) + (mkinstalldirs (gtk+/d/27_mkinstalld 1.1 755)) + (install-sh (gtk+/d/28_install-sh 1.1 755)) + (configure.in (gtk+/d/30_configure. 1.8 644)) + (configure (gtk+/d/31_configure 1.8 755)) + (config.sub (gtk+/d/32_config.sub 1.2 755)) + (config.h.in (gtk+/d/33_config.h.i 1.4 644)) + (config.guess (gtk+/d/34_config.gue 1.2 755)) + (aclocal.m4 (gtk+/d/35_aclocal.m4 1.4 644)) + (acconfig.h (gtk+/d/36_acconfig.h 1.3 644)) + (README (gtk+/d/37_README 1.1 644)) + (NEWS (gtk+/d/38_NEWS 1.1 644)) + (Makefile.in (gtk+/d/39_Makefile.i 1.9 644)) + (Makefile.am (gtk+/d/40_Makefile.a 1.7 644)) + (INSTALL (gtk+/d/41_INSTALL 1.1 644)) + (ChangeLog (gtk+/d/42_ChangeLog 1.14 644)) + (COPYING (gtk+/d/43_COPYING 1.2 644)) + (AUTHORS (gtk+/d/44_AUTHORS 1.2 644)) + +; Files added by populate at Mon, 30 Dec 1996 13:14:24 -0800: + + (gtk/gtkmenufactory.h (gtk+/0_gtkmenufac 1.4 644)) + (gtk/gtkmenufactory.c (gtk+/1_gtkmenufac 1.4 644)) + +; Files added by populate at Thu, 02 Jan 1997 15:31:44 -0800: + + (gtk/testgtkrc (gtk+/0_testgtkrc 1.2 644)) + + +; Files added by populate at Fri, 10 Jan 1997 14:19:47 -0800: + + (gtk/gtkfilesel.h (gtk+/b/0_gtkfilesel.h 1.3 644)) + (gtk/gtkfilesel.c (gtk+/c/0_gtkfilesel.c 1.7 644)) + (glib/gstring.c (gtk+/d/0_gstring.c 1.4 644)) + +; Files added by populate at Fri, 10 Jan 1997 18:01:19 -0800: + + (gdk/gdkselection.c (gtk+/b/0_gdkselection.c 1.5 644)) + +; Files added by populate at Sun, 19 Jan 1997 18:29:12 -0800: + + (gtk/gtktext.h (gtk+/b/0_gtktext.h 1.4 644)) + (gtk/gtktext.c (gtk+/c/0_gtktext.c 1.7 644)) + (gtk/gtkdialog.h (gtk+/d/0_gtkdialog.h 1.2 644)) + (gtk/gtkdialog.c (gtk+/d/47_gtkdialog. 1.4 644)) + (gdk/gdkxid.c (gtk+/d/48_gdkxid.c 1.2 644)) + +; Files added by populate at Thu, 23 Jan 1997 01:29:17 -0800: + + (gtk/gtknotebook.h (gtk+/b/0_gtknotebook.h 1.3 644)) + (gtk/gtknotebook.c (gtk+/c/0_gtknotebook.c 1.6 644)) + +; Files added by populate at Thu, 23 Jan 1997 02:06:11 -0800: + + (gtk/line-wrap.xbm (gtk+/b/0_line-wrap.xbm 1.1 644)) + (gtk/line-arrow.xbm (gtk+/c/0_line-arrow.xbm 1.1 644)) + +; Files added by populate at Fri, 24 Jan 1997 13:02:44 -0800: + + + + + + +; Files deleted by populate at Fri, 24 Jan 1997 13:02:44 -0800: + + ; `docs/texinfo3.7.patch' + +; Files added by populate at Tue, 28 Jan 1997 16:54:35 -0800: + + (gtk/simple.c (gtk+/e/0_simple.c 1.1 644)) + (glib/ltmain.sh (gtk+/e/1_ltmain.sh 1.3 644)) + (glib/ltconfig (gtk+/e/2_ltconfig 1.3 755)) + (ltmain.sh (gtk+/e/3_ltmain.sh 1.3 644)) + (ltconfig (gtk+/e/4_ltconfig 1.3 755)) + +; Files added by populate at Thu, 30 Jan 1997 01:30:38 -0800: + + (glib/gtree.c (gtk+/b/0_gtree.c 1.3 644)) + +; Files added by populate at Mon, 03 Feb 1997 19:46:14 -0800: + + (makecopyright (gtk+/b/0_makecopyright 1.1 755)) + +; Files added by populate at Sat, 08 Feb 1997 14:41:52 -0800: + + (gtk/gtkprogressbar.h (gtk+/b/0_gtkprogressbar.h 1.1 644)) + (gtk/gtkprogressbar.c (gtk+/c/0_gtkprogressbar.c 1.1 644)) + (glib/garray.c (gtk+/d/0_garray.c 1.1 644)) + +; Files deleted by populate at Sat, 08 Feb 1997 14:41:52 -0800: + + ; `interp/Makefile.am' + ; `interp/Makefile.in' + ; `interp/interp.c' + +;; Files added by populate at Wed, 19 Feb 1997 15:48:04 -0800: + + (gtk+.xconfig.in (gtk+/b/0_gtk+.xconfig.in 1.1 644)) + +;; Files deleted by populate at Wed, 19 Feb 1997 15:48:04 -0800: + + ; docs/proposal.tex + +;; Files added by populate at Thu, 17 Apr 1997 17:39:47 -0700: + + (docs/macros.texi ()) + (gdk/gdkproperty.c ()) + (glib/missing () :symlink) + (missing () :symlink) + +;; Files deleted by populate at Thu, 17 Apr 1997 17:39:47 -0700: + + ; gtk/gtkcanvas.c + ; gtk/gtkcanvas.h + ; gtk/gtkfill.c + ; gtk/gtkfill.h + +;; Files added by populate at Thu, 17 Apr 1997 17:41:14 -0700: + + (gtk/gtktooltips.h ()) + (gtk/gtktooltips.c ()) + (gtk/gtkradiomenuitem.h ()) + (gtk/gtkradiomenuitem.c ()) + (gtk/gtkpreview.h ()) + (gtk/gtkpreview.c ()) + (gtk/gtkcolorsel.h ()) + (gtk/gtkcolorsel.c ()) + (gtk/gtkcheckmenuitem.h ()) + (gtk/gtkcheckmenuitem.c ()) + (gtk/gtkaspectframe.h ()) + (gtk/gtkaspectframe.c ()) +) +(Merge-Parents) +(New-Merge-Parents) diff --git a/gtk+.xconfig.in b/gtk+.xconfig.in new file mode 100644 index 000000000..8843df6ce --- /dev/null +++ b/gtk+.xconfig.in @@ -0,0 +1,3 @@ +X_CFLAGS = @x_cflags@ +X_LDFLAGS = @x_ldflags@ +X_LIBS = @x_libs@ diff --git a/gtk/.cvsignore b/gtk/.cvsignore new file mode 100644 index 000000000..e5ac5d91d --- /dev/null +++ b/gtk/.cvsignore @@ -0,0 +1,9 @@ +*.lo +Makefile +.deps +_libs +libgtk.la +testgtk +testinput +testselection +simple diff --git a/gtk/3DRings.xpm b/gtk/3DRings.xpm new file mode 100644 index 000000000..1ca75da75 --- /dev/null +++ b/gtk/3DRings.xpm @@ -0,0 +1,116 @@ +/* XPM */ +static char * DRings_xpm[] = { +"48 48 65 1", +" c None", +". c #104010404103", +"X c #1040208130C2", +"o c #104014515144", +"O c #000010402081", +"+ c #1040104030C2", +"@ c #208120815144", +"# c #28A241035965", +"$ c #30C230C26185", +"% c #208130C24103", +"& c #104010402081", +"* c #104000002081", +"= c #000010401040", +"- c #492441036185", +"; c #596559659E79", +": c #30C220815144", +"> c #0820186128A2", +", c #000000001040", +"< c #2081104030C2", +"1 c #514459659658", +"2 c #514455556185", +"3 c #104000001040", +"4 c #000008200000", +"5 c #618569A6AEBA", +"6 c #618569A69658", +"7 c #410345148E38", +"8 c #104020814103", +"9 c #79E782079658", +"0 c #208120814103", +"q c #596571C69E79", +"w c #4103514471C6", +"e c #2081208130C2", +"r c #6185618571C6", +"t c #28A228A25965", +"y c #596561858617", +"u c #96589E79BEFB", +"i c #28A230C271C6", +"p c #38E345145144", +"a c #79E78207A699", +"s c #30C2492469A6", +"d c #410330C25965", +"f c #410351446185", +"g c #AEBAAAAAD75C", +"h c #38E338E34103", +"j c #EFBEEBADEFBE", +"k c #208130C25144", +"l c #9658A289DF7D", +"z c #208110404103", +"x c #28A228A26185", +"c c #8E388A28BEFB", +"v c #208118612081", +"b c #38E3451479E7", +"n c #4924618579E7", +"m c #86178617B6DA", +"M c #30C220814103", +"N c #104030C25144", +"B c #4103410371C6", +"V c #86178A28D75C", +"C c #DF7DDB6CE79D", +"Z c #BEFBC30BD75C", +"A c #410330C271C6", +"S c #30C228A230C2", +"D c #082008201861", +"F c #186130C238E3", +"G c #0000208130C2", +" .Xo ", +" O+O@#$% ", +" &*=+X-;: ", +" >&=,=<11#2 ", +" +O34,X567& ", +" 8X+=,90q9w. ", +" +e<>3r tyu-& ", +" Xi%.= paus+ ", +" Od-@= fga$h ", +" @y7X, Xrjak ", +" 2:eaw+ $ag;@ ", +" .X@8@k@o@X+ +pl9tO ", +" +zX@x$$isikt8o02crv ", +" 8@%ip7757ywbs$Ohn6#. ", +" &0%$p7r215ybw1pzp2-0= ", +" 8tk$#yw21665n;1+%-p$O ", +" O3& ", +" 9.NtpBw16amclVcm1t%kX*88 ", +" +&etd7r6y9ulgglm6>e>3s@83 ", +" +0k$y-y69cgCCCZVam%+#ik8X ", +" O&oi$d725amgCjCZu962ybtx8+p ", +" &X0x$sBym9VZCCCZca;yBbi%08& ", +" =++@sApMy5muZZgum6y2wds:>+& ", +" #tp;1;yB#i25cVucma5;w-pti@8& ", +" .#2alumnBp:@1r59y9y6ywBS$%0X+= ", +" %$wmZVu;#tX8X07r1656y2wbp$k@%@OD ", +" 0Byc9a;h%0>&D&hBrr2r1bwB-AF:0<&*= ", +" kBf;yr#@X+&<%MkhsBwBwpsB#Bktkt8+Oh ", +" xt7B-t8*,3O.X00:$i#dBd#bptFek0X.+* ", +" Xt#b#@=, =&O+X0Ft%ibsp$p$ki%l5sX&= ", +" &+Xt>tktktv0%@k;Cls+ ", +" =+O*4*X:p;9cy3&&8ve0FMtt$ee0>z7cZ6k ", +" D=D4,=.k$sBs$ee=+X0Fk%-#t%0X&O0nu9bG ", +" ,,434*&ze@F&D =0S-2i& ", +" +>puB> >0h7s. ", +" SM5VqM &0t#$8 ", +" XpVV70 &0kMk. ", +" XdyB%z *X<%@+ ", +" &k$b0X+=8X08o ", +" &e:e+=*X.X+& ", +" +X.O+X0O.=, ", +" +>&+0>3&* ", +" &X0k+O, ", +" >v,3 ", +" "}; diff --git a/gtk/FilesQueue.xpm b/gtk/FilesQueue.xpm new file mode 100644 index 000000000..586d27ec4 --- /dev/null +++ b/gtk/FilesQueue.xpm @@ -0,0 +1,98 @@ +/* XPM */ +static char * FilesQueue_xpm[] = { +"44 31 64 1", +" c None", +". c #E79DE38DDF7D", +"X c #CF3CC71BCF3C", +"o c #71C675D671C6", +"O c #B6DAB2CAB6DA", +"+ c #CF3CD34CCF3C", +"@ c #DF7DE38DE79D", +"# c #FFFFFBEEFFFF", +"$ c #EFBEEFBEEFBE", +"% c #DF7DDB6CDF7D", +"& c #BEFBBAEAC71B", +"* c #BEFBBAEABEFB", +"= c #BEFBC30BC71B", +"- c #71C66DB671C6", +"; c #D75CD34CD75C", +": c #9E799A699E79", +"> c #E79DE38DE79D", +", c #CF3CCB2BC71B", +"< c #B6DAB2CABEFB", +"1 c #BEFBBAEAB6DA", +"2 c #B6DAB6DAB6DA", +"3 c #618561856185", +"4 c #C71BBAEABEFB", +"5 c #AEBAAAAAAEBA", +"6 c #965892488E38", +"7 c #A699A699A699", +"8 c #38E338E338E3", +"9 c #F7DEF7DEF7DE", +"0 c #E79DEFBEEFBE", +"q c #DF7DE38DDF7D", +"w c #C71BC71BC71B", +"e c #C71BC30BBEFB", +"r c #BEFBC30BBEFB", +"t c #B6DAAAAAAEBA", +"y c #410345144103", +"u c #D75CDB6CD75C", +"i c #C71BCB2BC71B", +"p c #BEFBCB2BBEFB", +"a c #9E79A289A699", +"s c #86178E388E38", +"d c #CF3CCF3CD75C", +"f c #CF3CD75CCF3C", +"g c #C71BC30BCF3C", +"h c #28A22CB228A2", +"j c #000000000000", +"k c #D75CD34CDF7D", +"l c #10400C300820", +"z c #E79DEBADEFBE", +"x c #DF7DDB6CD75C", +"c c #514459655965", +"v c #8617861779E7", +"b c #DF7DD34CD75C", +"n c #CF3CCB2BCF3C", +"m c #618555555965", +"M c #861786178617", +"N c #30C234D330C2", +"B c #EFBEEBADE79D", +"V c #DF7DDB6CE79D", +"C c #D75CE38DD75C", +"Z c #514449245144", +"A c #186120812081", +"S c #79E77DF779E7", +"D c #6185659569A6", +"F c #9E7992489E79", +" .XoOX+ ", +" @#$%&*=-o;: ", +" @>,=O<12*&:-<3X ", +" >%&1*4*2*OO**56758790 ", +" 9qX+we=r*&e<<<251t5555yu9 ", +" $qu++;ipi=p*=p**2tOOO27a5s<- ", +" #9udfXi;,gi&**4**4r*Ot5t55tehj ", +" 0qku+u;+d,gg=*=r*&**&<255t<*yl1 ", +" $$zq@%xk%uf;,w,i=i=e**r=12tO1=8cvj ", +" $@%>.%.%%%xbkx,w+ni,wwrwe*4*1=;8mMNj ", +" zz@Bz>>>V%%%C+u;;dfnnfwggi&=&X+yZsNll ", +" af#9@B0>q>qqq>xk.;;;kfX+XnXw=g,fycMhhN5 ", +" al5#9$$>qzBV.%x%%b;x+fnf+,X,iiqym6NAo-j ", +" #roS%#$zz>>V%%xkk%f;;+df,XnwnVZD:8AS-j* ", +" D-9Oy*9$Bz>q%qx%%u;x;;dknX+d>Zm:hhSDjr ", +" a3o+>S3z#90@@z.%>qCC%uu;ff%@Zm:NhMoj= ", +" wlvvo#:3599$>B>q>%%%%+f;fk$ymaalMvjr ", +" 0.a--S49mct9$z@.qkkqC;xu%@Zm5AlvSj* ", +" ohu%3:Z:9@y609q@@>..>Cx>$Zm5NhMvjr ", +" -j797Zv5705y=#$0>>V.%>#Z378AMMj* ", +" Zj9Xo-McBXDv%90.%%#9cc78AsMj* ", +" 8hM#M-DSF96cvz0>z#c35Nhs6j1 ", +" jl9#o63vx#-D###mmt8N66j* ", +" 5jc@fZF3o%+ZFDm<8A6FjO ", +" :j50sSay<$ss2Nh:FjO ", +" 6880&SDMF.rNNFFj1 ", +" 8jr#:SFScA6ajO ", +" Alr$DSysajO ", +" >jy#51:jO ", +" %Dy*gjO ", +" alla "}; diff --git a/gtk/Makefile.am b/gtk/Makefile.am new file mode 100644 index 000000000..60d43b1d2 --- /dev/null +++ b/gtk/Makefile.am @@ -0,0 +1,248 @@ +## Process this file with automake to produce Makefile.in + +gtkincludedir = $(includedir)/gtk + +lib_LTLIBRARIES = libgtk.la + +libgtk_la_SOURCES = \ + gtkaccelerator.c \ + gtkadjustment.c \ + gtkaspectframe.c \ + gtkalignment.c \ + gtkarrow.c \ + gtkbin.c \ + gtkbbox.c \ + gtkbox.c \ + gtkbutton.c \ + gtkcheckbutton.c \ + gtkcheckmenuitem.c \ + gtkcolorsel.c \ + gtkcontainer.c \ + gtkcurve.c \ + gtkdata.c \ + gtkdialog.c \ + gtkdrawingarea.c \ + gtkentry.c \ + gtkeventbox.c \ + gtkfilesel.c \ + gtkfixed.c \ + gtkframe.c \ + gtkgamma.c \ + gtkgc.c \ + gtkhbbox.c \ + gtkhbox.c \ + gtkhpaned.c \ + gtkhruler.c \ + gtkhscale.c \ + gtkhscrollbar.c \ + gtkhseparator.c \ + gtkimage.c \ + gtkinputdialog.c \ + gtkitem.c \ + gtklabel.c \ + gtklist.c \ + gtklistitem.c \ + gtkmain.c \ + gtkmenu.c \ + gtkmenubar.c \ + gtkmenufactory.c \ + gtkmenuitem.c \ + gtkmenushell.c \ + gtkmisc.c \ + gtknotebook.c \ + gtkobject.c \ + gtkoptionmenu.c \ + gtkpaned.c \ + gtkpixmap.c \ + gtkpreview.c \ + gtkprogressbar.c \ + gtkradiobutton.c \ + gtkradiomenuitem.c \ + gtkrange.c \ + gtkrc.c \ + gtkruler.c \ + gtkscale.c \ + gtkscrollbar.c \ + gtkscrolledwindow.c \ + gtkselection.c \ + gtkseparator.c \ + gtksignal.c \ + gtkstyle.c \ + gtktable.c \ + gtktext.c \ + gtktogglebutton.c \ + gtktooltips.c \ + gtktree.c \ + gtktreeitem.c \ + gtktypeutils.c \ + gtkvbbox.c \ + gtkvbox.c \ + gtkviewport.c \ + gtkvpaned.c \ + gtkvruler.c \ + gtkvscale.c \ + gtkvscrollbar.c \ + gtkvseparator.c \ + gtkwidget.c \ + gtkwindow.c \ + fnmatch.c \ + fnmatch.h + +gtkinclude_HEADERS = \ + gtk.h \ + gtkaccelerator.h \ + gtkadjustment.h \ + gtkaspectframe.h \ + gtkalignment.h \ + gtkarrow.h \ + gtkbin.h \ + gtkbbox.h \ + gtkbox.h \ + gtkbutton.h \ + gtkcheckbutton.h \ + gtkcheckmenuitem.h \ + gtkcolorsel.h \ + gtkcontainer.h \ + gtkcurve.h \ + gtkdata.h \ + gtkdialog.h \ + gtkdrawingarea.h \ + gtkentry.h \ + gtkenums.h \ + gtkeventbox.h \ + gtkfilesel.h \ + gtkfixed.h \ + gtkframe.h \ + gtkgamma.h \ + gtkgc.h \ + gtkhbbox.h \ + gtkhbox.h \ + gtkhpaned.h \ + gtkhruler.h \ + gtkhscale.h \ + gtkhscrollbar.h \ + gtkhseparator.h \ + gtkimage.h \ + gtkinputdialog.h \ + gtkitem.h \ + gtklabel.h \ + gtklist.h \ + gtklistitem.h \ + gtkmain.h \ + gtkmenu.h \ + gtkmenubar.h \ + gtkmenufactory.h \ + gtkmenuitem.h \ + gtkmenushell.h \ + gtkmisc.h \ + gtknotebook.h \ + gtkobject.h \ + gtkoptionmenu.h \ + gtkpaned.h \ + gtkpixmap.h \ + gtkpreview.h \ + gtkprogressbar.h \ + gtkradiobutton.h \ + gtkradiomenuitem.h \ + gtkrange.h \ + gtkrc.h \ + gtkruler.h \ + gtkscale.h \ + gtkscrollbar.h \ + gtkscrolledwindow.h \ + gtkselection.h \ + gtkseparator.h \ + gtksignal.h \ + gtkstyle.h \ + gtktable.h \ + gtktext.h \ + gtktogglebutton.h \ + gtktooltips.h \ + gtktree.h \ + gtktreeitem.h \ + gtktypeutils.h \ + gtkvbbox.h \ + gtkvbox.h \ + gtkviewport.h \ + gtkvpaned.h \ + gtkvruler.h \ + gtkvscale.h \ + gtkvscrollbar.h \ + gtkvseparator.h \ + gtkwidget.h \ + gtkwindow.h \ + gtktypebuiltins.h + +../gtk/gtktypebuiltins.h: gtk.defs gentypeinfo.el + $(srcdir)/runelisp $(srcdir)/gentypeinfo.el idmac $< $@ + +gtktypebuiltins.c: gtk.defs gentypeinfo.el + $(srcdir)/runelisp $(srcdir)/gentypeinfo.el id $< $@ + +libgtk_la_LDFLAGS = -version-info 1:0: + +EXTRA_DIST = \ + line-arrow.xbm \ + line-wrap.xbm \ + testgtkrc \ + gtk.defs \ + runelisp \ + gentypeinfo.el \ + gtktypebuiltins.c \ + test.xpm \ + marble.xpm \ + 3DRings.xpm \ + FilesQueue.xpm \ + Modeller.xpm + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/glib @x_cflags@ + +noinst_PROGRAMS = testgtk testinput testselection simple +testgtk_LDADD = \ + libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + @x_ldflags@ \ + @x_libs@ \ + $(top_builddir)/glib/libglib.la \ + -lm + +testinput_LDADD = \ + libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + @x_ldflags@ \ + @x_libs@ \ + $(top_builddir)/glib/libglib.la \ + -lm + +testselection_LDADD = \ + libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + @x_ldflags@ \ + @x_libs@ \ + $(top_builddir)/glib/libglib.la \ + -lm + +simple_LDADD = \ + libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + @x_ldflags@ \ + @x_libs@ \ + $(top_builddir)/glib/libglib.la \ + -lm + +DEPS = \ + $(top_builddir)/gtk/libgtk.la \ + $(top_builddir)/gdk/libgdk.la \ + $(top_builddir)/glib/libglib.la + +testgtk_DEPENDENCIES = $(DEPS) +testinput_DEPENDENCIES = $(DEPS) +testselection_DEPENDENCIES = $(DEPS) +simple_DEPENDENCIES = $(DEPS) + +.PHONY: files + +files: + @files=`ls $(DISTFILES) 2> /dev/null `; for p in $$files; do \ + echo $$p; \ + done diff --git a/gtk/Modeller.xpm b/gtk/Modeller.xpm new file mode 100644 index 000000000..62e27f985 --- /dev/null +++ b/gtk/Modeller.xpm @@ -0,0 +1,117 @@ +/* XPM */ +static char * InterfaceModeller_app_2_Tile_xpm[] = { +"48 48 66 1", +" c None", +". c #86174D344103", +"X c #69A651445144", +"o c #8617410330C2", +"O c #69A6410338E3", +"+ c #30C218611861", +"@ c #AEBA6DB66185", +"# c #71C638E328A2", +"$ c #69A634D328A2", +"% c #30C228A228A2", +"& c #79E73CF330C2", +"* c #BEFB9E799E79", +"= c #8E3869A66185", +"- c #514424921861", +"; c #A699A289B6DA", +": c #A6999E79A699", +"> c #71C65D756185", +", c #9E799A69A699", +"< c #8E3882078E38", +"1 c #861779E78617", +"2 c #A6999A69AEBA", +"3 c #8E388A289658", +"4 c #71C675D679E7", +"5 c #96588A289E79", +"6 c #30C230C238E3", +"7 c #C71BC71BC71B", +"8 c #9E79A289AEBA", +"9 c #AEBAAAAABEFB", +"0 c #96589248A699", +"q c #A699AAAAB6DA", +"w c #AEBAAAAAB6DA", +"e c #D75CD34CD75C", +"r c #EFBEE79DEFBE", +"t c #BEFBB6DABEFB", +"y c #B6DABAEAC71B", +"u c #AEBAAEBAB6DA", +"i c #E79DDB6CDF7D", +"p c #96588E389658", +"a c #596559656185", +"s c #AEBA8E388E38", +"d c #CF3CCB2BCF3C", +"f c #9E799A699E79", +"g c #86177DF78E38", +"h c #69A6659571C6", +"j c #AEBAAEBABEFB", +"k c #96589E799E79", +"l c #B6DAA699A699", +"z c #E79DC71BC71B", +"x c #B6DAB6DAB6DA", +"c c #861786179658", +"v c #B6DAB2CABEFB", +"b c #BEFBAAAAAEBA", +"n c #C71BBEFBC71B", +"m c #514441034103", +"M c #41033CF34103", +"N c #492428A228A2", +"B c #AEBAA289B6DA", +"V c #618530C22081", +"C c #69A630C228A2", +"Z c #69A630C22081", +"A c #596528A22081", +"S c #492428A22081", +"D c #618528A22081", +"F c #596520811861", +"G c #69A628A22081", +"H c #FFFF14514103", +" .X ", +" .oO+ ", +" @.o#++ ", +" @.o$%+ ", +" @.&#++ ", +" @.o#++ ", +" @.o$++ ", +" @.&#++ ", +" .O#++ ", +" *=-$++ ", +" ;:>+++ ", +" ;,<1% ", +" 2,34 ", +" 2;,51 ", +" 2,,,,6 ", +" 7777 28888,6 ", +" 77777777 2829,,,06 ", +" 9qwwe7rrrrr77rr 828,9tyt,6 ", +" uuwriirrieiiieii77pa< 82,8,,,8,06 ", +" s=1ttiieeeeded77eufgh>j,8,8,k,0,6 ", +" =@lzieeeeee77eeex:fpcg4>9,,,,qjv6 ", +" =O=blt7eeee7deenw:ffpmV##&&O$mX ", +" =O&&o....zrrieieuxunx7txx:nnfwpMmVZ#$ZZZVVN ", +" =O&oooo.*rrde77ewxnxxtnw:f4M%M%+NA#$Z$ZZVmN> ", +" =Oo&ooo@iree7inxn7nnuuff4h%M>m%S-AZ$CCZDZmSX ", +" =O&o.o.@rrn7eulun7xxuwp4mm6ahM%--AZCCZDDDANX ", +" =Ooooo.*rixenuwwn7nxupph%M>>h6mAADVVZVVDDANX ", +" =O&o.o.zrexwwnwuxxnughX%mahhmMN-AZCCVVDDAAN> ", +" *XOoo.*iin7n777xxxtphaM+ama>MSNFVCZZVVDAAAS> ", +" 1O..izewxux7nuuux4%++%hha>%N-DDCZZVDAAAASX ", +" 1.=ituu:uButnxxuX%>hh>M%++NADZZZVDADAA--X ", +" :e7f::lnn7*ppnx6ahm6++mNN-ADCZVDDAAAA-SX ", +" 7nupp:wxxg%MMau6%++NmmmADADVVVVVDAA---NX ", +" 7uBgh1wwxg6h>m%:MmmVNAVDZVZCVZZDAAAAF-S+X ", +" nfgaM%pnwhX6%mXb6$DVVZC$C#C$ZZDVAAA---+NX ", +" 27a%MaM47:mN.OoolmODGZ####$$ZZVDDA-----SSX ", +" 2gmg paMa HX.@@@oZ$###$$CZVDDAAAA---SS+X ", +" 43 p=&@@&&$##$CCCVVVAAA--+S+S+%X ", +" k =o@.##$VVmmmNNNSSSSSS%XXXX ", +" s>OSSNmN>>aaa177777 "}; diff --git a/gtk/fnmatch.c b/gtk/fnmatch.c new file mode 100644 index 000000000..0a45770a4 --- /dev/null +++ b/gtk/fnmatch.c @@ -0,0 +1,200 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library 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. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include "fnmatch.h" +#include + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +extern int errno; +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + register const char *p = pattern, *n = string; + register char c; + +/* Note that this evalutes C many times. */ +#define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c)) + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + c = FOLD (c); + } + if (FOLD (*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_FILE_NAME) && *n == '/') || + (c == '?' && *n == '\0')) + return FNM_NOMATCH; + + if (c == '\0') + return 0; + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD (*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD (*n) >= cstart && FOLD (*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD (*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/gtk/fnmatch.h b/gtk/fnmatch.h new file mode 100644 index 000000000..d9d73b3d8 --- /dev/null +++ b/gtk/fnmatch.h @@ -0,0 +1,67 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library 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. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(protos) protos +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(protos) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in . */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((const char *__pattern, const char *__string, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/gtk/gentypeinfo.el b/gtk/gentypeinfo.el new file mode 100644 index 000000000..2de6a92d2 --- /dev/null +++ b/gtk/gentypeinfo.el @@ -0,0 +1,137 @@ +(require 'cl) + +;;; file access + +(defun read-file (name) + (let ((buf (generate-new-buffer "infile")) + (res nil)) + (save-excursion + (set-buffer buf) + (insert-file-contents name) + (condition-case nil + (while t + (setq res (cons (read buf) res))) + (end-of-file (reverse res)))))) + +(defun setup-outfile () + (setq standard-output (generate-new-buffer "outfile"))) + +(defun write-outfile (name) + (save-excursion + (set-buffer standard-output) + (write-region (point-min) (point-max) name))) + +;;; string stunts + +(defun char-upper-case-p (ch) + (eql (upcase ch) ch)) + +(defun char-lower-case-p (ch) + (eql (downcase ch) ch)) + +(defun canonicalize (str) + (if (symbolp str) + (setq str (symbol-name str))) + (let ((res nil) + (start 0) + (pos 0) + (end (length str)) + (prevlower nil)) + (while (< pos end) + (let ((ch (elt str pos))) + (cond ((memq ch '(?- ?_)) + (setq res (cons (substring str start pos) res) + prevlower nil + pos (1+ pos) + start pos)) + ((and (char-upper-case-p ch) + prevlower) + (setq res (cons (substring str start pos) res) + start pos + pos (1+ pos) + prevlower nil)) + (t + (setq pos (1+ pos) + prevlower (char-lower-case-p ch)))))) + (reverse (mapcar 'downcase (cons (substring str start end) res))))) + +(defun syllables-to-string (syls del) + (let ((res "")) + (while syls + (setq res (format "%s%s%s" res (car syls) + (if (cdr syls) del "")) + syls (cdr syls))) + res)) + +(defun macroname (canon) + (syllables-to-string (mapcar 'upcase canon) "_")) + +(defun funcname (canon) + (syllables-to-string canon "_")) + +(defun typename (canon) + (syllables-to-string (mapcar 'capitalize canon) "")) + +(defun scmname (canon) + (syllables-to-string canon "-")) + +(defun short-name (canon) + (if (equal (car canon) "gtk") (cdr canon) canon)) + +;;; Code generation + +(defun printf (&rest args) + (princ (apply 'format args))) + +(defun interestingp (form) + (and (listp form) + (memq (car form) '(define-enum define-flags define-boxed)))) + +(defun map-interesting (func defs) + (mapcar #'(lambda (form) + (if (interestingp form) + (funcall func form))) + defs)) + +(defun emit-idmacs (defs) + (let ((i 0)) + (map-interesting + #'(lambda (form) + (let ((name (canonicalize (cadr form)))) + (printf "#define GTK_TYPE_%s (gtk_type_builtins[%d])\n" + (macroname (short-name name)) i)) + (setq i (1+ i))) + defs) + (printf "#define GTK_TYPE_NUM_BUILTINS %d\n" i))) + +(defun emit-ids (defs) + (map-interesting + #'(lambda (form) + (printf " { %S, %s },\n" + (symbol-name (cadr form)) + (case (car form) + ((define-enum) "GTK_TYPE_ENUM") + ((define-flags) "GTK_TYPE_FLAGS") + ((define-boxed) "GTK_TYPE_BOXED")))) + defs)) + + + +(if (< (length command-line-args-left) 3) + (error "args: op def-file output-file")) + +(setq op (intern (car command-line-args-left))) +(setq defs (read-file (cadr command-line-args-left))) +(setq outfile (caddr command-line-args-left)) +(setq command-line-args-left nil) + +(setup-outfile) +(printf "/* generated by gentypeinfo from \"gtk.defs\" */\n\n") +(case op + ((idmac) + (emit-idmacs defs)) + ((id) + (emit-ids defs)) + (else + (error "supported ops are: idmac id"))) +(write-outfile outfile) diff --git a/gtk/gtk.defs b/gtk/gtk.defs new file mode 100644 index 000000000..0228e7a8b --- /dev/null +++ b/gtk/gtk.defs @@ -0,0 +1,810 @@ +; -*- scheme -*- + +;;; Gtk enums + +(define-enum GtkWindowType + (toplevel GTK_WINDOW_TOPLEVEL) + (dialog GTK_WINDOW_DIALOG) + (popup GTK_WINDOW_POPUP)) + +(define-enum GtkStateType + (normal GTK_STATE_NORMAL) + (active GTK_STATE_ACTIVE) + (prelight GTK_STATE_PRELIGHT) + (selected GTK_STATE_SELECTED) + (insensitive GTK_STATE_INSENSITIVE)) + +(define-enum GtkDirectionType + (tab-forward GTK_DIR_TAB_FORWARD) + (tab-backward GTK_DIR_TAB_BACKWARD) + (up GTK_DIR_UP) + (down GTK_DIR_DOWN) + (left GTK_DIR_LEFT) + (right GTK_DIR_RIGHT)) + +(define-enum GtkShadowType + (none GTK_SHADOW_NONE) + (in GTK_SHADOW_IN) + (out GTK_SHADOW_OUT) + (etched-in GTK_SHADOW_ETCHED_IN) + (etched-out GTK_SHADOW_ETCHED_OUT)) + +(define-enum GtkArrowType + (up GTK_ARROW_UP) + (down GTK_ARROW_DOWN) + (left GTK_ARROW_LEFT) + (right GTK_ARROW_RIGHT)) + +(define-enum GtkPackType + (start GTK_PACK_START) + (end GTK_PACK_END)) + +(define-enum GtkPolicyType + (always GTK_POLICY_ALWAYS) + (automatic GTK_POLICY_AUTOMATIC)) + +(define-enum GtkUpdateType + (continous GTK_UPDATE_CONTINUOUS) + (discontinous GTK_UPDATE_DISCONTINUOUS) + (delayed GTK_UPDATE_DELAYED)) + +(define-flags GtkAttachOptions + (expand GTK_EXPAND) + (shrink GTK_SHRINK) + (fill GTK_FILL)) + +(define-flags GtkSignalRunType + (first GTK_RUN_FIRST) + (last GTK_RUN_LAST) + (both GTK_RUN_BOTH) + (mask GTK_RUN_MASK) + (no-recurse GTK_RUN_NO_RECURSE)) + +(define-enum GtkWindowPosition + (none GTK_WIN_POS_NONE) + (center GTK_WIN_POS_CENTER) + (mouse GTK_WIN_POS_MOUSE)) + +(define-enum GtkSubmenuDirection + (left GTK_DIRECTION_LEFT) + (right GTK_DIRECTION_RIGHT)) + +(define-enum GtkSubmenuPlacement + (top-bottom GTK_TOP_BOTTOM) + (left-right GTK_LEFT_RIGHT)) + +(define-enum GtkMenuFactoryType + (menu GTK_MENU_FACTORY_MENU) + (menu-bar GTK_MENU_FACTORY_MENU_BAR) + (option-menu GTK_MENU_FACTORY_OPTION_MENU)) + +(define-enum GtkMetricType + (pixels GTK_PIXELS) + (inches GTK_INCHES) + (centimeters GTK_CENTIMETERS)) + +(define-enum GtkScrollType + (none GTK_SCROLL_NONE) + (step-backward GTK_SCROLL_STEP_BACKWARD) + (step-forward GTK_SCROLL_STEP_FORWARD) + (page-backward GTK_SCROLL_PAGE_BACKWARD) + (page-forward GTK_SCROLL_PAGE_FORWARD)) + +(define-enum GtkTroughType + (none GTK_TROUGH_NONE) + (start GTK_TROUGH_START) + (end GTK_TROUGH_END)) + +(define-enum GtkPositionType + (left GTK_POS_LEFT) + (right GTK_POS_RIGHT) + (top GTK_POS_TOP) + (bottom GTK_POS_BOTTOM)) + +(define-enum GtkPreviewType + (color GTK_PREVIEW_COLOR) + (grayscale GTK_PREVIEW_GRAYSCALE)) + +(define-flags GtkWidgetFlags + (visible GTK_VISIBLE) + (mapped GTK_MAPPED) + (unmapped GTK_UNMAPPED) + (realized GTK_REALIZED) + (sensitive GTK_SENSITIVE) + (parent-sensitive GTK_PARENT_SENSITIVE) + (no-window GTK_NO_WINDOW) + (has-focus GTK_HAS_FOCUS) + (can-focus GTK_CAN_FOCUS) + (has-default GTK_HAS_DEFAULT) + (can-default GTK_CAN_DEFAULT) + (propagate-state GTK_PROPAGATE_STATE) + (anchored GTK_ANCHORED) + (basic GTK_BASIC) + (user-style GTK_USER_STYLE)) + +;;; Gdk enums + +(define-enum GdkWindowType + (root GDK_WINDOW_ROOT) + (toplevel GDK_WINDOW_TOPLEVEL) + (child GDK_WINDOW_CHILD) + (dialog GDK_WINDOW_DIALOG) + (temp GDK_WINDOW_TEMP) + (pixmap GDK_WINDOW_PIXMAP)) + +(define-enum GdkWindowClass + (input-output GDK_INPUT_OUTPUT) + (input-only GDK_INPUT_ONLY)) + +(define-enum GdkImageType + (normal GDK_IMAGE_NORMAL) + (shared GDK_IMAGE_SHARED) + (fastest GDK_IMAGE_FASTEST)) + +(define-enum GdkVisualType + (static-gray GDK_VISUAL_STATIC_GRAY) + (grayscale GDK_VISUAL_GRAYSCALE) + (static-color GDK_VISUAL_STATIC_COLOR) + (pseudo-color GDK_VISUAL_PSEUDO_COLOR) + (true-color GDK_VISUAL_TRUE_COLOR) + (direct-color GDK_VISUAL_DIRECT_COLOR)) + +(define-flags GdkWindowAttributesType + (title GDK_WA_TITLE) + (x GDK_WA_X) + (y GDK_WA_Y) + (cursor GDK_WA_CURSOR) + (colormap GDK_WA_COLORMAP) + (visual GDK_WA_VISUAL)) + +(define-flags GdkWindowHints + (pos GDK_HINT_POS) + (min-size GDK_HINT_MIN_SIZE) + (max-size GDK_HINT_MAX_SIZE)) + +(define-enum GdkFunction + (copy GDK_COPY) + (invert GDK_INVERT) + (xor GDK_XOR)) + +(define-enum GdkFill + (solid GDK_SOLID) + (tiled GDK_TILED) + (stippled GDK_STIPPLED) + (opaque-stippled GDK_OPAQUE_STIPPLED)) + +(define-enum GdkLineStyle + (solid GDK_LINE_SOLID) + (on-off-dash GDK_LINE_ON_OFF_DASH) + (double-dash GDK_LINE_DOUBLE_DASH)) + +(define-enum GdkCapStyle + (not-last GDK_CAP_NOT_LAST) + (butt GDK_CAP_BUTT) + (round GDK_CAP_ROUND) + (projecting GDK_CAP_PROJECTING)) + +(define-enum GdkJoinStyle + (miter GDK_JOIN_MITER) + (round GDK_JOIN_ROUND) + (bevel GDK_JOIN_BEVEL)) + +(define-enum GdkCursorType + (cursor GDK_LAST_CURSOR)) + +(define-enum GdkEventType + (nothing GDK_NOTHING) + (delete GDK_DELETE) + (destroy GDK_DESTROY) + (expose GDK_EXPOSE) + (motion-notify GDK_MOTION_NOTIFY) + (button-press GDK_BUTTON_PRESS) + (2button-press GDK_2BUTTON_PRESS) + (3button-press GDK_3BUTTON_PRESS) + (button-release GDK_BUTTON_RELEASE) + (key-press GDK_KEY_PRESS) + (key-release GDK_KEY_RELEASE) + (enter-notify GDK_ENTER_NOTIFY) + (leave-notify GDK_LEAVE_NOTIFY) + (focus-change GDK_FOCUS_CHANGE) + (configure GDK_CONFIGURE) + (map GDK_MAP) + (unmap GDK_UNMAP) + (property-notify GDK_PROPERTY_NOTIFY) + (selection-clear GDK_SELECTION_CLEAR) + (selection-request GDK_SELECTION_REQUEST) + (selection-notify GDK_SELECTION_NOTIFY) + (other-event GDK_OTHER_EVENT)) + +(define-flags GdkEventMask + (exposure-mask GDK_EXPOSURE_MASK) + (pointer-motion-mask GDK_POINTER_MOTION_MASK) + (pointer-motion-hint-mask GDK_POINTER_MOTION_HINT_MASK) + (button-motion-mask GDK_BUTTON_MOTION_MASK) + (button1-motion-mask GDK_BUTTON1_MOTION_MASK) + (button2-motion-mask GDK_BUTTON2_MOTION_MASK) + (button3-motion-mask GDK_BUTTON3_MOTION_MASK) + (button-press-mask GDK_BUTTON_PRESS_MASK) + (button-release-mask GDK_BUTTON_RELEASE_MASK) + (key-press-mask GDK_KEY_PRESS_MASK) + (key-release-mask GDK_KEY_RELEASE_MASK) + (enter-notify-mask GDK_ENTER_NOTIFY_MASK) + (leave-notify-mask GDK_LEAVE_NOTIFY_MASK) + (focus-change-mask GDK_FOCUS_CHANGE_MASK) + (structure-mask GDK_STRUCTURE_MASK) + (all-events-mask GDK_ALL_EVENTS_MASK)) + +(define-enum GdkNotifyType + (ancestor GDK_NOTIFY_ANCESTOR) + (virtual GDK_NOTIFY_VIRTUAL) + (inferior GDK_NOTIFY_INFERIOR) + (nonlinear GDK_NOTIFY_NONLINEAR) + (nonlinear-virtual GDK_NOTIFY_NONLINEAR_VIRTUAL) + (unknown GDK_NOTIFY_UNKNOWN)) + +(define-flags GdkModifierType + (shift-mask GDK_SHIFT_MASK) + (lock-mask GDK_LOCK_MASK) + (control-mask GDK_CONTROL_MASK) + (mod1-mask GDK_MOD1_MASK) + (mod2-mask GDK_MOD2_MASK) + (mod3-mask GDK_MOD3_MASK) + (mod4-mask GDK_MOD4_MASK) + (mod5-mask GDK_MOD5_MASK) + (button1-mask GDK_BUTTON1_MASK) + (button2-mask GDK_BUTTON2_MASK) + (button3-mask GDK_BUTTON3_MASK) + (button4-mask GDK_BUTTON4_MASK) + (button5-mask GDK_BUTTON5_MASK)) + +(define-enum GdkSubwindowMode + (clip-by-children GDK_CLIP_BY_CHILDREN) + (include-inferiors GDK_INCLUDE_INFERIORS)) + +(define-flags GdkInputCondition + (read GDK_INPUT_READ) + (write GDK_INPUT_WRITE) + (exception GDK_INPUT_EXCEPTION)) + +(define-enum GdkStatus + (ok GDK_OK) + (error GDK_ERROR) + (error-param GDK_ERROR_PARAM) + (error-file GDK_ERROR_FILE) + (error-mem GDK_ERROR_MEM)) + +(define-enum GdkByteOrder + (lsb-first GDK_LSB_FIRST) + (msb-first GDK_MSB_FIRST)) + +(define-flags GdkGCValuesMask + (foreground GDK_GC_FOREGROUND) + (background GDK_GC_BACKGROUND) + (font GDK_GC_FONT) + (function GDK_GC_FUNCTION) + (fill GDK_GC_FILL) + (tile GDK_GC_TILE) + (stipple GDK_GC_STIPPLE) + (clip-mask GDK_GC_CLIP_MASK) + (subwindow GDK_GC_SUBWINDOW) + (ts-x-origin GDK_GC_TS_X_ORIGIN) + (ts-y-origin GDK_GC_TS_Y_ORIGIN) + (clip-x-origin GDK_GC_CLIP_X_ORIGIN) + (clip-y-origin GDK_GC_CLIP_Y_ORIGIN) + (exposures GDK_GC_EXPOSURES) + (line-width GDK_GC_LINE_WIDTH) + (line-style GDK_GC_LINE_STYLE) + (cap-style GDK_GC_CAP_STYLE) + (join-style GDK_GC_JOIN_STYLE)) + +(define-enum GdkSelection + (primary GDK_SELECTION_PRIMARY) + (secondary GDK_SELECTION_SECONDARY)) + +(define-enum GdkPropertyState + (new-value GDK_PROPERTY_NEW_VALUE) + (delete GDK_PROPERTY_DELETE)) + +(define-enum GdkPropMode + (replace GDK_PROP_MODE_REPLACE) + (prepend GDK_PROP_MODE_PREPEND) + (append GDK_PROP_MODE_APPEND)) + +;;; Gtk boxed types + +(define-boxed GtkAcceleratorTable + gtk_accelerator_table_ref + gtk_accelerator_table_unref) + +(define-boxed GtkStyle + gtk_style_ref + gtk_style_unref) + +;;; Gdk boxed types + +;(define-boxed GdkPoint +; gdk_point_copy +; gdk_point_destroy) + +(define-boxed GdkColormap + gdk_colormap_ref + gdk_colormap_unref) + +(define-boxed GdkVisual + gdk_visual_ref + gdk_visual_unref) + +(define-boxed GdkFont + gdk_font_ref + gdk_font_free) + +(define-boxed GdkWindow + gdk_window_ref + gdk_window_unref) + +(define-boxed GdkEvent + gdk_event_copy + gdk_event_free) + +;;; Functions + +(define-func gtk_exit + none + (int code 0)) + +(define-func gtk_rc_parse + none + (string file)) + +(define-func g_mem_chunk_info + none) + +;; GtkObject + +(define-func gtk_object_destroy + none + (GtkObject object)) + +;; GtkWidget + +(define-object GtkWidget (GtkObject)) + +(define-func GTK_WIDGET_STATE + GtkStateType + (GtkWidget widget)) + +(define-func GTK_WIDGET_FLAGS + GtkWidgetFlags + (GtkWidget widget)) + +(define-func GTK_WIDGET_SET_FLAGS + none + (GtkWidget widget) + (GtkWidgetFlags flags)) + +(define-func GTK_WIDGET_UNSET_FLAGS + none + (GtkWidget widget) + (GtkWidgetFlags flags)) + +(define-func gtk_widget_destroy + none + (GtkWidget widget)) + +(define-func gtk_widget_unparent + none + (GtkWidget widget)) + +(define-func gtk_widget_show + none + (GtkWidget widget)) + +(define-func gtk_widget_hide + none + (GtkWidget widget)) + +(define-func gtk_widget_map + none + (GtkWidget widget)) + +(define-func gtk_widget_unmap + none + (GtkWidget widget)) + +(define-func gtk_widget_realize + none + (GtkWidget widget)) + +(define-func gtk_widget_unrealize + none + (GtkWidget widget)) + +;(define-func gtk_widget_install_accelerator +; none +; (GtkWidget widget) +; (GtkAcceleratorTable table) +; (string signal_name) +; (char key) +; (...)) + +(define-func gtk_widget_remove_accelerator + none + (GtkWidget widget) + (GtkAcceleratorTable table) + (string signal_name)) + +;(define-func gtk_widget_event +; bool +; (GtkWidget widget) +; (GdkEvent event)) + +(define-func gtk_widget_activate + none + (GtkWidget widget)) + +(define-func gtk_widget_reparent + none + (GtkWidget widget) + (GtkWidget new_parent)) + +(define-func gtk_widget_popup + none + (GtkWidget widget) + (int x) + (int y)) + +(define-func gtk_widget_basic + bool + (GtkWidget widget)) + +(define-func gtk_widget_grab_focus + none + (GtkWidget widget)) + +(define-func gtk_widget_grab_default + none + (GtkWidget widget)) + +(define-func gtk_widget_restore_state + none + (GtkWidget widget)) + +(define-func gtk_widget_set_name + none + (GtkWidget widget) + (string name)) + +(define-func gtk_widget_get_name + static_string + (GtkWidget widget)) + +(define-func gtk_widget_set_state + none + (GtkWidget widget) + (GtkStateType state)) + +(define-func gtk_widget_set_sensitive + none + (GtkWidget widget) + (bool sensitive)) + +(define-func gtk_widget_set_style + none + (GtkWidget widget) + (GtkStyle style)) + +(define-func gtk_widget_set_uposition + none + (GtkWidget widget) + (int x) + (int y)) + +(define-func gtk_widget_set_usize + none + (GtkWidget widget) + (int height) + (int width)) + +(define-func gtk_widget_set_events + none + (GtkWidget widget) + (GdkEventMask events)) + +(define-func gtk_widget_set_extension_events + none + (GtkWidget widget) + (GdkEventMask events)) + +(define-func gtk_widget_get_toplevel + GtkWidget + (GtkWidget widget)) + +;(define-func gtk_widget_get_ancestor +; GtkWidget +; (GtkWidget widget) +; (GtkType type)) + +(define-func gtk_widget_get_colormap + GdkColormap + (GtkWidget widget)) + +(define-func gtk_widget_get_visual + GdkVisual + (GtkWidget widget)) + +(define-func gtk_widget_get_style + GtkStyle + (GtkWidget widget)) + +(define-func gtk_widget_get_events + GdkEventMask + (GtkWidget widget)) + +(define-func gtk_widget_get_extension_events + GdkEventMask + (GtkWidget widget)) + +(define-func gtk_widget_push_colormap + none + (GdkColormap cmap)) + +(define-func gtk_widget_push_visual + none + (GdkVisual visual)) + +(define-func gtk_widget_push_style + none + (GtkStyle style)) + +(define-func gtk_widget_pop_colormap + none) + +(define-func gtk_widget_pop_visual + none) + +(define-func gtk_widget_pop_style + none) + +(define-func gtk_widget_set_default_colormap + none + (GdkColormap cmap)) + +(define-func gtk_widget_set_default_visual + none + (GdkVisual visual)) + +(define-func gtk_widget_set_default_style + none + (GtkStyle style)) + +(define-func gtk_widget_get_default_colormap + GdkColormap) + +(define-func gtk_widget_get_default_visual + GdkVisual) + +(define-func gtk_widget_get_default_style + GtkStyle) + +;;; Container + +(define-object GtkContainer (GtkWidget)) + +(define-func gtk_container_border_width + none + (GtkContainer container) + (int border_width)) + +(define-func gtk_container_add + none + (GtkContainer container) + (GtkWidget widget)) + +(define-func gtk_container_remove + none + (GtkContainer container) + (GtkWidget widget)) + +(define-func gtk_container_disable_resize + none + (GtkContainer container)) + +(define-func gtk_container_enable_resize + none + (GtkContainer container)) + +(define-func gtk_container_block_resize + none + (GtkContainer container)) + +(define-func gtk_container_unblock_resize + none + (GtkContainer container)) + +(define-func gtk_container_need_resize + bool + (GtkContainer container) + (GtkWidget widget)) + +(define-func gtk_container_check_resize + none + (GtkContainer container) + (GtkWidget widget)) + +(define-func gtk_container_focus + GtkDirectionType + (GtkContainer container) + (GtkDirectionType direction)) + +;;; Bin + +(define-object GtkBin (GtkContainer)) + +;;; Window + +(define-object GtkWindow (GtkBin)) + +(define-func gtk_window_new + GtkWidget + (GtkWindowType type)) + +(define-func gtk_window_set_title + none + (GtkWindow window) + (string title)) + +(define-func gtk_window_set_focus + none + (GtkWindow window) + (GtkWidget focus)) + +(define-func gtk_window_set_default + none + (GtkWindow window) + (GtkWidget default)) + +(define-func gtk_window_set_policy + none + (GtkWindow window) + (bool allow_shrink) + (bool allow_grow) + (bool auto_shrink)) + +(define-func gtk_window_add_accelerator_table + none + (GtkWindow window) + (GtkAcceleratorTable table)) + +(define-func gtk_window_remove_accelerator_table + none + (GtkWindow window) + (GtkAcceleratorTable table)) + +(define-func gtk_window_position + none + (GtkWindow window) + (GtkWindowPosition position)) + +;;; Box + +(define-object GtkBox (GtkContainer)) + +;;; Table + +(define-object GtkTable (GtkContainer)) + +;;; Button + +(define-object GtkButton (GtkContainer)) + +;;; ToggleButton + +(define-object GtkToggleButton (GtkButton)) + +;;; CheckButton + +(define-object GtkCheckButton (GtkToggleButton)) + +;;; RadioButton + +(define-object GtkRadioButton (GtkCheckButton)) + + +;; misc + + +(define-func gtk_button_new_with_label + GtkWidget + (string label)) + +(define-func gtk_vbox_new + GtkWidget + (bool homogenous) + (int spacing)) + +(define-func gtk_hbox_new + GtkWidget + (bool homogenous) + (int spacing)) + +(define-func gtk_hseparator_new + GtkWidget) + +(define-func gtk_box_pack_start + none + (GtkBox box) + (GtkWidget child) + (bool expand) + (bool fill) + (int padding)) + +(define-func gtk_table_new + GtkWidget + (int rows) + (int columns) + (bool homogenous)) + +(define-func gtk_table_attach + none + (GtkTable table) + (GtkWidget child) + (int left_attach) + (int right_attach) + (int top_attach) + (int bottom_attach) + (GtkAttachOptions xoptions) + (GtkAttachOptions yoptions) + (int xpadding) + (int ypadding)) + +(define-func gtk_table_attach_defaults + none + (GtkTable table) + (GtkWidget child) + (int left_attach) + (int right_attach) + (int top_attach) + (int bottom_attach)) + +(define-func gtk_table_set_row_spacing + none + (GtkTable table) + (int row) + (int spacing)) + +(define-func gtk_table_set_col_spacing + none + (GtkTable table) + (int col) + (int spacing)) + +(define-func gtk_table_set_row_spacings + none + (GtkTable table) + (int spacing)) + +(define-func gtk_table_set_col_spacings + none + (GtkTable table) + (int spacing)) + +(define-func gtk_toggle_button_new_with_label + GtkWidget + (string label)) + +(define-func gtk_check_button_new_with_label + GtkWidget + (string label)) + +(define-func gtk_radio_button_new_with_label_from_widget + GtkWidget + (GtkRadioButton group) + (string label)) + +(define-func gtk_label_new + GtkWidget + (string label)) + +(define-func gtk_frame_new + GtkWidget + (string label)) diff --git a/gtk/gtk.h b/gtk/gtk.h new file mode 100644 index 000000000..acd1b1046 --- /dev/null +++ b/gtk/gtk.h @@ -0,0 +1,106 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_H__ +#define __GTK_H__ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#endif /* __GTK_H__ */ diff --git a/gtk/gtkaccelerator.c b/gtk/gtkaccelerator.c new file mode 100644 index 000000000..a06a06a99 --- /dev/null +++ b/gtk/gtkaccelerator.c @@ -0,0 +1,352 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkaccelerator.h" +#include "gtksignal.h" +#include "gtkwidget.h" + + +typedef struct _GtkAcceleratorEntry GtkAcceleratorEntry; + +struct _GtkAcceleratorEntry +{ + guint8 modifiers; + GtkObject *object; + gint signal_num; +}; + + +static void gtk_accelerator_table_init (GtkAcceleratorTable *table); +static void gtk_accelerator_table_clean (GtkAcceleratorTable *table); + + +static GtkAcceleratorTable *default_table = NULL; +static GSList *tables = NULL; +static guint8 gtk_accelerator_table_default_mod_mask = ~0; + + +GtkAcceleratorTable* +gtk_accelerator_table_new () +{ + GtkAcceleratorTable *table; + + table = g_new (GtkAcceleratorTable, 1); + gtk_accelerator_table_init (table); + + tables = g_slist_prepend (tables, table); + + return table; +} + +GtkAcceleratorTable* +gtk_accelerator_table_find (GtkObject *object, + const gchar *signal_name, + guchar accelerator_key, + guint8 accelerator_mods) +{ + GtkAcceleratorTable *table; + GtkAcceleratorEntry *entry; + GSList *tmp_list; + GList *entries; + gint signal_num; + guint hash; + + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (signal_name != NULL, NULL); + + signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object)); + hash = (guint) accelerator_key; + + tmp_list = tables; + while (tmp_list) + { + table = tmp_list->data; + tmp_list = tmp_list->next; + + entries = table->entries[hash]; + while (entries) + { + entry = entries->data; + entries = entries->next; + + if ((entry->object == object) && + (entry->signal_num == signal_num) && + ((entry->modifiers & table->modifier_mask) == + (accelerator_mods & table->modifier_mask))) + return table; + } + } + + return NULL; +} + +void +gtk_accelerator_table_destroy (GtkAcceleratorTable *table) +{ + g_return_if_fail (table != NULL); + g_return_if_fail (table->ref_count <= 0); + + tables = g_slist_remove (tables, table); + gtk_accelerator_table_clean (table); + g_free (table); +} + +GtkAcceleratorTable* +gtk_accelerator_table_ref (GtkAcceleratorTable *table) +{ + g_return_val_if_fail (table != NULL, NULL); + + table->ref_count += 1; + return table; +} + +void +gtk_accelerator_table_unref (GtkAcceleratorTable *table) +{ + g_return_if_fail (table != NULL); + + table->ref_count -= 1; + if (table->ref_count <= 0) + gtk_accelerator_table_destroy (table); +} + +void +gtk_accelerator_table_install (GtkAcceleratorTable *table, + GtkObject *object, + const gchar *signal_name, + guchar accelerator_key, + guint8 accelerator_mods) +{ + GtkAcceleratorEntry *entry; + GList *entries; + gchar *signame; + gint signal_num; + guint hash; + + g_return_if_fail (object != NULL); + + if (!table) + { + if (!default_table) + default_table = gtk_accelerator_table_new (); + table = default_table; + } + + signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object)); + g_return_if_fail (signal_num != 0); + + hash = (guint) accelerator_key; + entries = table->entries[hash]; + + while (entries) + { + entry = entries->data; + + if ((entry->modifiers & table->modifier_mask) == + (accelerator_mods & table->modifier_mask)) + { + if (GTK_IS_WIDGET (entry->object)) + { + signame = gtk_signal_name (entry->signal_num); + gtk_signal_emit_by_name (entry->object, + "remove_accelerator", + signame); + } + + entry->modifiers = accelerator_mods; + entry->object = object; + entry->signal_num = signal_num; + return; + } + + entries = entries->next; + } + + entry = g_new (GtkAcceleratorEntry, 1); + entry->modifiers = accelerator_mods; + entry->object = object; + entry->signal_num = signal_num; + + table->entries[hash] = g_list_prepend (table->entries[hash], entry); +} + +void +gtk_accelerator_table_remove (GtkAcceleratorTable *table, + GtkObject *object, + const gchar *signal_name) +{ + GtkAcceleratorEntry *entry; + GList *entries; + GList *temp_list; + gint signal_num; + gint i; + + g_return_if_fail (object != NULL); + + if (!table) + { + if (!default_table) + default_table = gtk_accelerator_table_new (); + table = default_table; + } + + signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (object)); + g_return_if_fail (signal_num != 0); + + for (i = 0; i < 256; i++) + { + entries = table->entries[i]; + + while (entries) + { + entry = entries->data; + + if ((entry->object == object) && (entry->signal_num == signal_num)) + { + g_free (entry); + + temp_list = entries; + if (entries->next) + entries->next->prev = entries->prev; + if (entries->prev) + entries->prev->next = entries->next; + if (table->entries[i] == entries) + table->entries[i] = entries->next; + + temp_list->next = NULL; + temp_list->prev = NULL; + g_list_free (temp_list); + + return; + } + + entries = entries->next; + } + } +} + +gint +gtk_accelerator_table_check (GtkAcceleratorTable *table, + const guchar accelerator_key, + guint8 accelerator_mods) +{ + GtkAcceleratorEntry *entry; + GList *entries; + guint hash; + + if (!table) + { + if (!default_table) + default_table = gtk_accelerator_table_new (); + table = default_table; + } + + hash = (guint) accelerator_key; + entries = table->entries[hash]; + + while (entries) + { + entry = entries->data; + + if ((entry->modifiers & table->modifier_mask) == + (accelerator_mods & table->modifier_mask)) + { + gtk_signal_emit (entry->object, entry->signal_num); + return TRUE; + } + + entries = entries->next; + } + + if (!isupper (hash)) + { + hash = toupper (hash); + entries = table->entries[hash]; + + while (entries) + { + entry = entries->data; + + if (((entry->modifiers & table->modifier_mask) == + (accelerator_mods & table->modifier_mask)) && + (GTK_IS_WIDGET (entry->object) && + GTK_WIDGET_SENSITIVE (entry->object))) + { + gtk_signal_emit (entry->object, entry->signal_num); + return TRUE; + } + + entries = entries->next; + } + } + + return FALSE; +} + +void +gtk_accelerator_table_set_mod_mask (GtkAcceleratorTable *table, + guint8 modifier_mask) +{ + if (table == NULL) + { + gtk_accelerator_table_default_mod_mask = modifier_mask; + } + else + { + table->modifier_mask = modifier_mask; + } +} + +static void +gtk_accelerator_table_init (GtkAcceleratorTable *table) +{ + gint i; + + g_return_if_fail (table != NULL); + + for (i = 0; i < 256; i++) + table->entries[i] = NULL; + + table->ref_count = 0; + table->modifier_mask = gtk_accelerator_table_default_mod_mask; +} + +static void +gtk_accelerator_table_clean (GtkAcceleratorTable *table) +{ + GtkAcceleratorEntry *entry; + GList *entries; + gint i; + + g_return_if_fail (table != NULL); + + for (i = 0; i < 256; i++) + { + entries = table->entries[i]; + while (entries) + { + entry = entries->data; + entries = entries->next; + + g_free (entry); + } + + g_list_free (table->entries[i]); + table->entries[i] = NULL; + } +} diff --git a/gtk/gtkaccelerator.h b/gtk/gtkaccelerator.h new file mode 100644 index 000000000..ac6323209 --- /dev/null +++ b/gtk/gtkaccelerator.h @@ -0,0 +1,73 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_ACCELERATOR_H__ +#define __GTK_ACCELERATOR_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GtkAcceleratorTable GtkAcceleratorTable; + +struct _GtkAcceleratorTable +{ + GList *entries[256]; + gint ref_count; + guint8 modifier_mask; +}; + + +/* Accelerator tables. + */ +GtkAcceleratorTable* gtk_accelerator_table_new (void); +GtkAcceleratorTable* gtk_accelerator_table_find (GtkObject *object, + const gchar *signal_name, + guchar accelerator_key, + guint8 accelerator_mods); + +void gtk_accelerator_table_destroy (GtkAcceleratorTable *table); +GtkAcceleratorTable *gtk_accelerator_table_ref (GtkAcceleratorTable *table); +void gtk_accelerator_table_unref (GtkAcceleratorTable *table); +void gtk_accelerator_table_install (GtkAcceleratorTable *table, + GtkObject *object, + const gchar *signal_name, + guchar accelerator_key, + guint8 accelerator_mods); +void gtk_accelerator_table_remove (GtkAcceleratorTable *table, + GtkObject *object, + const gchar *signal_name); +gint gtk_accelerator_table_check (GtkAcceleratorTable *table, + const guchar accelerator_key, + guint8 accelerator_mods); + +void gtk_accelerator_table_set_mod_mask (GtkAcceleratorTable *table, + guint8 modifier_mask); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ACCELERATOR_H__ */ diff --git a/gtk/gtkadjustment.c b/gtk/gtkadjustment.c new file mode 100644 index 000000000..ab6e63d21 --- /dev/null +++ b/gtk/gtkadjustment.c @@ -0,0 +1,118 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkadjustment.h" +#include "gtksignal.h" + + +enum { + CHANGED, + VALUE_CHANGED, + LAST_SIGNAL +}; + + +static void gtk_adjustment_class_init (GtkAdjustmentClass *klass); +static void gtk_adjustment_init (GtkAdjustment *adjustment); + + +static gint adjustment_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_adjustment_get_type () +{ + static guint adjustment_type = 0; + + if (!adjustment_type) + { + GtkTypeInfo adjustment_info = + { + "GtkAdjustment", + sizeof (GtkAdjustment), + sizeof (GtkAdjustmentClass), + (GtkClassInitFunc) gtk_adjustment_class_init, + (GtkObjectInitFunc) gtk_adjustment_init, + (GtkArgFunc) NULL, + }; + + adjustment_type = gtk_type_unique (gtk_data_get_type (), &adjustment_info); + } + + return adjustment_type; +} + +static void +gtk_adjustment_class_init (GtkAdjustmentClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; + + adjustment_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_FIRST | GTK_RUN_NO_RECURSE, + object_class->type, + GTK_SIGNAL_OFFSET (GtkAdjustmentClass, changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + adjustment_signals[VALUE_CHANGED] = + gtk_signal_new ("value_changed", + GTK_RUN_FIRST | GTK_RUN_NO_RECURSE, + object_class->type, + GTK_SIGNAL_OFFSET (GtkAdjustmentClass, value_changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, adjustment_signals, LAST_SIGNAL); + + class->changed = NULL; + class->value_changed = NULL; +} + +static void +gtk_adjustment_init (GtkAdjustment *adjustment) +{ + adjustment->value = 0.0; + adjustment->lower = 0.0; + adjustment->upper = 0.0; + adjustment->step_increment = 0.0; + adjustment->page_increment = 0.0; + adjustment->page_size = 0.0; +} + +GtkObject* +gtk_adjustment_new (gfloat value, + gfloat lower, + gfloat upper, + gfloat step_increment, + gfloat page_increment, + gfloat page_size) +{ + GtkAdjustment *adjustment; + + adjustment = gtk_type_new (gtk_adjustment_get_type ()); + + adjustment->value = value; + adjustment->lower = lower; + adjustment->upper = upper; + adjustment->step_increment = step_increment; + adjustment->page_increment = page_increment; + adjustment->page_size = page_size; + + return GTK_OBJECT (adjustment); +} diff --git a/gtk/gtkadjustment.h b/gtk/gtkadjustment.h new file mode 100644 index 000000000..7832d1dd1 --- /dev/null +++ b/gtk/gtkadjustment.h @@ -0,0 +1,74 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_ADJUSTMENT_H__ +#define __GTK_ADJUSTMENT_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ADJUSTMENT(obj) GTK_CHECK_CAST (obj, gtk_adjustment_get_type (), GtkAdjustment) +#define GTK_ADJUSTMENT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_adjustment_get_type (), GtkAdjustmentClass) +#define GTK_IS_ADJUSTMENT(obj) GTK_CHECK_TYPE (obj, gtk_adjustment_get_type ()) + + +typedef struct _GtkAdjustment GtkAdjustment; +typedef struct _GtkAdjustmentClass GtkAdjustmentClass; + +struct _GtkAdjustment +{ + GtkData data; + + gfloat lower; + gfloat upper; + gfloat value; + gfloat step_increment; + gfloat page_increment; + gfloat page_size; +}; + +struct _GtkAdjustmentClass +{ + GtkDataClass parent_class; + + void (* changed) (GtkAdjustment *adjustment); + void (* value_changed) (GtkAdjustment *adjustment); +}; + + +guint gtk_adjustment_get_type (void); +GtkObject* gtk_adjustment_new (gfloat value, + gfloat lower, + gfloat upper, + gfloat step_increment, + gfloat page_increment, + gfloat page_size); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ADJUSTMENT_H__ */ diff --git a/gtk/gtkalignment.c b/gtk/gtkalignment.c new file mode 100644 index 000000000..b562cff77 --- /dev/null +++ b/gtk/gtkalignment.c @@ -0,0 +1,193 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkalignment.h" + + +static void gtk_alignment_class_init (GtkAlignmentClass *klass); +static void gtk_alignment_init (GtkAlignment *alignment); +static void gtk_alignment_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_alignment_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +guint +gtk_alignment_get_type () +{ + static guint alignment_type = 0; + + if (!alignment_type) + { + GtkTypeInfo alignment_info = + { + "GtkAlignment", + sizeof (GtkAlignment), + sizeof (GtkAlignmentClass), + (GtkClassInitFunc) gtk_alignment_class_init, + (GtkObjectInitFunc) gtk_alignment_init, + (GtkArgFunc) NULL, + }; + + alignment_type = gtk_type_unique (gtk_bin_get_type (), &alignment_info); + } + + return alignment_type; +} + +static void +gtk_alignment_class_init (GtkAlignmentClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_alignment_size_request; + widget_class->size_allocate = gtk_alignment_size_allocate; +} + +static void +gtk_alignment_init (GtkAlignment *alignment) +{ + GTK_WIDGET_SET_FLAGS (alignment, GTK_NO_WINDOW | GTK_BASIC); + + alignment->xalign = 0.5; + alignment->yalign = 0.5; + alignment->xscale = 1.0; + alignment->yscale = 1.0; +} + +GtkWidget* +gtk_alignment_new (gfloat xalign, + gfloat yalign, + gfloat xscale, + gfloat yscale) +{ + GtkAlignment *alignment; + + alignment = gtk_type_new (gtk_alignment_get_type ()); + + alignment->xalign = CLAMP (xalign, 0.0, 1.0); + alignment->yalign = CLAMP (yalign, 0.0, 1.0); + alignment->xscale = CLAMP (xscale, 0.0, 1.0); + alignment->yscale = CLAMP (yscale, 0.0, 1.0); + + return GTK_WIDGET (alignment); +} + +void +gtk_alignment_set (GtkAlignment *alignment, + gfloat xalign, + gfloat yalign, + gfloat xscale, + gfloat yscale) +{ + g_return_if_fail (alignment != NULL); + g_return_if_fail (GTK_IS_ALIGNMENT (alignment)); + + xalign = CLAMP (xalign, 0.0, 1.0); + yalign = CLAMP (yalign, 0.0, 1.0); + xscale = CLAMP (xscale, 0.0, 1.0); + yscale = CLAMP (yscale, 0.0, 1.0); + + if ((alignment->xalign != xalign) || + (alignment->yalign != yalign) || + (alignment->xscale != xscale) || + (alignment->yscale != yscale)) + { + alignment->xalign = xalign; + alignment->yalign = yalign; + alignment->xscale = xscale; + alignment->yscale = yscale; + + gtk_widget_size_allocate (GTK_WIDGET (alignment), &(GTK_WIDGET (alignment)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (alignment)); + } +} + + +static void +gtk_alignment_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkAlignment *alignment; + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ALIGNMENT (widget)); + g_return_if_fail (requisition != NULL); + + alignment = GTK_ALIGNMENT (widget); + bin = GTK_BIN (widget); + + requisition->width = GTK_CONTAINER (widget)->border_width * 2; + requisition->height = GTK_CONTAINER (widget)->border_width * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += bin->child->requisition.width; + requisition->height += bin->child->requisition.height; + } +} + +static void +gtk_alignment_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkAlignment *alignment; + GtkBin *bin; + GtkAllocation child_allocation; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ALIGNMENT (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + alignment = GTK_ALIGNMENT (widget); + bin = GTK_BIN (widget); + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + x = GTK_CONTAINER (alignment)->border_width; + y = GTK_CONTAINER (alignment)->border_width; + width = allocation->width - 2 * x; + height = allocation->height - 2 * y; + + if (width > bin->child->requisition.width) + child_allocation.width = (bin->child->requisition.width * + (1.0 - alignment->xscale) + + width * alignment->xscale); + else + child_allocation.width = width; + + if (height > bin->child->requisition.height) + child_allocation.height = (bin->child->requisition.height * + (1.0 - alignment->yscale) + + height * alignment->yscale); + else + child_allocation.height = height; + + child_allocation.x = alignment->xalign * (width - child_allocation.width) + allocation->x + x; + child_allocation.y = alignment->yalign * (height - child_allocation.height) + allocation->y + y; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} diff --git a/gtk/gtkalignment.h b/gtk/gtkalignment.h new file mode 100644 index 000000000..c80ad7f14 --- /dev/null +++ b/gtk/gtkalignment.h @@ -0,0 +1,72 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_ALIGNMENT_H__ +#define __GTK_ALIGNMENT_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ALIGNMENT(obj) GTK_CHECK_CAST (obj, gtk_alignment_get_type (), GtkAlignment) +#define GTK_ALIGNMENT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_alignment_get_type (), GtkAlignmentClass) +#define GTK_IS_ALIGNMENT(obj) GTK_CHECK_TYPE (obj, gtk_alignment_get_type ()) + + +typedef struct _GtkAlignment GtkAlignment; +typedef struct _GtkAlignmentClass GtkAlignmentClass; + +struct _GtkAlignment +{ + GtkBin bin; + + gfloat xalign; + gfloat yalign; + gfloat xscale; + gfloat yscale; +}; + +struct _GtkAlignmentClass +{ + GtkBinClass parent_class; +}; + + +guint gtk_alignment_get_type (void); +GtkWidget* gtk_alignment_new (gfloat xalign, + gfloat yalign, + gfloat xscale, + gfloat yscale); +void gtk_alignment_set (GtkAlignment *alignment, + gfloat xalign, + gfloat yalign, + gfloat xscale, + gfloat yscale); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ALIGNMENT_H__ */ diff --git a/gtk/gtkarrow.c b/gtk/gtkarrow.c new file mode 100644 index 000000000..b8bc2143e --- /dev/null +++ b/gtk/gtkarrow.c @@ -0,0 +1,165 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkarrow.h" + + +#define MIN_ARROW_SIZE 11 + + +static void gtk_arrow_class_init (GtkArrowClass *klass); +static void gtk_arrow_init (GtkArrow *arrow); +static gint gtk_arrow_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_arrow_get_type () +{ + static guint arrow_type = 0; + + if (!arrow_type) + { + GtkTypeInfo arrow_info = + { + "GtkArrow", + sizeof (GtkArrow), + sizeof (GtkArrowClass), + (GtkClassInitFunc) gtk_arrow_class_init, + (GtkObjectInitFunc) gtk_arrow_init, + (GtkArgFunc) NULL, + }; + + arrow_type = gtk_type_unique (gtk_misc_get_type (), &arrow_info); + } + + return arrow_type; +} + +static void +gtk_arrow_class_init (GtkArrowClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->expose_event = gtk_arrow_expose; +} + +static void +gtk_arrow_init (GtkArrow *arrow) +{ + GTK_WIDGET_SET_FLAGS (arrow, GTK_NO_WINDOW); + + arrow->arrow_type = GTK_ARROW_RIGHT; + arrow->shadow_type = GTK_SHADOW_OUT; +} + +GtkWidget* +gtk_arrow_new (GtkArrowType arrow_type, + GtkShadowType shadow_type) +{ + GtkArrow *arrow; + + arrow = gtk_type_new (gtk_arrow_get_type ()); + + GTK_WIDGET (arrow)->requisition.width = MIN_ARROW_SIZE + GTK_MISC (arrow)->xpad * 2; + GTK_WIDGET (arrow)->requisition.height = MIN_ARROW_SIZE + GTK_MISC (arrow)->ypad * 2; + + arrow->arrow_type = arrow_type; + arrow->shadow_type = shadow_type; + + return GTK_WIDGET (arrow); +} + +void +gtk_arrow_set (GtkArrow *arrow, + GtkArrowType arrow_type, + GtkShadowType shadow_type) +{ + g_return_if_fail (arrow != NULL); + g_return_if_fail (GTK_IS_ARROW (arrow)); + + if (((GtkArrowType) arrow->arrow_type != arrow_type) || + ((GtkShadowType) arrow->shadow_type != shadow_type)) + { + arrow->arrow_type = arrow_type; + arrow->shadow_type = shadow_type; + + if (GTK_WIDGET_DRAWABLE (arrow)) + { + gdk_window_clear_area (GTK_WIDGET (arrow)->window, + GTK_WIDGET (arrow)->allocation.x + 1, + GTK_WIDGET (arrow)->allocation.y + 1, + GTK_WIDGET (arrow)->allocation.width - 2, + GTK_WIDGET (arrow)->allocation.height - 2); + gtk_widget_queue_draw (GTK_WIDGET (arrow)); + } + } +} + + +static gint +gtk_arrow_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkArrow *arrow; + GtkMisc *misc; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + gint extent; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ARROW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + arrow = GTK_ARROW (widget); + misc = GTK_MISC (widget); + + width = widget->allocation.width - misc->xpad * 2; + height = widget->allocation.height - misc->ypad * 2; + extent = MIN (width, height); + + x = ((widget->allocation.x + misc->xpad) * (1.0 - misc->xalign) + + (widget->allocation.x + widget->allocation.width - extent - misc->ypad) * misc->xalign); + y = ((widget->allocation.y + misc->ypad) * (1.0 - misc->yalign) + + (widget->allocation.y + widget->allocation.height - extent - misc->ypad) * misc->yalign); + + shadow_type = arrow->shadow_type; + + if (widget->state == GTK_STATE_ACTIVE) + { + if (shadow_type == GTK_SHADOW_IN) + shadow_type = GTK_SHADOW_OUT; + else if (shadow_type == GTK_SHADOW_OUT) + shadow_type = GTK_SHADOW_IN; + else if (shadow_type == GTK_SHADOW_ETCHED_IN) + shadow_type = GTK_SHADOW_ETCHED_OUT; + else if (shadow_type == GTK_SHADOW_ETCHED_OUT) + shadow_type = GTK_SHADOW_ETCHED_IN; + } + + gtk_draw_arrow (widget->style, widget->window, + widget->state, shadow_type, arrow->arrow_type, TRUE, + x, y, extent, extent); + } + + return FALSE; +} diff --git a/gtk/gtkarrow.h b/gtk/gtkarrow.h new file mode 100644 index 000000000..5a2edb0f5 --- /dev/null +++ b/gtk/gtkarrow.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_ARROW_H__ +#define __GTK_ARROW_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ARROW(obj) GTK_CHECK_CAST (obj, gtk_arrow_get_type (), GtkArrow) +#define GTK_ARROW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_arrow_get_type (), GtkArrowClass) +#define GTK_IS_ARROW(obj) GTK_CHECK_TYPE (obj, gtk_arrow_get_type ()) + + +typedef struct _GtkArrow GtkArrow; +typedef struct _GtkArrowClass GtkArrowClass; + +struct _GtkArrow +{ + GtkMisc misc; + + gint16 arrow_type; + gint16 shadow_type; +}; + +struct _GtkArrowClass +{ + GtkMiscClass parent_class; +}; + + +guint gtk_arrow_get_type (void); +GtkWidget* gtk_arrow_new (GtkArrowType arrow_type, + GtkShadowType shadow_type); +void gtk_arrow_set (GtkArrow *arrow, + GtkArrowType arrow_type, + GtkShadowType shadow_type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ARROW_H__ */ diff --git a/gtk/gtkaspectframe.c b/gtk/gtkaspectframe.c new file mode 100644 index 000000000..2e4795bca --- /dev/null +++ b/gtk/gtkaspectframe.c @@ -0,0 +1,336 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GtkAspectFrame: Ensure that the child window has a specified aspect ratio + * or, if obey_child, has the same aspect ratio as its requested size + * + * Copyright Owen Taylor 4/9/97 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkaspectframe.h" + +static void gtk_aspect_frame_class_init (GtkAspectFrameClass *klass); +static void gtk_aspect_frame_init (GtkAspectFrame *aspect_frame); +static void gtk_aspect_frame_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_aspect_frame_paint (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_aspect_frame_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_aspect_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +#define MAX_RATIO 10000.0 +#define MIN_RATIO 0.0001 + +guint +gtk_aspect_frame_get_type () +{ + static guint aspect_frame_type = 0; + + if (!aspect_frame_type) + { + GtkTypeInfo aspect_frame_info = + { + "GtkAspectFrame", + sizeof (GtkAspectFrame), + sizeof (GtkAspectFrameClass), + (GtkClassInitFunc) gtk_aspect_frame_class_init, + (GtkObjectInitFunc) gtk_aspect_frame_init, + (GtkArgFunc) NULL, + }; + + aspect_frame_type = gtk_type_unique (gtk_frame_get_type (), &aspect_frame_info); + } + + return aspect_frame_type; +} + +static void +gtk_aspect_frame_class_init (GtkAspectFrameClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->draw = gtk_aspect_frame_draw; + widget_class->expose_event = gtk_aspect_frame_expose; + widget_class->size_allocate = gtk_aspect_frame_size_allocate; +} + +static void +gtk_aspect_frame_init (GtkAspectFrame *aspect_frame) +{ + aspect_frame->xalign = 0.5; + aspect_frame->yalign = 0.5; + aspect_frame->ratio = 1.0; + aspect_frame->obey_child = 1; + aspect_frame->center_allocation.x = -1; + aspect_frame->center_allocation.y = -1; + aspect_frame->center_allocation.width = 1; + aspect_frame->center_allocation.height = 1; +} + +GtkWidget* +gtk_aspect_frame_new (const gchar *label, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child) +{ + GtkAspectFrame *aspect_frame; + + aspect_frame = gtk_type_new (gtk_aspect_frame_get_type ()); + + aspect_frame->xalign = CLAMP (xalign, 0.0, 1.0); + aspect_frame->yalign = CLAMP (yalign, 0.0, 1.0); + aspect_frame->ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO); + aspect_frame->obey_child = obey_child; + + gtk_frame_set_label (GTK_FRAME(aspect_frame), label); + + return GTK_WIDGET (aspect_frame); +} + +void +gtk_aspect_frame_set (GtkAspectFrame *aspect_frame, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child) +{ + g_return_if_fail (aspect_frame != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (aspect_frame)); + + xalign = CLAMP (xalign, 0.0, 1.0); + yalign = CLAMP (yalign, 0.0, 1.0); + ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO); + + if ((aspect_frame->xalign != xalign) || + (aspect_frame->yalign != yalign) || + (aspect_frame->ratio != ratio) || + (aspect_frame->obey_child != obey_child)) + { + aspect_frame->xalign = xalign; + aspect_frame->yalign = yalign; + aspect_frame->ratio = ratio; + aspect_frame->obey_child = obey_child; + + gtk_widget_size_allocate (GTK_WIDGET (aspect_frame), &(GTK_WIDGET (aspect_frame)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (aspect_frame)); + } +} + +static void +gtk_aspect_frame_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkFrame *frame; + GtkStateType state; + gint height_extra; + gint label_area_width; + gint x, y; + GtkAllocation *allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + frame = GTK_FRAME (widget); + allocation = >K_ASPECT_FRAME(widget)->center_allocation; + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + height_extra = frame->label_height - widget->style->klass->xthickness; + height_extra = MAX (height_extra, 0); + + x = GTK_CONTAINER (frame)->border_width; + y = GTK_CONTAINER (frame)->border_width; + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, frame->shadow_type, + allocation->x + x, + allocation->y + y + height_extra / 2, + allocation->width - x * 2, + allocation->height - y * 2 - height_extra / 2); + + if (frame->label) + { + label_area_width = (allocation->width + + GTK_CONTAINER (frame)->border_width * 2 - + widget->style->klass->xthickness * 2); + + x = ((label_area_width - frame->label_width) * frame->label_xalign + + GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness); + y = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent); + + gdk_window_clear_area (widget->window, + allocation->x + x + 2, + allocation->y + GTK_CONTAINER (frame)->border_width, + frame->label_width - 4, frame->label_height); + gtk_draw_string (widget->style, widget->window, state, + allocation->x + x + 3, + allocation->y + y, + frame->label); + } + } +} + +/* the only modification to the next two routines is to call + gtk_aspect_frame_paint instead of gtk_frame_paint */ + +static void +gtk_aspect_frame_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_aspect_frame_paint (widget, area); + + if (bin->child && gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } +} + +static gint +gtk_aspect_frame_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ASPECT_FRAME (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_aspect_frame_paint (widget, &event->area); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static void +gtk_aspect_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkFrame *frame; + GtkAspectFrame *aspect_frame; + GtkBin *bin; + + GtkAllocation child_allocation; + gint x,y; + gint width,height; + gdouble ratio; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (widget)); + g_return_if_fail (allocation != NULL); + + aspect_frame = GTK_ASPECT_FRAME (widget); + frame = GTK_FRAME (widget); + bin = GTK_BIN (widget); + + if (GTK_WIDGET_MAPPED (widget) && + ((widget->allocation.x != allocation->x) || + (widget->allocation.y != allocation->y) || + (widget->allocation.width != allocation->width) || + (widget->allocation.height != allocation->height)) && + (widget->allocation.width != 0) && + (widget->allocation.height != 0)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + + widget->allocation = *allocation; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + if (aspect_frame->obey_child) + { + if (bin->child->requisition.height != 0) + { + ratio = (gdouble)bin->child->requisition.width / + bin->child->requisition.height; + if (ratio < MIN_RATIO) ratio = MIN_RATIO; + } + else + if (bin->child->requisition.height != 0) + ratio = MAX_RATIO; + else + ratio = 1.0; + } + else + ratio = aspect_frame->ratio; + + x = (GTK_CONTAINER (frame)->border_width + + GTK_WIDGET (frame)->style->klass->xthickness); + width = allocation->width - x * 2; + + y = (GTK_CONTAINER (frame)->border_width + + MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness)); + height = (allocation->height - y - + GTK_CONTAINER (frame)->border_width - + GTK_WIDGET (frame)->style->klass->ythickness); + + if (ratio * height > width) + { + child_allocation.width = width; + child_allocation.height = width/ratio; + } + else + { + child_allocation.width = ratio*height; + child_allocation.height = height; + } + + child_allocation.x = aspect_frame->xalign * (width - child_allocation.width) + allocation->x + x; + child_allocation.y = aspect_frame->yalign * (height - child_allocation.height) + allocation->y + y; + + aspect_frame->center_allocation.width = child_allocation.width + 2*x; + aspect_frame->center_allocation.x = child_allocation.x - x; + aspect_frame->center_allocation.height = child_allocation.height + y + + GTK_CONTAINER (frame)->border_width + + GTK_WIDGET (frame)->style->klass->ythickness; + aspect_frame->center_allocation.y = child_allocation.y - y; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} diff --git a/gtk/gtkaspectframe.h b/gtk/gtkaspectframe.h new file mode 100644 index 000000000..07f08a4cc --- /dev/null +++ b/gtk/gtkaspectframe.h @@ -0,0 +1,75 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_ASPECT_FRAME_H__ +#define __GTK_ASPECT_FRAME_H__ + + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ASPECT_FRAME(obj) ((GtkAspectFrame*) obj) +#define GTK_ASPECT_FRAME_CLASS(obj) ((GtkAspectFrameClass*) GTK_OBJECT_CLASS (obj)) +#define GTK_IS_ASPECT_FRAME(obj) (gtk_type_is_a (GTK_WIDGET_TYPE (obj), gtk_aspect_frame_get_type ())) + + +typedef struct _GtkAspectFrame GtkAspectFrame; +typedef struct _GtkAspectFrameClass GtkAspectFrameClass; + +struct _GtkAspectFrame +{ + GtkFrame frame; + + gfloat xalign; + gfloat yalign; + gfloat ratio; + gint obey_child; + + GtkAllocation center_allocation; +}; + +struct _GtkAspectFrameClass +{ + GtkBinClass parent_class; +}; + + +guint gtk_aspect_frame_get_type (void); +GtkWidget* gtk_aspect_frame_new (const gchar *label, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child); +void gtk_aspect_frame_set (GtkAspectFrame *aspect_frame, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ASPECT_FRAME_H__ */ diff --git a/gtk/gtkbbox.c b/gtk/gtkbbox.c new file mode 100644 index 000000000..818493f9a --- /dev/null +++ b/gtk/gtkbbox.c @@ -0,0 +1,228 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkbbox.h" + + +static void gtk_button_box_class_init (GtkButtonBoxClass *klass); +static void gtk_button_box_init (GtkButtonBox *box); + + +static gint default_child_min_width = 85; +static gint default_child_min_height = 27; +static gint default_child_ipad_x = 7; +static gint default_child_ipad_y = 0; + + +guint +gtk_button_box_get_type () +{ + static guint button_box_type = 0; + + if (!button_box_type) + { + GtkTypeInfo button_box_info = + { + "GtkButtonBox", + sizeof (GtkButtonBox), + sizeof (GtkButtonBoxClass), + (GtkClassInitFunc) gtk_button_box_class_init, + (GtkObjectInitFunc) gtk_button_box_init, + (GtkArgFunc) NULL, + }; + + button_box_type = gtk_type_unique (gtk_box_get_type (), &button_box_info); + } + + return button_box_type; +} + +static void +gtk_button_box_class_init (GtkButtonBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; +} + +static void +gtk_button_box_init (GtkButtonBox *button_box) +{ + button_box->spacing = GTK_BUTTONBOX_DEFAULT; + button_box->child_min_width = GTK_BUTTONBOX_DEFAULT; + button_box->child_min_height = GTK_BUTTONBOX_DEFAULT; + button_box->child_ipad_x = GTK_BUTTONBOX_DEFAULT; + button_box->child_ipad_y = GTK_BUTTONBOX_DEFAULT; + button_box->layout_style = GTK_BUTTONBOX_DEFAULT; +} + + +/* set default values for child size and child internal padding */ +/* default spacing is in defined in subclasses */ + +void gtk_button_box_set_child_size_default (gint width, gint height) +{ + default_child_min_width = width; + default_child_min_height = height; +} + +void gtk_button_box_set_child_ipadding_default (gint ipad_x, gint ipad_y) +{ + default_child_ipad_x = ipad_x; + default_child_ipad_y = ipad_y; +} + +/* get default values for child size and child internal padding */ + +void gtk_button_box_get_child_size_default (gint *width, gint *height) +{ + *width = default_child_min_width; + *height = default_child_min_height; +} + +void gtk_button_box_get_child_ipadding_default (gint *ipad_x, gint *ipad_y) +{ + *ipad_x = default_child_ipad_x; + *ipad_y = default_child_ipad_y; +} + +/* set per widget values for spacing, child size and child internal padding */ + +void gtk_button_box_set_spacing (GtkButtonBox *widget, gint spacing) +{ + widget->spacing = spacing; +} + +void gtk_button_box_set_child_size (GtkButtonBox *widget, gint width, gint height) +{ + widget->child_min_width = width; + widget->child_min_height = height; +} + +void gtk_button_box_set_child_ipadding (GtkButtonBox *widget, + gint ipad_x, gint ipad_y) +{ + widget->child_ipad_x = ipad_x; + widget->child_ipad_y = ipad_y; +} + +void gtk_button_box_set_layout (GtkButtonBox *widget, gint layout_style) +{ + widget->layout_style = layout_style; +} + + +/* get per widget values for spacing, child size and child internal padding */ + +gint gtk_button_box_get_spacing (GtkButtonBox *widget) +{ + return widget->spacing; +} + +void gtk_button_box_get_child_size (GtkButtonBox *widget, + gint *width, gint *height) +{ + *width = widget->child_min_width; + *height = widget->child_min_height; +} + +void gtk_button_box_get_child_ipadding (GtkButtonBox *widget, + gint* ipad_x, gint *ipad_y) +{ + *ipad_x = widget->child_ipad_x; + *ipad_y = widget->child_ipad_y; +} + +gint gtk_button_box_get_layout (GtkButtonBox *widget) +{ + return widget->layout_style; +} + + + +/* Ask children how much space they require and round up + to match minimum size and internal padding. + Returns the size each single child should have. */ +void +gtk_button_box_child_requisition (GtkWidget *widget, + int *nvis_children, + int *width, + int *height) +{ + GtkButtonBox *bbox; + GtkBoxChild *child; + GList *children; + gint nchildren; + gint needed_width; + gint needed_height; + GtkRequisition child_requisition; + gint ipad_w; + gint ipad_h; + gint width_default; + gint height_default; + gint ipad_x_default; + gint ipad_y_default; + + gint child_min_width; + gint child_min_height; + gint ipad_x; + gint ipad_y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON_BOX (widget)); + + bbox = GTK_BUTTON_BOX (widget); + + gtk_button_box_get_child_size_default (&width_default, &height_default); + gtk_button_box_get_child_ipadding_default (&ipad_x_default, &ipad_y_default); + + child_min_width = bbox->child_min_width != GTK_BUTTONBOX_DEFAULT + ? bbox->child_min_width : width_default; + child_min_height = bbox->child_min_height !=GTK_BUTTONBOX_DEFAULT + ? bbox->child_min_height : height_default; + ipad_x = bbox->child_ipad_x != GTK_BUTTONBOX_DEFAULT + ? bbox->child_ipad_x : ipad_x_default; + ipad_y = bbox->child_ipad_y != GTK_BUTTONBOX_DEFAULT + ? bbox->child_ipad_y : ipad_y_default; + + nchildren = 0; + children = GTK_BOX(bbox)->children; + needed_width = child_min_width; + needed_height = child_min_height; + ipad_w = ipad_x * 2; + ipad_h = ipad_y * 2; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + nchildren += 1; + gtk_widget_size_request (child->widget, &child_requisition); + if (child_requisition.width + ipad_w > needed_width) + needed_width = child_requisition.width + ipad_w; + if (child_requisition.height + ipad_h > needed_height) + needed_height = child_requisition.height + ipad_h; + } + } + + *nvis_children = nchildren; + *width = needed_width; + *height = needed_height; +} diff --git a/gtk/gtkbbox.h b/gtk/gtkbbox.h new file mode 100644 index 000000000..816f1f0c2 --- /dev/null +++ b/gtk/gtkbbox.h @@ -0,0 +1,93 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_BUTTON_BOX_H__ +#define __GTK_BUTTON_BOX_H__ + +#include "gtkbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_BUTTON_BOX(obj) GTK_CHECK_CAST (obj, gtk_button_box_get_type (), GtkButtonBox) +#define GTK_BUTTON_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_button_box_get_type (), GtkButtonBoxClass) +#define GTK_IS_BUTTON_BOX(obj) GTK_CHECK_TYPE (obj, gtk_button_box_get_type ()) + +#define GTK_BUTTONBOX_DEFAULT -1 +#define GTK_BUTTONBOX_SPREAD 1 +#define GTK_BUTTONBOX_EDGE 2 +#define GTK_BUTTONBOX_START 3 +#define GTK_BUTTONBOX_END 4 + +typedef struct _GtkButtonBox GtkButtonBox; +typedef struct _GtkButtonBoxClass GtkButtonBoxClass; + +struct _GtkButtonBox +{ + GtkBox box; + gint spacing; + gint child_min_width; + gint child_min_height; + gint child_ipad_x; + gint child_ipad_y; + gint layout_style; +}; + +struct _GtkButtonBoxClass +{ + GtkBoxClass parent_class; +}; + + +guint gtk_button_box_get_type (void); + +void gtk_button_box_get_child_size_default (gint *min_width, gint *min_height); +void gtk_button_box_get_child_ipadding_default (gint *ipad_x, gint *ipad_y); + +void gtk_button_box_set_child_size_default (gint min_width, gint min_height); +void gtk_button_box_set_child_ipadding_default (gint ipad_x, gint ipad_y); + +gint gtk_button_box_get_spacing (GtkButtonBox *widget); +gint gtk_button_box_get_layout (GtkButtonBox *widget); +void gtk_button_box_get_child_size (GtkButtonBox *widget, + gint *min_width, gint *min_height); +void gtk_button_box_get_child_ipadding (GtkButtonBox *widget, gint *ipad_x, gint *ipad_y); + +void gtk_button_box_set_spacing (GtkButtonBox *widget, gint spacing); +void gtk_button_box_set_layout (GtkButtonBox *widget, gint layout_style); +void gtk_button_box_set_child_size (GtkButtonBox *widget, + gint min_width, gint min_height); +void gtk_button_box_set_child_ipadding (GtkButtonBox *widget, gint ipad_x, gint ipad_y); + + +/* Internal method - do not use. */ +void gtk_button_box_child_requisition (GtkWidget *widget, + int *nvis_children, + int *width, + int *height); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_BUTTON_BOX_H__ */ + + diff --git a/gtk/gtkbin.c b/gtk/gtkbin.c new file mode 100644 index 000000000..4cb7efcc1 --- /dev/null +++ b/gtk/gtkbin.c @@ -0,0 +1,286 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkbin.h" + + +static void gtk_bin_class_init (GtkBinClass *klass); +static void gtk_bin_init (GtkBin *bin); +static void gtk_bin_destroy (GtkObject *object); +static void gtk_bin_map (GtkWidget *widget); +static void gtk_bin_unmap (GtkWidget *widget); +static void gtk_bin_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_bin_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_bin_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_bin_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_bin_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_bin_get_type () +{ + static guint bin_type = 0; + + if (!bin_type) + { + GtkTypeInfo bin_info = + { + "GtkBin", + sizeof (GtkBin), + sizeof (GtkBinClass), + (GtkClassInitFunc) gtk_bin_class_init, + (GtkObjectInitFunc) gtk_bin_init, + (GtkArgFunc) NULL, + }; + + bin_type = gtk_type_unique (gtk_container_get_type (), &bin_info); + } + + return bin_type; +} + +static void +gtk_bin_class_init (GtkBinClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_bin_destroy; + + widget_class->map = gtk_bin_map; + widget_class->unmap = gtk_bin_unmap; + widget_class->draw = gtk_bin_draw; + widget_class->expose_event = gtk_bin_expose; + + container_class->add = gtk_bin_add; + container_class->remove = gtk_bin_remove; + container_class->foreach = gtk_bin_foreach; +} + +static void +gtk_bin_init (GtkBin *bin) +{ + GTK_WIDGET_SET_FLAGS (bin, GTK_NO_WINDOW); + + bin->child = NULL; +} + + +static void +gtk_bin_destroy (GtkObject *object) +{ + GtkBin *bin; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_BIN (object)); + + bin = GTK_BIN (object); + + if (bin->child) + { + bin->child->parent = NULL; + gtk_object_unref (GTK_OBJECT (bin->child)); + gtk_widget_destroy (bin->child); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_bin_map (GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BIN (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + bin = GTK_BIN (widget); + + if (!GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_show (widget->window); + else + gtk_widget_queue_draw (widget); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + !GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_map (bin->child); +} + +static void +gtk_bin_unmap (GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BIN (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + bin = GTK_BIN (widget); + + if (GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + else + gdk_window_hide (widget->window); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_unmap (bin->child); +} + +static void +gtk_bin_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BIN (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + bin = GTK_BIN (widget); + + if (bin->child && + gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } +} + +static gint +gtk_bin_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BIN (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + + +static void +gtk_bin_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BIN (container)); + g_return_if_fail (widget != NULL); + + bin = GTK_BIN (container); + + if (!bin->child) + { + gtk_widget_set_parent (widget, GTK_WIDGET (container)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + bin->child = widget; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (widget); + } +} + +static void +gtk_bin_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BIN (container)); + g_return_if_fail (widget != NULL); + + bin = GTK_BIN (container); + + if (bin->child == widget) + { + gtk_widget_unparent (widget); + + bin->child = NULL; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +gtk_bin_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkBin *bin; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BIN (container)); + g_return_if_fail (callback != NULL); + + bin = GTK_BIN (container); + + if (bin->child) + (* callback) (bin->child, callback_data); +} diff --git a/gtk/gtkbin.h b/gtk/gtkbin.h new file mode 100644 index 000000000..c8676ab84 --- /dev/null +++ b/gtk/gtkbin.h @@ -0,0 +1,60 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_BIN_H__ +#define __GTK_BIN_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_BIN(obj) GTK_CHECK_CAST (obj, gtk_bin_get_type (), GtkBin) +#define GTK_BIN_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_bin_get_type (), GtkBinClass) +#define GTK_IS_BIN(obj) GTK_CHECK_TYPE (obj, gtk_bin_get_type ()) + + +typedef struct _GtkBin GtkBin; +typedef struct _GtkBinClass GtkBinClass; + +struct _GtkBin +{ + GtkContainer container; + + GtkWidget *child; +}; + +struct _GtkBinClass +{ + GtkContainerClass parent_class; +}; + + +guint gtk_bin_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_BIN_H__ */ diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c new file mode 100644 index 000000000..dfb2fed08 --- /dev/null +++ b/gtk/gtkbox.c @@ -0,0 +1,453 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkbox.h" + + +static void gtk_box_class_init (GtkBoxClass *klass); +static void gtk_box_init (GtkBox *box); +static void gtk_box_destroy (GtkObject *object); +static void gtk_box_map (GtkWidget *widget); +static void gtk_box_unmap (GtkWidget *widget); +static void gtk_box_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_box_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_box_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_box_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_box_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_box_get_type () +{ + static guint box_type = 0; + + if (!box_type) + { + GtkTypeInfo box_info = + { + "GtkBox", + sizeof (GtkBox), + sizeof (GtkBoxClass), + (GtkClassInitFunc) gtk_box_class_init, + (GtkObjectInitFunc) gtk_box_init, + (GtkArgFunc) NULL, + }; + + box_type = gtk_type_unique (gtk_container_get_type (), &box_info); + } + + return box_type; +} + +static void +gtk_box_class_init (GtkBoxClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_box_destroy; + + widget_class->map = gtk_box_map; + widget_class->unmap = gtk_box_unmap; + widget_class->draw = gtk_box_draw; + widget_class->expose_event = gtk_box_expose; + + container_class->add = gtk_box_add; + container_class->remove = gtk_box_remove; + container_class->foreach = gtk_box_foreach; +} + +static void +gtk_box_init (GtkBox *box) +{ + GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW | GTK_BASIC); + + box->children = NULL; + box->spacing = 0; + box->homogeneous = FALSE; +} + +void +gtk_box_pack_start (GtkBox *box, + GtkWidget *child, + gint expand, + gint fill, + gint padding) +{ + GtkBoxChild *child_info; + + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + g_return_if_fail (child != NULL); + + child_info = g_new (GtkBoxChild, 1); + child_info->widget = child; + child_info->padding = padding; + child_info->expand = expand ? TRUE : FALSE; + child_info->fill = fill ? TRUE : FALSE; + child_info->pack = GTK_PACK_START; + + box->children = g_list_append (box->children, child_info); + + gtk_widget_set_parent (child, GTK_WIDGET (box)); + + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box))) + { + if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box)) + gtk_widget_queue_resize (child); +} + +void +gtk_box_pack_end (GtkBox *box, + GtkWidget *child, + gint expand, + gint fill, + gint padding) +{ + GtkBoxChild *child_info; + + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + g_return_if_fail (child != NULL); + + child_info = g_new (GtkBoxChild, 1); + child_info->widget = child; + child_info->padding = padding; + child_info->expand = expand ? TRUE : FALSE; + child_info->fill = fill ? TRUE : FALSE; + child_info->pack = GTK_PACK_END; + + box->children = g_list_append (box->children, child_info); + + gtk_widget_set_parent (child, GTK_WIDGET (box)); + + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box))) + { + if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box)) + gtk_widget_queue_resize (child); +} + +void +gtk_box_pack_start_defaults (GtkBox *box, + GtkWidget *child) +{ + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + g_return_if_fail (child != NULL); + + gtk_box_pack_start (box, child, TRUE, TRUE, 0); +} + +void +gtk_box_pack_end_defaults (GtkBox *box, + GtkWidget *child) +{ + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + g_return_if_fail (child != NULL); + + gtk_box_pack_end (box, child, TRUE, TRUE, 0); +} + +void +gtk_box_set_homogeneous (GtkBox *box, + gint homogeneous) +{ + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + + if ((homogeneous ? TRUE : FALSE) != box->homogeneous) + { + box->homogeneous = homogeneous ? TRUE : FALSE; + gtk_widget_queue_resize (GTK_WIDGET (box)); + } +} + +void +gtk_box_set_spacing (GtkBox *box, + gint spacing) +{ + g_return_if_fail (box != NULL); + g_return_if_fail (GTK_IS_BOX (box)); + + if (spacing != box->spacing) + { + box->spacing = spacing; + gtk_widget_queue_resize (GTK_WIDGET (box)); + } +} + + +static void +gtk_box_destroy (GtkObject *object) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_BOX (object)); + + box = GTK_BOX (object); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + child->widget->parent = NULL; + gtk_object_unref (GTK_OBJECT (child->widget)); + gtk_widget_destroy (child->widget); + g_free (child); + } + + g_list_free (box->children); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_box_map (GtkWidget *widget) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BOX (widget)); + + box = GTK_BOX (widget); + GTK_WIDGET_SET_FLAGS (box, GTK_MAPPED); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + !GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); + } +} + +static void +gtk_box_unmap (GtkWidget *widget) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BOX (widget)); + + box = GTK_BOX (widget); + GTK_WIDGET_UNSET_FLAGS (box, GTK_MAPPED); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_unmap (child->widget); + } +} + +static void +gtk_box_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBox *box; + GtkBoxChild *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BOX (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + box = GTK_BOX (widget); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); + } + } +} + +static gint +gtk_box_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBox *box; + GtkBoxChild *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + box = GTK_BOX (widget); + + child_event = *event; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child->widget) && + gtk_widget_intersect (child->widget, &event->area, &child_event.area)) + gtk_widget_event (child->widget, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static void +gtk_box_add (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BOX (container)); + g_return_if_fail (widget != NULL); + + gtk_box_pack_start_defaults (GTK_BOX (container), widget); +} + +static void +gtk_box_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BOX (container)); + g_return_if_fail (widget != NULL); + + box = GTK_BOX (container); + + children = box->children; + while (children) + { + child = children->data; + + if (child->widget == widget) + { + gtk_widget_unparent (widget); + + box->children = g_list_remove_link (box->children, children); + g_list_free (children); + g_free (child); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + + break; + } + + children = children->next; + } +} + +static void +gtk_box_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BOX (container)); + g_return_if_fail (callback != NULL); + + box = GTK_BOX (container); + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (child->pack == GTK_PACK_START) + (* callback) (child->widget, callback_data); + } + + children = g_list_last (box->children); + while (children) + { + child = children->data; + children = children->prev; + + if (child->pack == GTK_PACK_END) + (* callback) (child->widget, callback_data); + } +} diff --git a/gtk/gtkbox.h b/gtk/gtkbox.h new file mode 100644 index 000000000..5ff0dd22a --- /dev/null +++ b/gtk/gtkbox.h @@ -0,0 +1,90 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_BOX_H__ +#define __GTK_BOX_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_BOX(obj) GTK_CHECK_CAST (obj, gtk_box_get_type (), GtkBox) +#define GTK_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_box_get_type (), GtkBoxClass) +#define GTK_IS_BOX(obj) GTK_CHECK_TYPE (obj, gtk_box_get_type ()) + + +typedef struct _GtkBox GtkBox; +typedef struct _GtkBoxClass GtkBoxClass; +typedef struct _GtkBoxChild GtkBoxChild; + +struct _GtkBox +{ + GtkContainer container; + + GList *children; + gint16 spacing; + guint homogeneous : 1; +}; + +struct _GtkBoxClass +{ + GtkContainerClass parent_class; +}; + +struct _GtkBoxChild +{ + GtkWidget *widget; + guint16 padding; + guint expand : 1; + guint fill : 1; + guint pack : 1; +}; + + +guint gtk_box_get_type (void); +void gtk_box_pack_start (GtkBox *box, + GtkWidget *child, + gint expand, + gint fill, + gint padding); +void gtk_box_pack_end (GtkBox *box, + GtkWidget *child, + gint expand, + gint fill, + gint padding); +void gtk_box_pack_start_defaults (GtkBox *box, + GtkWidget *widget); +void gtk_box_pack_end_defaults (GtkBox *box, + GtkWidget *widget); +void gtk_box_set_homogeneous (GtkBox *box, + gint homogeneous); +void gtk_box_set_spacing (GtkBox *box, + gint spacing); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_BOX_H__ */ diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c new file mode 100644 index 000000000..18afb177a --- /dev/null +++ b/gtk/gtkbutton.c @@ -0,0 +1,915 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkbutton.h" +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtksignal.h" + + +#define CHILD_SPACING 1 +#define DEFAULT_LEFT_POS 4 +#define DEFAULT_TOP_POS 4 +#define DEFAULT_SPACING 7 + + +enum { + PRESSED, + RELEASED, + CLICKED, + ENTER, + LEAVE, + LAST_SIGNAL +}; + + +static void gtk_button_class_init (GtkButtonClass *klass); +static void gtk_button_init (GtkButton *button); +static void gtk_button_arg (GtkButton *button, + GtkArg *arg); +static void gtk_button_destroy (GtkObject *object); +static void gtk_button_map (GtkWidget *widget); +static void gtk_button_unmap (GtkWidget *widget); +static void gtk_button_realize (GtkWidget *widget); +static void gtk_button_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_button_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_button_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_button_draw_focus (GtkWidget *widget); +static void gtk_button_draw_default (GtkWidget *widget); +static gint gtk_button_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_button_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_button_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_button_enter_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_button_leave_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_button_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_button_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_button_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_button_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_button_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +static void gtk_real_button_pressed (GtkButton *button); +static void gtk_real_button_released (GtkButton *button); +static void gtk_real_button_enter (GtkButton *button); +static void gtk_real_button_leave (GtkButton *button); + + +static GtkContainerClass *parent_class; +static gint button_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_button_get_type () +{ + static guint button_type = 0; + + if (!button_type) + { + GtkTypeInfo button_info = + { + "GtkButton", + sizeof (GtkButton), + sizeof (GtkButtonClass), + (GtkClassInitFunc) gtk_button_class_init, + (GtkObjectInitFunc) gtk_button_init, + (GtkArgFunc) gtk_button_arg, + }; + + button_type = gtk_type_unique (gtk_container_get_type (), &button_info); + } + + return button_type; +} + +static void +gtk_button_class_init (GtkButtonClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + container_class = (GtkContainerClass*) klass; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + gtk_object_add_arg_type ("GtkButton::label", GTK_TYPE_STRING); + + button_signals[PRESSED] = + gtk_signal_new ("pressed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, pressed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + button_signals[RELEASED] = + gtk_signal_new ("released", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, released), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + button_signals[CLICKED] = + gtk_signal_new ("clicked", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, clicked), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + button_signals[ENTER] = + gtk_signal_new ("enter", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, enter), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + button_signals[LEAVE] = + gtk_signal_new ("leave", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkButtonClass, leave), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, button_signals, LAST_SIGNAL); + + object_class->destroy = gtk_button_destroy; + + widget_class->activate_signal = button_signals[CLICKED]; + widget_class->map = gtk_button_map; + widget_class->unmap = gtk_button_unmap; + widget_class->realize = gtk_button_realize; + widget_class->draw = gtk_button_draw; + widget_class->draw_focus = gtk_button_draw_focus; + widget_class->draw_default = gtk_button_draw_default; + widget_class->size_request = gtk_button_size_request; + widget_class->size_allocate = gtk_button_size_allocate; + widget_class->expose_event = gtk_button_expose; + widget_class->button_press_event = gtk_button_button_press; + widget_class->button_release_event = gtk_button_button_release; + widget_class->enter_notify_event = gtk_button_enter_notify; + widget_class->leave_notify_event = gtk_button_leave_notify; + widget_class->focus_in_event = gtk_button_focus_in; + widget_class->focus_out_event = gtk_button_focus_out; + + container_class->add = gtk_button_add; + container_class->remove = gtk_button_remove; + container_class->foreach = gtk_button_foreach; + + klass->pressed = gtk_real_button_pressed; + klass->released = gtk_real_button_released; + klass->clicked = NULL; + klass->enter = gtk_real_button_enter; + klass->leave = gtk_real_button_leave; +} + +static void +gtk_button_init (GtkButton *button) +{ + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS); + + button->child = NULL; + button->in_button = FALSE; + button->button_down = FALSE; +} + +static void +gtk_button_arg (GtkButton *button, + GtkArg *arg) +{ + if (strcmp (arg->name, "label") == 0) + { + GtkWidget *label; + + gtk_container_disable_resize (GTK_CONTAINER (button)); + + if (button->child) + gtk_widget_destroy (button->child); + + label = gtk_label_new (GTK_VALUE_STRING(*arg)); + gtk_widget_show (label); + + gtk_container_add (GTK_CONTAINER (button), label); + gtk_container_enable_resize (GTK_CONTAINER (button)); + } +} + +GtkWidget* +gtk_button_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_button_get_type ())); +} + +GtkWidget* +gtk_button_new_with_label (const gchar *label) +{ + GtkWidget *button; + GtkWidget *label_widget; + + button = gtk_button_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5); + + gtk_container_add (GTK_CONTAINER (button), label_widget); + gtk_widget_show (label_widget); + + return button; +} + +void +gtk_button_pressed (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[PRESSED]); +} + +void +gtk_button_released (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[RELEASED]); +} + +void +gtk_button_clicked (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]); +} + +void +gtk_button_enter (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[ENTER]); +} + +void +gtk_button_leave (GtkButton *button) +{ + gtk_signal_emit (GTK_OBJECT (button), button_signals[LEAVE]); +} + +static void +gtk_button_destroy (GtkObject *object) +{ + GtkButton *button; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_BUTTON (object)); + + button = GTK_BUTTON (object); + + if (button->child) + { + button->child->parent = NULL; + gtk_object_unref (GTK_OBJECT (button->child)); + gtk_widget_destroy (button->child); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_button_map (GtkWidget *widget) +{ + GtkButton *button; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + gdk_window_show (widget->window); + + button = GTK_BUTTON (widget); + + if (button->child && + GTK_WIDGET_VISIBLE (button->child) && + !GTK_WIDGET_MAPPED (button->child)) + gtk_widget_map (button->child); +} + +static void +gtk_button_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_button_realize (GtkWidget *widget) +{ + GtkButton *button; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + button = GTK_BUTTON (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, button); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_button_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkButton *button; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + g_return_if_fail (requisition != NULL); + + button = GTK_BUTTON (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING + + GTK_WIDGET (widget)->style->klass->xthickness) * 2; + requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING + + GTK_WIDGET (widget)->style->klass->ythickness) * 2; + + if (GTK_WIDGET_CAN_DEFAULT (widget)) + { + requisition->width += (GTK_WIDGET (widget)->style->klass->xthickness * 2 + + DEFAULT_SPACING); + requisition->height += (GTK_WIDGET (widget)->style->klass->ythickness * 2 + + DEFAULT_SPACING); + } + + if (button->child && GTK_WIDGET_VISIBLE (button->child)) + { + gtk_widget_size_request (button->child, &button->child->requisition); + + requisition->width += button->child->requisition.width; + requisition->height += button->child->requisition.height; + } +} + +static void +gtk_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkButton *button; + GtkAllocation child_allocation; + gint border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + border_width = GTK_CONTAINER (widget)->border_width; + + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + widget->allocation.x + border_width, + widget->allocation.y + border_width, + widget->allocation.width - border_width * 2, + widget->allocation.height - border_width * 2); + + button = GTK_BUTTON (widget); + + if (button->child && GTK_WIDGET_VISIBLE (button->child)) + { + child_allocation.x = (CHILD_SPACING + GTK_WIDGET (widget)->style->klass->xthickness); + child_allocation.y = (CHILD_SPACING + GTK_WIDGET (widget)->style->klass->ythickness); + + child_allocation.width = widget->allocation.width - child_allocation.x * 2 - + border_width * 2; + child_allocation.height = widget->allocation.height - child_allocation.y * 2 - + border_width * 2; + + if (GTK_WIDGET_CAN_DEFAULT (button)) + { + child_allocation.x += (GTK_WIDGET (widget)->style->klass->xthickness + + DEFAULT_LEFT_POS); + child_allocation.y += (GTK_WIDGET (widget)->style->klass->ythickness + + DEFAULT_TOP_POS); + child_allocation.width -= (GTK_WIDGET (widget)->style->klass->xthickness * 2 + + DEFAULT_SPACING); + child_allocation.height -= (GTK_WIDGET (widget)->style->klass->xthickness * 2 + + DEFAULT_SPACING); + } + + gtk_widget_size_allocate (button->child, &child_allocation); + } +} + +static void +gtk_button_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GdkRectangle restrict_area; + GdkRectangle new_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + restrict_area.x = GTK_WIDGET (widget)->style->klass->xthickness; + restrict_area.y = GTK_WIDGET (widget)->style->klass->ythickness; + restrict_area.width = (GTK_WIDGET (widget)->allocation.width - restrict_area.x * 2 - + GTK_CONTAINER (widget)->border_width * 2); + restrict_area.height = (GTK_WIDGET (widget)->allocation.height - restrict_area.y * 2 - + GTK_CONTAINER (widget)->border_width * 2); + + if (GTK_WIDGET_CAN_DEFAULT (widget)) + { + restrict_area.x += DEFAULT_LEFT_POS; + restrict_area.y += DEFAULT_TOP_POS; + restrict_area.width -= DEFAULT_SPACING; + restrict_area.height -= DEFAULT_SPACING; + } + + if (gdk_rectangle_intersect (area, &restrict_area, &new_area)) + { + gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (widget)); + gdk_window_clear_area (widget->window, + new_area.x, new_area.y, + new_area.width, new_area.height); + } + } +} + +static void +gtk_button_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkButton *button; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + button = GTK_BUTTON (widget); + + gtk_button_paint (widget, area); + + if (button->child && gtk_widget_intersect (button->child, area, &child_area)) + gtk_widget_draw (button->child, &child_area); + + gtk_widget_draw_default (widget); + gtk_widget_draw_focus (widget); + } +} + +static void +gtk_button_draw_focus (GtkWidget *widget) +{ + GtkButton *button; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + button = GTK_BUTTON (widget); + + x = 0; + y = 0; + width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2; + height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2; + + if (GTK_WIDGET_CAN_DEFAULT (widget)) + { + x += widget->style->klass->xthickness; + y += widget->style->klass->ythickness; + width -= 2 * x + DEFAULT_SPACING; + height -= 2 * y + DEFAULT_SPACING; + x += DEFAULT_LEFT_POS; + y += DEFAULT_TOP_POS; + } + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + } + else + { + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE, + x + 1, y + 1, width - 4, height - 4); + else + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE, + x + 2, y + 2, width - 5, height - 5); + } + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), shadow_type, + x, y, width, height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x -= 1; + y -= 1; + width += 2; + height += 2; + + gdk_draw_rectangle (widget->window, + widget->style->black_gc, FALSE, + x, y, width - 1, height - 1); + } + } +} + +static void +gtk_button_draw_default (GtkWidget *widget) +{ + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_BUTTON (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + x = 0; + y = 0; + width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2; + height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2; + + if (GTK_WIDGET_HAS_DEFAULT (widget)) + { + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + x, y, width, height); + } + else + { + gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL], + FALSE, x, y, width - 1, height - 1); + gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL], + FALSE, x + 1, y + 1, width - 3, height - 3); + } + } +} + +static gint +gtk_button_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkButton *button; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + button = GTK_BUTTON (widget); + + gtk_button_paint (widget, &event->area); + + child_event = *event; + if (button->child && GTK_WIDGET_NO_WINDOW (button->child) && + gtk_widget_intersect (button->child, &event->area, &child_event.area)) + gtk_widget_event (button->child, (GdkEvent*) &child_event); + + gtk_widget_draw_default (widget); + gtk_widget_draw_focus (widget); + } + + return FALSE; +} + +static gint +gtk_button_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkButton *button; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->type == GDK_BUTTON_PRESS) + { + button = GTK_BUTTON (widget); + + if (GTK_WIDGET_CAN_DEFAULT (widget) && (event->button == 1)) + gtk_widget_grab_default (widget); + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + if (event->button == 1) + { + gtk_grab_add (GTK_WIDGET (button)); + gtk_button_pressed (button); + } + } + + return TRUE; +} + +static gint +gtk_button_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkButton *button; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->button == 1) + { + button = GTK_BUTTON (widget); + gtk_grab_remove (GTK_WIDGET (button)); + gtk_button_released (button); + } + + return TRUE; +} + +static gint +gtk_button_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkButton *button; + GtkWidget *event_widget; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + button = GTK_BUTTON (widget); + event_widget = gtk_get_event_widget ((GdkEvent*) event); + + if ((event_widget == widget) && + (event->detail != GDK_NOTIFY_INFERIOR)) + { + button->in_button = TRUE; + gtk_button_enter (button); + } + + return FALSE; +} + +static gint +gtk_button_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkButton *button; + GtkWidget *event_widget; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + button = GTK_BUTTON (widget); + event_widget = gtk_get_event_widget ((GdkEvent*) event); + + if ((event_widget == widget) && + (event->detail != GDK_NOTIFY_INFERIOR)) + { + button->in_button = FALSE; + gtk_button_leave (button); + } + + return FALSE; +} + +static gint +gtk_button_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_button_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static void +gtk_button_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkButton *button; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BUTTON (container)); + g_return_if_fail (widget != NULL); + g_return_if_fail (gtk_widget_basic (widget)); + + button = GTK_BUTTON (container); + + if (!button->child) + { + gtk_widget_set_parent (widget, GTK_WIDGET (container)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + button->child = widget; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (widget); + } +} + +static void +gtk_button_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkButton *button; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BUTTON (container)); + + button = GTK_BUTTON (container); + + if (button->child == widget) + { + gtk_widget_unparent (widget); + + button->child = NULL; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +gtk_button_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkButton *button; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_BUTTON (container)); + g_return_if_fail (callback != NULL); + + button = GTK_BUTTON (container); + + if (button->child) + (* callback) (button->child, callback_data); +} + +static void +gtk_real_button_pressed (GtkButton *button) +{ + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_BUTTON (button)); + + button->button_down = TRUE; + + new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} + +static void +gtk_real_button_released (GtkButton *button) +{ + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_BUTTON (button)); + + if (button->button_down) + { + button->button_down = FALSE; + + if (button->in_button) + gtk_button_clicked (button); + + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } + } +} + +static void +gtk_real_button_enter (GtkButton *button) +{ + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_BUTTON (button)); + + new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} + +static void +gtk_real_button_leave (GtkButton *button) +{ + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_BUTTON (button)); + + if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL) + { + gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_NORMAL); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} diff --git a/gtk/gtkbutton.h b/gtk/gtkbutton.h new file mode 100644 index 000000000..ec72c99f7 --- /dev/null +++ b/gtk/gtkbutton.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_BUTTON_H__ +#define __GTK_BUTTON_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_BUTTON(obj) GTK_CHECK_CAST (obj, gtk_button_get_type (), GtkButton) +#define GTK_BUTTON_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_button_get_type (), GtkButtonClass) +#define GTK_IS_BUTTON(obj) GTK_CHECK_TYPE (obj, gtk_button_get_type ()) + + +typedef struct _GtkButton GtkButton; +typedef struct _GtkButtonClass GtkButtonClass; + +struct _GtkButton +{ + GtkContainer container; + + GtkWidget *child; + + guint in_button : 1; + guint button_down : 1; +}; + +struct _GtkButtonClass +{ + GtkContainerClass parent_class; + + void (* pressed) (GtkButton *button); + void (* released) (GtkButton *button); + void (* clicked) (GtkButton *button); + void (* enter) (GtkButton *button); + void (* leave) (GtkButton *button); +}; + + +guint gtk_button_get_type (void); +GtkWidget* gtk_button_new (void); +GtkWidget* gtk_button_new_with_label (const gchar *label); +void gtk_button_pressed (GtkButton *button); +void gtk_button_released (GtkButton *button); +void gtk_button_clicked (GtkButton *button); +void gtk_button_enter (GtkButton *button); +void gtk_button_leave (GtkButton *button); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_BUTTON_H__ */ diff --git a/gtk/gtkcheckbutton.c b/gtk/gtkcheckbutton.c new file mode 100644 index 000000000..d7f72ce1c --- /dev/null +++ b/gtk/gtkcheckbutton.c @@ -0,0 +1,362 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkcheckbutton.h" +#include "gtklabel.h" + + +#define INDICATOR_SIZE 10 +#define INDICATOR_SPACING 2 + +#define CHECK_BUTTON_CLASS(w) GTK_CHECK_BUTTON_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_check_button_class_init (GtkCheckButtonClass *klass); +static void gtk_check_button_init (GtkCheckButton *check_button); +static void gtk_check_button_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_check_button_draw_focus (GtkWidget *widget); +static void gtk_check_button_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_check_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_check_button_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_check_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area); +static void gtk_real_check_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area); + + +static GtkToggleButtonClass *parent_class = NULL; + + +guint +gtk_check_button_get_type () +{ + static guint check_button_type = 0; + + if (!check_button_type) + { + GtkTypeInfo check_button_info = + { + "GtkCheckButton", + sizeof (GtkCheckButton), + sizeof (GtkCheckButtonClass), + (GtkClassInitFunc) gtk_check_button_class_init, + (GtkObjectInitFunc) gtk_check_button_init, + (GtkArgFunc) NULL, + }; + + check_button_type = gtk_type_unique (gtk_toggle_button_get_type (), &check_button_info); + } + + return check_button_type; +} + +static void +gtk_check_button_class_init (GtkCheckButtonClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + parent_class = gtk_type_class (gtk_toggle_button_get_type ()); + + widget_class->draw = gtk_check_button_draw; + widget_class->draw_focus = gtk_check_button_draw_focus; + widget_class->size_request = gtk_check_button_size_request; + widget_class->size_allocate = gtk_check_button_size_allocate; + widget_class->expose_event = gtk_check_button_expose; + + class->indicator_size = INDICATOR_SIZE; + class->indicator_spacing = INDICATOR_SPACING; + class->draw_indicator = gtk_real_check_button_draw_indicator; +} + +static void +gtk_check_button_init (GtkCheckButton *check_button) +{ + check_button->toggle_button.draw_indicator = TRUE; +} + +GtkWidget* +gtk_check_button_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_check_button_get_type ())); +} + + +GtkWidget* +gtk_check_button_new_with_label (const gchar *label) +{ + GtkWidget *check_button; + GtkWidget *label_widget; + + check_button = gtk_check_button_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (check_button), label_widget); + gtk_widget_show (label_widget); + + return check_button; +} + +static void +gtk_check_button_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkButton *button; + GtkCheckButton *check_button; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + check_button = GTK_CHECK_BUTTON (widget); + + if (check_button->toggle_button.draw_indicator) + { + button = GTK_BUTTON (widget); + + gtk_check_button_draw_indicator (check_button, area); + + if (button->child && GTK_WIDGET_NO_WINDOW (button->child) && + gtk_widget_intersect (button->child, area, &child_area)) + gtk_widget_draw (button->child, &child_area); + + gtk_widget_draw_focus (widget); + } + else + { + if (GTK_WIDGET_CLASS (parent_class)->draw) + (* GTK_WIDGET_CLASS (parent_class)->draw) (widget, area); + } + } +} + +static void +gtk_check_button_draw_focus (GtkWidget *widget) +{ + GtkCheckButton *check_button; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + check_button = GTK_CHECK_BUTTON (widget); + if (check_button->toggle_button.draw_indicator) + { + if (GTK_WIDGET_HAS_FOCUS (widget)) + gdk_draw_rectangle (widget->window, + widget->style->black_gc, FALSE, 0, 0, + widget->allocation.width - 1, + widget->allocation.height - 1); + else + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_STATE_NORMAL], FALSE, 0, 0, + widget->allocation.width - 1, + widget->allocation.height - 1); + } + else + { + if (GTK_WIDGET_CLASS (parent_class)->draw_focus) + (* GTK_WIDGET_CLASS (parent_class)->draw_focus) (widget); + } + } +} + +static void +gtk_check_button_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkCheckButton *check_button; + GtkButton *button; + gint temp; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (widget)); + g_return_if_fail (requisition != NULL); + + check_button = GTK_CHECK_BUTTON (widget); + + if (GTK_WIDGET_CLASS (parent_class)->size_request) + (* GTK_WIDGET_CLASS (parent_class)->size_request) (widget, requisition); + + if (check_button->toggle_button.draw_indicator) + { + button = GTK_BUTTON (widget); + + requisition->width += (CHECK_BUTTON_CLASS (widget)->indicator_size + + CHECK_BUTTON_CLASS (widget)->indicator_spacing * 3 + 2); + + temp = (CHECK_BUTTON_CLASS (widget)->indicator_size + + CHECK_BUTTON_CLASS (widget)->indicator_spacing * 2); + requisition->height = MAX (requisition->height, temp) + 2; + } +} + +static void +gtk_check_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkCheckButton *check_button; + GtkButton *button; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (widget)); + g_return_if_fail (allocation != NULL); + + check_button = GTK_CHECK_BUTTON (widget); + if (check_button->toggle_button.draw_indicator) + { + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + button = GTK_BUTTON (widget); + + if (button->child && GTK_WIDGET_VISIBLE (button->child)) + { + child_allocation.x = (GTK_CONTAINER (widget)->border_width + + CHECK_BUTTON_CLASS (widget)->indicator_size + + CHECK_BUTTON_CLASS (widget)->indicator_spacing * 3 + 1); + child_allocation.y = GTK_CONTAINER (widget)->border_width + 1; + child_allocation.width = (allocation->width - child_allocation.x - + GTK_CONTAINER (widget)->border_width - 1); + child_allocation.height = allocation->height - child_allocation.y * 2; + + gtk_widget_size_allocate (button->child, &child_allocation); + } + } + else + { + if (GTK_WIDGET_CLASS (parent_class)->size_allocate) + (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation); + } +} + +static gint +gtk_check_button_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkButton *button; + GtkCheckButton *check_button; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CHECK_BUTTON (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + check_button = GTK_CHECK_BUTTON (widget); + + if (check_button->toggle_button.draw_indicator) + { + button = GTK_BUTTON (widget); + + gtk_check_button_draw_indicator (check_button, &event->area); + + child_event = *event; + if (button->child && GTK_WIDGET_NO_WINDOW (button->child) && + gtk_widget_intersect (button->child, &event->area, &child_event.area)) + gtk_widget_event (button->child, (GdkEvent*) &child_event); + + gtk_widget_draw_focus (widget); + } + else + { + if (GTK_WIDGET_CLASS (parent_class)->expose_event) + (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); + } + } + + return FALSE; +} + + +static void +gtk_check_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area) +{ + GtkCheckButtonClass *class; + + g_return_if_fail (check_button != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (check_button)); + g_return_if_fail (CHECK_BUTTON_CLASS (check_button) != NULL); + + class = CHECK_BUTTON_CLASS (check_button); + + if (class->draw_indicator) + (* class->draw_indicator) (check_button, area); +} + +static void +gtk_real_check_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area) +{ + GtkWidget *widget; + GtkToggleButton *toggle_button; + GtkStateType state_type; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + + g_return_if_fail (check_button != NULL); + g_return_if_fail (GTK_IS_CHECK_BUTTON (check_button)); + + if (GTK_WIDGET_DRAWABLE (check_button)) + { + widget = GTK_WIDGET (check_button); + toggle_button = GTK_TOGGLE_BUTTON (check_button); + + state_type = GTK_WIDGET_STATE (widget); + if ((state_type != GTK_STATE_NORMAL) && + (state_type != GTK_STATE_PRELIGHT)) + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (widget->style, widget->window, state_type); + gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height); + + x = CHECK_BUTTON_CLASS (widget)->indicator_spacing + GTK_CONTAINER (widget)->border_width; + y = (widget->allocation.height - CHECK_BUTTON_CLASS (widget)->indicator_size) / 2; + width = CHECK_BUTTON_CLASS (widget)->indicator_size; + height = CHECK_BUTTON_CLASS (widget)->indicator_size; + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + shadow_type = GTK_SHADOW_IN; + else if ((GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) && toggle_button->active) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], + TRUE, x + 1, y + 1, width, height); + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), shadow_type, + x + 1, y + 1, width, height); + } +} diff --git a/gtk/gtkcheckbutton.h b/gtk/gtkcheckbutton.h new file mode 100644 index 000000000..8994db563 --- /dev/null +++ b/gtk/gtkcheckbutton.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_CHECK_BUTTON_H__ +#define __GTK_CHECK_BUTTON_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_CHECK_BUTTON(obj) GTK_CHECK_CAST (obj, gtk_check_button_get_type (), GtkCheckButton) +#define GTK_CHECK_BUTTON_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_check_button_get_type (), GtkCheckButtonClass) +#define GTK_IS_CHECK_BUTTON(obj) GTK_CHECK_TYPE (obj, gtk_check_button_get_type ()) + + +typedef struct _GtkCheckButton GtkCheckButton; +typedef struct _GtkCheckButtonClass GtkCheckButtonClass; + +struct _GtkCheckButton +{ + GtkToggleButton toggle_button; +}; + +struct _GtkCheckButtonClass +{ + GtkToggleButtonClass parent_class; + + guint16 indicator_size; + guint16 indicator_spacing; + + void (* draw_indicator) (GtkCheckButton *check_button, + GdkRectangle *area); +}; + + +guint gtk_check_button_get_type (void); +GtkWidget* gtk_check_button_new (void); +GtkWidget* gtk_check_button_new_with_label (const gchar *label); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_CHECK_BUTTON_H__ */ diff --git a/gtk/gtkcheckmenuitem.c b/gtk/gtkcheckmenuitem.c new file mode 100644 index 000000000..a36dfa75a --- /dev/null +++ b/gtk/gtkcheckmenuitem.c @@ -0,0 +1,250 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkcheckmenuitem.h" +#include "gtklabel.h" +#include "gtksignal.h" + + +#define CHECK_MENU_ITEM_CLASS(w) GTK_CHECK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass) + + +enum { + TOGGLED, + LAST_SIGNAL +}; + + +static void gtk_check_menu_item_class_init (GtkCheckMenuItemClass *klass); +static void gtk_check_menu_item_init (GtkCheckMenuItem *check_menu_item); +static void gtk_check_menu_item_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_check_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_check_menu_item_activate (GtkMenuItem *menu_item); +static void gtk_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area); +static void gtk_real_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area); + + +static GtkMenuItemClass *parent_class = NULL; +static gint check_menu_item_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_check_menu_item_get_type () +{ + static guint check_menu_item_type = 0; + + if (!check_menu_item_type) + { + GtkTypeInfo check_menu_item_info = + { + "GtkCheckMenuItem", + sizeof (GtkCheckMenuItem), + sizeof (GtkCheckMenuItemClass), + (GtkClassInitFunc) gtk_check_menu_item_class_init, + (GtkObjectInitFunc) gtk_check_menu_item_init, + (GtkArgFunc) NULL, + }; + + check_menu_item_type = gtk_type_unique (gtk_menu_item_get_type (), &check_menu_item_info); + } + + return check_menu_item_type; +} + +GtkWidget* +gtk_check_menu_item_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_check_menu_item_get_type ())); +} + +GtkWidget* +gtk_check_menu_item_new_with_label (const gchar *label) +{ + GtkWidget *check_menu_item; + GtkWidget *label_widget; + + check_menu_item = gtk_check_menu_item_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (check_menu_item), label_widget); + gtk_widget_show (label_widget); + + return check_menu_item; +} + +void +gtk_check_menu_item_set_state (GtkCheckMenuItem *check_menu_item, + gint state) +{ + g_return_if_fail (check_menu_item != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item)); + + if (check_menu_item->active != state) + gtk_menu_item_activate (GTK_MENU_ITEM (check_menu_item)); +} + +void +gtk_check_menu_item_toggled (GtkCheckMenuItem *check_menu_item) +{ + gtk_signal_emit (GTK_OBJECT (check_menu_item), check_menu_item_signals[TOGGLED]); +} + + +static void +gtk_check_menu_item_class_init (GtkCheckMenuItemClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkMenuItemClass *menu_item_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + menu_item_class = (GtkMenuItemClass*) klass; + + parent_class = gtk_type_class (gtk_menu_item_get_type ()); + + check_menu_item_signals[TOGGLED] = + gtk_signal_new ("toggled", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkCheckMenuItemClass, toggled), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, check_menu_item_signals, LAST_SIGNAL); + + widget_class->draw = gtk_check_menu_item_draw; + widget_class->expose_event = gtk_check_menu_item_expose; + + menu_item_class->activate = gtk_check_menu_item_activate; + menu_item_class->toggle_size = 12; + + klass->toggled = NULL; + klass->draw_indicator = gtk_real_check_menu_item_draw_indicator; +} + +static void +gtk_check_menu_item_init (GtkCheckMenuItem *check_menu_item) +{ + check_menu_item->active = FALSE; +} + +static void +gtk_check_menu_item_draw (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_CLASS (parent_class)->draw) + (* GTK_WIDGET_CLASS (parent_class)->draw) (widget, area); + + gtk_check_menu_item_draw_indicator (GTK_CHECK_MENU_ITEM (widget), area); +} + +static gint +gtk_check_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CHECK_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_CLASS (parent_class)->expose_event) + (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); + + gtk_check_menu_item_draw_indicator (GTK_CHECK_MENU_ITEM (widget), &event->area); + + return FALSE; +} + +static void +gtk_check_menu_item_activate (GtkMenuItem *menu_item) +{ + GtkCheckMenuItem *check_menu_item; + + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (menu_item)); + + check_menu_item = GTK_CHECK_MENU_ITEM (menu_item); + check_menu_item->active = !check_menu_item->active; + + gtk_check_menu_item_toggled (check_menu_item); + gtk_widget_queue_draw (GTK_WIDGET (check_menu_item)); +} + +static void +gtk_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area) +{ + g_return_if_fail (check_menu_item != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item)); + g_return_if_fail (CHECK_MENU_ITEM_CLASS (check_menu_item) != NULL); + + if (CHECK_MENU_ITEM_CLASS (check_menu_item)->draw_indicator) + (* CHECK_MENU_ITEM_CLASS (check_menu_item)->draw_indicator) (check_menu_item, area); +} + +static void +gtk_real_check_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area) +{ + GtkWidget *widget; + GtkStateType state_type; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + + g_return_if_fail (check_menu_item != NULL); + g_return_if_fail (GTK_IS_CHECK_MENU_ITEM (check_menu_item)); + + if (GTK_WIDGET_DRAWABLE (check_menu_item)) + { + widget = GTK_WIDGET (check_menu_item); + + width = 8; + height = 8; + x = (GTK_CONTAINER (check_menu_item)->border_width + + widget->style->klass->xthickness + 2); + y = (widget->allocation.height - height) / 2; + + gdk_window_clear_area (widget->window, x, y, width, height); + + if (check_menu_item->active || + (GTK_WIDGET_STATE (check_menu_item) == GTK_STATE_PRELIGHT)) + { + state_type = GTK_WIDGET_STATE (widget); + + shadow_type = GTK_SHADOW_IN; + if (check_menu_item->active && (state_type == GTK_STATE_PRELIGHT)) + shadow_type = GTK_SHADOW_OUT; + + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[state_type], + TRUE, x, y, width, height); + gtk_draw_shadow (widget->style, widget->window, + state_type, shadow_type, + x, y, width, height); + } + } +} diff --git a/gtk/gtkcheckmenuitem.h b/gtk/gtkcheckmenuitem.h new file mode 100644 index 000000000..1dc816c7c --- /dev/null +++ b/gtk/gtkcheckmenuitem.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_MENU_CHECK_ITEM_H__ +#define __GTK_MENU_CHECK_ITEM_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_CHECK_MENU_ITEM(obj) ((GtkCheckMenuItem*) obj) +#define GTK_CHECK_MENU_ITEM_CLASS(obj) ((GtkCheckMenuItemClass*) GTK_OBJECT_CLASS (obj)) +#define GTK_IS_CHECK_MENU_ITEM(obj) (gtk_type_is_a (GTK_WIDGET_TYPE (obj), gtk_check_menu_item_get_type ())) + + +typedef struct _GtkCheckMenuItem GtkCheckMenuItem; +typedef struct _GtkCheckMenuItemClass GtkCheckMenuItemClass; + +struct _GtkCheckMenuItem +{ + GtkMenuItem menu_item; + + guint active : 1; +}; + +struct _GtkCheckMenuItemClass +{ + GtkMenuItemClass parent_class; + + void (* toggled) (GtkCheckMenuItem *check_menu_item); + void (* draw_indicator) (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area); +}; + + +guint gtk_check_menu_item_get_type (void); +GtkWidget* gtk_check_menu_item_new (void); +GtkWidget* gtk_check_menu_item_new_with_label (const gchar *label); +void gtk_check_menu_item_set_state (GtkCheckMenuItem *check_menu_item, + gint state); +void gtk_check_menu_item_toggled (GtkCheckMenuItem *check_menu_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_CHECK_MENU_ITEM_H__ */ diff --git a/gtk/gtkcolorsel.c b/gtk/gtkcolorsel.c new file mode 100644 index 000000000..78780b2ff --- /dev/null +++ b/gtk/gtkcolorsel.c @@ -0,0 +1,1463 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkcolorsel.h" + + +#define DEGTORAD(a) (2.0*M_PI*a/360.0) +#define SQR(a) (a*a) + +#define TIMER_DELAY 300 + +#define CIRCLE_RADIUS 65 + +#define WHEEL_WIDTH 2*CIRCLE_RADIUS+2 +#define WHEEL_HEIGHT 2*CIRCLE_RADIUS+2 + +#define VALUE_WIDTH 32 +#define VALUE_HEIGHT WHEEL_HEIGHT + +#define SAMPLE_WIDTH WHEEL_WIDTH+VALUE_WIDTH+5 +#define SAMPLE_HEIGHT 28 + + +enum +{ + COLOR_CHANGED, + LAST_SIGNAL +}; + +enum +{ + RGB_INPUTS = 1 << 0, + HSV_INPUTS = 1 << 1, + OPACITY_INPUTS = 1 << 2 +}; + +enum +{ + SCALE, + ENTRY, + BOTH +}; + +enum +{ + HUE, + SATURATION, + VALUE, + RED, + GREEN, + BLUE, + OPACITY, + NUM_CHANNELS +}; + +typedef struct +{ + gchar *label; + gfloat lower, upper, step_inc, page_inc; + GtkSignalFunc updater; +} scale_val_type; + + +#define HSV_TO_RGB() gtk_color_selection_hsv_to_rgb( \ + colorsel->values[HUE], \ + colorsel->values[SATURATION], \ + colorsel->values[VALUE], \ + &colorsel->values[RED], \ + &colorsel->values[GREEN], \ + &colorsel->values[BLUE]) + +#define RGB_TO_HSV() gtk_color_selection_rgb_to_hsv( \ + colorsel->values[RED], \ + colorsel->values[GREEN], \ + colorsel->values[BLUE], \ + &colorsel->values[HUE], \ + &colorsel->values[SATURATION], \ + &colorsel->values[VALUE]) + + +static void gtk_color_selection_hsv_updater (GtkWidget *widget, + gpointer data); +static void gtk_color_selection_rgb_updater (GtkWidget *widget, + gpointer data); +static void gtk_color_selection_opacity_updater (GtkWidget *widget, + gpointer data); +static void gtk_color_selection_realize (GtkWidget *widget); +static void gtk_color_selection_destroy (GtkObject *object); +static void gtk_color_selection_color_changed (GtkColorSelection *colorsel); +static void gtk_color_selection_update_input (GtkWidget *scale, + GtkWidget *entry, + gdouble value); +static void gtk_color_selection_update_inputs (GtkColorSelection *colorsel, + gint inputs, + gint which); +static void gtk_color_selection_update_value (GtkColorSelection *colorsel, + gint y); +static void gtk_color_selection_update_wheel (GtkColorSelection *colorsel, + gint x, + gint y); +static void gtk_color_selection_value_resize (GtkWidget *widget, + gpointer data); +static gint gtk_color_selection_value_events (GtkWidget *area, + GdkEvent *event); +static gint gtk_color_selection_value_timeout (GtkColorSelection *colorsel); +static void gtk_color_selection_wheel_resize (GtkWidget *widget, + gpointer data); +static gint gtk_color_selection_wheel_events (GtkWidget *area, + GdkEvent *event); +static gint gtk_color_selection_wheel_timeout (GtkColorSelection *colorsel); +static void gtk_color_selection_sample_resize (GtkWidget *widget, + gpointer data); +static void gtk_color_selection_drop_handle (GtkWidget *widget, + GdkEvent *event); +static void gtk_color_selection_drag_handle (GtkWidget *widget, + GdkEvent *event); +static void gtk_color_selection_draw_wheel_marker (GtkColorSelection *colorsel); +static void gtk_color_selection_draw_wheel_frame (GtkColorSelection *colorsel); +static void gtk_color_selection_draw_value_marker (GtkColorSelection *colorsel); +static void gtk_color_selection_draw_value_bar (GtkColorSelection *colorsel, + gint resize); +static void gtk_color_selection_draw_wheel (GtkColorSelection *colorsel, + gint resize); +static void gtk_color_selection_draw_sample (GtkColorSelection *colorsel, + gint resize); + +static gint gtk_color_selection_eval_wheel (gint x, gint y, + gdouble cx, gdouble cy, + gdouble *h, gdouble *s); + +static void gtk_color_selection_hsv_to_rgb (gdouble h, gdouble s, gdouble v, + gdouble *r, gdouble *g, gdouble *b); +static void gtk_color_selection_rgb_to_hsv (gdouble r, gdouble g, gdouble b, + gdouble *h, gdouble *s, gdouble *v); + +static void gtk_color_selection_dialog_destroy (GtkObject *object); + + +static GtkVBoxClass *color_selection_parent_class = NULL; +static GtkWindowClass *color_selection_dialog_parent_class = NULL; + + +static gint color_selection_signals[LAST_SIGNAL] = {0}; + + +#define SF GtkSignalFunc + + +scale_val_type scale_vals[NUM_CHANNELS] = +{ + {"Hue:", 0.0, 360.0, 1.00, 10.00, (SF) gtk_color_selection_hsv_updater}, + {"Saturation:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_hsv_updater}, + {"Value:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_hsv_updater}, + {"Red:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_rgb_updater}, + {"Green:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_rgb_updater}, + {"Blue:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_rgb_updater}, + {"Opacity:", 0.0, 1.0, 0.01, 0.01, (SF) gtk_color_selection_opacity_updater} +}; + +guint +gtk_color_selection_get_type () +{ + static guint color_selection_type = 0; + + if (!color_selection_type) + { + GtkTypeInfo colorsel_info = + { + "color selection widget", + sizeof (GtkColorSelection), + sizeof (GtkColorSelectionClass), + (GtkClassInitFunc) gtk_color_selection_class_init, + (GtkObjectInitFunc) gtk_color_selection_init, + }; + + color_selection_type = gtk_type_unique (gtk_vbox_get_type (), &colorsel_info); + } + + return color_selection_type; +} + +void +gtk_color_selection_class_init (GtkColorSelectionClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + container_class = (GtkContainerClass*) klass; + + color_selection_parent_class = gtk_type_class (gtk_vbox_get_type ()); + + color_selection_signals[COLOR_CHANGED] = + gtk_signal_new ("color_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkColorSelectionClass, color_changed), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, color_selection_signals, LAST_SIGNAL); + + object_class->destroy = gtk_color_selection_destroy; + + widget_class->realize = gtk_color_selection_realize; +} + +void +gtk_color_selection_init (GtkColorSelection *colorsel) +{ + GtkWidget *frame, *hbox, *vbox, *hbox2, *label, *table; + GtkObject *adj; + gint old_mask, n; + gchar txt[32]; + + for (n = RED; n <= OPACITY; n++) + colorsel->values[n] = 1.0; + + RGB_TO_HSV (); + + for (n = HUE; n <= OPACITY; n++) + colorsel->old_values[n] = colorsel->values[n]; + + colorsel->wheel_gc = NULL; + colorsel->value_gc = NULL; + colorsel->sample_gc = NULL; + colorsel->wheel_buf = NULL; + colorsel->value_buf = NULL; + colorsel->sample_buf = NULL; + + colorsel->use_opacity = FALSE; + colorsel->timer_active = FALSE; + colorsel->policy = GTK_UPDATE_CONTINUOUS; + + hbox = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (hbox), 5); + gtk_container_add (GTK_CONTAINER (colorsel), hbox); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_container_add (GTK_CONTAINER (hbox), vbox); + gtk_widget_show (vbox); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_container_add (GTK_CONTAINER (vbox), hbox2); + gtk_widget_show (hbox2); + + colorsel->wheel_area = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_widget_set_events (colorsel->wheel_area, + old_mask | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + gtk_preview_size (GTK_PREVIEW (colorsel->wheel_area), WHEEL_WIDTH, WHEEL_HEIGHT); + gtk_preview_set_expand (GTK_PREVIEW (colorsel->wheel_area), TRUE); + gtk_container_add (GTK_CONTAINER (hbox2), colorsel->wheel_area); + gtk_widget_show (colorsel->wheel_area); + + old_mask = gtk_widget_get_events (colorsel->wheel_area); + + gtk_signal_connect (GTK_OBJECT (colorsel->wheel_area), "event", + (SF) gtk_color_selection_wheel_events, (gpointer) colorsel->wheel_area); + gtk_signal_connect_after (GTK_OBJECT (colorsel->wheel_area), "expose_event", + (SF) gtk_color_selection_wheel_events, (gpointer) colorsel->wheel_area); + gtk_signal_connect_after (GTK_OBJECT (colorsel->wheel_area), "size_allocate", + (SF) gtk_color_selection_wheel_resize, (gpointer) colorsel->wheel_area); + gtk_object_set_data (GTK_OBJECT (colorsel->wheel_area), "_GtkColorSelection", (gpointer) colorsel); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_container_border_width (GTK_CONTAINER (frame), 0); + gtk_box_pack_start (GTK_BOX (hbox2), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + + colorsel->value_area = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_size (GTK_PREVIEW (colorsel->value_area), VALUE_WIDTH, VALUE_HEIGHT); + gtk_preview_set_expand (GTK_PREVIEW (colorsel->value_area), TRUE); + gtk_container_add (GTK_CONTAINER (frame), colorsel->value_area); + gtk_widget_show (colorsel->value_area); + + old_mask = gtk_widget_get_events (colorsel->value_area); + gtk_widget_set_events (colorsel->value_area, + old_mask | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + gtk_signal_connect_after (GTK_OBJECT (colorsel->value_area), "expose_event", + (SF) gtk_color_selection_value_events, (gpointer) colorsel->value_area); + gtk_signal_connect_after (GTK_OBJECT (colorsel->value_area), "size_allocate", + (SF) gtk_color_selection_value_resize, (gpointer) colorsel->value_area); + gtk_signal_connect (GTK_OBJECT (colorsel->value_area), "event", + (SF) gtk_color_selection_value_events, (gpointer) colorsel->value_area); + gtk_object_set_data (GTK_OBJECT (colorsel->value_area), "_GtkColorSelection", (gpointer) colorsel); + + /* New/old color samples */ + /* ===================== */ + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + +/* colorsel->sample_area_eb = gtk_button_new (); + gtk_container_add (GTK_CONTAINER (frame), colorsel->sample_area_eb); + gtk_widget_show (colorsel->sample_area_eb); */ + + colorsel->sample_area = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_size (GTK_PREVIEW (colorsel->sample_area), SAMPLE_WIDTH, SAMPLE_HEIGHT); + gtk_preview_set_expand (GTK_PREVIEW (colorsel->sample_area), TRUE); + gtk_container_add (GTK_CONTAINER (frame), + colorsel->sample_area); + gtk_widget_set_events(colorsel->sample_area, + gtk_widget_get_events(colorsel->sample_area) + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK); + gtk_widget_show (colorsel->sample_area); + + gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area), + "size_allocate", + GTK_SIGNAL_FUNC (gtk_color_selection_sample_resize), + colorsel->sample_area); + gtk_object_set_data (GTK_OBJECT (colorsel->sample_area), "_GtkColorSelection", (gpointer) colorsel); + + table = gtk_table_new (NUM_CHANNELS, 3, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (table), 3); + gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, TRUE, 0); + + for (n = HUE; n <= OPACITY; n++) + { + label = gtk_label_new (scale_vals[n].label); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, n, n + 1); + + adj = gtk_adjustment_new (colorsel->values[n], scale_vals[n].lower, + scale_vals[n].upper, scale_vals[n].step_inc, + scale_vals[n].page_inc, 0.0); + colorsel->scales[n] = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_set_usize (colorsel->scales[n], 128, 0); + gtk_scale_set_value_pos (GTK_SCALE (colorsel->scales[n]), GTK_POS_TOP); + + gtk_range_set_update_policy (GTK_RANGE (colorsel->scales[n]), colorsel->policy); + gtk_scale_set_draw_value (GTK_SCALE (colorsel->scales[n]), FALSE); + gtk_scale_set_digits (GTK_SCALE (colorsel->scales[n]), 2); + gtk_table_attach_defaults (GTK_TABLE (table), colorsel->scales[n], 1, 2, n, n + 1); + + colorsel->entries[n] = gtk_entry_new (); + gtk_widget_set_usize (colorsel->entries[n], 40, 0); + sprintf (txt, "%.2f", colorsel->values[n]); + gtk_entry_set_text (GTK_ENTRY (colorsel->entries[n]), txt); + gtk_table_attach_defaults (GTK_TABLE (table), colorsel->entries[n], 2, 3, n, n + 1); + + if (n != OPACITY) + { + gtk_widget_show (label); + gtk_widget_show (colorsel->scales[n]); + gtk_widget_show (colorsel->entries[n]); + } + + gtk_signal_connect_object (GTK_OBJECT (adj), "value_changed", + scale_vals[n].updater, (gpointer) colorsel->scales[n]); + gtk_object_set_data (GTK_OBJECT (colorsel->scales[n]), "_GtkColorSelection", (gpointer) colorsel); + gtk_object_set_data (GTK_OBJECT (colorsel->scales[n]), "_ValueIndex", (gpointer) n); + gtk_signal_connect_object (GTK_OBJECT (colorsel->entries[n]), "changed", + scale_vals[n].updater, (gpointer) colorsel->entries[n]); + gtk_object_set_data (GTK_OBJECT (colorsel->entries[n]), "_GtkColorSelection", (gpointer) colorsel); + gtk_object_set_data (GTK_OBJECT (colorsel->entries[n]), "_ValueIndex", (gpointer) n); + } + + colorsel->opacity_label = label; + + gtk_widget_show (table); + gtk_widget_show (hbox); +} + +GtkWidget * +gtk_color_selection_new (void) +{ + GtkColorSelection *colorsel; + + colorsel = gtk_type_new (gtk_color_selection_get_type ()); + + return GTK_WIDGET (colorsel); +} + +void +gtk_color_selection_set_update_policy (GtkColorSelection *colorsel, + GtkUpdateType policy) +{ + gint n; + + g_return_if_fail (colorsel != NULL); + + if (policy != colorsel->policy) + { + colorsel->policy = policy; + + for (n = 0; n < NUM_CHANNELS; n++) + gtk_range_set_update_policy (GTK_RANGE (colorsel->scales[n]), policy); + } +} + + +void +gtk_color_selection_set_color (GtkColorSelection *colorsel, + gdouble *color) +{ + gint n, i = 0; + + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (colorsel))) + gtk_color_selection_draw_wheel_marker (colorsel); + + for (n = RED; n <= BLUE; n++) + { + colorsel->old_values[n] = colorsel->values[n]; + colorsel->values[n] = color[i++]; + } + + if (colorsel->use_opacity == TRUE) + { + colorsel->old_values[OPACITY] = colorsel->values[OPACITY]; + colorsel->values[OPACITY] = color[i]; + } + + RGB_TO_HSV (); + + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS | HSV_INPUTS | OPACITY_INPUTS, BOTH); + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (colorsel))) + { + gtk_color_selection_draw_value_bar (colorsel, FALSE); + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_draw_wheel_marker (colorsel); + } +} + +void +gtk_color_selection_get_color (GtkColorSelection *colorsel, + gdouble *color) +{ + gint n, i = 0; + + g_return_if_fail (colorsel != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel)); + + for (n = RED; n <= BLUE; n++) + color[i++] = colorsel->values[n]; + if (colorsel->use_opacity == TRUE) + color[i] = colorsel->values[OPACITY]; +} + +static void +gtk_color_selection_realize (GtkWidget *widget) +{ + GtkColorSelection *colorsel; + gchar *type_accept_list[] = {"application/x-color"}; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (widget)); + + colorsel = GTK_COLOR_SELECTION (widget); + + if (GTK_WIDGET_CLASS (color_selection_parent_class)->realize) + (*GTK_WIDGET_CLASS (color_selection_parent_class)->realize) (widget); + + gtk_widget_dnd_drag_set (colorsel->sample_area, + 1, type_accept_list, 1); + gtk_widget_dnd_drop_set (colorsel->sample_area, + 1, type_accept_list, 1, 0); + gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area), + "drop_data_available_event", + GTK_SIGNAL_FUNC (gtk_color_selection_drop_handle), + NULL); + gtk_signal_connect_after (GTK_OBJECT (colorsel->sample_area), + "drag_request_event", + GTK_SIGNAL_FUNC (gtk_color_selection_drag_handle), + NULL); +} + +static void +gtk_color_selection_destroy (GtkObject *object) +{ + GtkColorSelection *colorsel; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION (object)); + + colorsel = GTK_COLOR_SELECTION (object); + + if (colorsel->wheel_buf != NULL) + g_free (colorsel->wheel_buf); + if (colorsel->value_buf != NULL) + g_free (colorsel->value_buf); + if (colorsel->sample_buf != NULL) + g_free (colorsel->sample_buf); + + if (GTK_OBJECT_CLASS (color_selection_parent_class)->destroy) + (*GTK_OBJECT_CLASS (color_selection_parent_class)->destroy) (object); +} + +static void +gtk_color_selection_color_changed (GtkColorSelection *colorsel) +{ + gtk_signal_emit (GTK_OBJECT (colorsel), color_selection_signals[COLOR_CHANGED]); +} + +static void +gtk_color_selection_update_input (GtkWidget *scale, + GtkWidget *entry, + gdouble value) +{ + GtkAdjustment *adj; + gchar txt[32]; + + if (scale != NULL) + { + adj = gtk_range_get_adjustment (GTK_RANGE (scale)); + adj->value = (gfloat) value; + gtk_signal_handler_block_by_data (GTK_OBJECT (adj), (gpointer) scale); + gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); + gtk_range_slider_update (GTK_RANGE (scale)); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), (gpointer) scale); + } + + if (entry != NULL) + { + gtk_signal_handler_block_by_data (GTK_OBJECT (entry), (gpointer) entry); + sprintf (txt, "%.2f", value); + gtk_entry_set_text (GTK_ENTRY (entry), txt); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (entry), (gpointer) entry); + } +} + +static void +gtk_color_selection_update_inputs (GtkColorSelection *colorsel, + gint inputs, + gint which) +{ + gint n; + + switch (which) + { + case SCALE: + if ((inputs & RGB_INPUTS) != 0) + for (n = RED; n <= BLUE; n++) + gtk_color_selection_update_input (colorsel->scales[n], NULL, + colorsel->values[n]); + if ((inputs & HSV_INPUTS) != 0) + for (n = HUE; n <= VALUE; n++) + gtk_color_selection_update_input (colorsel->scales[n], NULL, + colorsel->values[n]); + if ((inputs & OPACITY_INPUTS) != 0) + gtk_color_selection_update_input(colorsel->scales[OPACITY], NULL, + colorsel->values[OPACITY]); + break; + case ENTRY: + if ((inputs & RGB_INPUTS) != 0) + for (n = RED; n <= BLUE; n++) + gtk_color_selection_update_input (NULL, colorsel->entries[n], colorsel->values[n]); + if ((inputs & HSV_INPUTS) != 0) + for (n = HUE; n <= VALUE; n++) + gtk_color_selection_update_input (NULL, colorsel->entries[n], colorsel->values[n]); + if ((inputs & OPACITY_INPUTS) != 0) + gtk_color_selection_update_input(NULL, colorsel->entries[OPACITY], colorsel->values[OPACITY]); + break; + default: + if ((inputs & RGB_INPUTS) != 0) + for (n = RED; n <= BLUE; n++) + gtk_color_selection_update_input (colorsel->scales[n], colorsel->entries[n], + colorsel->values[n]); + if ((inputs & HSV_INPUTS) != 0) + for (n = HUE; n <= VALUE; n++) + gtk_color_selection_update_input (colorsel->scales[n], colorsel->entries[n], + colorsel->values[n]); + if ((inputs & OPACITY_INPUTS) != 0) + gtk_color_selection_update_input(colorsel->scales[OPACITY], colorsel->entries[OPACITY], + colorsel->values[OPACITY]); + break; + } +} + +static void +gtk_color_selection_hsv_updater (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + GtkAdjustment *adj; + gdouble newvalue; + gint i, which = SCALE; + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (widget))) + { + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + i = (gint) gtk_object_get_data (GTK_OBJECT (widget), "_ValueIndex"); + + if (GTK_IS_SCALE (widget)) + { + adj = gtk_range_get_adjustment (GTK_RANGE (GTK_SCALE (widget))); + newvalue = (gdouble) adj->value; + which = ENTRY; + } + else + newvalue = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget))); + + if (i == VALUE) + { + gtk_color_selection_draw_value_marker (colorsel); + colorsel->values[i] = newvalue; + + HSV_TO_RGB (); + + gtk_color_selection_draw_value_marker (colorsel); + } + else + { + gtk_color_selection_draw_wheel_marker (colorsel); + colorsel->values[i] = newvalue; + + HSV_TO_RGB (); + + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_value_bar (colorsel, FALSE); + } + + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_color_changed (colorsel); + gtk_color_selection_update_inputs (colorsel, HSV_INPUTS, which); + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, BOTH); + } +} + +static void +gtk_color_selection_rgb_updater (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + GtkAdjustment *adj; + gdouble newvalue; + gint i, which = SCALE; + + if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (widget))) + { + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + i = (gint) gtk_object_get_data (GTK_OBJECT (widget), "_ValueIndex"); + + if (GTK_IS_SCALE (widget)) + { + adj = gtk_range_get_adjustment (GTK_RANGE (GTK_SCALE (widget))); + newvalue = (gdouble) adj->value; + which = ENTRY; + } + else + newvalue = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget))); + + gtk_color_selection_draw_wheel_marker (colorsel); + + colorsel->values[i] = newvalue; + RGB_TO_HSV (); + + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_value_bar (colorsel, FALSE); + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_color_changed (colorsel); + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, which); + gtk_color_selection_update_inputs (colorsel, HSV_INPUTS, BOTH); + } +} + +static void +gtk_color_selection_opacity_updater (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + GtkAdjustment *adj; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + + if (GTK_IS_SCALE (widget)) + { + adj = gtk_range_get_adjustment (GTK_RANGE (widget)); + colorsel->values[OPACITY] = (gdouble) adj->value; + gtk_color_selection_update_input (NULL, colorsel->entries[OPACITY], colorsel->values[OPACITY]); + } + else + { + colorsel->values[OPACITY] = (gdouble) atof (gtk_entry_get_text (GTK_ENTRY (widget))); + gtk_color_selection_update_input (colorsel->scales[OPACITY], NULL, colorsel->values[OPACITY]); + } + + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_color_changed (colorsel); +} + +void +gtk_color_selection_set_opacity (GtkColorSelection *colorsel, + gint use_opacity) +{ + g_return_if_fail (colorsel != NULL); + + colorsel->use_opacity = use_opacity; + + if (use_opacity == FALSE && GTK_WIDGET_VISIBLE (colorsel->scales[OPACITY])) + { + gtk_widget_hide (colorsel->opacity_label); + gtk_widget_hide (colorsel->scales[OPACITY]); + gtk_widget_hide (colorsel->entries[OPACITY]); + } + else if (use_opacity == TRUE && !GTK_WIDGET_VISIBLE (colorsel->scales[OPACITY])) + { + gtk_widget_show (colorsel->opacity_label); + gtk_widget_show (colorsel->scales[OPACITY]); + gtk_widget_show (colorsel->entries[OPACITY]); + } + + if (GTK_WIDGET_DRAWABLE (colorsel->sample_area)) + gtk_color_selection_draw_sample (colorsel, FALSE); +} + +static void +gtk_color_selection_value_resize (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + gtk_color_selection_draw_value_bar (colorsel, TRUE); +} + +static void +gtk_color_selection_wheel_resize (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + gtk_color_selection_draw_wheel (colorsel, TRUE); +} + +static void +gtk_color_selection_sample_resize (GtkWidget *widget, + gpointer data) +{ + GtkColorSelection *colorsel; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkColorSelection"); + gtk_color_selection_draw_sample (colorsel, TRUE); +} + +static void +gtk_color_selection_drop_handle (GtkWidget *widget, GdkEvent *event) +{ + int i; + GtkColorSelection *w; + gdouble *newbuf; + g_print("Handling drop in color selection\n"); + gtk_color_selection_set_color(GTK_COLOR_SELECTION(widget), + event->dropdataavailable.data); + g_free(event->dropdataavailable.data); + g_free(event->dropdataavailable.data_type); +} + +static void +gtk_color_selection_drag_handle (GtkWidget *widget, GdkEvent *event) +{ + g_print("Handling drag in color selector\n"); + gtk_widget_dnd_data_set(widget, event, GTK_COLOR_SELECTION(widget)->values, + sizeof(GTK_COLOR_SELECTION(widget)->values)); +} + +static void +gtk_color_selection_draw_wheel_marker (GtkColorSelection *colorsel) +{ + gint xpos, ypos; + + gdk_gc_set_function (colorsel->wheel_gc, GDK_INVERT); + + xpos = (gint) ((-(gdouble) (colorsel->wheel_area->allocation.width) / 2.0) * + colorsel->values[SATURATION] * cos (DEGTORAD ((colorsel->values[HUE] - 90)))) + + (colorsel->wheel_area->allocation.width >> 1) - 4; + ypos = (gint) (((gdouble) (colorsel->wheel_area->allocation.height) / 2.0) * + colorsel->values[SATURATION] * sin (DEGTORAD ((colorsel->values[HUE] - 90)))) + + (colorsel->wheel_area->allocation.height >> 1) - 4; + + gdk_draw_arc (colorsel->wheel_area->window, colorsel->wheel_gc, FALSE, xpos, ypos, 8, 8, 0, 360 * 64); +} + +static void +gtk_color_selection_draw_value_marker (GtkColorSelection *colorsel) +{ + gint y; + + gdk_gc_set_function (colorsel->value_gc, GDK_INVERT); + + y = (gint) ((gdouble) (colorsel->value_area->allocation.height) * (1.0 - colorsel->values[VALUE])); + gdk_draw_line (colorsel->value_area->window, colorsel->value_gc, + 0, y, colorsel->value_area->allocation.width, y); +} + +static void +gtk_color_selection_update_value (GtkColorSelection *colorsel, + gint y) +{ + gtk_color_selection_draw_value_marker (colorsel); + + if (y < 0) + y = 0; + else if (y > colorsel->value_area->allocation.height - 1) + y = colorsel->value_area->allocation.height - 1; + + colorsel->values[VALUE] = 1.0 - (gdouble) y / (gdouble) (colorsel->value_area->allocation.height); + + HSV_TO_RGB (); + + gtk_color_selection_draw_value_marker (colorsel); + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_update_input (colorsel->scales[VALUE], colorsel->entries[VALUE], + colorsel->values[VALUE]); + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS, BOTH); +} + +static void +gtk_color_selection_update_wheel (GtkColorSelection *colorsel, + gint x, + gint y) +{ + gdouble wid, heig; + gint res; + + gtk_color_selection_draw_wheel_marker (colorsel); + + wid = (gdouble) (colorsel->wheel_area->allocation.width) / 2.0; + heig = (gdouble) (colorsel->wheel_area->allocation.height) / 2.0; + + res = gtk_color_selection_eval_wheel (x, y, wid, heig, &colorsel->values[HUE], + &colorsel->values[SATURATION]); + + HSV_TO_RGB (); + + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_value_bar (colorsel, FALSE); + gtk_color_selection_draw_sample (colorsel, FALSE); + gtk_color_selection_update_inputs (colorsel, RGB_INPUTS | HSV_INPUTS, BOTH); +} + +static gint +gtk_color_selection_value_timeout (GtkColorSelection *colorsel) +{ + gint x, y; + + gdk_window_get_pointer (colorsel->value_area->window, &x, &y, NULL); + gtk_color_selection_update_value (colorsel, y); + gtk_color_selection_color_changed (colorsel); + + return (TRUE); +} + +static gint +gtk_color_selection_value_events (GtkWidget *area, + GdkEvent *event) +{ + GtkColorSelection *colorsel; + gint y; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (area), "_GtkColorSelection"); + + switch (event->type) + { + case GDK_MAP: + gtk_color_selection_draw_value_marker (colorsel); + break; + case GDK_EXPOSE: + if (colorsel->value_gc == NULL) + colorsel->value_gc = gdk_gc_new (colorsel->value_area->window); + gtk_color_selection_draw_value_marker (colorsel); + break; + case GDK_BUTTON_PRESS: + gtk_grab_add (area); + gtk_color_selection_update_value (colorsel, event->button.y); + gtk_color_selection_color_changed (colorsel); + break; + case GDK_BUTTON_RELEASE: + gtk_grab_remove (area); + if (colorsel->timer_active == TRUE) + gtk_timeout_remove (colorsel->timer_tag); + colorsel->timer_active = FALSE; + + y = event->button.y; + if (event->button.window != area->window) + gdk_window_get_pointer (area->window, NULL, &y, NULL); + + gtk_color_selection_update_value (colorsel, y); + gtk_color_selection_color_changed (colorsel); + break; + case GDK_MOTION_NOTIFY: + y = event->motion.y; + + if (event->motion.is_hint || (event->motion.window != area->window)) + gdk_window_get_pointer (area->window, NULL, &y, NULL); + + switch (colorsel->policy) + { + case GTK_UPDATE_CONTINUOUS: + gtk_color_selection_update_value (colorsel, y); + gtk_color_selection_color_changed (colorsel); + break; + case GTK_UPDATE_DELAYED: + if (colorsel->timer_active == TRUE) + gtk_timeout_remove (colorsel->timer_tag); + + colorsel->timer_tag = gtk_timeout_add (TIMER_DELAY, + (GtkFunction) gtk_color_selection_value_timeout, + (gpointer) colorsel); + colorsel->timer_active = TRUE; + break; + default: + break; + } + break; + default: + break; + } + + return (FALSE); +} + +static gint +gtk_color_selection_wheel_timeout (GtkColorSelection *colorsel) +{ + gint x, y; + + gdk_window_get_pointer (colorsel->wheel_area->window, &x, &y, NULL); + gtk_color_selection_update_wheel (colorsel, x, y); + gtk_color_selection_color_changed (colorsel); + + return (TRUE); +} + +static gint +gtk_color_selection_wheel_events (GtkWidget *area, + GdkEvent *event) +{ + GtkColorSelection *colorsel; + gint x, y; + + colorsel = (GtkColorSelection*) gtk_object_get_data (GTK_OBJECT (area), "_GtkColorSelection"); + + switch (event->type) + { + case GDK_MAP: + gtk_color_selection_draw_wheel (colorsel, TRUE); + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_sample (colorsel, TRUE); + break; + case GDK_EXPOSE: + if (colorsel->wheel_gc == NULL) + colorsel->wheel_gc = gdk_gc_new (colorsel->wheel_area->window); + if (colorsel->sample_gc == NULL) + colorsel->sample_gc = gdk_gc_new (colorsel->sample_area->window); + if (colorsel->value_gc == NULL) + colorsel->value_gc = gdk_gc_new (colorsel->value_area->window); + gtk_color_selection_draw_wheel_marker (colorsel); + gtk_color_selection_draw_wheel_frame (colorsel); + break; + case GDK_BUTTON_PRESS: + gtk_grab_add (area); + gtk_color_selection_update_wheel (colorsel, event->button.x, event->button.y); + gtk_color_selection_color_changed (colorsel); + break; + case GDK_BUTTON_RELEASE: + gtk_grab_remove (area); + if (colorsel->timer_active == TRUE) + gtk_timeout_remove (colorsel->timer_tag); + colorsel->timer_active = FALSE; + + x = event->button.x; + y = event->button.y; + + if (event->button.window != area->window) + gdk_window_get_pointer (area->window, &x, &y, NULL); + + gtk_color_selection_update_wheel (colorsel, x, y); + gtk_color_selection_color_changed (colorsel); + break; + case GDK_MOTION_NOTIFY: + x = event->motion.x; + y = event->motion.y; + + if (event->motion.is_hint || (event->motion.window != area->window)) + gdk_window_get_pointer (area->window, &x, &y, NULL); + + switch (colorsel->policy) + { + case GTK_UPDATE_CONTINUOUS: + gtk_color_selection_update_wheel (colorsel, x, y); + gtk_color_selection_color_changed (colorsel); + break; + case GTK_UPDATE_DELAYED: + if (colorsel->timer_active == TRUE) + gtk_timeout_remove (colorsel->timer_tag); + colorsel->timer_tag = gtk_timeout_add (TIMER_DELAY, + (GtkFunction) gtk_color_selection_wheel_timeout, + (gpointer) colorsel); + colorsel->timer_active = TRUE; + break; + default: + break; + } + break; + default: + break; + } + + return (FALSE); +} + +static void +gtk_color_selection_draw_value_bar (GtkColorSelection *colorsel, + gint resize) +{ + gint x, y, i, wid, heig, n; + gdouble sv, v, c[3]; + guchar rc[3]; + + wid = colorsel->value_area->allocation.width; + heig = colorsel->value_area->allocation.height; + + if (resize) + { + if (colorsel->value_buf != NULL) + g_free (colorsel->value_buf); + + colorsel->value_buf = g_new(guchar, 3 * wid); + } + + v = 1.0; + sv = 1.0 / (gdouble) (heig - 1); + + for (y = 0; y < heig; y++) + { + i = 0; + + gtk_color_selection_hsv_to_rgb (colorsel->values[HUE],colorsel->values[SATURATION],v, + &c[0], &c[1], &c[2]); + + for (n = 0; n < 3; n++) + rc[n] = (guchar) (255.0 * c[n]); + + for (x = 0; x < wid; x++) + { + for (n = 0; n < 3; n++) + colorsel->value_buf[i++] = rc[n]; + } + + gtk_preview_draw_row (GTK_PREVIEW (colorsel->value_area), colorsel->value_buf, 0, y, wid); + v -= sv; + } + + gtk_widget_draw (colorsel->value_area, NULL); +} + +static void +gtk_color_selection_draw_wheel_frame (GtkColorSelection *colorsel) +{ + GtkStyle *style; + gint w, h; + + style = gtk_widget_get_style (GTK_WIDGET (colorsel)); + + w = colorsel->wheel_area->allocation.width; + h = colorsel->wheel_area->allocation.height; + + gdk_draw_arc (colorsel->wheel_area->window, style->black_gc, + FALSE, 1, 1, w - 1, h - 1, 30 * 64, 180 * 64); + gdk_draw_arc (colorsel->wheel_area->window, style->mid_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, w, h, 30 * 64, 180 * 64); + + gdk_draw_arc (colorsel->wheel_area->window, style->bg_gc[GTK_STATE_NORMAL], + FALSE, 1, 1, w - 1, h - 1, 210 * 64, 180 * 64); + gdk_draw_arc (colorsel->wheel_area->window, style->light_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, w, h, 210 * 64, 180 * 64); +} + +static void +gtk_color_selection_draw_wheel (GtkColorSelection *colorsel, + gint resize) +{ + gint x, y, i, wid, heig, n; + gdouble cx, cy, h, s, c[3]; + guchar bg[3]; + GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (colorsel)); + + wid = colorsel->wheel_area->allocation.width; + heig = colorsel->wheel_area->allocation.height; + + if (resize) + { + if (colorsel->wheel_buf != NULL) + g_free (colorsel->wheel_buf); + + colorsel->wheel_buf = g_new(guchar, 3 * wid); + } + + cx = (gdouble) (wid) / 2.0; + cy = (gdouble) (heig) / 2.0; + + bg[0] = style->bg[GTK_STATE_NORMAL].red >> 8; + bg[1] = style->bg[GTK_STATE_NORMAL].green >> 8; + bg[2] = style->bg[GTK_STATE_NORMAL].blue >> 8; + + for (y = 0; y < heig; y++) + { + i = 0; + for (x = 0; x < wid; x++) + { + if (gtk_color_selection_eval_wheel (x, y, cx, cy, &h, &s) == TRUE) + { + for (n = 0; n < 3; n++) + colorsel->wheel_buf[i++] = bg[n]; + } + else + { + gtk_color_selection_hsv_to_rgb (h, s, 1.0, &c[0], &c[1], &c[2]); + for (n = 0; n < 3; n++) + colorsel->wheel_buf[i++] = (guchar) (255.0 * c[n]); + } + } + + gtk_preview_draw_row (GTK_PREVIEW (colorsel->wheel_area), colorsel->wheel_buf, 0, y, wid); + } + + gtk_widget_draw (colorsel->wheel_area, NULL); +} + +static void +gtk_color_selection_draw_sample (GtkColorSelection *colorsel, + gint resize) +{ + gint x, y, i, wid, heig, f, half, n; + guchar c[3 * 2], cc[3 * 4], *cp = c; + gdouble o, oldo; + + wid = colorsel->sample_area->allocation.width; + heig = colorsel->sample_area->allocation.height; + half = wid >> 1; + + if (resize) + { + if (colorsel->sample_buf != NULL) + g_free (colorsel->sample_buf); + + colorsel->sample_buf = g_new(guchar, 3 * wid); + } + + i = RED; + for (n = 0; n < 3; n++) + { + c[n] = (guchar) (255.0 * colorsel->old_values[i]); + c[n + 3] = (guchar) (255.0 * colorsel->values[i++]); + } + + if (colorsel->use_opacity == TRUE) + { + o = colorsel->values[OPACITY]; + oldo = colorsel->old_values[OPACITY]; + + for (n = 0; n < 3; n++) + { + cc[n] = (guchar) ((1.0 - oldo) * 192 + (oldo * (gdouble) c[n])); + cc[n + 3] = (guchar) ((1.0 - oldo) * 128 + (oldo * (gdouble) c[n])); + cc[n + 6] = (guchar) ((1.0 - o) * 192 + (o * (gdouble) c[n + 3])); + cc[n + 9] = (guchar) ((1.0 - o) * 128 + (o * (gdouble) c[n + 3])); + } + cp = cc; + } + + for (y = 0; y < heig; y++) + { + i = 0; + for (x = 0; x < wid; x++) + { + if (colorsel->use_opacity) + { + f = 3 * (((x % 32) < 16) ^ ((y % 32) < 16)); + f += (x > half) * 6; + } + else + f = (x > half) * 3; + + for (n = 0; n < 3; n++) + colorsel->sample_buf[i++] = cp[n + f]; + } + + gtk_preview_draw_row (GTK_PREVIEW (colorsel->sample_area), colorsel->sample_buf, 0, y, wid); + } + + gtk_widget_draw (colorsel->sample_area, NULL); +} + +static gint +gtk_color_selection_eval_wheel (gint x, gint y, + gdouble cx, gdouble cy, + gdouble *h, gdouble *s) +{ + gdouble d, r, rx, ry, l; + + rx = (gdouble) x - cx; + ry = (gdouble) y - cy; + + d = (SQR (cy) * SQR (rx) + SQR (cx) * SQR (ry) - SQR (cx) * SQR (cy)); + + r = sqrt (SQR (rx) + SQR (ry)); + + if (r != 0.0) + *h = atan2 (rx / r, ry / r); + else + *h = 0.0; + + l = sqrt (SQR ((cx * cos (*h + 0.5 * M_PI))) + SQR ((cy * sin (*h + 0.5 * M_PI)))); + *s = r / l; + *h = 360.0 * (*h) / (2.0 * M_PI) + 180; + + if (*s == 0.0) + *s = 0.00001; + else if (*s > 1.0) + *s = 1.0; + + return ((d > 0.0)); +} + +static void +gtk_color_selection_hsv_to_rgb (gdouble h, gdouble s, gdouble v, + gdouble *r, gdouble *g, gdouble *b) +{ + gint i; + gdouble f, w, q, t; + + if (s == 0.0) + s = 0.000001; + + if (h == -1.0) + { + *r = v; + *g = v; + *b = v; + } + else + { + if (h == 360.0) + h = 0.0; + h = h / 60.0; + i = (gint) h; + f = h - i; + w = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + switch (i) + { + case 0: + *r = v; + *g = t; + *b = w; + break; + case 1: + *r = q; + *g = v; + *b = w; + break; + case 2: + *r = w; + *g = v; + *b = t; + break; + case 3: + *r = w; + *g = q; + *b = v; + break; + case 4: + *r = t; + *g = w; + *b = v; + break; + case 5: + *r = v; + *g = w; + *b = q; + break; + } + } +} + +static void +gtk_color_selection_rgb_to_hsv (gdouble r, gdouble g, gdouble b, + gdouble *h, gdouble *s, gdouble *v) +{ + double max, min, delta; + + max = r; + if (g > max) + max = g; + if (b > max) + max = b; + + min = r; + if (g < min) + min = g; + if (b < min) + min = b; + + *v = max; + + if (max != 0.0) + *s = (max - min) / max; + else + *s = 0.0; + + if (*s == 0.0) + *h = -1.0; + else + { + delta = max - min; + + if (r == max) + *h = (g - b) / delta; + else if (g == max) + *h = 2.0 + (b - r) / delta; + else if (b == max) + *h = 4.0 + (r - g) / delta; + + *h = *h * 60.0; + + if (*h < 0.0) + *h = *h + 360; + } +} + +/***************************/ +/* GtkColorSelectionDialog */ +/***************************/ + +guint +gtk_color_selection_dialog_get_type () +{ + static guint color_selection_dialog_type = 0; + + if (!color_selection_dialog_type) + { + GtkTypeInfo colorsel_diag_info = + { + "color selection dialog", + sizeof (GtkColorSelectionDialog), + sizeof (GtkColorSelectionDialogClass), + (GtkClassInitFunc) gtk_color_selection_dialog_class_init, + (GtkObjectInitFunc) gtk_color_selection_dialog_init, + }; + + color_selection_dialog_type = gtk_type_unique (gtk_window_get_type (), &colorsel_diag_info); + } + + return color_selection_dialog_type; +} + +void +gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; + + color_selection_dialog_parent_class = gtk_type_class (gtk_window_get_type ()); + + object_class->destroy = gtk_color_selection_dialog_destroy; +} + +void +gtk_color_selection_dialog_init (GtkColorSelectionDialog *colorseldiag) +{ + GtkWidget *action_area, *frame; + + colorseldiag->main_vbox = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (colorseldiag), 10); + gtk_container_add (GTK_CONTAINER (colorseldiag), colorseldiag->main_vbox); + gtk_widget_show (colorseldiag->main_vbox); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); + gtk_container_add (GTK_CONTAINER (colorseldiag->main_vbox), frame); + gtk_widget_show (frame); + + colorseldiag->colorsel = gtk_color_selection_new (); + gtk_container_add (GTK_CONTAINER (frame), colorseldiag->colorsel); + gtk_widget_show (colorseldiag->colorsel); + + action_area = gtk_hbox_new (TRUE, 10); + gtk_box_pack_end (GTK_BOX (colorseldiag->main_vbox), action_area, FALSE, FALSE, 0); + gtk_widget_show (action_area); + + colorseldiag->ok_button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (colorseldiag->ok_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->ok_button, TRUE, TRUE, 0); + gtk_widget_grab_default (colorseldiag->ok_button); + gtk_widget_show (colorseldiag->ok_button); + + colorseldiag->cancel_button = gtk_button_new_with_label ("Cancel"); + GTK_WIDGET_SET_FLAGS (colorseldiag->cancel_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->cancel_button, TRUE, TRUE, 0); + gtk_widget_show (colorseldiag->cancel_button); + + colorseldiag->help_button = gtk_button_new_with_label ("Help"); + GTK_WIDGET_SET_FLAGS (colorseldiag->help_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), colorseldiag->help_button, TRUE, TRUE, 0); + gtk_widget_show (colorseldiag->help_button); +} + +GtkWidget * +gtk_color_selection_dialog_new (const gchar *title) +{ + GtkColorSelectionDialog *colorseldiag; + + colorseldiag = gtk_type_new (gtk_color_selection_dialog_get_type ()); + gtk_window_set_title (GTK_WINDOW (colorseldiag), title); + + return GTK_WIDGET (colorseldiag); +} + +static void +gtk_color_selection_dialog_destroy (GtkObject *object) +{ + GtkColorSelectionDialog *colorseldiag; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_COLOR_SELECTION_DIALOG (object)); + + colorseldiag = GTK_COLOR_SELECTION_DIALOG (object); + + + if (GTK_OBJECT_CLASS (color_selection_dialog_parent_class)->destroy) + (*GTK_OBJECT_CLASS (color_selection_dialog_parent_class)->destroy) (object); +} diff --git a/gtk/gtkcolorsel.h b/gtk/gtkcolorsel.h new file mode 100644 index 000000000..c29ea64f4 --- /dev/null +++ b/gtk/gtkcolorsel.h @@ -0,0 +1,152 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_COLORSEL_H__ +#define __GTK_COLORSEL_H__ + +#include +#include +#include +#include + +#include "gtkwindow.h" +#include "gtkvbox.h" +#include "gtkframe.h" +#include "gtkpreview.h" +#include "gtkbutton.h" +#include "gtkentry.h" +#include "gtkhbox.h" +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtksignal.h" +#include "gtkmisc.h" +#include "gtkrange.h" +#include "gtkscale.h" +#include "gtkhscale.h" +#include "gtktable.h" +#include "gtkeventbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_COLOR_SELECTION(obj) GTK_CHECK_CAST (obj, gtk_color_selection_get_type (), GtkColorSelection) +#define GTK_COLOR_SELECTION_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_color_selection_get_type (), GtkColorSelectionClass) +#define GTK_IS_COLOR_SELECTION(obj) GTK_CHECK_TYPE (obj, gtk_color_selection_get_type ()) + +#define GTK_COLOR_SELECTION_DIALOG(obj) GTK_CHECK_CAST (obj, gtk_color_selection_dialog_get_type (), GtkColorSelectionDialog) +#define GTK_COLOR_SELECTION_DIALOG_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_color_selection_dialog_get_type (), GtkColorSelectionDialogClass) +#define GTK_IS_COLOR_SELECTION_DIALOG(obj) GTK_CHECK_TYPE (obj, gtk_color_selection_dialog_get_type ()) + + +typedef struct _GtkColorSelection GtkColorSelection; +typedef struct _GtkColorSelectionClass GtkColorSelectionClass; + +typedef struct _GtkColorSelectionDialog GtkColorSelectionDialog; +typedef struct _GtkColorSelectionDialogClass GtkColorSelectionDialogClass; + + +struct _GtkColorSelection +{ + GtkVBox vbox; + + GtkWidget *wheel_area; + GtkWidget *value_area; + GtkWidget *sample_area, *sample_area_eb; + + GtkWidget *scales[8]; + GtkWidget *entries[8]; + GtkWidget *opacity_label; + + GdkGC *wheel_gc; + GdkGC *value_gc; + GdkGC *sample_gc; + + GtkUpdateType policy; + gint use_opacity; + gint timer_active; + gint timer_tag; + gdouble values[8]; + gdouble old_values[8]; + + guchar *wheel_buf; + guchar *value_buf; + guchar *sample_buf; +}; + +struct _GtkColorSelectionClass +{ + GtkVBoxClass parent_class; + + void (* color_changed) (GtkColorSelection *colorsel); +}; + +struct _GtkColorSelectionDialog +{ + GtkWindow window; + + GtkWidget *colorsel; + GtkWidget *main_vbox; + GtkWidget *ok_button; + GtkWidget *reset_button; + GtkWidget *cancel_button; + GtkWidget *help_button; +}; + +struct _GtkColorSelectionDialogClass +{ + GtkWindowClass parent_class; +}; + + +/* ColorSelection */ + +guint gtk_color_selection_get_type (void); +void gtk_color_selection_class_init (GtkColorSelectionClass *klass); +void gtk_color_selection_init (GtkColorSelection *colorsel); + +GtkWidget* gtk_color_selection_new (void); + +void gtk_color_selection_set_update_policy (GtkColorSelection *colorsel, + GtkUpdateType policy); + +void gtk_color_selection_set_opacity (GtkColorSelection *colorsel, + gint use_opacity); + +void gtk_color_selection_set_color (GtkColorSelection *colorsel, + gdouble *color); + +void gtk_color_selection_get_color (GtkColorSelection *colorsel, + gdouble *color); + +/* ColorSelectionDialog */ + +guint gtk_color_selection_dialog_get_type (void); +void gtk_color_selection_dialog_class_init (GtkColorSelectionDialogClass *klass); +void gtk_color_selection_dialog_init (GtkColorSelectionDialog *colorseldiag); + +GtkWidget* gtk_color_selection_dialog_new (const gchar *title); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_COLORSEL_H__ */ diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c new file mode 100644 index 000000000..977fabc29 --- /dev/null +++ b/gtk/gtkcontainer.c @@ -0,0 +1,844 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkcontainer.h" +#include "gtksignal.h" + + +enum { + ADD, + REMOVE, + NEED_RESIZE, + FOREACH, + FOCUS, + LAST_SIGNAL +}; + + +typedef void (*GtkContainerSignal1) (GtkObject *object, + gpointer arg1, + gpointer data); +typedef void (*GtkContainerSignal2) (GtkObject *object, + gpointer arg1, + gpointer arg2, + gpointer data); +typedef gint (*GtkContainerSignal3) (GtkObject *object, + gint arg1, + gpointer data); +typedef gint (*GtkContainerSignal4) (GtkObject *object, + gpointer data); + + +static void gtk_container_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_container_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_container_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_container_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + + +static void gtk_container_class_init (GtkContainerClass *klass); +static void gtk_container_init (GtkContainer *container); +static void gtk_container_arg (GtkContainer *container, + GtkArg *arg); +static gint gtk_real_container_need_resize (GtkContainer *container); +static gint gtk_real_container_focus (GtkContainer *container, + GtkDirectionType direction); +static gint gtk_container_focus_tab (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static gint gtk_container_focus_up_down (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static gint gtk_container_focus_left_right (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static gint gtk_container_focus_move (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static void gtk_container_children_callback (GtkWidget *widget, + gpointer client_data); + + +static gint container_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_container_get_type () +{ + static guint container_type = 0; + + if (!container_type) + { + GtkTypeInfo container_info = + { + "GtkContainer", + sizeof (GtkContainer), + sizeof (GtkContainerClass), + (GtkClassInitFunc) gtk_container_class_init, + (GtkObjectInitFunc) gtk_container_init, + (GtkArgFunc) gtk_container_arg, + }; + + container_type = gtk_type_unique (gtk_widget_get_type (), &container_info); + } + + return container_type; +} + +static void +gtk_container_class_init (GtkContainerClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + gtk_object_add_arg_type ("GtkContainer::border_width", GTK_TYPE_LONG); + gtk_object_add_arg_type ("GtkContainer::auto_resize", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkContainer::block_resize", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkContainer::child", GTK_TYPE_WIDGET); + + container_signals[ADD] = + gtk_signal_new ("add", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, add), + gtk_container_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + container_signals[REMOVE] = + gtk_signal_new ("remove", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, remove), + gtk_container_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + container_signals[NEED_RESIZE] = + gtk_signal_new ("need_resize", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, need_resize), + gtk_container_marshal_signal_4, + GTK_TYPE_BOOL, 0, + GTK_TYPE_WIDGET); + container_signals[FOREACH] = + gtk_signal_new ("foreach", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, foreach), + gtk_container_marshal_signal_2, + GTK_TYPE_NONE, 1, + GTK_TYPE_C_CALLBACK); + container_signals[FOCUS] = + gtk_signal_new ("focus", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkContainerClass, focus), + gtk_container_marshal_signal_3, + GTK_TYPE_DIRECTION_TYPE, 1, + GTK_TYPE_DIRECTION_TYPE); + + gtk_object_class_add_signals (object_class, container_signals, LAST_SIGNAL); + + class->need_resize = gtk_real_container_need_resize; + class->focus = gtk_real_container_focus; +} + +static void +gtk_container_init (GtkContainer *container) +{ + container->focus_child = NULL; + container->border_width = 0; + container->auto_resize = TRUE; + container->need_resize = FALSE; + container->block_resize = FALSE; +} + +static void +gtk_container_arg (GtkContainer *container, + GtkArg *arg) +{ + if (strcmp (arg->name, "border_width") == 0) + { + gtk_container_border_width (container, GTK_VALUE_LONG (*arg)); + } + else if (strcmp (arg->name, "auto_resize") == 0) + { + if (GTK_VALUE_BOOL (*arg)) + gtk_container_enable_resize (container); + else + gtk_container_disable_resize (container); + } + else if (strcmp (arg->name, "block_resize") == 0) + { + if (GTK_VALUE_BOOL (*arg)) + gtk_container_block_resize (container); + else + gtk_container_unblock_resize (container); + } + else if (strcmp (arg->name, "child") == 0) + { + gtk_container_add (container, GTK_WIDGET (GTK_VALUE_OBJECT (*arg))); + } +} + +void +gtk_container_border_width (GtkContainer *container, + gint border_width) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + if (container->border_width != border_width) + { + container->border_width = border_width; + + if (container->widget.parent && GTK_WIDGET_VISIBLE (container)) + gtk_container_need_resize (GTK_CONTAINER (container->widget.parent)); + } +} + +void +gtk_container_add (GtkContainer *container, + GtkWidget *widget) +{ + gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget); +} + +void +gtk_container_remove (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + if (container->focus_child == widget) + container->focus_child = NULL; + + gtk_signal_emit (GTK_OBJECT (container), container_signals[REMOVE], widget); +} + +void +gtk_container_disable_resize (GtkContainer *container) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + container->auto_resize = FALSE; +} + +void +gtk_container_enable_resize (GtkContainer *container) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + container->auto_resize = TRUE; + if (container->need_resize) + { + container->need_resize = FALSE; + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +void +gtk_container_block_resize (GtkContainer *container) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + container->block_resize = TRUE; +} + +void +gtk_container_unblock_resize (GtkContainer *container) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_CONTAINER (container)); + + container->block_resize = FALSE; +} + +gint +gtk_container_need_resize (GtkContainer *container) +{ + gint return_val; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE); + + return_val = FALSE; + + if (!container->block_resize) + { + if (container->auto_resize) + gtk_signal_emit (GTK_OBJECT (container), + container_signals[NEED_RESIZE], + &return_val); + else + container->need_resize = TRUE; + } + + return return_val; +} + +void +gtk_container_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + gtk_signal_emit (GTK_OBJECT (container), + container_signals[FOREACH], + callback, callback_data); +} + +gint +gtk_container_focus (GtkContainer *container, + GtkDirectionType direction) +{ + gint return_val; + + gtk_signal_emit (GTK_OBJECT (container), + container_signals[FOCUS], + direction, &return_val); + + return return_val; +} + +GList* +gtk_container_children (GtkContainer *container) +{ + GList *children; + + children = NULL; + + gtk_container_foreach (container, + gtk_container_children_callback, + &children); + + return g_list_reverse (children); +} + + +static void +gtk_container_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkContainerSignal1 rfunc; + + rfunc = (GtkContainerSignal1) func; + + (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data); +} + +static void +gtk_container_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkContainerSignal2 rfunc; + + rfunc = (GtkContainerSignal2) func; + + (* rfunc) (object, + GTK_VALUE_C_CALLBACK(args[0]).func, + GTK_VALUE_C_CALLBACK(args[0]).func_data, + func_data); +} + +static void +gtk_container_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkContainerSignal3 rfunc; + gint *return_val; + + rfunc = (GtkContainerSignal3) func; + return_val = GTK_RETLOC_ENUM (args[1]); + + *return_val = (* rfunc) (object, GTK_VALUE_ENUM(args[0]), func_data); +} + +static void +gtk_container_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkContainerSignal4 rfunc; + gint *return_val; + + rfunc = (GtkContainerSignal4) func; + return_val = GTK_RETLOC_BOOL (args[0]); + + *return_val = (* rfunc) (object, func_data); +} + +static gint +gtk_real_container_need_resize (GtkContainer *container) +{ + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE); + + if (GTK_WIDGET_VISIBLE (container) && container->widget.parent) + return gtk_container_need_resize (GTK_CONTAINER (container->widget.parent)); + + return FALSE; +} + +static gint +gtk_real_container_focus (GtkContainer *container, + GtkDirectionType direction) +{ + GList *children; + GList *tmp_list; + GList *tmp_list2; + gint return_val; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE); + + /* Fail if the container is insensitive + */ + if (!GTK_WIDGET_SENSITIVE (container)) + return FALSE; + + return_val = FALSE; + + if (GTK_WIDGET_CAN_FOCUS (container)) + { + gtk_widget_grab_focus (GTK_WIDGET (container)); + return_val = TRUE; + } + else + { + /* Get a list of the containers children + */ + children = gtk_container_children (container); + + if (children) + { + /* Remove any children which are insensitive + */ + tmp_list = children; + while (tmp_list) + { + if (!GTK_WIDGET_SENSITIVE (tmp_list->data)) + { + tmp_list2 = tmp_list; + tmp_list = tmp_list->next; + + children = g_list_remove_link (children, tmp_list2); + g_list_free_1 (tmp_list2); + } + else + tmp_list = tmp_list->next; + } + + switch (direction) + { + case GTK_DIR_TAB_FORWARD: + case GTK_DIR_TAB_BACKWARD: + return_val = gtk_container_focus_tab (container, children, direction); + break; + case GTK_DIR_UP: + case GTK_DIR_DOWN: + return_val = gtk_container_focus_up_down (container, children, direction); + break; + case GTK_DIR_LEFT: + case GTK_DIR_RIGHT: + return_val = gtk_container_focus_left_right (container, children, direction); + break; + } + + g_list_free (children); + } + } + + return return_val; +} + +static gint +gtk_container_focus_tab (GtkContainer *container, + GList *children, + GtkDirectionType direction) +{ + GtkWidget *child; + GtkWidget *child2; + GList *tmp_list; + gint length; + gint i, j; + + length = g_list_length (children); + + /* sort the children in the y direction */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + + while (j > 0) + { + child2 = tmp_list->prev->data; + if (child->allocation.y < child2->allocation.y) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* sort the children in the x direction while + * maintaining the y direction sort. + */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + + while (j > 0) + { + child2 = tmp_list->prev->data; + if ((child->allocation.x < child2->allocation.x) && + (child->allocation.y >= child2->allocation.y)) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* if we are going backwards then reverse the order + * of the children. + */ + if (direction == GTK_DIR_TAB_BACKWARD) + children = g_list_reverse (children); + + return gtk_container_focus_move (container, children, direction); +} + +static gint +gtk_container_focus_up_down (GtkContainer *container, + GList *children, + GtkDirectionType direction) +{ + GtkWidget *child; + GtkWidget *child2; + GList *tmp_list; + gint dist1, dist2; + gint focus_x; + gint focus_width; + gint length; + gint i, j; + + /* return failure if there isn't a focus child */ + if (container->focus_child) + { + focus_width = container->focus_child->allocation.width / 2; + focus_x = container->focus_child->allocation.x + focus_width; + } + else + { + focus_width = GTK_WIDGET (container)->allocation.width; + if (GTK_WIDGET_NO_WINDOW (container)) + focus_x = GTK_WIDGET (container)->allocation.x; + else + focus_x = 0; + } + + length = g_list_length (children); + + /* sort the children in the y direction */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + + while (j > 0) + { + child2 = tmp_list->prev->data; + if (child->allocation.y < child2->allocation.y) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* sort the children in distance in the x direction + * in distance from the current focus child while maintaining the + * sort in the y direction + */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x; + + while (j > 0) + { + child2 = tmp_list->prev->data; + dist2 = (child2->allocation.x + child2->allocation.width / 2) - focus_x; + + if ((dist1 < dist2) && + (child->allocation.y >= child2->allocation.y)) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* go and invalidate any widget which is too + * far from the focus widget. + */ + if (!container->focus_child && + (direction == GTK_DIR_UP)) + focus_x += focus_width; + + tmp_list = children; + while (tmp_list) + { + child = tmp_list->data; + + dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x; + if (((direction == GTK_DIR_DOWN) && (dist1 < 0)) || + ((direction == GTK_DIR_UP) && (dist1 > 0))) + tmp_list->data = NULL; + + tmp_list = tmp_list->next; + } + + if (direction == GTK_DIR_UP) + children = g_list_reverse (children); + + return gtk_container_focus_move (container, children, direction); +} + +static gint +gtk_container_focus_left_right (GtkContainer *container, + GList *children, + GtkDirectionType direction) +{ + GtkWidget *child; + GtkWidget *child2; + GList *tmp_list; + gint dist1, dist2; + gint focus_y; + gint focus_height; + gint length; + gint i, j; + + /* return failure if there isn't a focus child */ + if (container->focus_child) + { + focus_height = container->focus_child->allocation.height / 2; + focus_y = container->focus_child->allocation.y + focus_height; + } + else + { + focus_height = GTK_WIDGET (container)->allocation.height; + if (GTK_WIDGET_NO_WINDOW (container)) + focus_y = GTK_WIDGET (container)->allocation.y; + else + focus_y = 0; + } + + length = g_list_length (children); + + /* sort the children in the x direction */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + + while (j > 0) + { + child2 = tmp_list->prev->data; + if (child->allocation.x < child2->allocation.x) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* sort the children in distance in the y direction + * in distance from the current focus child while maintaining the + * sort in the x direction + */ + for (i = 1; i < length; i++) + { + j = i; + tmp_list = g_list_nth (children, j); + child = tmp_list->data; + dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y; + + while (j > 0) + { + child2 = tmp_list->prev->data; + dist2 = (child2->allocation.y + child2->allocation.height / 2) - focus_y; + + if ((dist1 < dist2) && + (child->allocation.x >= child2->allocation.x)) + { + tmp_list->data = tmp_list->prev->data; + tmp_list = tmp_list->prev; + j--; + } + else + break; + } + + tmp_list->data = child; + } + + /* go and invalidate any widget which is too + * far from the focus widget. + */ + if (!container->focus_child && + (direction == GTK_DIR_LEFT)) + focus_y += focus_height; + + tmp_list = children; + while (tmp_list) + { + child = tmp_list->data; + + dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y; + if (((direction == GTK_DIR_RIGHT) && (dist1 < 0)) || + ((direction == GTK_DIR_LEFT) && (dist1 > 0))) + tmp_list->data = NULL; + + tmp_list = tmp_list->next; + } + + if (direction == GTK_DIR_LEFT) + children = g_list_reverse (children); + + return gtk_container_focus_move (container, children, direction); +} + +static gint +gtk_container_focus_move (GtkContainer *container, + GList *children, + GtkDirectionType direction) +{ + GtkWidget *focus_child; + GtkWidget *child; + + focus_child = container->focus_child; + container->focus_child = NULL; + + while (children) + { + child = children->data; + children = children->next; + + if (!child) + continue; + + if (focus_child) + { + if (focus_child == child) + { + focus_child = NULL; + + if (GTK_WIDGET_VISIBLE (child) && + GTK_IS_CONTAINER (child) && + !GTK_WIDGET_HAS_FOCUS (child)) + if (gtk_container_focus (GTK_CONTAINER (child), direction)) + return TRUE; + } + } + else if (GTK_WIDGET_VISIBLE (child)) + { + if (GTK_WIDGET_CAN_FOCUS (child)) + { + gtk_widget_grab_focus (child); + return TRUE; + } + else if (GTK_IS_CONTAINER (child)) + { + if (gtk_container_focus (GTK_CONTAINER (child), direction)) + return TRUE; + } + } + } + + return FALSE; +} + + +static void +gtk_container_children_callback (GtkWidget *widget, + gpointer client_data) +{ + GList **children; + + children = (GList**) client_data; + *children = g_list_prepend (*children, widget); +} diff --git a/gtk/gtkcontainer.h b/gtk/gtkcontainer.h new file mode 100644 index 000000000..80c1ce033 --- /dev/null +++ b/gtk/gtkcontainer.h @@ -0,0 +1,95 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_CONTAINER_H__ +#define __GTK_CONTAINER_H__ + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_CONTAINER(obj) GTK_CHECK_CAST (obj, gtk_container_get_type (), GtkContainer) +#define GTK_CONTAINER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_container_get_type, GtkContainerClass) +#define GTK_IS_CONTAINER(obj) GTK_CHECK_TYPE (obj, gtk_container_get_type ()) + +#define GTK_TYPE_CONTAINER (gtk_container_get_type ()) + +typedef struct _GtkContainer GtkContainer; +typedef struct _GtkContainerClass GtkContainerClass; + +struct _GtkContainer +{ + GtkWidget widget; + + GtkWidget *focus_child; + gint16 border_width; + guint auto_resize : 1; + guint need_resize : 1; + guint block_resize : 1; +}; + +struct _GtkContainerClass +{ + GtkWidgetClass parent_class; + + void (* add) (GtkContainer *container, + GtkWidget *widget); + void (* remove) (GtkContainer *container, + GtkWidget *widget); + gint (* need_resize) (GtkContainer *container); + void (* foreach) (GtkContainer *container, + GtkCallback callback, + gpointer callbabck_data); + gint (* focus) (GtkContainer *container, + GtkDirectionType direction); +}; + + + +guint gtk_container_get_type (void); +void gtk_container_border_width (GtkContainer *container, + gint border_width); +void gtk_container_add (GtkContainer *container, + GtkWidget *widget); +void gtk_container_remove (GtkContainer *container, + GtkWidget *widget); +void gtk_container_disable_resize (GtkContainer *container); +void gtk_container_enable_resize (GtkContainer *container); +void gtk_container_block_resize (GtkContainer *container); +void gtk_container_unblock_resize (GtkContainer *container); +gint gtk_container_need_resize (GtkContainer *container); +void gtk_container_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +gint gtk_container_focus (GtkContainer *container, + GtkDirectionType direction); +GList* gtk_container_children (GtkContainer *container); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_CONTAINER_H__ */ diff --git a/gtk/gtkcurve.c b/gtk/gtkcurve.c new file mode 100644 index 000000000..d2b6e08c8 --- /dev/null +++ b/gtk/gtkcurve.c @@ -0,0 +1,860 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1997 David Mosberger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include + +#include "gtkcurve.h" +#include "gtkdrawingarea.h" +#include "gtkmain.h" +#include "gtkradiobutton.h" +#include "gtksignal.h" +#include "gtktable.h" + +#define BOUNDS(a,x,y) (((a) < (x)) ? (x) : (((a) > (y)) ? (y) : (a))) +#define RADIUS 3 /* radius of the control points */ +#define MIN_DISTANCE 8 /* min distance between control points */ + +#define GRAPH_MASK (GDK_EXPOSURE_MASK | \ + GDK_POINTER_MOTION_MASK | \ + GDK_POINTER_MOTION_HINT_MASK | \ + GDK_ENTER_NOTIFY_MASK | \ + GDK_BUTTON_PRESS_MASK | \ + GDK_BUTTON_RELEASE_MASK | \ + GDK_BUTTON1_MOTION_MASK) + +static GtkDrawingAreaClass *parent_class = NULL; +static gint curve_type_changed_signal = 0; + + +/* forward declarations: */ +static void gtk_curve_class_init (GtkCurveClass *class); +static void gtk_curve_init (GtkCurve *curve); +static void gtk_curve_destroy (GtkObject *object); + + +guint +gtk_curve_get_type (void) +{ + static guint curve_type = 0; + + if (!curve_type) + { + GtkTypeInfo curve_info = + { + "GtkCurve", + sizeof (GtkCurve), + sizeof (GtkCurveClass), + (GtkClassInitFunc) gtk_curve_class_init, + (GtkObjectInitFunc) gtk_curve_init, + (GtkArgFunc) NULL, + }; + + curve_type = gtk_type_unique (gtk_drawing_area_get_type (), &curve_info); + } + return curve_type; +} + +static void +gtk_curve_class_init (GtkCurveClass *class) +{ + GtkObjectClass *object_class; + + parent_class = gtk_type_class (gtk_drawing_area_get_type ()); + + object_class = (GtkObjectClass *) class; + + curve_type_changed_signal = + gtk_signal_new ("curve_type_changed", GTK_RUN_FIRST, object_class->type, + GTK_SIGNAL_OFFSET (GtkCurveClass, curve_type_changed), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + gtk_object_class_add_signals (object_class, &curve_type_changed_signal, 1); + + object_class->destroy = gtk_curve_destroy; +} + +static void +gtk_curve_init (GtkCurve *curve) +{ + curve->cursor_type = GDK_TOP_LEFT_ARROW; + curve->pixmap = NULL; + curve->curve_type = GTK_CURVE_TYPE_SPLINE; + curve->height = 0; + curve->grab_point = -1; + + curve->num_points = 0; + curve->point = 0; + + curve->num_ctlpoints = 0; + curve->ctlpoint = NULL; +} + +static int +project (gfloat value, gfloat min, gfloat max, int norm) +{ + return (norm - 1) * ((value - min) / (max - min)) + 0.5; +} + +static gfloat +unproject (gint value, gfloat min, gfloat max, int norm) +{ + return value / (gfloat) (norm - 1) * (max - min) + min; +} + +/* Solve the tridiagonal equation system that determines the second + derivatives for the interpolation points. (Based on Numerical + Recipies 2nd Edition.) */ +static void +spline_solve (int n, gfloat x[], gfloat y[], gfloat y2[]) +{ + gfloat p, sig, *u; + gint i, k; + + u = g_malloc ((n - 1) * sizeof (u[0])); + + y2[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */ + + for (i = 1; i < n - 1; ++i) + { + sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); + p = sig * y2[i - 1] + 2.0; + y2[i] = (sig - 1.0) / p; + u[i] = ((y[i + 1] - y[i]) + / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1])); + u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; + } + + y2[n - 1] = 0.0; + for (k = n - 2; k >= 0; --k) + y2[k] = y2[k] * y2[k + 1] + u[k]; + + g_free (u); +} + +static gfloat +spline_eval (int n, gfloat x[], gfloat y[], gfloat y2[], gfloat val) +{ + gint k_lo, k_hi, k; + gfloat h, b, a; + + /* do a binary search for the right interval: */ + k_lo = 0; k_hi = n - 1; + while (k_hi - k_lo > 1) + { + k = (k_hi + k_lo) / 2; + if (x[k] > val) + k_hi = k; + else + k_lo = k; + } + + h = x[k_hi] - x[k_lo]; + g_assert (h > 0.0); + + a = (x[k_hi] - val) / h; + b = (val - x[k_lo]) / h; + return a*y[k_lo] + b*y[k_hi] + + ((a*a*a - a)*y2[k_lo] + (b*b*b - b)*y2[k_hi]) * (h*h)/6.0; +} + +static void +gtk_curve_interpolate (GtkCurve *c, gint width, gint height) +{ + gfloat *vector; + int i; + + vector = g_malloc (width * sizeof (vector[0])); + + gtk_curve_get_vector (c, width, vector); + + c->height = height; + if (c->num_points != width) + { + c->num_points = width; + if (c->point) + g_free (c->point); + c->point = g_malloc (c->num_points * sizeof (c->point[0])); + } + + for (i = 0; i < width; ++i) + { + c->point[i].x = RADIUS + i; + c->point[i].y = RADIUS + height + - project (vector[i], c->min_y, c->max_y, height); + } +} + +static void +gtk_curve_draw (GtkCurve *c, gint width, gint height) +{ + GtkStateType state; + GtkStyle *style; + gint i; + + if (!c->pixmap) + return; + + if (c->height != height || c->num_points != width) + gtk_curve_interpolate (c, width, height); + + state = GTK_STATE_NORMAL; + if (!GTK_WIDGET_IS_SENSITIVE (GTK_WIDGET (c))) + state = GTK_STATE_INSENSITIVE; + + style = GTK_WIDGET (c)->style; + + /* clear the pixmap: */ + gdk_draw_rectangle (c->pixmap, style->bg_gc[state], TRUE, + 0, 0, width + RADIUS * 2, height + RADIUS * 2); + + /* draw the grid lines: (XXX make more meaningful) */ + for (i = 0; i < 5; i++) + { + gdk_draw_line (c->pixmap, style->dark_gc[state], + RADIUS, i * (height / 4.0) + RADIUS, + width + RADIUS, i * (height / 4.0) + RADIUS); + gdk_draw_line (c->pixmap, style->dark_gc[state], + i * (width / 4.0) + RADIUS, RADIUS, + i * (width / 4.0) + RADIUS, height + RADIUS); + } + + gdk_draw_points (c->pixmap, style->fg_gc[state], c->point, c->num_points); + if (c->curve_type != GTK_CURVE_TYPE_FREE) + for (i = 0; i < c->num_ctlpoints; ++i) + { + gint x, y; + + if (c->ctlpoint[i][0] < c->min_x) + continue; + + x = project (c->ctlpoint[i][0], c->min_x, c->max_x, + width); + y = height - + project (c->ctlpoint[i][1], c->min_y, c->max_y, + height); + + /* draw a bullet: */ + gdk_draw_arc (c->pixmap, style->fg_gc[state], TRUE, x, y, + RADIUS * 2, RADIUS*2, 0, 360*64); + } + gdk_draw_pixmap (GTK_WIDGET (c)->window, style->fg_gc[state], c->pixmap, + 0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2); +} + +static gint +gtk_curve_graph_events (GtkWidget *widget, GdkEvent *event, GtkCurve *c) +{ + GdkCursorType new_type = c->cursor_type; + gint i, src, dst, leftbound, rightbound; + GdkEventButton *bevent; + GdkEventMotion *mevent; + GtkWidget *w; + gint tx, ty; + gint cx, x, y, width, height; + gint closest_point = 0; + gfloat rx, ry, min_x; + guint distance; + gint x1, x2, y1, y2; + + w = GTK_WIDGET (c); + width = w->allocation.width - RADIUS * 2; + height = w->allocation.height - RADIUS * 2; + + /* get the pointer position */ + gdk_window_get_pointer (w->window, &tx, &ty, NULL); + x = BOUNDS ((tx - RADIUS), 0, width); + y = BOUNDS ((ty - RADIUS), 0, height); + + min_x = c->min_x; + + distance = ~0U; + for (i = 0; i < c->num_ctlpoints; ++i) + { + cx = project (c->ctlpoint[i][0], min_x, c->max_x, width); + if ((guint) abs (x - cx) < distance) + { + distance = abs (x - cx); + closest_point = i; + } + } + + switch (event->type) + { + case GDK_CONFIGURE: + if (c->pixmap) + gdk_pixmap_destroy (c->pixmap); + c->pixmap = 0; + /* fall through */ + case GDK_EXPOSE: + if (!c->pixmap) + c->pixmap = gdk_pixmap_new (w->window, + w->allocation.width, + w->allocation.height, -1); + gtk_curve_draw (c, width, height); + break; + + case GDK_BUTTON_PRESS: + gtk_grab_add (widget); + + bevent = (GdkEventButton *) event; + new_type = GDK_TCROSS; + + switch (c->curve_type) + { + case GTK_CURVE_TYPE_LINEAR: + case GTK_CURVE_TYPE_SPLINE: + if (distance > MIN_DISTANCE) + { + /* insert a new control point */ + if (c->num_ctlpoints > 0) + { + cx = project (c->ctlpoint[closest_point][0], min_x, + c->max_x, width); + if (x > cx) + ++closest_point; + } + ++c->num_ctlpoints; + c->ctlpoint = + g_realloc (c->ctlpoint, + c->num_ctlpoints * sizeof (*c->ctlpoint)); + for (i = c->num_ctlpoints - 1; i > closest_point; --i) + memcpy (c->ctlpoint + i, c->ctlpoint + i - 1, + sizeof (*c->ctlpoint)); + } + c->grab_point = closest_point; + c->ctlpoint[c->grab_point][0] = + unproject (x, min_x, c->max_x, width); + c->ctlpoint[c->grab_point][1] = + unproject (height - y, c->min_y, c->max_y, height); + + gtk_curve_interpolate (c, width, height); + break; + + case GTK_CURVE_TYPE_FREE: + c->point[x].x = RADIUS + x; + c->point[x].y = RADIUS + y; + c->grab_point = x; + c->last = y; + break; + } + gtk_curve_draw (c, width, height); + break; + + case GDK_BUTTON_RELEASE: + gtk_grab_remove (widget); + + /* delete inactive points: */ + if (c->curve_type != GTK_CURVE_TYPE_FREE) + { + for (src = dst = 0; src < c->num_ctlpoints; ++src) + { + if (c->ctlpoint[src][0] >= min_x) + { + memcpy (c->ctlpoint + dst, c->ctlpoint + src, + sizeof (*c->ctlpoint)); + ++dst; + } + } + if (dst < src) + { + c->num_ctlpoints -= (src - dst); + if (c->num_ctlpoints <= 0) + { + c->num_ctlpoints = 1; + c->ctlpoint[0][0] = min_x; + c->ctlpoint[0][1] = c->min_y; + gtk_curve_interpolate (c, width, height); + gtk_curve_draw (c, width, height); + } + c->ctlpoint = + g_realloc (c->ctlpoint, + c->num_ctlpoints * sizeof (*c->ctlpoint)); + } + } + new_type = GDK_FLEUR; + c->grab_point = -1; + break; + + case GDK_MOTION_NOTIFY: + mevent = (GdkEventMotion *) event; + if (mevent->is_hint) + { + mevent->x = tx; + mevent->y = ty; + } + switch (c->curve_type) + { + case GTK_CURVE_TYPE_LINEAR: + case GTK_CURVE_TYPE_SPLINE: + if (c->grab_point == -1) + { + /* if no point is grabbed... */ + if (distance <= MIN_DISTANCE) + new_type = GDK_FLEUR; + else + new_type = GDK_TCROSS; + } + else + { + /* drag the grabbed point */ + new_type = GDK_TCROSS; + + leftbound = -MIN_DISTANCE; + if (c->grab_point > 0) + leftbound = project (c->ctlpoint[c->grab_point - 1][0], + min_x, c->max_x, width); + + rightbound = width + RADIUS * 2 + MIN_DISTANCE; + if (c->grab_point + 1 < c->num_ctlpoints) + rightbound = project (c->ctlpoint[c->grab_point + 1][0], + min_x, c->max_x, width); + + if (tx <= leftbound || tx >= rightbound + || ty > height + RADIUS * 2 + MIN_DISTANCE + || ty < -MIN_DISTANCE) + c->ctlpoint[c->grab_point][0] = min_x - 1.0; + else + { + rx = unproject (x, min_x, c->max_x, width); + ry = unproject (height - y, c->min_y, c->max_y, height); + c->ctlpoint[c->grab_point][0] = rx; + c->ctlpoint[c->grab_point][1] = ry; + } + gtk_curve_interpolate (c, width, height); + gtk_curve_draw (c, width, height); + } + break; + + case GTK_CURVE_TYPE_FREE: + if (c->grab_point != -1) + { + if (c->grab_point > x) + { + x1 = x; + x2 = c->grab_point; + y1 = y; + y2 = c->last; + } + else + { + x1 = c->grab_point; + x2 = x; + y1 = c->last; + y2 = y; + } + + if (x2 != x1) + for (i = x1; i <= x2; i++) + { + c->point[i].x = RADIUS + i; + c->point[i].y = RADIUS + + (y1 + ((y2 - y1) * (i - x1)) / (x2 - x1)); + } + else + { + c->point[x].x = RADIUS + x; + c->point[x].y = RADIUS + y; + } + c->grab_point = x; + c->last = y; + gtk_curve_draw (c, width, height); + } + if (mevent->state & GDK_BUTTON1_MASK) + new_type = GDK_TCROSS; + else + new_type = GDK_PENCIL; + break; + } + if (new_type != (GdkCursorType) c->cursor_type) + { + GdkCursor *cursor; + + c->cursor_type = new_type; + + cursor = gdk_cursor_new (c->cursor_type); + gdk_window_set_cursor (w->window, cursor); + gdk_cursor_destroy (cursor); + } + break; + + default: + break; + } + return FALSE; +} + +void +gtk_curve_set_curve_type (GtkCurve *c, GtkCurveType new_type) +{ + gfloat rx, dx; + gint x, i; + + if (new_type != c->curve_type) + { + gint width, height; + + width = GTK_WIDGET(c)->allocation.width - RADIUS * 2; + height = GTK_WIDGET(c)->allocation.height - RADIUS * 2; + + if (new_type == GTK_CURVE_TYPE_FREE) + { + gtk_curve_interpolate (c, width, height); + c->curve_type = new_type; + } + else if (c->curve_type == GTK_CURVE_TYPE_FREE) + { + if (c->ctlpoint) + g_free (c->ctlpoint); + c->num_ctlpoints = 9; + c->ctlpoint = g_malloc (c->num_ctlpoints * sizeof (*c->ctlpoint)); + + rx = 0.0; + dx = (width - 1) / (gfloat) (c->num_ctlpoints - 1); + + for (i = 0; i < c->num_ctlpoints; ++i, rx += dx) + { + x = (int) (rx + 0.5); + c->ctlpoint[i][0] = + unproject (x, c->min_x, c->max_x, width); + c->ctlpoint[i][1] = + unproject (RADIUS + height - c->point[x].y, + c->min_y, c->max_y, height); + } + c->curve_type = new_type; + gtk_curve_interpolate (c, width, height); + } + else + { + c->curve_type = new_type; + gtk_curve_interpolate (c, width, height); + } + gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal); + gtk_curve_draw (c, width, height); + } +} + +static void +gtk_curve_size_graph (GtkCurve *curve) +{ + gint width, height; + gfloat aspect; + + width = (curve->max_x - curve->min_x) + 1; + height = (curve->max_y - curve->min_y) + 1; + aspect = width / (gfloat) height; + if (width > gdk_screen_width () / 4) + width = gdk_screen_width () / 4; + if (height > gdk_screen_height () / 4) + height = gdk_screen_height () / 4; + + if (aspect < 1.0) + width = height * aspect; + else + height = width / aspect; + + gtk_drawing_area_size (GTK_DRAWING_AREA (curve), + width + RADIUS * 2, height + RADIUS * 2); +} + +static void +gtk_curve_reset_vector (GtkCurve *curve) +{ + if (curve->ctlpoint) + g_free (curve->ctlpoint); + + curve->num_ctlpoints = 2; + curve->ctlpoint = g_malloc (2 * sizeof (curve->ctlpoint[0])); + curve->ctlpoint[0][0] = curve->min_x; + curve->ctlpoint[0][1] = curve->min_y; + curve->ctlpoint[1][0] = curve->max_x; + curve->ctlpoint[1][1] = curve->max_y; + + if (curve->pixmap) + { + gint width, height; + + width = GTK_WIDGET (curve)->allocation.width - RADIUS * 2; + height = GTK_WIDGET (curve)->allocation.height - RADIUS * 2; + + if (curve->curve_type == GTK_CURVE_TYPE_FREE) + { + curve->curve_type = GTK_CURVE_TYPE_LINEAR; + gtk_curve_interpolate (curve, width, height); + curve->curve_type = GTK_CURVE_TYPE_FREE; + } + else + gtk_curve_interpolate (curve, width, height); + gtk_curve_draw (curve, width, height); + } +} + +void +gtk_curve_reset (GtkCurve *c) +{ + GtkCurveType old_type; + + old_type = c->curve_type; + c->curve_type = GTK_CURVE_TYPE_SPLINE; + gtk_curve_reset_vector (c); + + if (old_type != GTK_CURVE_TYPE_SPLINE) + gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal); +} + +void +gtk_curve_set_gamma (GtkCurve *c, gfloat gamma) +{ + gfloat x, one_over_gamma, height, one_over_width; + GtkCurveType old_type; + gint i; + + if (c->num_points < 2) + return; + + old_type = c->curve_type; + c->curve_type = GTK_CURVE_TYPE_FREE; + + if (gamma <= 0) + one_over_gamma = 1.0; + else + one_over_gamma = 1.0 / gamma; + one_over_width = 1.0 / (c->num_points - 1); + height = c->height; + for (i = 0; i < c->num_points; ++i) + { + x = (gfloat) i / (c->num_points - 1); + c->point[i].x = RADIUS + i; + c->point[i].y = + RADIUS + (height * (1.0 - pow (x, one_over_gamma)) + 0.5); + } + + if (old_type != GTK_CURVE_TYPE_FREE) + gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal); + + gtk_curve_draw (c, c->num_points, c->height); +} + +void +gtk_curve_set_range (GtkCurve *curve, + gfloat min_x, gfloat max_x, gfloat min_y, gfloat max_y) +{ + curve->min_x = min_x; + curve->max_x = max_x; + curve->min_y = min_y; + curve->max_y = max_y; + + gtk_curve_size_graph (curve); + gtk_curve_reset_vector (curve); +} + +void +gtk_curve_set_vector (GtkCurve *c, int veclen, gfloat vector[]) +{ + GtkCurveType old_type; + gfloat rx, dx, ry; + gint i, height; + + old_type = c->curve_type; + c->curve_type = GTK_CURVE_TYPE_FREE; + + if (c->point) + height = GTK_WIDGET (c)->allocation.height - RADIUS * 2; + else + { + height = (c->max_y - c->min_y); + if (height > gdk_screen_height () / 4) + height = gdk_screen_height () / 4; + + c->height = height; + c->num_points = veclen; + c->point = g_malloc (c->num_points * sizeof (c->point[0])); + } + rx = 0; + dx = (veclen - 1.0) / (c->num_points - 1.0); + + for (i = 0; i < c->num_points; ++i, rx += dx) + { + ry = vector[(int) (rx + 0.5)]; + if (ry > c->max_y) ry = c->max_y; + if (ry < c->min_y) ry = c->min_y; + c->point[i].x = RADIUS + i; + c->point[i].y = + RADIUS + height - project (ry, c->min_y, c->max_y, height); + } + if (old_type != GTK_CURVE_TYPE_FREE) + gtk_signal_emit (GTK_OBJECT (c), curve_type_changed_signal); + + gtk_curve_draw (c, c->num_points, height); +} + +void +gtk_curve_get_vector (GtkCurve *c, int veclen, gfloat vector[]) +{ + gfloat rx, ry, dx, dy, min_x, delta_x, *mem, *xv, *yv, *y2v, prev; + gint dst, i, x, next, num_active_ctlpoints = 0, first_active = -1; + + min_x = c->min_x; + + if (c->curve_type != GTK_CURVE_TYPE_FREE) + { + /* count active points: */ + prev = min_x - 1.0; + for (i = num_active_ctlpoints = 0; i < c->num_ctlpoints; ++i) + if (c->ctlpoint[i][0] > prev) + { + if (first_active < 0) + first_active = i; + prev = c->ctlpoint[i][0]; + ++num_active_ctlpoints; + } + + /* handle degenerate case: */ + if (num_active_ctlpoints < 2) + { + if (num_active_ctlpoints > 0) + ry = c->ctlpoint[first_active][1]; + else + ry = c->min_y; + if (ry < c->min_y) ry = c->min_y; + if (ry > c->max_y) ry = c->max_y; + for (x = 0; x < veclen; ++x) + vector[x] = ry; + return; + } + } + + switch (c->curve_type) + { + case GTK_CURVE_TYPE_SPLINE: + mem = g_malloc (3 * num_active_ctlpoints * sizeof (gfloat)); + xv = mem; + yv = mem + num_active_ctlpoints; + y2v = mem + 2*num_active_ctlpoints; + + prev = min_x - 1.0; + for (i = dst = 0; i < c->num_ctlpoints; ++i) + if (c->ctlpoint[i][0] > prev) + { + prev = c->ctlpoint[i][0]; + xv[dst] = c->ctlpoint[i][0]; + yv[dst] = c->ctlpoint[i][1]; + ++dst; + } + + spline_solve (num_active_ctlpoints, xv, yv, y2v); + + rx = min_x; + dx = (c->max_x - min_x) / (veclen - 1); + for (x = 0; x < veclen; ++x, rx += dx) + { + ry = spline_eval (num_active_ctlpoints, xv, yv, y2v, rx); + if (ry < c->min_y) ry = c->min_y; + if (ry > c->max_y) ry = c->max_y; + vector[x] = ry; + } + + g_free (mem); + break; + + case GTK_CURVE_TYPE_LINEAR: + dx = (c->max_x - min_x) / (veclen - 1); + rx = min_x; + ry = c->min_y; + dy = 0.0; + i = first_active; + for (x = 0; x < veclen; ++x, rx += dx) + { + if (rx >= c->ctlpoint[i][0]) + { + if (rx > c->ctlpoint[i][0]) + ry = c->min_y; + dy = 0.0; + next = i + 1; + while (next < c->num_ctlpoints + && c->ctlpoint[next][0] <= c->ctlpoint[i][0]) + ++next; + if (next < c->num_ctlpoints) + { + delta_x = c->ctlpoint[next][0] - c->ctlpoint[i][0]; + dy = ((c->ctlpoint[next][1] - c->ctlpoint[i][1]) + / delta_x); + dy *= dx; + ry = c->ctlpoint[i][1]; + i = next; + } + } + vector[x] = ry; + ry += dy; + } + break; + + case GTK_CURVE_TYPE_FREE: + if (c->point) + { + rx = 0.0; + dx = c->num_points / (double) veclen; + for (x = 0; x < veclen; ++x, rx += dx) + vector[x] = unproject (RADIUS + c->height - c->point[(int) rx].y, + c->min_y, c->max_y, + c->height); + } + else + memset (vector, 0, veclen * sizeof (vector[0])); + break; + } +} + +GtkWidget* +gtk_curve_new (void) +{ + GtkCurve *curve; + gint old_mask; + + curve = gtk_type_new (gtk_curve_get_type ()); + curve->min_x = 0.0; + curve->max_x = 1.0; + curve->min_y = 0.0; + curve->max_y = 1.0; + + old_mask = gtk_widget_get_events (GTK_WIDGET (curve)); + gtk_widget_set_events (GTK_WIDGET (curve), old_mask | GRAPH_MASK); + gtk_signal_connect (GTK_OBJECT (curve), "event", + (GtkSignalFunc) gtk_curve_graph_events, curve); + gtk_curve_size_graph (curve); + + return GTK_WIDGET (curve); +} + +static void +gtk_curve_destroy (GtkObject *object) +{ + GtkCurve *curve; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_CURVE (object)); + + curve = GTK_CURVE (object); + if (curve->pixmap) + gdk_pixmap_destroy (curve->pixmap); + if (curve->point) + g_free (curve->point); + if (curve->ctlpoint) + g_free (curve->ctlpoint); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (*GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} diff --git a/gtk/gtkcurve.h b/gtk/gtkcurve.h new file mode 100644 index 000000000..0e1568bc7 --- /dev/null +++ b/gtk/gtkcurve.h @@ -0,0 +1,96 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_CURVE_H__ +#define __GTK_CURVE_H__ + + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_CURVE(obj) GTK_CHECK_CAST (obj, gtk_curve_get_type (), GtkCurve) +#define GTK_CURVE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_curve_get_type, GtkCurveClass) +#define GTK_IS_CURVE(obj) GTK_CHECK_TYPE (obj, gtk_curve_get_type ()) + + +typedef struct _GtkCurve GtkCurve; +typedef struct _GtkCurveClass GtkCurveClass; + +typedef enum +{ + GTK_CURVE_TYPE_LINEAR, /* linear interpolation */ + GTK_CURVE_TYPE_SPLINE, /* spline interpolation */ + GTK_CURVE_TYPE_FREE /* free form curve */ +} GtkCurveType; + +struct _GtkCurve +{ + GtkDrawingArea graph; + + gint cursor_type; + gfloat min_x; + gfloat max_x; + gfloat min_y; + gfloat max_y; + GdkPixmap *pixmap; + GtkCurveType curve_type; + gint height; /* (cached) graph height in pixels */ + gint grab_point; /* point currently grabbed */ + gint last; + + /* (cached) curve points: */ + gint num_points; + GdkPoint *point; + + /* control points: */ + gint num_ctlpoints; /* number of control points */ + gfloat (*ctlpoint)[2]; /* array of control points */ +}; + +struct _GtkCurveClass +{ + GtkDrawingAreaClass parent_class; + + void (* curve_type_changed) (GtkCurve *curve); +}; + + +guint gtk_curve_get_type (void); +GtkWidget* gtk_curve_new (void); +void gtk_curve_reset (GtkCurve *curve); +void gtk_curve_set_gamma (GtkCurve *curve, gfloat gamma); +void gtk_curve_set_range (GtkCurve *curve, + gfloat min_x, gfloat max_x, + gfloat min_y, gfloat max_y); +void gtk_curve_get_vector (GtkCurve *curve, + int veclen, gfloat vector[]); +void gtk_curve_set_vector (GtkCurve *curve, + int veclen, gfloat vector[]); +void gtk_curve_set_curve_type (GtkCurve *curve, GtkCurveType type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_CURVE_H__ */ diff --git a/gtk/gtkdata.c b/gtk/gtkdata.c new file mode 100644 index 000000000..63add29f3 --- /dev/null +++ b/gtk/gtkdata.c @@ -0,0 +1,73 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkdata.h" +#include "gtksignal.h" + + +enum { + DISCONNECT, + LAST_SIGNAL +}; + + +static void gtk_data_class_init (GtkDataClass *klass); + + +static gint data_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_data_get_type () +{ + static guint data_type = 0; + + if (!data_type) + { + GtkTypeInfo data_info = + { + "GtkData", + sizeof (GtkData), + sizeof (GtkDataClass), + (GtkClassInitFunc) gtk_data_class_init, + (GtkObjectInitFunc) NULL, + (GtkArgFunc) NULL, + }; + + data_type = gtk_type_unique (gtk_object_get_type (), &data_info); + } + + return data_type; +} + +static void +gtk_data_class_init (GtkDataClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; + + data_signals[DISCONNECT] = + gtk_signal_new ("disconnect", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkDataClass, disconnect), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, data_signals, LAST_SIGNAL); +} diff --git a/gtk/gtkdata.h b/gtk/gtkdata.h new file mode 100644 index 000000000..2e9d30b31 --- /dev/null +++ b/gtk/gtkdata.h @@ -0,0 +1,60 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_DATA_H__ +#define __GTK_DATA_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_DATA(obj) GTK_CHECK_CAST (obj, gtk_data_get_type (), GtkData) +#define GTK_DATA_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_data_get_type (), GtkDataClass) +#define GTK_IS_DATA(obj) GTK_CHECK_TYPE (obj, gtk_data_get_type ()) + + +typedef struct _GtkData GtkData; +typedef struct _GtkDataClass GtkDataClass; + +struct _GtkData +{ + GtkObject object; +}; + +struct _GtkDataClass +{ + GtkObjectClass parent_class; + + void (* disconnect) (GtkData *data); +}; + + +guint gtk_data_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_DATA_H__ */ diff --git a/gtk/gtkdialog.c b/gtk/gtkdialog.c new file mode 100644 index 000000000..55da2d137 --- /dev/null +++ b/gtk/gtkdialog.c @@ -0,0 +1,80 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkbutton.h" +#include "gtkdialog.h" +#include "gtkhbox.h" +#include "gtkhseparator.h" +#include "gtkvbox.h" + + +static void gtk_dialog_class_init (GtkDialogClass *klass); +static void gtk_dialog_init (GtkDialog *dialog); + + +guint +gtk_dialog_get_type () +{ + static guint dialog_type = 0; + + if (!dialog_type) + { + GtkTypeInfo dialog_info = + { + "GtkDialog", + sizeof (GtkDialog), + sizeof (GtkDialogClass), + (GtkClassInitFunc) gtk_dialog_class_init, + (GtkObjectInitFunc) gtk_dialog_init, + (GtkArgFunc) NULL, + }; + + dialog_type = gtk_type_unique (gtk_window_get_type (), &dialog_info); + } + + return dialog_type; +} + +static void +gtk_dialog_class_init (GtkDialogClass *class) +{ +} + +static void +gtk_dialog_init (GtkDialog *dialog) +{ + GtkWidget *separator; + + dialog->vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (dialog), dialog->vbox); + gtk_widget_show (dialog->vbox); + + dialog->action_area = gtk_hbox_new (TRUE, 5); + gtk_container_border_width (GTK_CONTAINER (dialog->action_area), 10); + gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->action_area, FALSE, TRUE, 0); + gtk_widget_show (dialog->action_area); + + separator = gtk_hseparator_new (); + gtk_box_pack_end (GTK_BOX (dialog->vbox), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); +} + +GtkWidget* +gtk_dialog_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_dialog_get_type ())); +} diff --git a/gtk/gtkdialog.h b/gtk/gtkdialog.h new file mode 100644 index 000000000..139699682 --- /dev/null +++ b/gtk/gtkdialog.h @@ -0,0 +1,64 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_DIALOG_H__ +#define __GTK_DIALOG_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_DIALOG(obj) GTK_CHECK_CAST (obj, gtk_dialog_get_type (), GtkDialog) +#define GTK_DIALOG_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dialog_get_type (), GtkDialogClass) +#define GTK_IS_DIALOG(obj) GTK_CHECK_TYPE (obj, gtk_dialog_get_type ()) + + +typedef struct _GtkDialog GtkDialog; +typedef struct _GtkDialogClass GtkDialogClass; +typedef struct _GtkDialogButton GtkDialogButton; + + +struct _GtkDialog +{ + GtkWindow window; + + GtkWidget *vbox; + GtkWidget *action_area; +}; + +struct _GtkDialogClass +{ + GtkWindowClass parent_class; +}; + + +guint gtk_dialog_get_type (void); +GtkWidget* gtk_dialog_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_DIALOG_H__ */ diff --git a/gtk/gtkdrawingarea.c b/gtk/gtkdrawingarea.c new file mode 100644 index 000000000..3220446a5 --- /dev/null +++ b/gtk/gtkdrawingarea.c @@ -0,0 +1,146 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkdrawingarea.h" + + +static void gtk_drawing_area_class_init (GtkDrawingAreaClass *klass); +static void gtk_drawing_area_init (GtkDrawingArea *darea); +static void gtk_drawing_area_realize (GtkWidget *widget); +static void gtk_drawing_area_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +guint +gtk_drawing_area_get_type () +{ + static guint drawing_area_type = 0; + + if (!drawing_area_type) + { + GtkTypeInfo drawing_area_info = + { + "GtkDrawingArea", + sizeof (GtkDrawingArea), + sizeof (GtkDrawingAreaClass), + (GtkClassInitFunc) gtk_drawing_area_class_init, + (GtkObjectInitFunc) gtk_drawing_area_init, + (GtkArgFunc) NULL, + }; + + drawing_area_type = gtk_type_unique (gtk_widget_get_type (), &drawing_area_info); + } + + return drawing_area_type; +} + +static void +gtk_drawing_area_class_init (GtkDrawingAreaClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_drawing_area_realize; + widget_class->size_allocate = gtk_drawing_area_size_allocate; +} + +static void +gtk_drawing_area_init (GtkDrawingArea *darea) +{ + GTK_WIDGET_SET_FLAGS (darea, GTK_BASIC); +} + + +GtkWidget* +gtk_drawing_area_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_drawing_area_get_type ())); +} + +void +gtk_drawing_area_size (GtkDrawingArea *darea, + gint width, + gint height) +{ + g_return_if_fail (darea != NULL); + g_return_if_fail (GTK_IS_DRAWING_AREA (darea)); + + GTK_WIDGET (darea)->requisition.width = width; + GTK_WIDGET (darea)->requisition.height = height; +} + +static void +gtk_drawing_area_realize (GtkWidget *widget) +{ + GtkDrawingArea *darea; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_DRAWING_AREA (widget)); + + darea = GTK_DRAWING_AREA (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, darea); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_drawing_area_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GdkEventConfigure event; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_DRAWING_AREA (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + event.type = GDK_CONFIGURE; + event.window = widget->window; + event.x = allocation->x; + event.y = allocation->y; + event.width = allocation->width; + event.height = allocation->height; + + gtk_widget_event (widget, (GdkEvent*) &event); + } +} diff --git a/gtk/gtkdrawingarea.h b/gtk/gtkdrawingarea.h new file mode 100644 index 000000000..d11445b03 --- /dev/null +++ b/gtk/gtkdrawingarea.h @@ -0,0 +1,62 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_DRAWING_AREA_H__ +#define __GTK_DRAWING_AREA_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_DRAWING_AREA(obj) GTK_CHECK_CAST (obj, gtk_drawing_area_get_type (), GtkDrawingArea) +#define GTK_DRAWING_AREA_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_drawing_area_get_type (), GtkDrawingAreaClass) +#define GTK_IS_DRAWING_AREA(obj) GTK_CHECK_TYPE (obj, gtk_drawing_area_get_type ()) + + +typedef struct _GtkDrawingArea GtkDrawingArea; +typedef struct _GtkDrawingAreaClass GtkDrawingAreaClass; + +struct _GtkDrawingArea +{ + GtkWidget widget; +}; + +struct _GtkDrawingAreaClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_drawing_area_get_type (void); +GtkWidget* gtk_drawing_area_new (void); +void gtk_drawing_area_size (GtkDrawingArea *darea, + gint width, + gint height); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_DRAWING_AREA_H__ */ diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c new file mode 100644 index 000000000..b9c25f63a --- /dev/null +++ b/gtk/gtkentry.c @@ -0,0 +1,1678 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk/gdkkeysyms.h" +#include "gtkentry.h" +#include "gtkmain.h" +#include "gtkselection.h" +#include "gtksignal.h" + +#define MIN_ENTRY_WIDTH 150 +#define DRAW_TIMEOUT 20 +#define INNER_BORDER 2 + + +enum { + INSERT_TEXT, + DELETE_TEXT, + CHANGED, + SET_TEXT, + ACTIVATE, + LAST_SIGNAL +}; + + +typedef void (*GtkTextFunction) (GtkEntry *entry); +typedef void (*GtkEntrySignal1) (GtkObject *object, + gpointer arg1, + gint arg2, + gpointer arg3, + gpointer data); +typedef void (*GtkEntrySignal2) (GtkObject *object, + gint arg1, + gint arg2, + gpointer data); + + +static void gtk_entry_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_entry_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + +static void gtk_entry_class_init (GtkEntryClass *klass); +static void gtk_entry_init (GtkEntry *entry); +static void gtk_entry_destroy (GtkObject *object); +static void gtk_entry_realize (GtkWidget *widget); +static void gtk_entry_unrealize (GtkWidget *widget); +static void gtk_entry_draw_focus (GtkWidget *widget); +static void gtk_entry_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_entry_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_entry_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_entry_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_entry_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_entry_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_entry_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_entry_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_entry_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_entry_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_entry_selection_clear (GtkWidget *widget, + GdkEventSelection *event); +static void gtk_entry_selection_handler (GtkWidget *widget, + GtkSelectionData *selection_data, + gpointer data); +static void gtk_entry_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data); +static void gtk_entry_draw_text (GtkEntry *entry); +static void gtk_entry_draw_cursor (GtkEntry *entry); +static void gtk_entry_queue_draw (GtkEntry *entry); +static gint gtk_entry_timer (gpointer data); +static gint gtk_entry_position (GtkEntry *entry, + gint x); + void gtk_entry_adjust_scroll (GtkEntry *entry); +static void gtk_entry_grow_text (GtkEntry *entry); +static void gtk_entry_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position); +static void gtk_entry_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos); +static void gtk_real_entry_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position); +static void gtk_real_entry_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos); + +static void gtk_move_forward_character (GtkEntry *entry); +static void gtk_move_backward_character (GtkEntry *entry); +static void gtk_move_forward_word (GtkEntry *entry); +static void gtk_move_backward_word (GtkEntry *entry); +static void gtk_move_beginning_of_line (GtkEntry *entry); +static void gtk_move_end_of_line (GtkEntry *entry); +static void gtk_delete_forward_character (GtkEntry *entry); +static void gtk_delete_backward_character (GtkEntry *entry); +static void gtk_delete_forward_word (GtkEntry *entry); +static void gtk_delete_backward_word (GtkEntry *entry); +static void gtk_delete_line (GtkEntry *entry); +static void gtk_delete_to_line_end (GtkEntry *entry); +static void gtk_delete_selection (GtkEntry *entry); +static void gtk_select_word (GtkEntry *entry); +static void gtk_select_line (GtkEntry *entry); +static void gtk_select_region (GtkEntry *entry, + gint start, + gint end); + + +static GtkWidgetClass *parent_class = NULL; +static gint entry_signals[LAST_SIGNAL] = { 0 }; + +static GtkTextFunction control_keys[26] = +{ + gtk_move_beginning_of_line, /* a */ + gtk_move_backward_character, /* b */ + NULL, /* c */ + gtk_delete_forward_character, /* d */ + gtk_move_end_of_line, /* e */ + gtk_move_forward_character, /* f */ + NULL, /* g */ + NULL, /* h */ + NULL, /* i */ + NULL, /* j */ + gtk_delete_to_line_end, /* k */ + NULL, /* l */ + NULL, /* m */ + NULL, /* n */ + NULL, /* o */ + NULL, /* p */ + NULL, /* q */ + NULL, /* r */ + NULL, /* s */ + NULL, /* t */ + gtk_delete_line, /* u */ + NULL, /* v */ + gtk_delete_backward_word, /* w */ + NULL, /* x */ + NULL, /* y */ + NULL, /* z */ +}; + +static GtkTextFunction alt_keys[26] = +{ + NULL, /* a */ + gtk_move_backward_word, /* b */ + NULL, /* c */ + gtk_delete_forward_word, /* d */ + NULL, /* e */ + gtk_move_forward_word, /* f */ + NULL, /* g */ + NULL, /* h */ + NULL, /* i */ + NULL, /* j */ + NULL, /* k */ + NULL, /* l */ + NULL, /* m */ + NULL, /* n */ + NULL, /* o */ + NULL, /* p */ + NULL, /* q */ + NULL, /* r */ + NULL, /* s */ + NULL, /* t */ + NULL, /* u */ + NULL, /* v */ + NULL, /* w */ + NULL, /* x */ + NULL, /* y */ + NULL, /* z */ +}; + + +guint +gtk_entry_get_type () +{ + static guint entry_type = 0; + + if (!entry_type) + { + GtkTypeInfo entry_info = + { + "GtkEntry", + sizeof (GtkEntry), + sizeof (GtkEntryClass), + (GtkClassInitFunc) gtk_entry_class_init, + (GtkObjectInitFunc) gtk_entry_init, + (GtkArgFunc) NULL, + }; + + entry_type = gtk_type_unique (gtk_widget_get_type (), &entry_info); + } + + return entry_type; +} + +static void +gtk_entry_class_init (GtkEntryClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + entry_signals[INSERT_TEXT] = + gtk_signal_new ("insert_text", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, insert_text), + gtk_entry_marshal_signal_1, + GTK_TYPE_NONE, 3, + GTK_TYPE_STRING, GTK_TYPE_INT, + GTK_TYPE_POINTER); + entry_signals[DELETE_TEXT] = + gtk_signal_new ("delete_text", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, delete_text), + gtk_entry_marshal_signal_2, + GTK_TYPE_NONE, 2, + GTK_TYPE_INT, GTK_TYPE_INT); + entry_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + entry_signals[SET_TEXT] = + gtk_signal_new ("set_text", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, set_text), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + entry_signals[ACTIVATE] = + gtk_signal_new ("activate", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkEntryClass, activate), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, entry_signals, LAST_SIGNAL); + + object_class->destroy = gtk_entry_destroy; + + widget_class->realize = gtk_entry_realize; + widget_class->unrealize = gtk_entry_unrealize; + widget_class->draw_focus = gtk_entry_draw_focus; + widget_class->size_request = gtk_entry_size_request; + widget_class->size_allocate = gtk_entry_size_allocate; + widget_class->draw = gtk_entry_draw; + widget_class->expose_event = gtk_entry_expose; + widget_class->button_press_event = gtk_entry_button_press; + widget_class->button_release_event = gtk_entry_button_release; + widget_class->motion_notify_event = gtk_entry_motion_notify; + widget_class->key_press_event = gtk_entry_key_press; + widget_class->focus_in_event = gtk_entry_focus_in; + widget_class->focus_out_event = gtk_entry_focus_out; + widget_class->selection_clear_event = gtk_entry_selection_clear; + widget_class->selection_received = gtk_entry_selection_received; + + class->insert_text = gtk_real_entry_insert_text; + class->delete_text = gtk_real_entry_delete_text; + class->changed = gtk_entry_adjust_scroll; + class->set_text = NULL; /* user defined handling */ + class->activate = NULL; /* user defined handling */ +} + +static void +gtk_entry_init (GtkEntry *entry) +{ + static GdkAtom text_atom = GDK_NONE; + + GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS); + + entry->text_area = NULL; + entry->text = NULL; + entry->text_size = 0; + entry->text_length = 0; + entry->current_pos = 0; + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; + entry->scroll_offset = 0; + entry->have_selection = FALSE; + entry->timer = 0; + entry->visible = 1; + + gtk_selection_add_handler (GTK_WIDGET(entry), GDK_SELECTION_PRIMARY, + GDK_TARGET_STRING, gtk_entry_selection_handler, + NULL, NULL); + + if (!text_atom) + text_atom = gdk_atom_intern ("TEXT", FALSE); + + gtk_selection_add_handler (GTK_WIDGET(entry), GDK_SELECTION_PRIMARY, + text_atom, + gtk_entry_selection_handler, + NULL, NULL); +} + +GtkWidget* +gtk_entry_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_entry_get_type ())); +} + +void +gtk_entry_set_text (GtkEntry *entry, + const gchar *text) +{ + gint tmp_pos; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + gtk_real_entry_delete_text (entry, 0, entry->text_length); + + tmp_pos = 0; + gtk_entry_insert_text (entry, text, strlen (text), &tmp_pos); + entry->current_pos = tmp_pos; + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; + + if (GTK_WIDGET_DRAWABLE (entry)) + gtk_entry_draw_text (entry); + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[SET_TEXT]); +} + +void +gtk_entry_append_text (GtkEntry *entry, + const gchar *text) +{ + gint tmp_pos; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + tmp_pos = entry->text_length; + gtk_entry_insert_text (entry, text, strlen (text), &tmp_pos); + entry->current_pos = tmp_pos; + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[SET_TEXT]); +} + +void +gtk_entry_prepend_text (GtkEntry *entry, + const gchar *text) +{ + gint tmp_pos; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + tmp_pos = 0; + gtk_entry_insert_text (entry, text, strlen (text), &tmp_pos); + entry->current_pos = tmp_pos; + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[SET_TEXT]); +} + +void +gtk_entry_set_position (GtkEntry *entry, + gint position) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if ((position == -1) || (position > entry->text_length)) + entry->current_pos = entry->text_length; + else + entry->current_pos = position; +} + +void +gtk_entry_set_visibility (GtkEntry *entry, + gint visible) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + entry->visible = visible; +} + +gchar* +gtk_entry_get_text (GtkEntry *entry) +{ + static char empty_str[2] = ""; + + g_return_val_if_fail (entry != NULL, NULL); + g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); + + if (!entry->text) + return empty_str; + return entry->text; +} + + +static void +gtk_entry_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkEntrySignal1 rfunc; + + rfunc = (GtkEntrySignal1) func; + + (* rfunc) (object, GTK_VALUE_STRING (args[0]), GTK_VALUE_INT (args[1]), + GTK_VALUE_POINTER (args[2]), func_data); +} + +static void +gtk_entry_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkEntrySignal2 rfunc; + + rfunc = (GtkEntrySignal2) func; + + (* rfunc) (object, GTK_VALUE_INT (args[0]), GTK_VALUE_INT (args[1]), + func_data); +} + +static void +gtk_entry_destroy (GtkObject *object) +{ + GtkEntry *entry; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_ENTRY (object)); + + entry = GTK_ENTRY (object); + + if (entry->have_selection) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); + + if (entry->timer) + gtk_timeout_remove (entry->timer); + + if (entry->text) + g_free (entry->text); + entry->text = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_entry_realize (GtkWidget *widget) +{ + GtkEntry *entry; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + entry = GTK_ENTRY (widget); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON3_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_KEY_PRESS_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, entry); + + attributes.x = widget->style->klass->xthickness + INNER_BORDER; + attributes.y = widget->style->klass->ythickness + INNER_BORDER; + attributes.width = widget->allocation.width - attributes.x * 2; + attributes.height = widget->allocation.height - attributes.y * 2; + + entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask); + gdk_window_set_user_data (entry->text_area, entry); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_background (widget->window, &widget->style->white); + gdk_window_set_background (entry->text_area, &widget->style->white); + + gdk_window_show (entry->text_area); +} + +static void +gtk_entry_unrealize (GtkWidget *widget) +{ + GtkEntry *entry; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED); + entry = GTK_ENTRY (widget); + + gtk_style_detach (widget->style); + + if (entry->text_area) + { + gdk_window_set_user_data (entry->text_area, NULL); + gdk_window_destroy (entry->text_area); + } + if (widget->window) + { + gdk_window_set_user_data (widget->window, NULL); + gdk_window_destroy (widget->window); + } + + entry->text_area = NULL; + widget->window = NULL; +} + +static void +gtk_entry_draw_focus (GtkWidget *widget) +{ + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + x = 0; + y = 0; + gdk_window_get_size (widget->window, &width, &height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + } + else + { + gdk_draw_rectangle (widget->window, widget->style->white_gc, FALSE, + x + 2, y + 2, width - 5, height - 5); + } + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + x, y, width, height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + gdk_window_get_size (widget->window, &width, &height); + gdk_draw_rectangle (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, width - 1, height - 1); + } + + gtk_entry_draw_cursor (GTK_ENTRY (widget)); + } +} + +static void +gtk_entry_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + g_return_if_fail (requisition != NULL); + + requisition->width = MIN_ENTRY_WIDTH + (widget->style->klass->xthickness + INNER_BORDER) * 2; + requisition->height = (widget->style->font->ascent + + widget->style->font->descent + + (widget->style->klass->ythickness + INNER_BORDER) * 2); +} + +static void +gtk_entry_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkEntry *entry; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + entry = GTK_ENTRY (widget); + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, + allocation->y + (allocation->height - widget->requisition.height) / 2, + allocation->width, widget->requisition.height); + gdk_window_move_resize (entry->text_area, + widget->style->klass->xthickness + INNER_BORDER, + widget->style->klass->ythickness + INNER_BORDER, + allocation->width - (widget->style->klass->xthickness + INNER_BORDER) * 2, + widget->requisition.height - (widget->style->klass->ythickness + INNER_BORDER) * 2); + + entry->scroll_offset = 0; + gtk_entry_adjust_scroll (entry); + } +} + +static void +gtk_entry_draw (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_widget_draw_focus (widget); + gtk_entry_draw_text (GTK_ENTRY (widget)); + } +} + +static gint +gtk_entry_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkEntry *entry; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + if (widget->window == event->window) + gtk_widget_draw_focus (widget); + else if (entry->text_area == event->window) + gtk_entry_draw_text (GTK_ENTRY (widget)); + + return FALSE; +} + +static gint +gtk_entry_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkEntry *entry; + gint tmp_pos; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + if (event->button == 1) + { + switch (event->type) + { + case GDK_BUTTON_PRESS: + gtk_grab_add (widget); + + tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + gtk_select_region (entry, tmp_pos, tmp_pos); + entry->current_pos = entry->selection_start_pos; + gtk_entry_queue_draw (entry); + break; + + case GDK_2BUTTON_PRESS: + gtk_select_word (entry); + gtk_entry_queue_draw (entry); + break; + + case GDK_3BUTTON_PRESS: + gtk_select_line (entry); + gtk_entry_queue_draw (entry); + break; + + default: + break; + } + } + else if (event->type == GDK_BUTTON_PRESS) + { + if (event->button == 2) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->current_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, + GDK_TARGET_STRING, event->time); + } + else + { + gtk_grab_add (widget); + + tmp_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + gtk_select_region (entry, tmp_pos, tmp_pos); + entry->have_selection = FALSE; + entry->current_pos = entry->selection_start_pos; + gtk_entry_queue_draw (entry); + } + } + + return FALSE; +} + +static gint +gtk_entry_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkEntry *entry; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->button == 1) + { + entry = GTK_ENTRY (widget); + gtk_grab_remove (widget); + + entry->have_selection = FALSE; + if (entry->selection_start_pos != entry->selection_end_pos) + { + if (gtk_selection_owner_set (widget, + GDK_SELECTION_PRIMARY, + event->time)) + { + entry->have_selection = TRUE; + gtk_entry_queue_draw (entry); + } + } + else + { + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); + } + } + else if (event->button == 3) + { + gtk_grab_remove (widget); + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); + } + + return FALSE; +} + +static gint +gtk_entry_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkEntry *entry; + gint x; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + x = event->x; + if (event->is_hint || (entry->text_area != event->window)) + gdk_window_get_pointer (entry->text_area, &x, NULL, NULL); + + entry->selection_end_pos = gtk_entry_position (entry, event->x + entry->scroll_offset); + entry->current_pos = entry->selection_end_pos; + gtk_entry_adjust_scroll (entry); + gtk_entry_queue_draw (entry); + + return FALSE; +} + +static gint +gtk_entry_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkEntry *entry; + gint return_val; + gint key; + gint tmp_pos; + gchar tmp; + gint extend_selection; + gint selection_pos; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + return_val = FALSE; + extend_selection = FALSE; + + if (entry->selection_start_pos == entry->selection_end_pos) + selection_pos = entry->current_pos; + else if (entry->selection_start_pos == entry->current_pos) + selection_pos = entry->selection_end_pos; + else + selection_pos = entry->selection_start_pos; + + switch (event->keyval) + { + case GDK_BackSpace: + return_val = TRUE; + if (entry->selection_start_pos != entry->selection_end_pos) + gtk_delete_selection (entry); + else if (event->state & GDK_CONTROL_MASK) + gtk_delete_backward_word (entry); + else + gtk_delete_backward_character (entry); + break; + case GDK_Clear: + return_val = TRUE; + gtk_delete_line (entry); + break; + case GDK_Insert: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + /* gtk_paste_clipboard(entry) -- NEEDS CLIPBOARD */ + } + else if (event->state & GDK_CONTROL_MASK) + { + /* gtk_copy_clipboard(entry) -- NEEDS CLIPBOARD */ + } + else + { + /* gtk_toggle_insert(entry) -- IMPLEMENT */ + } + break; + case GDK_Delete: + return_val = TRUE; + if (entry->selection_start_pos != entry->selection_end_pos) + gtk_delete_selection (entry); + else + { + if (event->state & GDK_CONTROL_MASK) + gtk_delete_line (entry); + else if (event->state & GDK_SHIFT_MASK) + /* gtk_cut_clipboard(entry) -- NEEDS CLIPBOARD */ ; + else + gtk_delete_forward_character (entry); + } + break; + case GDK_Home: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->selection_start_pos = entry->current_pos; + entry->current_pos = entry->selection_end_pos = 0; + } + else + gtk_move_beginning_of_line (entry); + break; + case GDK_End: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->selection_start_pos = entry->current_pos; + entry->current_pos = entry->selection_end_pos = entry->text_length; + } + else + gtk_move_end_of_line (entry); + break; + case GDK_Left: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->selection_start_pos = entry->selection_end_pos = entry->current_pos; + if (entry->selection_end_pos > 0) + entry->current_pos = --entry->selection_end_pos; + } + else + gtk_move_backward_character (entry); + break; + case GDK_Right: + return_val = TRUE; + if (event->state & GDK_SHIFT_MASK) + { + if (entry->selection_start_pos == entry->selection_end_pos) + entry->selection_start_pos = entry->selection_end_pos = entry->current_pos; + if (entry->selection_end_pos < entry->text_length) + entry->current_pos = ++entry->selection_end_pos; + } + else + gtk_move_forward_character (entry); + break; + case GDK_Return: + return_val = TRUE; + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[ACTIVATE]); + break; + default: + if ((event->keyval >= 0x20) && (event->keyval <= 0xFF)) + { + return_val = TRUE; + key = event->keyval; + + if (event->state & GDK_CONTROL_MASK) + { + if ((key >= 'A') && (key <= 'Z')) + key -= 'A' - 'a'; + + if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a']) + (* control_keys[key - 'a']) (entry); + } + else if (event->state & GDK_MOD1_MASK) + { + if ((key >= 'A') && (key <= 'Z')) + key -= 'A' - 'a'; + + if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a']) + (* alt_keys[key - 'a']) (entry); + } + else + { + tmp = (gchar) key; + gtk_delete_selection (entry); + + tmp_pos = entry->current_pos; + gtk_entry_insert_text (entry, &tmp, 1, &tmp_pos); + entry->current_pos = tmp_pos; + } + } + break; + } + + /* alex stuff */ + if (entry->selection_start_pos != entry->selection_end_pos) + { + if (gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time)) + { + entry->have_selection = TRUE; + gtk_entry_queue_draw (entry); + } + } + else + { + if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window) + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time); + } + /* end of alex stuff */ + + if (return_val) + { + gtk_entry_adjust_scroll (entry); + gtk_entry_queue_draw (entry); + } + + return return_val; +} + +static gint +gtk_entry_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_entry_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_entry_selection_clear (GtkWidget *widget, + GdkEventSelection *event) +{ + GtkEntry *entry; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + if (entry->have_selection) + { + entry->have_selection = FALSE; + gtk_entry_queue_draw (entry); + } + + return FALSE; +} + +static void +gtk_entry_selection_handler (GtkWidget *widget, + GtkSelectionData *selection_data, + gpointer data) +{ + GtkEntry *entry; + gint selection_start_pos; + gint selection_end_pos; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + entry = GTK_ENTRY (widget); + + selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); + selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); + + gtk_selection_data_set (selection_data, + GDK_SELECTION_TYPE_STRING, + 8*sizeof(gchar), + &entry->text[selection_start_pos], + selection_end_pos - selection_start_pos); +} + +static void +gtk_entry_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data) +{ + GtkEntry *entry; + gint reselect; + gint tmp_pos; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ENTRY (widget)); + + entry = GTK_ENTRY (widget); + + if (selection_data->length < 0) + return ; + + if (selection_data->target == GDK_TARGET_STRING) + { + reselect = FALSE; + if (entry->selection_start_pos != entry->selection_end_pos) + { + reselect = TRUE; + gtk_delete_selection (entry); + } + + tmp_pos = entry->current_pos; + + selection_data->data[selection_data->length] = 0; + gtk_entry_insert_text (entry, selection_data->data, + strlen (selection_data->data), &tmp_pos); + + if (reselect) + { + reselect = entry->have_selection; + gtk_select_region (entry, entry->current_pos, tmp_pos); + entry->have_selection = reselect; + } + + entry->current_pos = tmp_pos; + + gtk_entry_queue_draw (entry); + } +} + +static void +gtk_entry_draw_text (GtkEntry *entry) +{ + GtkWidget *widget; + GtkStateType selected_state; + gint selection_start_pos; + gint selection_end_pos; + gint selection_start_xoffset; + gint selection_end_xoffset; + gint width, height; + gint y; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (entry->timer) + { + gtk_timeout_remove (entry->timer); + entry->timer = 0; + } + + if (!entry->visible) + { + gtk_entry_draw_cursor (entry); + return; + } + + if (GTK_WIDGET_DRAWABLE (entry)) + { + widget = GTK_WIDGET (entry); + + gdk_window_clear (entry->text_area); + + if (entry->text) + { + gdk_window_get_size (entry->text_area, &width, &height); + y = (height - (widget->style->font->ascent + widget->style->font->descent)) / 2; + y += widget->style->font->ascent; + + if (entry->selection_start_pos != entry->selection_end_pos) + { + selected_state = GTK_STATE_SELECTED; + if (!entry->have_selection) + selected_state = GTK_STATE_ACTIVE; + + selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); + selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); + + selection_start_xoffset = gdk_text_width (widget->style->font, + entry->text, + selection_start_pos); + selection_end_xoffset = gdk_text_width (widget->style->font, + entry->text, + selection_end_pos); + + if (selection_start_pos > 0) + gdk_draw_text (entry->text_area, widget->style->font, + widget->style->fg_gc[GTK_STATE_NORMAL], + -entry->scroll_offset, y, + entry->text, selection_start_pos); + + gdk_draw_rectangle (entry->text_area, + widget->style->bg_gc[selected_state], + TRUE, + -entry->scroll_offset + selection_start_xoffset, + 0, + selection_end_xoffset - selection_start_xoffset, + -1); + + gdk_draw_text (entry->text_area, widget->style->font, + widget->style->fg_gc[selected_state], + -entry->scroll_offset + selection_start_xoffset, y, + entry->text + selection_start_pos, + selection_end_pos - selection_start_pos); + + if (selection_end_pos < entry->text_length) + gdk_draw_string (entry->text_area, widget->style->font, + widget->style->fg_gc[GTK_STATE_NORMAL], + -entry->scroll_offset + selection_end_xoffset, y, + entry->text + selection_end_pos); + } + else + { + GdkGCValues values; + + gdk_gc_get_values (widget->style->fg_gc[GTK_STATE_NORMAL], &values); + gdk_draw_string (entry->text_area, widget->style->font, + widget->style->fg_gc[GTK_STATE_NORMAL], + -entry->scroll_offset, y, + entry->text); + } + } + + gtk_entry_draw_cursor (entry); + } +} + +static void +gtk_entry_draw_cursor (GtkEntry *entry) +{ + GtkWidget *widget; + GdkGC *gc; + gint xoffset; + gint text_area_height; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (GTK_WIDGET_DRAWABLE (entry)) + { + widget = GTK_WIDGET (entry); + + if (entry->current_pos > 0 && entry->visible) + xoffset = gdk_text_width (widget->style->font, entry->text, entry->current_pos); + else + xoffset = 0; + xoffset -= entry->scroll_offset; + + if (GTK_WIDGET_HAS_FOCUS (widget) && + (entry->selection_start_pos == entry->selection_end_pos)) + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + else + gc = widget->style->white_gc; + + gdk_window_get_size (entry->text_area, &text_area_height, NULL); + gdk_draw_line (entry->text_area, gc, xoffset, 0, xoffset, text_area_height); + } +} + +static void +gtk_entry_queue_draw (GtkEntry *entry) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (!entry->timer) + entry->timer = gtk_timeout_add (DRAW_TIMEOUT, gtk_entry_timer, entry); +} + +static gint +gtk_entry_timer (gpointer data) +{ + GtkEntry *entry; + + g_return_val_if_fail (data != NULL, FALSE); + + entry = GTK_ENTRY (data); + entry->timer = 0; + gtk_entry_draw_text (entry); + + return FALSE; +} + +static gint +gtk_entry_position (GtkEntry *entry, + gint x) +{ + gint return_val; + gint char_width; + gint sum; + gint i; + + g_return_val_if_fail (entry != NULL, 0); + g_return_val_if_fail (GTK_IS_ENTRY (entry), 0); + + i = 0; + sum = 0; + + if (x > sum) + { + for (; i < entry->text_length; i++) + { + char_width = gdk_char_width (GTK_WIDGET (entry)->style->font, entry->text[i]); + + if (x < (sum + char_width / 2)) + break; + sum += char_width; + } + } + + return_val = i; + + return return_val; +} + +void +gtk_entry_adjust_scroll (GtkEntry *entry) +{ + gint xoffset; + gint text_area_width; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (!entry->text_area) + return; + + gdk_window_get_size (entry->text_area, &text_area_width, NULL); + + if (entry->current_pos > 0) + xoffset = gdk_text_width (GTK_WIDGET (entry)->style->font, entry->text, entry->current_pos); + else + xoffset = 0; + xoffset -= entry->scroll_offset; + + if (xoffset < 0) + entry->scroll_offset += xoffset; + else if (xoffset > text_area_width) + entry->scroll_offset += (xoffset - text_area_width) + 1; +} + +static void +gtk_entry_grow_text (GtkEntry *entry) +{ + gint previous_size; + gint i; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + previous_size = entry->text_size; + if (!entry->text_size) + entry->text_size = 128; + else + entry->text_size *= 2; + entry->text = g_realloc (entry->text, entry->text_size); + + for (i = previous_size; i < entry->text_size; i++) + entry->text[i] = '\0'; +} + +static void +gtk_entry_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position) +{ + gchar buf[64]; + gchar *text; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if (new_text_length <= 64) + text = buf; + else + text = g_new (gchar, new_text_length); + + strncpy (text, new_text, new_text_length); + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[INSERT_TEXT], + text, new_text_length, position); + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[CHANGED]); + + if (new_text_length > 64) + g_free (text); +} + +static void +gtk_entry_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[DELETE_TEXT], + start_pos, end_pos); + gtk_signal_emit (GTK_OBJECT (entry), entry_signals[CHANGED]); +} + +static void +gtk_real_entry_insert_text (GtkEntry *entry, + const gchar *new_text, + gint new_text_length, + gint *position) +{ + gchar *text; + gint start_pos; + gint end_pos; + gint last_pos; + gint i; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + start_pos = *position; + end_pos = start_pos + new_text_length; + last_pos = new_text_length + entry->text_length; + + while (last_pos >= entry->text_size) + gtk_entry_grow_text (entry); + + text = entry->text; + for (i = last_pos - 1; i >= end_pos; i--) + text[i] = text[i- (end_pos - start_pos)]; + for (i = start_pos; i < end_pos; i++) + text[i] = new_text[i - start_pos]; + + entry->text_length += new_text_length; + *position = end_pos; +} + +static void +gtk_real_entry_delete_text (GtkEntry *entry, + gint start_pos, + gint end_pos) +{ + gchar *text; + gint deletion_length; + gint i; + + g_return_if_fail (entry != NULL); + g_return_if_fail (GTK_IS_ENTRY (entry)); + + if ((start_pos < end_pos) && + (start_pos >= 0) && + (end_pos <= entry->text_length)) + { + text = entry->text; + deletion_length = end_pos - start_pos; + + for (i = end_pos; i < entry->text_length; i++) + text[i - deletion_length] = text[i]; + + for (i = entry->text_length - deletion_length; i < entry->text_length; i++) + text[i] = '\0'; + + entry->text_length -= deletion_length; + entry->current_pos = start_pos; + } +} + + +static void +gtk_move_forward_character (GtkEntry *entry) +{ + entry->current_pos += 1; + if (entry->current_pos > entry->text_length) + entry->current_pos = entry->text_length; + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_backward_character (GtkEntry *entry) +{ + entry->current_pos -= 1; + if (entry->current_pos < 0) + entry->current_pos = 0; + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_forward_word (GtkEntry *entry) +{ + gchar *text; + gint i; + + if (entry->text) + { + text = entry->text; + i = entry->current_pos; + + if (!((text[i] == '_') || isalnum (text[i]))) + for (; i < entry->text_length; i++) + if ((text[i] == '_') || isalnum (text[i])) + break; + + for (; i < entry->text_length; i++) + if (!((text[i] == '_') || isalnum (text[i]))) + break; + + entry->current_pos = i; + if (entry->current_pos > entry->text_length) + entry->current_pos = entry->text_length; + } + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_backward_word (GtkEntry *entry) +{ + gchar *text; + gint i; + + if (entry->text) + { + text = entry->text; + i = entry->current_pos - 1; + if (i < 0) /* Per */ + { + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; + return; + } + + if (!((text[i] == '_') || isalnum (text[i]))) + for (; i >= 0; i--) + if ((text[i] == '_') || isalnum (text[i])) + break; + + for (; i >= 0; i--) + if (!((text[i] == '_') || isalnum (text[i]))) + { + i += 1; + break; + } + + entry->current_pos = i; + if (entry->current_pos < 0) + entry->current_pos = 0; + + if (text[entry->current_pos] == ' ') + entry->current_pos += 1; + } + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_beginning_of_line (GtkEntry *entry) +{ + entry->current_pos = 0; + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_move_end_of_line (GtkEntry *entry) +{ + entry->current_pos = entry->text_length; + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_forward_character (GtkEntry *entry) +{ + gint old_pos; + + old_pos = entry->current_pos; + gtk_move_forward_character (entry); + gtk_entry_delete_text (entry, old_pos, entry->current_pos); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_backward_character (GtkEntry *entry) +{ + gint old_pos; + + old_pos = entry->current_pos; + gtk_move_backward_character (entry); + gtk_entry_delete_text (entry, entry->current_pos, old_pos); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_forward_word (GtkEntry *entry) +{ + gint old_pos; + + old_pos = entry->current_pos; + gtk_move_forward_word (entry); + gtk_entry_delete_text (entry, old_pos, entry->current_pos); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_backward_word (GtkEntry *entry) +{ + gint old_pos; + + old_pos = entry->current_pos; + gtk_move_backward_word (entry); + gtk_entry_delete_text (entry, entry->current_pos, old_pos); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_line (GtkEntry *entry) +{ + gtk_entry_delete_text (entry, 0, entry->text_length); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_to_line_end (GtkEntry *entry) +{ + gtk_entry_delete_text (entry, entry->current_pos, entry->text_length); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; +} + +static void +gtk_delete_selection (GtkEntry *entry) +{ + if (entry->selection_start_pos != entry->selection_end_pos) + gtk_entry_delete_text (entry, + MIN (entry->selection_start_pos, entry->selection_end_pos), + MAX (entry->selection_start_pos, entry->selection_end_pos)); + + entry->selection_start_pos = 0; + entry->selection_end_pos = 0; + + if (entry->have_selection) + { + entry->have_selection = FALSE; + gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); + } +} + +static void +gtk_select_word (GtkEntry *entry) +{ + gint start_pos; + gint end_pos; + + gtk_move_backward_word (entry); + start_pos = entry->current_pos; + + gtk_move_forward_word (entry); + end_pos = entry->current_pos; + + gtk_select_region (entry, start_pos, end_pos); +} + +static void +gtk_select_line (GtkEntry *entry) +{ + gtk_select_region (entry, 0, entry->text_length); + entry->current_pos = entry->selection_end_pos; +} + +static void +gtk_select_region (GtkEntry *entry, + gint start, + gint end) +{ + entry->have_selection = TRUE; + entry->selection_start_pos = start; + entry->selection_end_pos = end; +} diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h new file mode 100644 index 000000000..c24bee6c8 --- /dev/null +++ b/gtk/gtkentry.h @@ -0,0 +1,94 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_ENTRY_H__ +#define __GTK_ENTRY_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ENTRY(obj) GTK_CHECK_CAST (obj, gtk_entry_get_type (), GtkEntry) +#define GTK_ENTRY_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_entry_get_type (), GtkEntryClass) +#define GTK_IS_ENTRY(obj) GTK_CHECK_TYPE (obj, gtk_entry_get_type ()) + + +typedef struct _GtkEntry GtkEntry; +typedef struct _GtkEntryClass GtkEntryClass; + +struct _GtkEntry +{ + GtkWidget widget; + + GdkWindow *text_area; + gchar *text; + + guint16 text_size; + guint16 text_length; + gint16 current_pos; + gint16 selection_start_pos; + gint16 selection_end_pos; + gint16 scroll_offset; + guint have_selection : 1; + guint visible : 1; + guint32 timer; +}; + +struct _GtkEntryClass +{ + GtkWidgetClass parent_class; + + void (* insert_text) (GtkEntry *entry, + const gchar *text, + gint length, + gint *position); + void (* delete_text) (GtkEntry *entry, + gint start_pos, + gint end_pos); + void (* changed) (GtkEntry *entry); + void (* set_text) (GtkEntry *entry); + void (* activate) (GtkEntry *entry); +}; + + +guint gtk_entry_get_type (void); +GtkWidget* gtk_entry_new (void); +void gtk_entry_set_text (GtkEntry *entry, + const gchar *text); +void gtk_entry_append_text (GtkEntry *entry, + const gchar *text); +void gtk_entry_prepend_text (GtkEntry *entry, + const gchar *text); +void gtk_entry_set_position (GtkEntry *entry, + gint position); +gchar* gtk_entry_get_text (GtkEntry *entry); +void gtk_entry_set_visibility (GtkEntry *entry, + gint visible); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ENTRY_H__ */ diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h new file mode 100644 index 000000000..b82d5e497 --- /dev/null +++ b/gtk/gtkenums.h @@ -0,0 +1,191 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_ENUMS_H__ +#define __GTK_ENUMS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Widget states */ +typedef enum +{ + GTK_STATE_NORMAL, + GTK_STATE_ACTIVE, + GTK_STATE_PRELIGHT, + GTK_STATE_SELECTED, + GTK_STATE_INSENSITIVE +} GtkStateType; + +/* Window types */ +typedef enum +{ + GTK_WINDOW_TOPLEVEL, + GTK_WINDOW_DIALOG, + GTK_WINDOW_POPUP +} GtkWindowType; + +/* Focus movement types */ +typedef enum +{ + GTK_DIR_TAB_FORWARD, + GTK_DIR_TAB_BACKWARD, + GTK_DIR_UP, + GTK_DIR_DOWN, + GTK_DIR_LEFT, + GTK_DIR_RIGHT +} GtkDirectionType; + +/* Shadow types */ +typedef enum +{ + GTK_SHADOW_NONE, + GTK_SHADOW_IN, + GTK_SHADOW_OUT, + GTK_SHADOW_ETCHED_IN, + GTK_SHADOW_ETCHED_OUT +} GtkShadowType; + +/* Arrow types */ +typedef enum +{ + GTK_ARROW_UP, + GTK_ARROW_DOWN, + GTK_ARROW_LEFT, + GTK_ARROW_RIGHT +} GtkArrowType; + +/* Packing types (for boxes) */ +typedef enum +{ + GTK_PACK_START, + GTK_PACK_END +} GtkPackType; + +/* Scrollbar policy types (for scrolled windows) */ +typedef enum +{ + GTK_POLICY_ALWAYS, + GTK_POLICY_AUTOMATIC +} GtkPolicyType; + +/* Data update types (for ranges) */ +typedef enum +{ + GTK_UPDATE_CONTINUOUS, + GTK_UPDATE_DISCONTINUOUS, + GTK_UPDATE_DELAYED +} GtkUpdateType; + +/* Attach options (for tables) */ +typedef enum +{ + GTK_EXPAND = 1 << 0, + GTK_SHRINK = 1 << 1, + GTK_FILL = 1 << 2 +} GtkAttachOptions; + +typedef enum +{ + GTK_RUN_FIRST = 0x1, + GTK_RUN_LAST = 0x2, + GTK_RUN_BOTH = 0x3, + GTK_RUN_MASK = 0xF, + GTK_RUN_NO_RECURSE = 0x10 +} GtkSignalRunType; + +typedef enum +{ + GTK_WIN_POS_NONE, + GTK_WIN_POS_CENTER, + GTK_WIN_POS_MOUSE +} GtkWindowPosition; + +typedef enum +{ + GTK_DIRECTION_LEFT, + GTK_DIRECTION_RIGHT +} GtkSubmenuDirection; + +typedef enum +{ + GTK_TOP_BOTTOM, + GTK_LEFT_RIGHT +} GtkSubmenuPlacement; + +typedef enum +{ + GTK_MENU_FACTORY_MENU, + GTK_MENU_FACTORY_MENU_BAR, + GTK_MENU_FACTORY_OPTION_MENU +} GtkMenuFactoryType; + +typedef enum +{ + GTK_PIXELS, + GTK_INCHES, + GTK_CENTIMETERS +} GtkMetricType; + +typedef enum +{ + GTK_SCROLL_NONE, + GTK_SCROLL_STEP_BACKWARD, + GTK_SCROLL_STEP_FORWARD, + GTK_SCROLL_PAGE_BACKWARD, + GTK_SCROLL_PAGE_FORWARD +} GtkScrollType; + +typedef enum +{ + GTK_TROUGH_NONE, + GTK_TROUGH_START, + GTK_TROUGH_END +} GtkTroughType; + +typedef enum +{ + GTK_POS_LEFT, + GTK_POS_RIGHT, + GTK_POS_TOP, + GTK_POS_BOTTOM +} GtkPositionType; + +typedef enum +{ + GTK_PREVIEW_COLOR, + GTK_PREVIEW_GRAYSCALE +} GtkPreviewType; + +/* justification for label and maybe other widgets (text?) */ +typedef enum +{ + GTK_JUSTIFY_LEFT, + GTK_JUSTIFY_RIGHT, + GTK_JUSTIFY_CENTER, + GTK_JUSTIFY_FILL +} GtkJustification; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ENUMS_H__ */ diff --git a/gtk/gtkeventbox.c b/gtk/gtkeventbox.c new file mode 100644 index 000000000..44a0d7a9a --- /dev/null +++ b/gtk/gtkeventbox.c @@ -0,0 +1,226 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtksignal.h" +#include "gtkeventbox.h" + + +static void gtk_event_box_class_init (GtkEventBoxClass *klass); +static void gtk_event_box_init (GtkEventBox *event_box); +static void gtk_event_box_realize (GtkWidget *widget); +static void gtk_event_box_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_event_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_event_box_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_event_box_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_event_box_get_type () +{ + static guint event_box_type = 0; + + if (!event_box_type) + { + GtkTypeInfo event_box_info = + { + "GtkEventBox", + sizeof (GtkEventBox), + sizeof (GtkEventBoxClass), + (GtkClassInitFunc) gtk_event_box_class_init, + (GtkObjectInitFunc) gtk_event_box_init, + (GtkArgFunc) NULL, + }; + + event_box_type = gtk_type_unique (gtk_bin_get_type (), &event_box_info); + } + + return event_box_type; +} + +static void +gtk_event_box_class_init (GtkEventBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_event_box_realize; + widget_class->size_request = gtk_event_box_size_request; + widget_class->size_allocate = gtk_event_box_size_allocate; + widget_class->draw = gtk_event_box_draw; + widget_class->expose_event = gtk_event_box_expose; +} + +static void +gtk_event_box_init (GtkEventBox *event_box) +{ + GTK_WIDGET_UNSET_FLAGS (event_box, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (event_box, GTK_BASIC); +} + +GtkWidget* +gtk_event_box_new () +{ + return GTK_WIDGET ( gtk_type_new (gtk_event_box_get_type ())); +} + +static void +gtk_event_box_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EVENT_BOX (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) + | GDK_BUTTON_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_EXPOSURE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_event_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EVENT_BOX (widget)); + g_return_if_fail (requisition != NULL); + + bin = GTK_BIN (widget); + + requisition->width = GTK_CONTAINER (widget)->border_width * 2; + requisition->height = GTK_CONTAINER (widget)->border_width * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += bin->child->requisition.width; + requisition->height += bin->child->requisition.height; + } +} + +static void +gtk_event_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EVENT_BOX (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + bin = GTK_BIN (widget); + + child_allocation.x = 0; + child_allocation.y = 0; + child_allocation.width = allocation->width - GTK_CONTAINER (widget)->border_width * 2; + child_allocation.height = allocation->height - GTK_CONTAINER (widget)->border_width * 2; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x + GTK_CONTAINER (widget)->border_width, + allocation->y + GTK_CONTAINER (widget)->border_width, + child_allocation.width, + child_allocation.height); + } + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} + +static void +gtk_event_box_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_EVENT_BOX (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + if (bin->child) + { + if (gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } + } +} + +static gint +gtk_event_box_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_EVENT_BOX (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + diff --git a/gtk/gtkeventbox.h b/gtk/gtkeventbox.h new file mode 100644 index 000000000..d90213dee --- /dev/null +++ b/gtk/gtkeventbox.h @@ -0,0 +1,57 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_EVENT_BOX_H__ +#define __GTK_EVENT_BOX_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_EVENT_BOX(obj) GTK_CHECK_CAST (obj, gtk_event_box_get_type (), GtkEventBox) +#define GTK_EVENT_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_event_box_get_type (), GtkEventBoxClass) +#define GTK_IS_EVENT_BOX(obj) GTK_CHECK_TYPE (obj, gtk_event_box_get_type ()) + + +typedef struct _GtkEventBox GtkEventBox; +typedef struct _GtkEventBoxClass GtkEventBoxClass; + +struct _GtkEventBox +{ + GtkBin bin; +}; + +struct _GtkEventBoxClass +{ + GtkBinClass parent_class; +}; + +guint gtk_event_box_get_type (void); +GtkWidget* gtk_event_box_new (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_EVENT_BOX_H__ */ diff --git a/gtk/gtkfilesel.c b/gtk/gtkfilesel.c new file mode 100644 index 000000000..77f83a87a --- /dev/null +++ b/gtk/gtkfilesel.c @@ -0,0 +1,2161 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fnmatch.h" + +#include "gdk/gdkkeysyms.h" +#include "gtkbutton.h" +#include "gtkentry.h" +#include "gtkfilesel.h" +#include "gtkhbox.h" +#include "gtklabel.h" +#include "gtklist.h" +#include "gtklistitem.h" +#include "gtkmain.h" +#include "gtkscrolledwindow.h" +#include "gtksignal.h" +#include "gtkvbox.h" + + +#define DIR_LIST_WIDTH 160 +#define DIR_LIST_HEIGHT 175 +#define FILE_LIST_WIDTH 160 +#define FILE_LIST_HEIGHT 175 + + +typedef struct _CompletionState CompletionState; +typedef struct _CompletionDir CompletionDir; +typedef struct _CompletionDirSent CompletionDirSent; +typedef struct _CompletionDirEntry CompletionDirEntry; +typedef struct _CompletionUserDir CompletionUserDir; +typedef struct _PossibleCompletion PossibleCompletion; + +/* Non-external file completion decls and structures */ + +/* A contant telling PRCS how many directories to cache. Its actually + * kept in a list, so the geometry isn't important. */ +#define CMPL_DIRECTORY_CACHE_SIZE 10 + +/* A constant used to determine whether a substring was an exact + * match by first_diff_index() + */ +#define PATTERN_MATCH -1 +/* The arguments used by all fnmatch() calls below + */ +#define FNMATCH_FLAGS (FNM_PATHNAME | FNM_PERIOD) + +#define CMPL_ERRNO_TOO_LONG ((1<<16)-1) + +/* This structure contains all the useful information about a directory + * for the purposes of filename completion. These structures are cached + * in the CompletionState struct. CompletionDir's are reference counted. + */ +struct _CompletionDirSent +{ + ino_t inode; + time_t mtime; + + gint entry_count; + gchar *name_buffer; /* memory segment containing names of all entries */ + + struct _CompletionDirEntry *entries; +}; + +struct _CompletionDir +{ + CompletionDirSent *sent; + + gchar *fullname; + gint fullname_len; + + struct _CompletionDir *cmpl_parent; + gint cmpl_index; + gchar *cmpl_text; +}; + +/* This structure contains pairs of directory entry names with a flag saying + * whether or not they are a valid directory. NOTE: This information is used + * to provide the caller with information about whether to update its completions + * or try to open a file. Since directories are cached by the directory mtime, + * a symlink which points to an invalid file (which will not be a directory), + * will not be reevaluated if that file is created, unless the containing + * directory is touched. I consider this case to be worth ignoring (josh). + */ +struct _CompletionDirEntry +{ + gint is_dir; + gchar *entry_name; +}; + +struct _CompletionUserDir +{ + gchar *login; + gchar *homedir; +}; + +struct _PossibleCompletion +{ + /* accessible fields, all are accessed externally by functions + * declared above + */ + gchar *text; + gint is_a_completion; + gint is_directory; + + /* Private fields + */ + gint text_alloc; +}; + +struct _CompletionState +{ + gint last_valid_char; + gchar *updated_text; + gint updated_text_len; + gint updated_text_alloc; + gint re_complete; + + gchar *user_dir_name_buffer; + gint user_directories_len; + gchar *user_home_dir; + + gchar *last_completion_text; + + gint user_completion_index; /* if >= 0, currently completing ~user */ + + struct _CompletionDir *completion_dir; /* directory completing from */ + struct _CompletionDir *active_completion_dir; + + struct _PossibleCompletion the_completion; + + struct _CompletionDir *reference_dir; /* initial directory */ + + GList* directory_storage; + GList* directory_sent_storage; + + struct _CompletionUserDir *user_directories; +}; + + +/* File completion functions which would be external, were they used + * outside of this file. + */ + +static CompletionState* cmpl_init_state (void); +static void cmpl_free_state (CompletionState *cmpl_state); +static gint cmpl_state_okay (CompletionState* cmpl_state); +static gchar* cmpl_strerror (gint); + +static PossibleCompletion* cmpl_completion_matches(gchar *text_to_complete, + gchar **remaining_text, + CompletionState *cmpl_state); + +/* Returns a name for consideration, possibly a completion, this name + * will be invalid after the next call to cmpl_next_completion. + */ +static char* cmpl_this_completion (PossibleCompletion*); + +/* True if this completion matches the given text. Otherwise, this + * output can be used to have a list of non-completions. + */ +static gint cmpl_is_a_completion (PossibleCompletion*); + +/* True if the completion is a directory + */ +static gint cmpl_is_directory (PossibleCompletion*); + +/* Obtains the next completion, or NULL + */ +static PossibleCompletion* cmpl_next_completion (CompletionState*); + +/* Updating completions: the return value of cmpl_updated_text() will + * be text_to_complete completed as much as possible after the most + * recent call to cmpl_completion_matches. For the present + * application, this is the suggested replacement for the user's input + * string. You must CALL THIS AFTER ALL cmpl_text_completions have + * been received. + */ +static gchar* cmpl_updated_text (CompletionState* cmpl_state); + +/* After updating, to see if the completion was a directory, call + * this. If it was, you should consider re-calling completion_matches. + */ +static gint cmpl_updated_dir (CompletionState* cmpl_state); + +/* Current location: if using file completion, return the current + * directory, from which file completion begins. More specifically, + * the cwd concatenated with all exact completions up to the last + * directory delimiter('/'). + */ +static gchar* cmpl_reference_position (CompletionState* cmpl_state); + +/* backing up: if cmpl_completion_matches returns NULL, you may query + * the index of the last completable character into cmpl_updated_text. + */ +static gint cmpl_last_valid_char (CompletionState* cmpl_state); + +/* When the user selects a non-directory, call cmpl_completion_fullname + * to get the full name of the selected file. + */ +static gchar* cmpl_completion_fullname (gchar*, CompletionState* cmpl_state); + + +/* Directory operations. */ +static CompletionDir* open_ref_dir (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static CompletionDir* open_dir (gchar* dir_name, + CompletionState* cmpl_state); +static CompletionDir* open_user_dir (gchar* text_to_complete, + CompletionState *cmpl_state); +static CompletionDir* open_relative_dir (gchar* dir_name, CompletionDir* dir, + CompletionState *cmpl_state); +static CompletionDirSent* open_new_dir (gchar* dir_name, struct stat* sbuf); +static gint correct_dir_fullname (CompletionDir* cmpl_dir); +static gint correct_parent (CompletionDir* cmpl_dir, + struct stat *sbuf); +static gchar* find_parent_dir_fullname (gchar* dirname); +static CompletionDir* attach_dir (CompletionDirSent* sent, + gchar* dir_name, + CompletionState *cmpl_state); +static void free_dir_sent (CompletionDirSent* sent); +static void free_dir (CompletionDir *dir); +static void prune_memory_usage(CompletionState *cmpl_state); + +/* Completion operations */ +static PossibleCompletion* attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state); +static PossibleCompletion* attempt_file_completion(CompletionState *cmpl_state); +static CompletionDir* find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state); +static PossibleCompletion* append_completion_text(gchar* text, + CompletionState* cmpl_state); +static gint get_pwdb(CompletionState* cmpl_state); +static gint first_diff_index(gchar* pat, gchar* text); +static gint compare_user_dir(const void* a, const void* b); +static gint compare_cmpl_dir(const void* a, const void* b); +static void update_cmpl(PossibleCompletion* poss, + CompletionState* cmpl_state); + +static void gtk_file_selection_class_init (GtkFileSelectionClass *klass); +static void gtk_file_selection_init (GtkFileSelection *filesel); +static void gtk_file_selection_destroy (GtkObject *object); +static gint gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data); +static gint gtk_file_selection_file_button (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); +static gint gtk_file_selection_dir_button (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); +static void gtk_file_selection_file_list_changed (GtkList *gtklist, + gpointer func_data); +static void gtk_file_selection_dir_list_changed (GtkList *gtklist, + gpointer func_data); +static void gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete); +static void gtk_file_selection_abort (GtkFileSelection *fs); +static void gtk_file_selection_free_filename (GtkWidget *widget, + gpointer client_data); + + +static GtkWindowClass *parent_class = NULL; + +static gchar *list_changed_key = "_gtk_selection_changed_handler_key"; + +/* Saves errno when something cmpl does fails. */ +static gint cmpl_errno; + + +guint +gtk_file_selection_get_type () +{ + static guint file_selection_type = 0; + + if (!file_selection_type) + { + GtkTypeInfo filesel_info = + { + "GtkFileSelection", + sizeof (GtkFileSelection), + sizeof (GtkFileSelectionClass), + (GtkClassInitFunc) gtk_file_selection_class_init, + (GtkObjectInitFunc) gtk_file_selection_init, + (GtkArgFunc) NULL, + }; + + file_selection_type = gtk_type_unique (gtk_window_get_type (), &filesel_info); + } + + return file_selection_type; +} + +static void +gtk_file_selection_class_init (GtkFileSelectionClass *class) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) class; + + parent_class = gtk_type_class (gtk_window_get_type ()); + + object_class->destroy = gtk_file_selection_destroy; +} + +static void +gtk_file_selection_init (GtkFileSelection *filesel) +{ + GtkWidget *dir_vbox; + GtkWidget *file_vbox; + GtkWidget *entry_vbox; + GtkWidget *listbox; + GtkWidget *label; + GtkWidget *list_hbox; + GtkWidget *action_area; + gint key; + + filesel->cmpl_state = cmpl_init_state (); + + /* The dialog-sized vertical box */ + filesel->main_vbox = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (filesel), 10); + gtk_container_add (GTK_CONTAINER (filesel), filesel->main_vbox); + gtk_widget_show (filesel->main_vbox); + + /* The horizontal box containing the directory and file listboxes */ + list_hbox = gtk_hbox_new (TRUE, 5); + gtk_box_pack_start (GTK_BOX (filesel->main_vbox), list_hbox, TRUE, TRUE, 0); + gtk_widget_show (list_hbox); + + + /* The directories listbox */ + dir_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (list_hbox), dir_vbox, TRUE, TRUE, 0); + gtk_widget_show (dir_vbox); + + label = gtk_label_new ("Directories"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (dir_vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + listbox = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (listbox), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + gtk_box_pack_start (GTK_BOX (dir_vbox), listbox, TRUE, TRUE, 0); + gtk_widget_set_usize (listbox, DIR_LIST_WIDTH, DIR_LIST_HEIGHT); + gtk_widget_show (listbox); + + filesel->dir_list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (filesel->dir_list), GTK_SELECTION_BROWSE); + gtk_signal_connect (GTK_OBJECT (filesel->dir_list), "button_press_event", + (GtkSignalFunc) gtk_file_selection_dir_button, filesel); + key = gtk_signal_connect (GTK_OBJECT (filesel->dir_list), + "selection_changed", + (GtkSignalFunc) gtk_file_selection_dir_list_changed, + filesel); + gtk_object_set_data (GTK_OBJECT (filesel->dir_list), list_changed_key, (gpointer) key); + gtk_container_add (GTK_CONTAINER (listbox), filesel->dir_list); + gtk_widget_show (filesel->dir_list); + + + /* The files listbox */ + file_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (list_hbox), file_vbox, TRUE, TRUE, 0); + gtk_widget_show (file_vbox); + + label = gtk_label_new ("Files"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (file_vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + listbox = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (listbox), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_ALWAYS); + gtk_box_pack_start (GTK_BOX (file_vbox), listbox, TRUE, TRUE, 0); + gtk_widget_set_usize (listbox, FILE_LIST_WIDTH, FILE_LIST_HEIGHT); + gtk_widget_show (listbox); + + filesel->file_list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (filesel->file_list), GTK_SELECTION_BROWSE); + gtk_signal_connect (GTK_OBJECT (filesel->file_list), "button_press_event", + (GtkSignalFunc) gtk_file_selection_file_button, filesel); + key = gtk_signal_connect (GTK_OBJECT (filesel->file_list), + "selection_changed", + (GtkSignalFunc) gtk_file_selection_file_list_changed, + filesel); + gtk_object_set_data (GTK_OBJECT (filesel->file_list), list_changed_key, (gpointer) key); + gtk_container_add (GTK_CONTAINER (listbox), filesel->file_list); + gtk_widget_show (filesel->file_list); + + + /* The action area */ + action_area = gtk_hbox_new (TRUE, 10); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), action_area, FALSE, FALSE, 0); + gtk_widget_show (action_area); + + /* The OK button */ + filesel->ok_button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (filesel->ok_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), filesel->ok_button, TRUE, TRUE, 0); + gtk_widget_grab_default (filesel->ok_button); + gtk_widget_show (filesel->ok_button); + + /* The Cancel button */ + filesel->cancel_button = gtk_button_new_with_label ("Cancel"); + GTK_WIDGET_SET_FLAGS (filesel->cancel_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), filesel->cancel_button, TRUE, TRUE, 0); + gtk_widget_show (filesel->cancel_button); + + /* The Help button */ + filesel->help_button = gtk_button_new_with_label ("Help"); + GTK_WIDGET_SET_FLAGS (filesel->help_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (action_area), filesel->help_button, TRUE, TRUE, 0); + gtk_widget_show (filesel->help_button); + + + /* The selection entry widget */ + entry_vbox = gtk_vbox_new (FALSE, 2); + gtk_box_pack_end (GTK_BOX (filesel->main_vbox), entry_vbox, FALSE, FALSE, 0); + gtk_widget_show (entry_vbox); + + filesel->selection_text = label = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + filesel->selection_entry = gtk_entry_new (); + gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "key_press_event", + (GtkSignalFunc) gtk_file_selection_key_press, filesel); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "focus_in_event", + (GtkSignalFunc) gtk_widget_grab_default, + GTK_OBJECT (filesel->ok_button)); + gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "activate", + (GtkSignalFunc) gtk_button_clicked, + GTK_OBJECT (filesel->ok_button)); + gtk_box_pack_start (GTK_BOX (entry_vbox), filesel->selection_entry, TRUE, TRUE, 0); + gtk_widget_show (filesel->selection_entry); + + if (!cmpl_state_okay (filesel->cmpl_state)) + { + gchar err_buf[256]; + + sprintf (err_buf, "Directory unreadable: %s", cmpl_strerror (cmpl_errno)); + + gtk_label_set (GTK_LABEL (filesel->selection_text), err_buf); + } + else + { + gtk_file_selection_populate (filesel, "", FALSE); + } + + gtk_widget_grab_focus (filesel->selection_entry); +} + +GtkWidget* +gtk_file_selection_new (const gchar *title) +{ + GtkFileSelection *filesel; + + filesel = gtk_type_new (gtk_file_selection_get_type ()); + gtk_window_set_title (GTK_WINDOW (filesel), title); + + return GTK_WIDGET (filesel); +} + +void +gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename) +{ + char buf[MAXPATHLEN]; + const char *name, *last_slash; + + g_return_if_fail (filesel != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); + g_return_if_fail (filename != NULL); + + last_slash = strrchr (filename, '/'); + + if (!last_slash) + { + buf[0] = 0; + name = filename; + } + else + { + gint len = MIN (MAXPATHLEN - 1, last_slash - filename + 1); + + strncpy (buf, filename, len); + buf[len] = 0; + + name = last_slash + 1; + } + + gtk_file_selection_populate (filesel, buf, FALSE); + + if (filesel->selection_entry) + gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), name); +} + +gchar* +gtk_file_selection_get_filename (GtkFileSelection *filesel) +{ + static char nothing[2] = ""; + char *text; + char *filename; + + g_return_val_if_fail (filesel != NULL, nothing); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), nothing); + + text = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry)); + if (text) + { + filename = cmpl_completion_fullname (text, filesel->cmpl_state); + return filename; + } + + return nothing; +} + +static void +gtk_file_selection_destroy (GtkObject *object) +{ + GtkFileSelection *filesel; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (object)); + + filesel = GTK_FILE_SELECTION (object); + + cmpl_free_state (filesel->cmpl_state); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static gint +gtk_file_selection_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + GtkFileSelection *fs; + char *text; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->keyval == GDK_Tab) + { + gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event"); + + fs = GTK_FILE_SELECTION (user_data); + text = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + gtk_file_selection_populate (fs, text, TRUE); + + return TRUE; + } + + return FALSE; +} + +static gint +gtk_file_selection_file_button (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + GtkFileSelection *fs; + GtkWidget *event_widget; + gchar *filename; + gboolean handled; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fs = GTK_FILE_SELECTION (user_data); + g_return_val_if_fail (fs != NULL, FALSE); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs), FALSE); + + event_widget = gtk_get_event_widget ((GdkEvent*) event); + handled = FALSE; + if (GTK_IS_LIST_ITEM (event_widget)) + { + switch (event->type) + { + case GDK_BUTTON_PRESS: + filename = gtk_object_get_user_data (GTK_OBJECT (event_widget)); + gtk_widget_grab_focus (fs->selection_entry); + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + handled = TRUE; + break; + + case GDK_2BUTTON_PRESS: + gtk_button_clicked (GTK_BUTTON (fs->ok_button)); + handled = TRUE; + break; + + default: + break; + } + } + + return handled; +} + +static void +gtk_file_selection_file_list_changed (GtkList *list, + gpointer func_data) +{ + GtkFileSelection *fs; + + g_return_if_fail (func_data != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (func_data)); + + fs = GTK_FILE_SELECTION (func_data); + + /* only act on an appropriate selection + */ + if (list->selection && list->selection->data) + { + GtkListItem *item; + + item = list->selection->data; + + if (GTK_IS_LIST_ITEM (item)) + { + gchar *filename; + + filename = gtk_object_get_user_data (GTK_OBJECT (item)); + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + } + } +} + +static gint +gtk_file_selection_dir_button (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + GtkFileSelection *fs; + GtkWidget *event_widget; + gchar *filename; + gboolean handled; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + fs = GTK_FILE_SELECTION (user_data); + g_return_val_if_fail (fs != NULL, FALSE); + g_return_val_if_fail (GTK_IS_FILE_SELECTION (fs), FALSE); + + event_widget = gtk_get_event_widget ((GdkEvent*) event); + handled = FALSE; + if (GTK_IS_LIST_ITEM (event_widget)) + { + gint key; + + filename = gtk_object_get_user_data (GTK_OBJECT (event_widget)); + + key = (gint) gtk_object_get_data (GTK_OBJECT (widget), list_changed_key); + + switch (event->type) + { + case GDK_BUTTON_PRESS: + + gtk_signal_handler_block (GTK_OBJECT (widget), key); + gtk_widget_activate (GTK_WIDGET (event_widget)); + gtk_signal_handler_unblock (GTK_OBJECT (widget), key); + + gtk_widget_grab_focus (fs->selection_entry); + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), filename); + handled = TRUE; + break; + + case GDK_2BUTTON_PRESS: + gtk_file_selection_populate (fs, filename, FALSE); + handled = TRUE; + break; + + default: + break; + } + } + + return handled; +} + +static void +gtk_file_selection_dir_list_changed (GtkList *list, + gpointer func_data) +{ + GtkFileSelection *fs; + + g_return_if_fail (func_data != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (func_data)); + + fs = GTK_FILE_SELECTION (func_data); + + /* only act on an appropriate selection + */ + if (list->selection && list->selection->data) + { + GtkListItem *item; + + item = list->selection->data; + + if (GTK_IS_LIST_ITEM (item)) + { + gchar *filename; + + filename = gtk_object_get_user_data (GTK_OBJECT (item)); + + if (filename) + gtk_file_selection_populate (fs, filename, FALSE); + } + } +} + +static void +gtk_file_selection_populate (GtkFileSelection *fs, + gchar *rel_path, + gint try_complete) +{ + CompletionState *cmpl_state; + PossibleCompletion* poss; + GList *dir_list = NULL; + GList *file_list = NULL; + GtkWidget *label; + gchar* filename; + gchar* rem_path = rel_path; + gchar* sel_text; + gint did_recurse = FALSE; + gint possible_count = 0; + gint selection_index = -1; + gint dir_changed_key; + + g_return_if_fail (fs != NULL); + g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); + + dir_changed_key = (gint) gtk_object_get_data (GTK_OBJECT (fs->dir_list), list_changed_key); + gtk_signal_handler_block (GTK_OBJECT (fs->dir_list), dir_changed_key); + + cmpl_state = (CompletionState*) fs->cmpl_state; + poss = cmpl_completion_matches (rel_path, &rem_path, cmpl_state); + + if (!cmpl_state_okay (cmpl_state)) + { + /* Something went wrong. */ + gtk_file_selection_abort (fs); + gtk_signal_handler_unblock (GTK_OBJECT (fs->dir_list), dir_changed_key); + return; + } + + g_assert (cmpl_state->reference_dir); + + /* Set the dir_list and file_list to be GLists of strdup'd + * filenames, including ./ and ../ */ + dir_list = g_list_prepend (dir_list, g_strdup("./")); + dir_list = g_list_prepend (dir_list, g_strdup("../")); + + while (poss) + { + if (cmpl_is_a_completion (poss)) + { + possible_count += 1; + + filename = g_strdup (cmpl_this_completion (poss)); + + if (cmpl_is_directory (poss)) + { + if (strcmp (filename, "./") != 0 && + strcmp (filename, "../") != 0) + dir_list = g_list_prepend (dir_list, filename); + } + else + file_list = g_list_prepend (file_list, filename); + } + + poss = cmpl_next_completion (cmpl_state); + } + + /* File lists are set. */ + + g_assert (cmpl_state->reference_dir); + + if (try_complete) + { + /* User is trying to complete filenames, so advance the user's input + * string to the updated_text, which is the common leading substring + * of all possible completions, and if its a directory attempt + * attempt completions in it. */ + + if (cmpl_updated_text (cmpl_state)[0]) + { + if (cmpl_updated_dir (cmpl_state)) + { + gchar* dir_name = g_strdup (cmpl_updated_text (cmpl_state)); + + did_recurse = TRUE; + + gtk_file_selection_populate (fs, dir_name, TRUE); + + g_free (dir_name); + } + else + { + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), + cmpl_updated_text (cmpl_state)); + } + } + else + { + selection_index = cmpl_last_valid_char (cmpl_state) - + (strlen (rel_path) - strlen (rem_path)); + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), rem_path); + } + } + else + { + if (fs->selection_entry) + gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), ""); + } + + if (!did_recurse) + { + GList *file_label_list = NULL; + GList *dir_label_list = NULL; + + /* This reverses the lists. */ + while (file_list) + { + label = gtk_list_item_new_with_label (file_list->data); + gtk_object_set_user_data (GTK_OBJECT (label), file_list->data); + gtk_widget_show (label); + + file_label_list = g_list_prepend (file_label_list, label); + file_list = file_list->next; + } + + while (dir_list) + { + label = gtk_list_item_new_with_label (dir_list->data); + gtk_object_set_user_data (GTK_OBJECT (label), dir_list->data); + gtk_widget_show (label); + + dir_label_list = g_list_prepend (dir_label_list, label); + dir_list = dir_list->next; + } + + gtk_container_disable_resize (GTK_CONTAINER (fs)); + + if (fs->selection_entry) + gtk_entry_set_position (GTK_ENTRY (fs->selection_entry), selection_index); + + if (fs->selection_entry) + { + sel_text = g_new (char, strlen (cmpl_reference_position (cmpl_state)) + + sizeof ("Selection: ")); + strcpy (sel_text, "Selection: "); + strcat (sel_text, cmpl_reference_position (cmpl_state)); + + gtk_label_set (GTK_LABEL (fs->selection_text), sel_text); + g_free (sel_text); + } + + if (fs->dir_list) + { + gtk_container_foreach (GTK_CONTAINER (fs->dir_list), + gtk_file_selection_free_filename, NULL); + gtk_list_clear_items (GTK_LIST (fs->dir_list), 0, -1); + + if (dir_label_list) + gtk_list_append_items (GTK_LIST (fs->dir_list), dir_label_list); + } + if (fs->file_list) + { + gtk_container_foreach (GTK_CONTAINER (fs->file_list), + gtk_file_selection_free_filename, NULL); + gtk_list_clear_items (GTK_LIST (fs->file_list), 0, -1); + + if (file_label_list) + gtk_list_append_items (GTK_LIST (fs->file_list), file_label_list); + } + + gtk_container_enable_resize (GTK_CONTAINER (fs)); + } + else + { + GList *dir_list0 = dir_list; + GList *file_list0 = file_list; + + while (dir_list) + { + GList *tmp = dir_list; + dir_list = dir_list->next; + + if (tmp) + g_free (tmp->data); + } + + while (file_list) + { + GList *tmp = file_list; + file_list = file_list->next; + + if (tmp) + g_free (tmp->data); + } + + g_list_free (dir_list0); + g_list_free (file_list0); + } + + gtk_signal_handler_unblock (GTK_OBJECT (fs->dir_list), dir_changed_key); +} + +static void +gtk_file_selection_abort (GtkFileSelection *fs) +{ + gchar err_buf[256]; + + sprintf (err_buf, "Directory unreadable: %s", cmpl_strerror (cmpl_errno)); + + /* BEEP gdk_beep(); */ + + if (fs->selection_entry) + gtk_label_set (GTK_LABEL (fs->selection_text), err_buf); +} + +static void +gtk_file_selection_free_filename (GtkWidget *widget, + gpointer client_data) +{ + g_return_if_fail (widget != NULL); + + g_free (gtk_object_get_user_data (GTK_OBJECT (widget))); + gtk_object_set_user_data (GTK_OBJECT (widget), NULL); +} + + + +/**********************************************************************/ +/* External Interface */ +/**********************************************************************/ + +/* The four completion state selectors + */ +static gchar* +cmpl_updated_text (CompletionState* cmpl_state) +{ + return cmpl_state->updated_text; +} + +static gint +cmpl_updated_dir (CompletionState* cmpl_state) +{ + return cmpl_state->re_complete; +} + +static gchar* +cmpl_reference_position (CompletionState* cmpl_state) +{ + return cmpl_state->reference_dir->fullname; +} + +static gint +cmpl_last_valid_char (CompletionState* cmpl_state) +{ + return cmpl_state->last_valid_char; +} + +static gchar* +cmpl_completion_fullname (gchar* text, CompletionState* cmpl_state) +{ + if (text[0] == '/') + { + strcpy (cmpl_state->updated_text, text); + } + else if (text[0] == '~') + { + CompletionDir* dir; + char* slash; + + dir = open_user_dir (text, cmpl_state); + + if (!dir) + { + /* spencer says just return ~something, so + * for now just do it. */ + strcpy (cmpl_state->updated_text, text); + } + else + { + + strcpy (cmpl_state->updated_text, dir->fullname); + + slash = strchr (text, '/'); + + if (slash) + strcat (cmpl_state->updated_text, slash); + } + } + else + { + strcpy (cmpl_state->updated_text, cmpl_state->reference_dir->fullname); + strcat (cmpl_state->updated_text, "/"); + strcat (cmpl_state->updated_text, text); + } + + return cmpl_state->updated_text; +} + +/* The three completion selectors + */ +static gchar* +cmpl_this_completion (PossibleCompletion* pc) +{ + return pc->text; +} + +static gint +cmpl_is_directory (PossibleCompletion* pc) +{ + return pc->is_directory; +} + +static gint +cmpl_is_a_completion (PossibleCompletion* pc) +{ + return pc->is_a_completion; +} + +/**********************************************************************/ +/* Construction, deletion */ +/**********************************************************************/ + +static CompletionState* +cmpl_init_state (void) +{ + gchar getcwd_buf[2*MAXPATHLEN]; + CompletionState *new_state; + + new_state = g_new (CompletionState, 1); + + if (!getcwd (getcwd_buf, MAXPATHLEN)) + { + cmpl_errno = errno; + return NULL; + } + + new_state->reference_dir = NULL; + new_state->completion_dir = NULL; + new_state->active_completion_dir = NULL; + + if ((new_state->user_home_dir = getenv("HOME")) != NULL) + { + /* if this fails, get_pwdb will fill it in. */ + new_state->user_home_dir = g_strdup(new_state->user_home_dir); + } + + new_state->directory_storage = NULL; + new_state->directory_sent_storage = NULL; + new_state->last_valid_char = 0; + new_state->updated_text = g_new (gchar, MAXPATHLEN); + new_state->updated_text_alloc = MAXPATHLEN; + new_state->the_completion.text = g_new (gchar, MAXPATHLEN); + new_state->the_completion.text_alloc = MAXPATHLEN; + new_state->user_dir_name_buffer = NULL; + new_state->user_directories = NULL; + + new_state->reference_dir = open_dir (getcwd_buf, new_state); + + if (!new_state->reference_dir) + return NULL; + + return new_state; +} + +static void +cmpl_free_dir_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_dir_sent_list(GList* dp0) +{ + GList *dp = dp0; + + while (dp) { + free_dir_sent (dp->data); + dp = dp->next; + } + + g_list_free(dp0); +} + +static void +cmpl_free_state (CompletionState* cmpl_state) +{ + cmpl_free_dir_list(cmpl_state->directory_storage); + cmpl_free_dir_sent_list(cmpl_state->directory_sent_storage); + + if (cmpl_state->user_dir_name_buffer) + g_free (cmpl_state->user_dir_name_buffer); + if (cmpl_state->user_directories) + g_free (cmpl_state->user_directories); + if (cmpl_state->the_completion.text) + g_free (cmpl_state->the_completion.text); + if (cmpl_state->updated_text) + g_free (cmpl_state->updated_text); + + g_free (cmpl_state); +} + +static void +free_dir(CompletionDir* dir) +{ + g_free(dir->fullname); + g_free(dir); +} + +static void +free_dir_sent(CompletionDirSent* sent) +{ + g_free(sent->name_buffer); + g_free(sent->entries); + g_free(sent); +} + +static void +prune_memory_usage(CompletionState *cmpl_state) +{ + GList* cdsl = cmpl_state->directory_sent_storage; + GList* cdl = cmpl_state->directory_storage; + GList* cdl0 = cdl; + gint len = 0; + + for(; cdsl && len < CMPL_DIRECTORY_CACHE_SIZE; len += 1) + cdsl = cdsl->next; + + if (cdsl) { + cmpl_free_dir_sent_list(cdsl->next); + cdsl->next = NULL; + } + + while (cdl) { + if (cdl->data == cmpl_state->reference_dir) + cmpl_state->directory_storage = g_list_prepend(NULL, cdl->data); + else + free_dir (cdl->data); + cdl = cdl->next; + } + + g_list_free(cdl0); +} + +/**********************************************************************/ +/* The main entrances. */ +/**********************************************************************/ + +static PossibleCompletion* +cmpl_completion_matches (gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + PossibleCompletion *poss; + + prune_memory_usage(cmpl_state); + + g_assert(text_to_complete); + + cmpl_state->user_completion_index = -1; + cmpl_state->last_completion_text = text_to_complete; + cmpl_state->the_completion.text[0] = 0; + cmpl_state->last_valid_char = 0; + cmpl_state->updated_text_len = -1; + cmpl_state->updated_text[0] = 0; + cmpl_state->re_complete = FALSE; + + first_slash = strchr(text_to_complete, '/'); + + if(text_to_complete[0] == '~' && !first_slash) + { + /* Text starts with ~ and there is no slash, show all the + * home directory completions. + */ + poss = attempt_homedir_completion(text_to_complete, cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; + } + + cmpl_state->reference_dir = + open_ref_dir(text_to_complete, remaining_text, cmpl_state); + + if(!cmpl_state->reference_dir) + return NULL; + + cmpl_state->completion_dir = + find_completion_dir(*remaining_text, remaining_text, cmpl_state); + + cmpl_state->last_valid_char = *remaining_text - text_to_complete; + + if(!cmpl_state->completion_dir) + return NULL; + + cmpl_state->completion_dir->cmpl_index = -1; + cmpl_state->completion_dir->cmpl_parent = NULL; + cmpl_state->completion_dir->cmpl_text = *remaining_text; + + cmpl_state->active_completion_dir = cmpl_state->completion_dir; + + cmpl_state->reference_dir = cmpl_state->completion_dir; + + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +static PossibleCompletion* +cmpl_next_completion (CompletionState* cmpl_state) +{ + PossibleCompletion* poss = NULL; + + cmpl_state->the_completion.text[0] = 0; + + if(cmpl_state->user_completion_index >= 0) + poss = attempt_homedir_completion(cmpl_state->last_completion_text, cmpl_state); + else + poss = attempt_file_completion(cmpl_state); + + update_cmpl(poss, cmpl_state); + + return poss; +} + +/**********************************************************************/ +/* Directory Operations */ +/**********************************************************************/ + +/* Open the directory where completion will begin from, if possible. */ +static CompletionDir* +open_ref_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash; + CompletionDir *new_dir; + + first_slash = strchr(text_to_complete, '/'); + + if (text_to_complete[0] == '/' || !cmpl_state->reference_dir) + { + new_dir = open_dir("/", cmpl_state); + + if(new_dir) + *remaining_text = text_to_complete + 1; + } + else if (text_to_complete[0] == '~') + { + new_dir = open_user_dir(text_to_complete, cmpl_state); + + if(new_dir) + { + if(first_slash) + *remaining_text = first_slash + 1; + else + *remaining_text = text_to_complete + strlen(text_to_complete); + } + else + { + return NULL; + } + } + else + { + *remaining_text = text_to_complete; + + new_dir = open_dir(cmpl_state->reference_dir->fullname, cmpl_state); + } + + if(new_dir) + { + new_dir->cmpl_index = -1; + new_dir->cmpl_parent = NULL; + } + + return new_dir; +} + +/* open a directory by user name */ +static CompletionDir* +open_user_dir(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gchar *first_slash; + gint cmp_len; + + g_assert(text_to_complete && text_to_complete[0] == '~'); + + first_slash = strchr(text_to_complete, '/'); + + if (first_slash) + cmp_len = first_slash - text_to_complete - 1; + else + cmp_len = strlen(text_to_complete + 1); + + if(!cmp_len) + { + /* ~/ */ + if (!cmpl_state->user_home_dir && + !get_pwdb(cmpl_state)) + return NULL; + return open_dir(cmpl_state->user_home_dir, cmpl_state); + } + else + { + /* ~user/ */ + char* copy = g_new(char, cmp_len + 1); + struct passwd *pwd; + strncpy(copy, text_to_complete + 1, cmp_len); + copy[cmp_len] = 0; + pwd = getpwnam(copy); + g_free(copy); + if (!pwd) + { + cmpl_errno = errno; + return NULL; + } + + return open_dir(pwd->pw_dir, cmpl_state); + } +} + +/* open a directory relative the the current relative directory */ +static CompletionDir* +open_relative_dir(gchar* dir_name, + CompletionDir* dir, + CompletionState *cmpl_state) +{ + gchar path_buf[2*MAXPATHLEN]; + + if(dir->fullname_len + strlen(dir_name) + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir->fullname); + + if(dir->fullname_len > 1) + { + path_buf[dir->fullname_len] = '/'; + strcpy(path_buf + dir->fullname_len + 1, dir_name); + } + else + { + strcpy(path_buf + dir->fullname_len, dir_name); + } + + return open_dir(path_buf, cmpl_state); +} + +/* after the cache lookup fails, really open a new directory */ +static CompletionDirSent* +open_new_dir(gchar* dir_name, struct stat* sbuf) +{ + CompletionDirSent* sent; + DIR* directory; + gchar *buffer_ptr; + struct dirent *dirent_ptr; + gint buffer_size = 0; + gint entry_count = 0; + gint i; + struct stat ent_sbuf; + char path_buf[MAXPATHLEN*2]; + gint path_buf_len; + + sent = g_new(CompletionDirSent, 1); + sent->mtime = sbuf->st_mtime; + sent->inode = sbuf->st_ino; + + path_buf_len = strlen(dir_name); + + if (path_buf_len > MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + return NULL; + } + + strcpy(path_buf, dir_name); + + directory = opendir(dir_name); + + if(!directory) + { + cmpl_errno = errno; + return NULL; + } + + while((dirent_ptr = readdir(directory)) != NULL) + { + int entry_len = strlen(dirent_ptr->d_name); + buffer_size += entry_len + 1; + entry_count += 1; + + if(path_buf_len + entry_len + 2 >= MAXPATHLEN) + { + cmpl_errno = CMPL_ERRNO_TOO_LONG; + closedir(directory); + return NULL; + } + } + + sent->name_buffer = g_new(gchar, buffer_size); + sent->entries = g_new(CompletionDirEntry, entry_count); + sent->entry_count = entry_count; + + buffer_ptr = sent->name_buffer; + + rewinddir(directory); + + for(i = 0; i < entry_count; i += 1) + { + dirent_ptr = readdir(directory); + + if(!dirent_ptr) + { + cmpl_errno = errno; + closedir(directory); + return NULL; + } + + strcpy(buffer_ptr, dirent_ptr->d_name); + sent->entries[i].entry_name = buffer_ptr; + buffer_ptr += strlen(dirent_ptr->d_name); + *buffer_ptr = 0; + buffer_ptr += 1; + + path_buf[path_buf_len] = '/'; + strcpy(path_buf + path_buf_len + 1, dirent_ptr->d_name); + + if(stat(path_buf, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) + sent->entries[i].is_dir = 1; + else + /* stat may fail, and we don't mind, since it could be a + * dangling symlink. */ + sent->entries[i].is_dir = 0; + } + + qsort(sent->entries, sent->entry_count, sizeof(CompletionDirEntry), compare_cmpl_dir); + + closedir(directory); + + return sent; +} + +/* open a directory by absolute pathname */ +static CompletionDir* +open_dir(gchar* dir_name, CompletionState* cmpl_state) +{ + struct stat sbuf; + CompletionDirSent *sent; + GList* cdsl; + + if(stat(dir_name, &sbuf) < 0) + { + cmpl_errno = errno; + return NULL; + } + + cdsl = cmpl_state->directory_sent_storage; + + while (cdsl) + { + sent = cdsl->data; + + if(sent->inode == sbuf.st_ino && + sent->mtime == sbuf.st_mtime) + return attach_dir(sent, dir_name, cmpl_state); + + cdsl = cdsl->next; + } + + sent = open_new_dir(dir_name, &sbuf); + + if (sent) { + cmpl_state->directory_sent_storage = + g_list_prepend(cmpl_state->directory_sent_storage, sent); + + return attach_dir(sent, dir_name, cmpl_state); + } + + return NULL; +} + +static CompletionDir* +attach_dir(CompletionDirSent* sent, gchar* dir_name, CompletionState *cmpl_state) +{ + CompletionDir* new_dir; + + new_dir = g_new(CompletionDir, 1); + + cmpl_state->directory_storage = + g_list_prepend(cmpl_state->directory_storage, new_dir); + + new_dir->sent = sent; + new_dir->fullname = g_strdup(dir_name); + new_dir->fullname_len = strlen(dir_name); + + return new_dir; +} + +static gint +correct_dir_fullname(CompletionDir* cmpl_dir) +{ + gint length = strlen(cmpl_dir->fullname); + struct stat sbuf; + + if (strcmp(cmpl_dir->fullname + length - 2, "/.") == 0) + cmpl_dir->fullname[length - 2] = 0; + else if (strcmp(cmpl_dir->fullname + length - 3, "/./") == 0) + cmpl_dir->fullname[length - 3] = 0; + else if (strcmp(cmpl_dir->fullname + length - 3, "/..") == 0) + { + if(length == 3) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 3] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + else if (strcmp(cmpl_dir->fullname + length - 4, "/../") == 0) + { + if(length == 4) + { + strcpy(cmpl_dir->fullname, "/"); + cmpl_dir->fullname_len = 1; + return TRUE; + } + + if(stat(cmpl_dir->fullname, &sbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + cmpl_dir->fullname[length - 4] = 0; + + if(!correct_parent(cmpl_dir, &sbuf)) + return FALSE; + } + + cmpl_dir->fullname_len = strlen(cmpl_dir->fullname); + + return TRUE; +} + +static gint +correct_parent(CompletionDir* cmpl_dir, struct stat *sbuf) +{ + struct stat parbuf; + gchar *last_slash; + gchar *new_name; + gchar c = 0; + + last_slash = strrchr(cmpl_dir->fullname, '/'); + + g_assert(last_slash); + + if(last_slash != cmpl_dir->fullname) + last_slash[0] = 0; + else + { + c = last_slash[1]; + last_slash[1] = 0; + } + + if (stat(cmpl_dir->fullname, &parbuf) < 0) + { + cmpl_errno = errno; + return FALSE; + } + + if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev) + /* it wasn't a link */ + return TRUE; + + if(c) + last_slash[1] = c; + else + last_slash[0] = '/'; + + /* it was a link, have to figure it out the hard way */ + + new_name = find_parent_dir_fullname(cmpl_dir->fullname); + + if (!new_name) + return FALSE; + + g_free(cmpl_dir->fullname); + + cmpl_dir->fullname = new_name; + + return TRUE; +} + +static gchar* +find_parent_dir_fullname(gchar* dirname) +{ + gchar buffer[MAXPATHLEN]; + gchar buffer2[MAXPATHLEN]; + + if(!getcwd(buffer, MAXPATHLEN)) + { + cmpl_errno = errno; + return NULL; + } + + if(chdir(dirname) != 0 || chdir("..") != 0) + { + cmpl_errno = errno; + return NULL; + } + + if(!getcwd(buffer2, MAXPATHLEN)) + { + chdir(buffer); + cmpl_errno = errno; + + return NULL; + } + + if(chdir(buffer) != 0) + { + cmpl_errno = errno; + return NULL; + } + + return g_strdup(buffer2); +} + +/**********************************************************************/ +/* Completion Operations */ +/**********************************************************************/ + +static PossibleCompletion* +attempt_homedir_completion(gchar* text_to_complete, + CompletionState *cmpl_state) +{ + gint index, length; + + if (!cmpl_state->user_dir_name_buffer && + !get_pwdb(cmpl_state)) + return NULL; + length = strlen(text_to_complete) - 1; + + cmpl_state->user_completion_index += 1; + + while(cmpl_state->user_completion_index < cmpl_state->user_directories_len) + { + index = first_diff_index(text_to_complete + 1, + cmpl_state->user_directories + [cmpl_state->user_completion_index].login); + + switch(index) + { + case PATTERN_MATCH: + break; + default: + if(cmpl_state->last_valid_char < (index + 1)) + cmpl_state->last_valid_char = index + 1; + cmpl_state->user_completion_index += 1; + continue; + } + + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + append_completion_text("~", cmpl_state); + + append_completion_text(cmpl_state-> + user_directories[cmpl_state->user_completion_index].login, + cmpl_state); + + return append_completion_text("/", cmpl_state); + } + + if(text_to_complete[1] || + cmpl_state->user_completion_index > cmpl_state->user_directories_len) + { + cmpl_state->user_completion_index = -1; + return NULL; + } + else + { + cmpl_state->user_completion_index += 1; + cmpl_state->the_completion.is_a_completion = 1; + cmpl_state->the_completion.is_directory = 1; + + return append_completion_text("~/", cmpl_state); + } +} + +/* returns the index (>= 0) of the first differing character, + * PATTERN_MATCH if the completion matches */ +static gint +first_diff_index(gchar* pat, gchar* text) +{ + gint diff = 0; + + while(*pat && *text && *text == *pat) + { + pat += 1; + text += 1; + diff += 1; + } + + if(*pat) + return diff; + + return PATTERN_MATCH; +} + +static PossibleCompletion* +append_completion_text(gchar* text, CompletionState* cmpl_state) +{ + gint len, i = 1; + + if(!cmpl_state->the_completion.text) + return NULL; + + len = strlen(text) + strlen(cmpl_state->the_completion.text) + 1; + + if(cmpl_state->the_completion.text_alloc > len) + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } + + while(i < len) { i <<= 1; } + + cmpl_state->the_completion.text_alloc = i; + + cmpl_state->the_completion.text = (gchar*)g_realloc(cmpl_state->the_completion.text, i); + + if(!cmpl_state->the_completion.text) + return NULL; + else + { + strcat(cmpl_state->the_completion.text, text); + return &cmpl_state->the_completion; + } +} + +static CompletionDir* +find_completion_dir(gchar* text_to_complete, + gchar** remaining_text, + CompletionState* cmpl_state) +{ + gchar* first_slash = strchr(text_to_complete, '/'); + CompletionDir* dir = cmpl_state->reference_dir; + *remaining_text = text_to_complete; + + while(first_slash) + { + gint len = first_slash - *remaining_text; + gint found = 0; + gint found_index = -1; + gint i; + gchar* pat_buf = g_new (gchar, len + 1); + + strncpy(pat_buf, *remaining_text, len); + pat_buf[len] = 0; + + for(i = 0; i < dir->sent->entry_count; i += 1) + { + if(dir->sent->entries[i].is_dir && + fnmatch(pat_buf, dir->sent->entries[i].entry_name, + FNMATCH_FLAGS)!= FNM_NOMATCH) + { + if(found) + { + g_free (pat_buf); + return dir; + } + else + { + found = 1; + found_index = i; + } + } + } + + if(found) + { + CompletionDir* next = open_relative_dir(dir->sent->entries[found_index].entry_name, + dir, cmpl_state); + + if(!next) + { + g_free (pat_buf); + return NULL; + } + + next->cmpl_parent = dir; + + dir = next; + + if(!correct_dir_fullname(dir)) + { + g_free(pat_buf); + return NULL; + } + + *remaining_text = first_slash + 1; + first_slash = strchr(*remaining_text, '/'); + } + else + { + g_free (pat_buf); + return NULL; + } + + g_free (pat_buf); + } + + return dir; +} + +static void +update_cmpl(PossibleCompletion* poss, CompletionState* cmpl_state) +{ + gint cmpl_len; + + if(!poss || !cmpl_is_a_completion(poss)) + return; + + cmpl_len = strlen(cmpl_this_completion(poss)); + + if(cmpl_state->updated_text_alloc < cmpl_len + 1) + { + cmpl_state->updated_text = + (gchar*)g_realloc(cmpl_state->updated_text, + cmpl_state->updated_text_alloc); + cmpl_state->updated_text_alloc = 2*cmpl_len; + } + + if(cmpl_state->updated_text_len < 0) + { + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + cmpl_state->updated_text_len = cmpl_len; + cmpl_state->re_complete = cmpl_is_directory(poss); + } + else if(cmpl_state->updated_text_len == 0) + { + cmpl_state->re_complete = FALSE; + } + else + { + gint first_diff = + first_diff_index(cmpl_state->updated_text, + cmpl_this_completion(poss)); + + cmpl_state->re_complete = FALSE; + + if(first_diff == PATTERN_MATCH) + return; + + if(first_diff > cmpl_state->updated_text_len) + strcpy(cmpl_state->updated_text, cmpl_this_completion(poss)); + + cmpl_state->updated_text_len = first_diff; + cmpl_state->updated_text[first_diff] = 0; + } +} + +static PossibleCompletion* +attempt_file_completion(CompletionState *cmpl_state) +{ + gchar *pat_buf, *first_slash; + CompletionDir *dir = cmpl_state->active_completion_dir; + + dir->cmpl_index += 1; + + if(dir->cmpl_index == dir->sent->entry_count) + { + if(dir->cmpl_parent == NULL) + { + cmpl_state->active_completion_dir = NULL; + + return NULL; + } + else + { + cmpl_state->active_completion_dir = dir->cmpl_parent; + + return attempt_file_completion(cmpl_state); + } + } + + g_assert(dir->cmpl_text); + + first_slash = strchr(dir->cmpl_text, '/'); + + if(first_slash) + { + gint len = first_slash - dir->cmpl_text; + + pat_buf = g_new (gchar, len + 1); + strncpy(pat_buf, dir->cmpl_text, len); + pat_buf[len] = 0; + } + else + { + gint len = strlen(dir->cmpl_text); + + pat_buf = g_new (gchar, len + 2); + strcpy(pat_buf, dir->cmpl_text); + strcpy(pat_buf + len, "*"); + } + + if(first_slash) + { + if(dir->sent->entries[dir->cmpl_index].is_dir) + { + if(fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH) + { + CompletionDir* new_dir; + + new_dir = open_relative_dir(dir->sent->entries[dir->cmpl_index].entry_name, + dir, cmpl_state); + + if(!new_dir) + { + g_free (pat_buf); + return NULL; + } + + new_dir->cmpl_parent = dir; + + new_dir->cmpl_index = -1; + new_dir->cmpl_text = first_slash + 1; + + cmpl_state->active_completion_dir = new_dir; + + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + g_free (pat_buf); + return attempt_file_completion(cmpl_state); + } + } + else + { + if(dir->cmpl_parent != NULL) + { + append_completion_text(dir->fullname + + strlen(cmpl_state->completion_dir->fullname) + 1, + cmpl_state); + append_completion_text("/", cmpl_state); + } + + append_completion_text(dir->sent->entries[dir->cmpl_index].entry_name, cmpl_state); + + cmpl_state->the_completion.is_a_completion = + (fnmatch(pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, + FNMATCH_FLAGS) != FNM_NOMATCH); + + cmpl_state->the_completion.is_directory = dir->sent->entries[dir->cmpl_index].is_dir; + if(dir->sent->entries[dir->cmpl_index].is_dir) + append_completion_text("/", cmpl_state); + + g_free (pat_buf); + return &cmpl_state->the_completion; + } +} + + +static gint +get_pwdb(CompletionState* cmpl_state) +{ + struct passwd *pwd_ptr; + gchar* buf_ptr, *home_dir = NULL; + gint len = 0, i, count = 0; + + if(cmpl_state->user_dir_name_buffer) + return TRUE; + setpwent (); + + while ((pwd_ptr = getpwent()) != NULL) + { + len += strlen(pwd_ptr->pw_name); + len += strlen(pwd_ptr->pw_dir); + len += 2; + count += 1; + } + + if (!cmpl_state->user_home_dir) + { + /* the loser doesn't have $HOME set */ + setpwent (); + + pwd_ptr = getpwuid(getuid()); + if(!pwd_ptr) + { + cmpl_errno = errno; + goto error; + } + home_dir = pwd_ptr->pw_dir; + + len += strlen(home_dir); + len += 1; + } + + setpwent (); + + cmpl_state->user_dir_name_buffer = g_new(gchar, len); + cmpl_state->user_directories = g_new(CompletionUserDir, count); + cmpl_state->user_directories_len = count; + + buf_ptr = cmpl_state->user_dir_name_buffer; + + if (!cmpl_state->user_home_dir) + { + strcpy(buf_ptr, home_dir); + cmpl_state->user_home_dir = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + } + + for(i = 0; i < count; i += 1) + { + pwd_ptr = getpwent(); + if(!pwd_ptr) + { + cmpl_errno = errno; + goto error; + } + + strcpy(buf_ptr, pwd_ptr->pw_name); + cmpl_state->user_directories[i].login = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + strcpy(buf_ptr, pwd_ptr->pw_dir); + cmpl_state->user_directories[i].homedir = buf_ptr; + buf_ptr += strlen(buf_ptr); + buf_ptr += 1; + } + + qsort(cmpl_state->user_directories, + cmpl_state->user_directories_len, + sizeof(CompletionUserDir), + compare_user_dir); + + endpwent(); + + return TRUE; + +error: + + if(cmpl_state->user_dir_name_buffer) + g_free(cmpl_state->user_dir_name_buffer); + if(cmpl_state->user_directories) + g_free(cmpl_state->user_directories); + + cmpl_state->user_dir_name_buffer = NULL; + cmpl_state->user_directories = NULL; + + return FALSE; +} + +static gint +compare_user_dir(const void* a, const void* b) +{ + return strcmp((((CompletionUserDir*)a))->login, + (((CompletionUserDir*)b))->login); +} + +static gint +compare_cmpl_dir(const void* a, const void* b) +{ + return strcmp((((CompletionDirEntry*)a))->entry_name, + (((CompletionDirEntry*)b))->entry_name); +} + +static gint +cmpl_state_okay(CompletionState* cmpl_state) +{ + return cmpl_state && cmpl_state->reference_dir; +} + +static gchar* +cmpl_strerror(gint err) +{ + if(err == CMPL_ERRNO_TOO_LONG) + return "Name too long"; + else + return g_strerror (err); +} diff --git a/gtk/gtkfilesel.h b/gtk/gtkfilesel.h new file mode 100644 index 000000000..1248ac6a9 --- /dev/null +++ b/gtk/gtkfilesel.h @@ -0,0 +1,73 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_FILESEL_H__ +#define __GTK_FILESEL_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_FILE_SELECTION(obj) GTK_CHECK_CAST (obj, gtk_file_selection_get_type (), GtkFileSelection) +#define GTK_FILE_SELECTION_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_file_selection_get_type (), GtkFileSelectionClass) +#define GTK_IS_FILE_SELECTION(obj) GTK_CHECK_TYPE (obj, gtk_file_selection_get_type ()) + + +typedef struct _GtkFileSelection GtkFileSelection; +typedef struct _GtkFileSelectionClass GtkFileSelectionClass; + +struct _GtkFileSelection +{ + GtkWindow window; + + GtkWidget *dir_list; + GtkWidget *file_list; + GtkWidget *selection_entry; + GtkWidget *selection_text; + GtkWidget *main_vbox; + GtkWidget *ok_button; + GtkWidget *cancel_button; + GtkWidget *help_button; + + gpointer cmpl_state; +}; + +struct _GtkFileSelectionClass +{ + GtkWindowClass parent_class; +}; + + +guint gtk_file_selection_get_type (void); +GtkWidget* gtk_file_selection_new (const gchar *title); +void gtk_file_selection_set_filename (GtkFileSelection *filesel, + const gchar *filename); +gchar* gtk_file_selection_get_filename (GtkFileSelection *filesel); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_FILESEL_H__ */ diff --git a/gtk/gtkfixed.c b/gtk/gtkfixed.c new file mode 100644 index 000000000..59eba1f46 --- /dev/null +++ b/gtk/gtkfixed.c @@ -0,0 +1,525 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkfixed.h" + + +static void gtk_fixed_class_init (GtkFixedClass *klass); +static void gtk_fixed_init (GtkFixed *fixed); +static void gtk_fixed_destroy (GtkObject *object); +static void gtk_fixed_map (GtkWidget *widget); +static void gtk_fixed_unmap (GtkWidget *widget); +static void gtk_fixed_realize (GtkWidget *widget); +static void gtk_fixed_unrealize (GtkWidget *widget); +static void gtk_fixed_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_fixed_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_fixed_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_fixed_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_fixed_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_fixed_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_fixed_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_fixed_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_fixed_get_type () +{ + static guint fixed_type = 0; + + if (!fixed_type) + { + GtkTypeInfo fixed_info = + { + "GtkFixed", + sizeof (GtkFixed), + sizeof (GtkFixedClass), + (GtkClassInitFunc) gtk_fixed_class_init, + (GtkObjectInitFunc) gtk_fixed_init, + (GtkArgFunc) NULL, + }; + + fixed_type = gtk_type_unique (gtk_container_get_type (), &fixed_info); + } + + return fixed_type; +} + +static void +gtk_fixed_class_init (GtkFixedClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_fixed_destroy; + + widget_class->map = gtk_fixed_map; + widget_class->unmap = gtk_fixed_unmap; + widget_class->realize = gtk_fixed_realize; + widget_class->unrealize = gtk_fixed_unrealize; + widget_class->size_request = gtk_fixed_size_request; + widget_class->size_allocate = gtk_fixed_size_allocate; + widget_class->draw = gtk_fixed_draw; + widget_class->expose_event = gtk_fixed_expose; + + container_class->add = gtk_fixed_add; + container_class->remove = gtk_fixed_remove; + container_class->foreach = gtk_fixed_foreach; +} + +static void +gtk_fixed_init (GtkFixed *fixed) +{ + GTK_WIDGET_UNSET_FLAGS (fixed, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (fixed, GTK_BASIC); + + fixed->children = NULL; +} + +GtkWidget* +gtk_fixed_new () +{ + GtkFixed *fixed; + + fixed = gtk_type_new (gtk_fixed_get_type ()); + return GTK_WIDGET (fixed); +} + +void +gtk_fixed_put (GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y) +{ + GtkFixedChild *child_info; + + g_return_if_fail (fixed != NULL); + g_return_if_fail (GTK_IS_FIXED (fixed)); + g_return_if_fail (widget != NULL); + + child_info = g_new (GtkFixedChild, 1); + child_info->widget = widget; + child_info->x = x; + child_info->y = y; + + gtk_widget_set_parent (widget, GTK_WIDGET (fixed)); + + fixed->children = g_list_append (fixed->children, child_info); + + if (GTK_WIDGET_REALIZED (fixed) && !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (fixed) && !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (fixed)) + gtk_widget_queue_resize (GTK_WIDGET (fixed)); +} + +void +gtk_fixed_move (GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y) +{ + GtkFixedChild *child; + GList *children; + + g_return_if_fail (fixed != NULL); + g_return_if_fail (GTK_IS_FIXED (fixed)); + g_return_if_fail (widget != NULL); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (child->widget == widget) + { + child->x = x; + child->y = y; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (fixed)) + gtk_widget_queue_resize (GTK_WIDGET (fixed)); + + break; + } + } +} + +static void +gtk_fixed_destroy (GtkObject *object) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_FIXED (object)); + + fixed = GTK_FIXED (object); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + child->widget->parent = NULL; + gtk_object_unref (GTK_OBJECT (child->widget)); + gtk_widget_destroy (child->widget); + g_free (child); + } + + g_list_free (fixed->children); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_fixed_map (GtkWidget *widget) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + fixed = GTK_FIXED (widget); + + gdk_window_show (widget->window); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + !GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); + } +} + +static void +gtk_fixed_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); +} + +static void +gtk_fixed_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, + attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_fixed_unrealize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + gdk_window_destroy (widget->window); + widget->window = NULL; +} + +static void +gtk_fixed_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + g_return_if_fail (requisition != NULL); + + fixed = GTK_FIXED (widget); + requisition->width = 0; + requisition->height = 0; + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + gtk_widget_size_request (child->widget, &child->widget->requisition); + + requisition->height = MAX (requisition->height, + child->y + + child->widget->requisition.height); + requisition->width = MAX (requisition->width, + child->x + + child->widget->requisition.width); + } + } + + requisition->height += GTK_CONTAINER (fixed)->border_width * 2; + requisition->width += GTK_CONTAINER (fixed)->border_width * 2; +} + +static void +gtk_fixed_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GtkAllocation child_allocation; + GList *children; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED(widget)); + g_return_if_fail (allocation != NULL); + + fixed = GTK_FIXED (widget); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, + allocation->y, + allocation->width, + allocation->height); + + border_width = GTK_CONTAINER (fixed)->border_width; + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + child_allocation.x = child->x + border_width; + child_allocation.y = child->y + border_width; + child_allocation.width = child->widget->requisition.width; + child_allocation.height = child->widget->requisition.height; + gtk_widget_size_allocate (child->widget, &child_allocation); + } + } +} + +static void +gtk_fixed_paint (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + gdk_window_clear_area (widget->window, + area->x, area->y, + area->width, area->height); +} + +static void +gtk_fixed_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FIXED (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + fixed = GTK_FIXED (widget); + gtk_fixed_paint (widget, area); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); + } + } +} + +static gint +gtk_fixed_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_FIXED (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + fixed = GTK_FIXED (widget); + + child_event = *event; + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child->widget) && + gtk_widget_intersect (child->widget, &event->area, + &child_event.area)) + gtk_widget_event (child->widget, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static void +gtk_fixed_add (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_FIXED (container)); + g_return_if_fail (widget != NULL); + + gtk_fixed_put (GTK_FIXED (container), widget, 0, 0); +} + +static void +gtk_fixed_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_FIXED (container)); + g_return_if_fail (widget != NULL); + + fixed = GTK_FIXED (container); + + children = fixed->children; + while (children) + { + child = children->data; + + if (child->widget == widget) + { + gtk_widget_unparent (widget); + + fixed->children = g_list_remove_link (fixed->children, children); + g_list_free (children); + g_free (child); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + + break; + } + + children = children->next; + } +} + +static void +gtk_fixed_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkFixed *fixed; + GtkFixedChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_FIXED (container)); + g_return_if_fail (callback != NULL); + + fixed = GTK_FIXED (container); + + children = fixed->children; + while (children) + { + child = children->data; + children = children->next; + + (* callback) (child->widget, callback_data); + } +} diff --git a/gtk/gtkfixed.h b/gtk/gtkfixed.h new file mode 100644 index 000000000..ee9c131a0 --- /dev/null +++ b/gtk/gtkfixed.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_FIXED_H__ +#define __GTK_FIXED_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_FIXED(obj) GTK_CHECK_CAST (obj, gtk_fixed_get_type (), GtkFixed) +#define GTK_FIXED_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_fixed_get_type (), GtkFixedClass) +#define GTK_IS_FIXED(obj) GTK_CHECK_TYPE (obj, gtk_fixed_get_type ()) + + +typedef struct _GtkFixed GtkFixed; +typedef struct _GtkFixedClass GtkFixedClass; +typedef struct _GtkFixedChild GtkFixedChild; + +struct _GtkFixed +{ + GtkContainer container; + + GList *children; +}; + +struct _GtkFixedClass +{ + GtkContainerClass parent_class; +}; + +struct _GtkFixedChild +{ + GtkWidget *widget; + gint16 x; + gint16 y; +}; + + +guint gtk_fixed_get_type (void); +GtkWidget* gtk_fixed_new (); +void gtk_fixed_put (GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y); +void gtk_fixed_move (GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_FIXED_H__ */ diff --git a/gtk/gtkframe.c b/gtk/gtkframe.c new file mode 100644 index 000000000..fe7889743 --- /dev/null +++ b/gtk/gtkframe.c @@ -0,0 +1,419 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkframe.h" + + +static void gtk_frame_class_init (GtkFrameClass *klass); +static void gtk_frame_init (GtkFrame *frame); +static void gtk_frame_destroy (GtkObject *object); +static void gtk_frame_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_frame_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_frame_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_frame_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +static GtkBinClass *parent_class = NULL; + + +guint +gtk_frame_get_type () +{ + static guint frame_type = 0; + + if (!frame_type) + { + GtkTypeInfo frame_info = + { + "GtkFrame", + sizeof (GtkFrame), + sizeof (GtkFrameClass), + (GtkClassInitFunc) gtk_frame_class_init, + (GtkObjectInitFunc) gtk_frame_init, + (GtkArgFunc) NULL, + }; + + frame_type = gtk_type_unique (gtk_bin_get_type (), &frame_info); + } + + return frame_type; +} + +static void +gtk_frame_class_init (GtkFrameClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_bin_get_type ()); + + object_class->destroy = gtk_frame_destroy; + + widget_class->draw = gtk_frame_draw; + widget_class->expose_event = gtk_frame_expose; + widget_class->size_request = gtk_frame_size_request; + widget_class->size_allocate = gtk_frame_size_allocate; +} + +static void +gtk_frame_init (GtkFrame *frame) +{ + GTK_WIDGET_SET_FLAGS (frame, GTK_BASIC); + + frame->label = NULL; + frame->shadow_type = GTK_SHADOW_ETCHED_IN; + frame->label_width = 0; + frame->label_height = 0; + frame->label_xalign = 0.0; + frame->label_yalign = 0.5; +} + +GtkWidget* +gtk_frame_new (const gchar *label) +{ + GtkFrame *frame; + + frame = gtk_type_new (gtk_frame_get_type ()); + + gtk_frame_set_label (frame, label); + + return GTK_WIDGET (frame); +} + +void +gtk_frame_set_label (GtkFrame *frame, + const gchar *label) +{ + g_return_if_fail (frame != NULL); + g_return_if_fail (GTK_IS_FRAME (frame)); + + if ((label && frame->label && (strcmp (frame->label, label) == 0)) || + (!label && !frame->label)) + return; + + if (frame->label) + g_free (frame->label); + frame->label = NULL; + + if (label) + { + frame->label = g_strdup (label); + frame->label_width = gdk_string_measure (GTK_WIDGET (frame)->style->font, frame->label) + 7; + frame->label_height = (GTK_WIDGET (frame)->style->font->ascent + + GTK_WIDGET (frame)->style->font->descent + 1); + } + else + { + frame->label_width = 0; + frame->label_height = 0; + } + + if (GTK_WIDGET_DRAWABLE (frame)) + { + GtkWidget *widget; + + /* clear the old label area + */ + widget = GTK_WIDGET (frame); + gdk_window_clear_area (widget->window, + widget->allocation.x + GTK_CONTAINER (frame)->border_width, + widget->allocation.y + GTK_CONTAINER (frame)->border_width, + widget->allocation.width - GTK_CONTAINER (frame)->border_width, + widget->allocation.y + frame->label_height); + + gtk_widget_queue_resize (GTK_WIDGET (frame)); + } +} + +void +gtk_frame_set_label_align (GtkFrame *frame, + gfloat xalign, + gfloat yalign) +{ + g_return_if_fail (frame != NULL); + g_return_if_fail (GTK_IS_FRAME (frame)); + + xalign = CLAMP (xalign, 0.0, 1.0); + yalign = CLAMP (yalign, 0.0, 1.0); + + if ((xalign != frame->label_xalign) || (yalign != frame->label_yalign)) + { + frame->label_xalign = xalign; + frame->label_yalign = yalign; + + if (GTK_WIDGET_VISIBLE (frame)) + { + GtkWidget *widget; + + /* clear the old label area + */ + widget = GTK_WIDGET (frame); + gdk_window_clear_area (widget->window, + widget->allocation.x + GTK_CONTAINER (frame)->border_width, + widget->allocation.y + GTK_CONTAINER (frame)->border_width, + widget->allocation.width - GTK_CONTAINER (frame)->border_width, + widget->allocation.y + frame->label_height); + + gtk_widget_size_allocate (GTK_WIDGET (frame), &(GTK_WIDGET (frame)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (frame)); + } + } +} + +void +gtk_frame_set_shadow_type (GtkFrame *frame, + GtkShadowType type) +{ + g_return_if_fail (frame != NULL); + g_return_if_fail (GTK_IS_FRAME (frame)); + + if ((GtkShadowType) frame->shadow_type != type) + { + frame->shadow_type = type; + + if (GTK_WIDGET_MAPPED (frame)) + { + gdk_window_clear_area (GTK_WIDGET (frame)->window, + GTK_WIDGET (frame)->allocation.x, + GTK_WIDGET (frame)->allocation.y, + GTK_WIDGET (frame)->allocation.width, + GTK_WIDGET (frame)->allocation.height); + gtk_widget_size_allocate (GTK_WIDGET (frame), &(GTK_WIDGET (frame)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (frame)); + } + } +} + + +static void +gtk_frame_destroy (GtkObject *object) +{ + GtkFrame *frame; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_FRAME (object)); + + frame = GTK_FRAME (object); + + if (frame->label) + g_free (frame->label); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_frame_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkFrame *frame; + GtkStateType state; + gint height_extra; + gint label_area_width; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FRAME (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + frame = GTK_FRAME (widget); + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + height_extra = frame->label_height - widget->style->klass->xthickness; + height_extra = MAX (height_extra, 0); + + x = GTK_CONTAINER (frame)->border_width; + y = GTK_CONTAINER (frame)->border_width; + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, frame->shadow_type, + widget->allocation.x + x, + widget->allocation.y + y + height_extra / 2, + widget->allocation.width - x * 2, + widget->allocation.height - y * 2 - height_extra / 2); + + if (frame->label) + { + label_area_width = (widget->allocation.width - + GTK_CONTAINER (frame)->border_width * 2 - + widget->style->klass->xthickness * 2); + + x = ((label_area_width - frame->label_width) * frame->label_xalign + + GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness); + y = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent); + + gdk_window_clear_area (widget->window, + widget->allocation.x + x + 2, + widget->allocation.y + GTK_CONTAINER (frame)->border_width, + frame->label_width - 4, + frame->label_height); + gtk_draw_string (widget->style, widget->window, state, + widget->allocation.x + x + 3, + widget->allocation.y + y, + frame->label); + } + } +} + +static void +gtk_frame_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FRAME (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_frame_paint (widget, area); + + if (bin->child && gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } +} + +static gint +gtk_frame_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_FRAME (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_frame_paint (widget, &event->area); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static void +gtk_frame_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkFrame *frame; + GtkBin *bin; + gint tmp_height; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FRAME (widget)); + g_return_if_fail (requisition != NULL); + + frame = GTK_FRAME (widget); + bin = GTK_BIN (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->xthickness) * 2; + + tmp_height = frame->label_height - GTK_WIDGET (widget)->style->klass->ythickness; + tmp_height = MAX (tmp_height, 0); + + requisition->height = tmp_height + (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->ythickness) * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += MAX (bin->child->requisition.width, frame->label_width); + requisition->height += bin->child->requisition.height; + } + else + { + requisition->width += frame->label_width; + } +} + +static void +gtk_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkFrame *frame; + GtkBin *bin; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_FRAME (widget)); + g_return_if_fail (allocation != NULL); + + frame = GTK_FRAME (widget); + bin = GTK_BIN (widget); + + if (GTK_WIDGET_MAPPED (widget) && + ((widget->allocation.x != allocation->x) || + (widget->allocation.y != allocation->y) || + (widget->allocation.width != allocation->width) || + (widget->allocation.height != allocation->height)) && + (widget->allocation.width != 0) && + (widget->allocation.height != 0)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + + widget->allocation = *allocation; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + child_allocation.x = (GTK_CONTAINER (frame)->border_width + + GTK_WIDGET (frame)->style->klass->xthickness); + child_allocation.width = MAX(0, allocation->width - child_allocation.x * 2); + + child_allocation.y = (GTK_CONTAINER (frame)->border_width + + MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness)); + child_allocation.height = MAX (0, (allocation->height - child_allocation.y - + GTK_CONTAINER (frame)->border_width - + GTK_WIDGET (frame)->style->klass->ythickness)); + + child_allocation.x += allocation->x; + child_allocation.y += allocation->y; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} diff --git a/gtk/gtkframe.h b/gtk/gtkframe.h new file mode 100644 index 000000000..3fe17a3cb --- /dev/null +++ b/gtk/gtkframe.h @@ -0,0 +1,73 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_FRAME_H__ +#define __GTK_FRAME_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_FRAME(obj) GTK_CHECK_CAST (obj, gtk_frame_get_type (), GtkFrame) +#define GTK_FRAME_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_frame_get_type (), GtkFrameClass) +#define GTK_IS_FRAME(obj) GTK_CHECK_TYPE (obj, gtk_frame_get_type ()) + + +typedef struct _GtkFrame GtkFrame; +typedef struct _GtkFrameClass GtkFrameClass; + +struct _GtkFrame +{ + GtkBin bin; + + gchar *label; + gint16 shadow_type; + gint16 label_width; + gint16 label_height; + gfloat label_xalign; + gfloat label_yalign; +}; + +struct _GtkFrameClass +{ + GtkBinClass parent_class; +}; + + +guint gtk_frame_get_type (void); +GtkWidget* gtk_frame_new (const gchar *label); +void gtk_frame_set_label (GtkFrame *frame, + const gchar *label); +void gtk_frame_set_label_align (GtkFrame *frame, + gfloat xalign, + gfloat yalign); +void gtk_frame_set_shadow_type (GtkFrame *frame, + GtkShadowType type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_FRAME_H__ */ diff --git a/gtk/gtkgamma.c b/gtk/gtkgamma.c new file mode 100644 index 000000000..1d7abc6fb --- /dev/null +++ b/gtk/gtkgamma.c @@ -0,0 +1,464 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1997 David Mosberger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include + +#include "gtkgamma.h" +#include "gtkcurve.h" +#include "gtkdialog.h" +#include "gtkdrawingarea.h" +#include "gtkentry.h" +#include "gtkhbox.h" +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtkpixmap.h" +#include "gtkradiobutton.h" +#include "gtksignal.h" +#include "gtktable.h" +#include "gtkvbox.h" +#include "gtkwindow.h" + +static GtkVBoxClass *parent_class = NULL; + + +/* forward declarations: */ +static void gtk_gamma_curve_class_init (GtkGammaCurveClass *class); +static void gtk_gamma_curve_init (GtkGammaCurve *curve); +static void gtk_gamma_curve_destroy (GtkObject *object); + +enum + { + LINEAR = 0, + SPLINE, + FREE, + GAMMA, + RESET, + NUM_XPMS + }; + +static char *xpm[][27] = + { + /* spline: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 4 1", + /* colors */ + ". c None", + "B c #000000", + "+ c #BC2D2D", + "r c #FF0000", + /* pixels */ + "..............BB", + ".........rrrrrrB", + ".......rr.......", + ".....B+.........", + "....BBB.........", + "....+B..........", + "....r...........", + "...r............", + "...r............", + "..r.............", + "..r.............", + ".r..............", + ".r..............", + ".r..............", + "B+..............", + "BB.............." + }, + /* linear: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 5 1", + /* colors */ + ". c None", /* transparent */ + "B c #000000", + "' c #7F7F7F", + "+ c #824141", + "r c #FF0000", + /* pixels */ + "..............BB", + "..............+B", + "..............r.", + ".............r..", + ".............r..", + "....'B'.....r...", + "....BBB.....r...", + "....+B+....r....", + "....r.r....r....", + "...r...r..r.....", + "...r...r..r.....", + "..r.....rB+.....", + "..r.....BBB.....", + ".r......'B'.....", + "B+..............", + "BB.............." + }, + /* free: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 2 1", + /* colors */ + ". c None", + "r c #FF0000", + /* pixels */ + "................", + "................", + "......r.........", + "......r.........", + ".......r........", + ".......r........", + ".......r........", + "........r.......", + "........r.......", + "........r.......", + ".....r...r.rrrrr", + "....r....r......", + "...r.....r......", + "..r.......r.....", + ".r........r.....", + "r..............." + }, + /* gamma: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 10 1", + /* colors */ + ". c None", + "B c #000000", + "& c #171717", + "# c #2F2F2F", + "X c #464646", + "= c #5E5E5E", + "/ c #757575", + "+ c #8C8C8C", + "- c #A4A4A4", + "` c #BBBBBB", + /* pixels */ + "................", + "................", + "................", + "....B=..+B+.....", + "....X&`./&-.....", + "...../+.XX......", + "......B.B+......", + "......X.X.......", + "......X&+.......", + "......-B........", + "....../=........", + "......#B........", + "......BB........", + "......B#........", + "................", + "................" + }, + /* reset: */ + { + /* width height ncolors chars_per_pixel */ + "16 16 4 1", + /* colors */ + ". c None", + "B c #000000", + "+ c #824141", + "r c #FF0000", + /* pixels */ + "..............BB", + "..............+B", + ".............r..", + "............r...", + "...........r....", + "..........r.....", + ".........r......", + "........r.......", + ".......r........", + "......r.........", + ".....r..........", + "....r...........", + "...r............", + "..r.............", + "B+..............", + "BB.............." + } + }; + +guint +gtk_gamma_curve_get_type (void) +{ + static guint gamma_curve_type = 0; + + if (!gamma_curve_type) + { + GtkTypeInfo gamma_curve_info = + { + "GtkGammaCurve", + sizeof (GtkGammaCurve), + sizeof (GtkGammaCurveClass), + (GtkClassInitFunc) gtk_gamma_curve_class_init, + (GtkObjectInitFunc) gtk_gamma_curve_init, + (GtkArgFunc) NULL, + }; + + gamma_curve_type = + gtk_type_unique (gtk_vbox_get_type (), &gamma_curve_info); + } + return gamma_curve_type; +} + +static void +gtk_gamma_curve_class_init (GtkGammaCurveClass *class) +{ + GtkObjectClass *object_class; + + parent_class = gtk_type_class (gtk_vbox_get_type ()); + + object_class = (GtkObjectClass *) class; + object_class->destroy = gtk_gamma_curve_destroy; +} + +static void +gtk_gamma_curve_init (GtkGammaCurve *curve) +{ + curve->gamma = 1.0; +} + +static void +button_realize_callback (GtkWidget *w) +{ + GtkWidget *pixmap; + GdkBitmap *mask; + GdkPixmap *pm; + int i; + + i = (long) gtk_object_get_data (GTK_OBJECT (w), "_GtkGammaCurveIndex"); + pm = gdk_pixmap_create_from_xpm_d (w->window, &mask, + &w->style->bg[GTK_STATE_NORMAL], xpm[i]); + + pixmap = gtk_pixmap_new (pm, mask); + gtk_container_add (GTK_CONTAINER (w), pixmap); + gtk_widget_show (pixmap); + + gdk_pixmap_destroy (pm); + gdk_pixmap_destroy (mask); /* a bitmap is really just a special pixmap */ +} + +static void +button_toggled_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + GtkCurveType type; + int active, i; + + if (!GTK_TOGGLE_BUTTON (w)->active) + return; + + active = (long) gtk_object_get_data (GTK_OBJECT (w), "_GtkGammaCurveIndex"); + + for (i = 0; i < 3; ++i) + if ((i != active) && GTK_TOGGLE_BUTTON (c->button[i])->active) + break; + + if (i < 3) + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (c->button[i]), FALSE); + + switch (active) + { + case 0: type = GTK_CURVE_TYPE_SPLINE; break; + case 1: type = GTK_CURVE_TYPE_LINEAR; break; + default: type = GTK_CURVE_TYPE_FREE; break; + } + gtk_curve_set_curve_type (GTK_CURVE (c->curve), type); +} + +static void +gamma_cancel_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + + gtk_widget_destroy (c->gamma_dialog); + c->gamma_dialog = 0; +} + +static void +gamma_ok_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + gchar *start, *end; + gfloat v; + + start = gtk_entry_get_text (GTK_ENTRY (c->gamma_text)); + if (start) + { + v = strtod (start, &end); + if (end > start && v > 0.0) + c->gamma = v; + } + gtk_curve_set_gamma (GTK_CURVE (c->curve), c->gamma); + gamma_cancel_callback (w, data); +} + +static void +button_clicked_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + int active; + + active = (long) gtk_object_get_data (GTK_OBJECT (w), "_GtkGammaCurveIndex"); + if (active == 3) + /* set gamma */ + if (c->gamma_dialog) + return; + else + { + GtkWidget *vbox, *hbox, *label, *button; + gchar buf[64]; + + c->gamma_dialog = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (c->gamma_dialog), "Gamma"); + vbox = GTK_DIALOG (c->gamma_dialog)->vbox; + + hbox = gtk_hbox_new (/* homogeneous */ FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 2); + gtk_widget_show (hbox); + + label = gtk_label_new ("Gamma value"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2); + gtk_widget_show (label); + + sprintf (buf, "%g", c->gamma); + c->gamma_text = gtk_entry_new (); + gtk_entry_set_text (GTK_ENTRY (c->gamma_text), buf); + gtk_box_pack_start (GTK_BOX (hbox), c->gamma_text, TRUE, TRUE, 2); + gtk_widget_show (c->gamma_text); + + /* fill in action area: */ + hbox = GTK_DIALOG (c->gamma_dialog)->action_area; + + button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gamma_ok_callback, c); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Cancel"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gamma_cancel_callback, c); + gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_widget_show (c->gamma_dialog); + } + else + /* reset */ + gtk_curve_reset (GTK_CURVE (c->curve)); +} + +static void +curve_type_changed_callback (GtkWidget *w, gpointer data) +{ + GtkGammaCurve *c = data; + GtkCurveType new_type; + int active; + + new_type = GTK_CURVE (w)->curve_type; + switch (new_type) + { + case GTK_CURVE_TYPE_SPLINE: active = 0; break; + case GTK_CURVE_TYPE_LINEAR: active = 1; break; + default: active = 2; break; + } + if (!GTK_TOGGLE_BUTTON (c->button[active])->active) + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (c->button[active]), TRUE); +} + +GtkWidget* +gtk_gamma_curve_new (void) +{ + GtkGammaCurve *c; + GtkWidget *vbox; + int i; + + c = gtk_type_new (gtk_gamma_curve_get_type ()); + + c->table = gtk_table_new (1, 2, FALSE); + gtk_table_set_col_spacings (GTK_TABLE (c->table), 3); + gtk_container_add (GTK_CONTAINER (c), c->table); + + c->curve = gtk_curve_new (); + gtk_signal_connect (GTK_OBJECT (c->curve), "curve_type_changed", + (GtkSignalFunc) curve_type_changed_callback, c); + gtk_table_attach_defaults (GTK_TABLE (c->table), c->curve, 0, 1, 0, 1); + + vbox = gtk_vbox_new (/* homogeneous */ FALSE, /* spacing */ 3); + gtk_table_attach (GTK_TABLE (c->table), vbox, 1, 2, 0, 1, 0, 0, 0, 0); + + /* toggle buttons: */ + for (i = 0; i < 3; ++i) + { + c->button[i] = gtk_toggle_button_new (); + gtk_object_set_data (GTK_OBJECT (c->button[i]), "_GtkGammaCurveIndex", + (gpointer) (long) i); + gtk_container_add (GTK_CONTAINER (vbox), c->button[i]); + gtk_signal_connect (GTK_OBJECT (c->button[i]), "realize", + (GtkSignalFunc) button_realize_callback, 0); + gtk_signal_connect (GTK_OBJECT (c->button[i]), "toggled", + (GtkSignalFunc) button_toggled_callback, c); + gtk_widget_show (c->button[i]); + } + + /* push buttons: */ + for (i = 3; i < 5; ++i) + { + c->button[i] = gtk_button_new (); + gtk_object_set_data (GTK_OBJECT (c->button[i]), "_GtkGammaCurveIndex", + (gpointer) (long) i); + gtk_container_add (GTK_CONTAINER (vbox), c->button[i]); + gtk_signal_connect (GTK_OBJECT (c->button[i]), "realize", + (GtkSignalFunc) button_realize_callback, 0); + gtk_signal_connect (GTK_OBJECT (c->button[i]), "clicked", + (GtkSignalFunc) button_clicked_callback, c); + gtk_widget_show (c->button[i]); + } + + gtk_widget_show (vbox); + gtk_widget_show (c->table); + gtk_widget_show (c->curve); + + return GTK_WIDGET (c); +} + +static void +gtk_gamma_curve_destroy (GtkObject *object) +{ + GtkGammaCurve *c; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_GAMMA_CURVE (object)); + + c = GTK_GAMMA_CURVE (object); + + if (c->gamma_dialog) + { + gtk_widget_destroy (c->gamma_dialog); + c->gamma_dialog = 0; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} diff --git a/gtk/gtkgamma.h b/gtk/gtkgamma.h new file mode 100644 index 000000000..872a7bd43 --- /dev/null +++ b/gtk/gtkgamma.h @@ -0,0 +1,71 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1997 David Mosberger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_GAMMA_CURVE_H__ +#define __GTK_GAMMA_CURVE_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_GAMMA_CURVE(obj) \ + GTK_CHECK_CAST (obj, gtk_gamma_curve_get_type (), GtkGammaCurve) +#define GTK_GAMMA_CURVE_CLASS(klass) \ + GTK_CHECK_CLASS_CAST (klass, gtk_gamma_curve_get_type, GtkGammaCurveClass) +#define GTK_IS_GAMMA_CURVE(obj) \ + GTK_CHECK_TYPE (obj, gtk_gamma_curve_get_type ()) + + +typedef struct _GtkGammaCurve GtkGammaCurve; +typedef struct _GtkGammaCurveClass GtkGammaCurveClass; + + +struct _GtkGammaCurve +{ + GtkVBox vbox; + + GtkWidget *table; + GtkWidget *curve; + GtkWidget *button[5]; /* spline, linear, free, gamma, reset */ + + gfloat gamma; + GtkWidget *gamma_dialog; + GtkWidget *gamma_text; +}; + +struct _GtkGammaCurveClass +{ + GtkVBoxClass parent_class; +}; + + +guint gtk_gamma_curve_get_type (void); +GtkWidget* gtk_gamma_curve_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_GAMMA_CURVE_H__ */ diff --git a/gtk/gtkgc.c b/gtk/gtkgc.c new file mode 100644 index 000000000..c9da06984 --- /dev/null +++ b/gtk/gtkgc.c @@ -0,0 +1,382 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkgc.h" + + +typedef struct _GtkGCKey GtkGCKey; +typedef struct _GtkGCDrawable GtkGCDrawable; + +struct _GtkGCKey +{ + gint depth; + GdkColormap *colormap; + GdkGCValues values; + GdkGCValuesMask mask; +}; + +struct _GtkGCDrawable +{ + gint depth; + GdkPixmap *drawable; +}; + + +static void gtk_gc_init (void); +static GtkGCKey* gtk_gc_key_dup (GtkGCKey *key); +static void gtk_gc_key_destroy (GtkGCKey *key); +static gpointer gtk_gc_new (gpointer key); +static void gtk_gc_destroy (gpointer value); +static guint gtk_gc_key_hash (gpointer key); +static guint gtk_gc_value_hash (gpointer value); +static gint gtk_gc_key_compare (gpointer a, + gpointer b); +static guint gtk_gc_drawable_hash (GtkGCDrawable *d); +static gint gtk_gc_drawable_compare (GtkGCDrawable *a, + GtkGCDrawable *b); + + +static gint initialize = TRUE; +static GCache *gc_cache = NULL; +static GHashTable *gc_drawable_ht = NULL; + +static GMemChunk *key_mem_chunk = NULL; + + +GdkGC* +gtk_gc_get (gint depth, + GdkColormap *colormap, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GtkGCKey key; + GdkGC *gc; + + if (initialize) + gtk_gc_init (); + + key.depth = depth; + key.colormap = colormap; + key.values = *values; + key.mask = values_mask; + + gc = g_cache_insert (gc_cache, &key); + + return gc; +} + +void +gtk_gc_release (GdkGC *gc) +{ + if (initialize) + gtk_gc_init (); + + g_cache_remove (gc_cache, gc); +} + + +static void +gtk_gc_init () +{ + initialize = FALSE; + + gc_cache = g_cache_new ((GCacheNewFunc) gtk_gc_new, + (GCacheDestroyFunc) gtk_gc_destroy, + (GCacheDupFunc) gtk_gc_key_dup, + (GCacheDestroyFunc) gtk_gc_key_destroy, + (GHashFunc) gtk_gc_key_hash, + (GHashFunc) gtk_gc_value_hash, + (GCompareFunc) gtk_gc_key_compare); + + gc_drawable_ht = g_hash_table_new ((GHashFunc) gtk_gc_drawable_hash, + (GCompareFunc) gtk_gc_drawable_compare); +} + +static GtkGCKey* +gtk_gc_key_dup (GtkGCKey *key) +{ + GtkGCKey *new_key; + + if (!key_mem_chunk) + key_mem_chunk = g_mem_chunk_new ("key mem chunk", sizeof (GtkGCKey), + 1024, G_ALLOC_AND_FREE); + + new_key = g_chunk_new (GtkGCKey, key_mem_chunk); + + *new_key = *key; + + return new_key; +} + +static void +gtk_gc_key_destroy (GtkGCKey *key) +{ + g_mem_chunk_free (key_mem_chunk, key); +} + +static gpointer +gtk_gc_new (gpointer key) +{ + GtkGCKey *keyval; + GtkGCDrawable *drawable; + GdkGC *gc; + + keyval = key; + + drawable = g_hash_table_lookup (gc_drawable_ht, &keyval->depth); + if (!drawable) + { + drawable = g_new (GtkGCDrawable, 1); + drawable->depth = keyval->depth; + drawable->drawable = gdk_pixmap_new (NULL, 1, 1, drawable->depth); + + g_hash_table_insert (gc_drawable_ht, &drawable->depth, drawable); + } + + gc = gdk_gc_new_with_values (drawable->drawable, &keyval->values, keyval->mask); + + return (gpointer) gc; +} + +static void +gtk_gc_destroy (gpointer value) +{ + gdk_gc_destroy ((GdkGC*) value); +} + +static guint +gtk_gc_key_hash (gpointer key) +{ + GtkGCKey *keyval; + guint hash_val; + + keyval = key; + hash_val = 0; + + if (keyval->mask & GDK_GC_FOREGROUND) + { + hash_val += keyval->values.foreground.pixel; + } + if (keyval->mask & GDK_GC_BACKGROUND) + { + hash_val += keyval->values.background.pixel; + } + if (keyval->mask & GDK_GC_FONT) + { + hash_val += gdk_font_id (keyval->values.font); + } + if (keyval->mask & GDK_GC_FUNCTION) + { + hash_val += (gint) keyval->values.function; + } + if (keyval->mask & GDK_GC_FILL) + { + hash_val += (gint) keyval->values.fill; + } + if (keyval->mask & GDK_GC_TILE) + { + hash_val += (glong) keyval->values.tile; + } + if (keyval->mask & GDK_GC_STIPPLE) + { + hash_val += (glong) keyval->values.stipple; + } + if (keyval->mask & GDK_GC_CLIP_MASK) + { + hash_val += (glong) keyval->values.clip_mask; + } + if (keyval->mask & GDK_GC_SUBWINDOW) + { + hash_val += (gint) keyval->values.subwindow_mode; + } + if (keyval->mask & GDK_GC_TS_X_ORIGIN) + { + hash_val += (gint) keyval->values.ts_x_origin; + } + if (keyval->mask & GDK_GC_TS_Y_ORIGIN) + { + hash_val += (gint) keyval->values.ts_y_origin; + } + if (keyval->mask & GDK_GC_CLIP_X_ORIGIN) + { + hash_val += (gint) keyval->values.clip_x_origin; + } + if (keyval->mask & GDK_GC_CLIP_Y_ORIGIN) + { + hash_val += (gint) keyval->values.clip_y_origin; + } + if (keyval->mask & GDK_GC_EXPOSURES) + { + hash_val += (gint) keyval->values.graphics_exposures; + } + if (keyval->mask & GDK_GC_LINE_WIDTH) + { + hash_val += (gint) keyval->values.line_width; + } + if (keyval->mask & GDK_GC_LINE_STYLE) + { + hash_val += (gint) keyval->values.line_style; + } + if (keyval->mask & GDK_GC_CAP_STYLE) + { + hash_val += (gint) keyval->values.cap_style; + } + if (keyval->mask & GDK_GC_JOIN_STYLE) + { + hash_val += (gint) keyval->values.join_style; + } + + return hash_val; +} + +static guint +gtk_gc_value_hash (gpointer value) +{ + return (gulong) value; +} + +static gint +gtk_gc_key_compare (gpointer a, + gpointer b) +{ + GtkGCKey *akey; + GtkGCKey *bkey; + GdkGCValues *avalues; + GdkGCValues *bvalues; + + akey = a; + bkey = b; + + avalues = &akey->values; + bvalues = &bkey->values; + + if (akey->mask != bkey->mask) + return FALSE; + + if (akey->depth != bkey->depth) + return FALSE; + + if (akey->colormap != bkey->colormap) + return FALSE; + + if (akey->mask & GDK_GC_FOREGROUND) + { + if (avalues->foreground.pixel != bvalues->foreground.pixel) + return FALSE; + } + if (akey->mask & GDK_GC_BACKGROUND) + { + if (avalues->background.pixel != bvalues->background.pixel) + return FALSE; + } + if (akey->mask & GDK_GC_FONT) + { + if (!gdk_font_equal (avalues->font, bvalues->font)) + return FALSE; + } + if (akey->mask & GDK_GC_FUNCTION) + { + if (avalues->function != bvalues->function) + return FALSE; + } + if (akey->mask & GDK_GC_FILL) + { + if (avalues->fill != bvalues->fill) + return FALSE; + } + if (akey->mask & GDK_GC_TILE) + { + if (avalues->tile != bvalues->tile) + return FALSE; + } + if (akey->mask & GDK_GC_STIPPLE) + { + if (avalues->stipple != bvalues->stipple) + return FALSE; + } + if (akey->mask & GDK_GC_CLIP_MASK) + { + if (avalues->clip_mask != bvalues->clip_mask) + return FALSE; + } + if (akey->mask & GDK_GC_SUBWINDOW) + { + if (avalues->subwindow_mode != bvalues->subwindow_mode) + return FALSE; + } + if (akey->mask & GDK_GC_TS_X_ORIGIN) + { + if (avalues->ts_x_origin != bvalues->ts_x_origin) + return FALSE; + } + if (akey->mask & GDK_GC_TS_Y_ORIGIN) + { + if (avalues->ts_y_origin != bvalues->ts_y_origin) + return FALSE; + } + if (akey->mask & GDK_GC_CLIP_X_ORIGIN) + { + if (avalues->clip_x_origin != bvalues->clip_x_origin) + return FALSE; + } + if (akey->mask & GDK_GC_CLIP_Y_ORIGIN) + { + if (avalues->clip_y_origin != bvalues->clip_y_origin) + return FALSE; + } + if (akey->mask & GDK_GC_EXPOSURES) + { + if (avalues->graphics_exposures != bvalues->graphics_exposures) + return FALSE; + } + if (akey->mask & GDK_GC_LINE_WIDTH) + { + if (avalues->line_width != bvalues->line_width) + return FALSE; + } + if (akey->mask & GDK_GC_LINE_STYLE) + { + if (avalues->line_style != bvalues->line_style) + return FALSE; + } + if (akey->mask & GDK_GC_CAP_STYLE) + { + if (avalues->cap_style != bvalues->cap_style) + return FALSE; + } + if (akey->mask & GDK_GC_JOIN_STYLE) + { + if (avalues->join_style != bvalues->join_style) + return FALSE; + } + + return TRUE; +} + + +static guint +gtk_gc_drawable_hash (GtkGCDrawable *d) +{ + return d->depth; +} + +static gint +gtk_gc_drawable_compare (GtkGCDrawable *a, + GtkGCDrawable *b) +{ + return (a->depth == b->depth); +} diff --git a/gtk/gtkgc.h b/gtk/gtkgc.h new file mode 100644 index 000000000..ff4ecc466 --- /dev/null +++ b/gtk/gtkgc.h @@ -0,0 +1,42 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_GC_H__ +#define __GTK_GC_H__ + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +GdkGC* gtk_gc_get (gint depth, + GdkColormap *colormap, + GdkGCValues *values, + GdkGCValuesMask values_mask); +void gtk_gc_release (GdkGC *gc); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_GC_H__ */ diff --git a/gtk/gtkhbbox.c b/gtk/gtkhbbox.c new file mode 100644 index 000000000..9d86c010e --- /dev/null +++ b/gtk/gtkhbbox.c @@ -0,0 +1,269 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "gtkhbbox.h" + + +static void gtk_hbutton_box_class_init (GtkHButtonBoxClass *klass); +static void gtk_hbutton_box_init (GtkHButtonBox *box); +static void gtk_hbutton_box_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hbutton_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +static gint default_spacing = 30; +static gint default_layout_style = GTK_BUTTONBOX_EDGE; + +guint +gtk_hbutton_box_get_type () +{ + static guint hbutton_box_type = 0; + + if (!hbutton_box_type) + { + GtkTypeInfo hbutton_box_info = + { + "GtkHButtonBox", + sizeof (GtkHButtonBox), + sizeof (GtkHButtonBoxClass), + (GtkClassInitFunc) gtk_hbutton_box_class_init, + (GtkObjectInitFunc) gtk_hbutton_box_init, + (GtkArgFunc) NULL, + }; + + hbutton_box_type = gtk_type_unique (gtk_button_box_get_type (), &hbutton_box_info); + } + + return hbutton_box_type; +} + +static void +gtk_hbutton_box_class_init (GtkHButtonBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_hbutton_box_size_request; + widget_class->size_allocate = gtk_hbutton_box_size_allocate; +} + +static void +gtk_hbutton_box_init (GtkHButtonBox *hbutton_box) +{ + /* button_box_init has done everything allready */ +} + +GtkWidget* +gtk_hbutton_box_new () +{ + GtkHButtonBox *hbutton_box; + + hbutton_box = gtk_type_new (gtk_hbutton_box_get_type ()); + + return GTK_WIDGET (hbutton_box); +} + + +/* set default value for spacing */ + +void gtk_hbutton_box_set_spacing_default (gint spacing) +{ + default_spacing = spacing; +} + + +/* set default value for layout style */ + +void gtk_hbutton_box_set_layout_default (gint layout) +{ + default_layout_style = layout; +} + +/* get default value for spacing */ + +gint gtk_hbutton_box_get_spacing_default (void) +{ + return default_spacing; +} + + +/* get default value for layout style */ + +gint gtk_hbutton_box_get_layout_default (void) +{ + return default_layout_style; +} + + + +static void +gtk_hbutton_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBox *box; + GtkButtonBox *bbox; + gint nvis_children; + gint child_width; + gint child_height; + gint spacing; + gint layout; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HBUTTON_BOX (widget)); + g_return_if_fail (requisition != NULL); + + box = GTK_BOX (widget); + bbox = GTK_BUTTON_BOX (widget); + + spacing = bbox->spacing != GTK_BUTTONBOX_DEFAULT + ? bbox->spacing : default_spacing; + layout = bbox->layout_style != GTK_BUTTONBOX_DEFAULT + ? bbox->layout_style : default_layout_style; + + gtk_button_box_child_requisition (widget, + &nvis_children, + &child_width, + &child_height); + + if (nvis_children == 0) + { + requisition->width = 0; + requisition->height = 0; + } + else + { + switch (layout) + { + case GTK_BUTTONBOX_SPREAD: + requisition->width = + nvis_children*child_width + ((nvis_children+1)*spacing); + break; + case GTK_BUTTONBOX_EDGE: + case GTK_BUTTONBOX_START: + case GTK_BUTTONBOX_END: + requisition->width = nvis_children*child_width + ((nvis_children-1)*spacing); + break; + default: + g_assert_not_reached(); + break; + } + + requisition->height = child_height; + } + + requisition->width += GTK_CONTAINER (box)->border_width * 2; + requisition->height += GTK_CONTAINER (box)->border_width * 2; +} + + + +static void +gtk_hbutton_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkButtonBox *box; + GtkHButtonBox *hbox; + GtkBoxChild *child; + GList *children; + GtkAllocation child_allocation; + gint nvis_children; + gint child_width; + gint child_height; + gint x = 0; + gint y = 0; + gint width; + gint childspace; + gint childspacing = 0; + gint layout; + gint spacing; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HBUTTON_BOX (widget)); + g_return_if_fail (allocation != NULL); + + box = GTK_BUTTON_BOX (widget); + hbox = GTK_HBUTTON_BOX (widget); + spacing = box->spacing != GTK_BUTTONBOX_DEFAULT + ? box->spacing : default_spacing; + layout = box->layout_style != GTK_BUTTONBOX_DEFAULT + ? box->layout_style : default_layout_style; + gtk_button_box_child_requisition (widget, + &nvis_children, + &child_width, + &child_height); + widget->allocation = *allocation; + width = allocation->width - GTK_CONTAINER (box)->border_width*2; + switch (layout) + { + case GTK_BUTTONBOX_SPREAD: + childspacing = (width - (nvis_children*child_width)) / (nvis_children+1); + x = allocation->x + GTK_CONTAINER (box)->border_width + childspacing; + break; + case GTK_BUTTONBOX_EDGE: + if (nvis_children >= 2) + { + childspacing = + (width - (nvis_children*child_width)) / (nvis_children-1); + x = allocation->x + GTK_CONTAINER (box)->border_width; + } + else + { + /* one or zero children, just center */ + childspacing = width; + x = allocation->x + (allocation->width - child_width) / 2; + } + break; + case GTK_BUTTONBOX_START: + childspacing = spacing; + x = allocation->x + GTK_CONTAINER (box)->border_width; + break; + case GTK_BUTTONBOX_END: + childspacing = spacing; + x = allocation->x + allocation->width - child_width * nvis_children + - spacing *(nvis_children-1) + - GTK_CONTAINER (box)->border_width; + break; + default: + g_assert_not_reached(); + break; + } + + + y = allocation->y + (allocation->height - child_height) / 2; + childspace = child_width + childspacing; + + children = GTK_BOX (box)->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + child_allocation.width = child_width; + child_allocation.height = child_height; + child_allocation.x = x; + child_allocation.y = y; + gtk_widget_size_allocate (child->widget, &child_allocation); + x += childspace; + } + } +} + diff --git a/gtk/gtkhbbox.h b/gtk/gtkhbbox.h new file mode 100644 index 000000000..c61c138b9 --- /dev/null +++ b/gtk/gtkhbbox.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_HBUTTON_BOX_H__ +#define __GTK_HBUTTON_BOX_H__ + + +#include "gtk/gtkbbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HBUTTON_BOX(obj) GTK_CHECK_CAST (obj, gtk_hbutton_box_get_type (), GtkHButtonBox) +#define GTK_HBUTTON_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hbutton_box_get_type (), GtkHButtonBoxClass) +#define GTK_IS_HBUTTON_BOX(obj) GTK_CHECK_TYPE (obj, gtk_hbutton_box_get_type ()) + + +typedef struct _GtkHButtonBox GtkHButtonBox; +typedef struct _GtkHButtonBoxClass GtkHButtonBoxClass; + +struct _GtkHButtonBox +{ + GtkButtonBox button_box; +}; + +struct _GtkHButtonBoxClass +{ + GtkButtonBoxClass parent_class; +}; + + +guint gtk_hbutton_box_get_type (void); +GtkWidget *gtk_hbutton_box_new (void); + +/* buttons can be added by gtk_container_add() */ + +gint gtk_hbutton_box_get_spacing_default (void); +gint gtk_hbutton_box_get_layout_default (void); + +void gtk_hbutton_box_set_spacing_default (gint spacing); +void gtk_hbutton_box_set_layout_default (gint layout); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HBUTTON_BOX_H__ */ diff --git a/gtk/gtkhbox.c b/gtk/gtkhbox.c new file mode 100644 index 000000000..4cdc926cd --- /dev/null +++ b/gtk/gtkhbox.c @@ -0,0 +1,306 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkhbox.h" + + +static void gtk_hbox_class_init (GtkHBoxClass *klass); +static void gtk_hbox_init (GtkHBox *box); +static void gtk_hbox_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hbox_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +guint +gtk_hbox_get_type () +{ + static guint hbox_type = 0; + + if (!hbox_type) + { + GtkTypeInfo hbox_info = + { + "GtkHBox", + sizeof (GtkHBox), + sizeof (GtkHBoxClass), + (GtkClassInitFunc) gtk_hbox_class_init, + (GtkObjectInitFunc) gtk_hbox_init, + (GtkArgFunc) NULL, + }; + + hbox_type = gtk_type_unique (gtk_box_get_type (), &hbox_info); + } + + return hbox_type; +} + +static void +gtk_hbox_class_init (GtkHBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_hbox_size_request; + widget_class->size_allocate = gtk_hbox_size_allocate; +} + +static void +gtk_hbox_init (GtkHBox *hbox) +{ +} + +GtkWidget* +gtk_hbox_new (gint homogeneous, + gint spacing) +{ + GtkHBox *hbox; + + hbox = gtk_type_new (gtk_hbox_get_type ()); + + GTK_BOX (hbox)->spacing = spacing; + GTK_BOX (hbox)->homogeneous = homogeneous ? TRUE : FALSE; + + return GTK_WIDGET (hbox); +} + + +static void +gtk_hbox_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + gint nvis_children; + gint width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HBOX (widget)); + g_return_if_fail (requisition != NULL); + + box = GTK_BOX (widget); + requisition->width = 0; + requisition->height = 0; + nvis_children = 0; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + gtk_widget_size_request (child->widget, &child->widget->requisition); + + if (box->homogeneous) + { + width = child->widget->requisition.width + child->padding * 2; + requisition->width = MAX (requisition->width, width); + } + else + { + requisition->width += child->widget->requisition.width + child->padding * 2; + } + + requisition->height = MAX (requisition->height, child->widget->requisition.height); + + nvis_children += 1; + } + } + + if (nvis_children > 0) + { + if (box->homogeneous) + requisition->width *= nvis_children; + requisition->width += (nvis_children - 1) * box->spacing; + } + + requisition->width += GTK_CONTAINER (box)->border_width * 2; + requisition->height += GTK_CONTAINER (box)->border_width * 2; +} + +static void +gtk_hbox_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + GtkAllocation child_allocation; + gint nvis_children; + gint nexpand_children; + gint child_width; + gint width; + gint extra; + gint x; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HBOX (widget)); + g_return_if_fail (allocation != NULL); + + box = GTK_BOX (widget); + widget->allocation = *allocation; + + nvis_children = 0; + nexpand_children = 0; + children = box->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + nvis_children += 1; + if (child->expand) + nexpand_children += 1; + } + } + + if (nvis_children > 0) + { + if (box->homogeneous) + { + width = (allocation->width - + GTK_CONTAINER (box)->border_width * 2 - + (nvis_children - 1) * box->spacing); + extra = width / nvis_children; + } + else if (nexpand_children > 0) + { + width = allocation->width - widget->requisition.width; + extra = width / nexpand_children; + } + else + { + width = 0; + extra = 0; + } + + x = allocation->x + GTK_CONTAINER (box)->border_width; + child_allocation.y = allocation->y + GTK_CONTAINER (box)->border_width; + child_allocation.height = allocation->height - GTK_CONTAINER (box)->border_width * 2; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget)) + { + if (box->homogeneous) + { + if (nvis_children == 1) + child_width = width; + else + child_width = extra; + + nvis_children -= 1; + width -= extra; + } + else + { + child_width = child->widget->requisition.width + child->padding * 2; + + if (child->expand) + { + if (nexpand_children == 1) + child_width += width; + else + child_width += extra; + + nexpand_children -= 1; + width -= extra; + } + } + + if (child->fill) + { + child_allocation.width = child_width - child->padding * 2; + child_allocation.x = x + child->padding; + } + else + { + child_allocation.width = child->widget->requisition.width; + child_allocation.x = x + (child_width - child_allocation.width) / 2; + } + + gtk_widget_size_allocate (child->widget, &child_allocation); + + x += child_width + box->spacing; + } + } + + x = allocation->x + allocation->width - GTK_CONTAINER (box)->border_width; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget)) + { + if (box->homogeneous) + { + if (nvis_children == 1) + child_width = width; + else + child_width = extra; + + nvis_children -= 1; + width -= extra; + } + else + { + child_width = child->widget->requisition.width + child->padding * 2; + + if (child->expand) + { + if (nexpand_children == 1) + child_width += width; + else + child_width += extra; + + nexpand_children -= 1; + width -= extra; + } + } + + if (child->fill) + { + child_allocation.width = child_width - child->padding * 2; + child_allocation.x = x + child->padding - child_width; + } + else + { + child_allocation.width = child->widget->requisition.width; + child_allocation.x = x + (child_width - child_allocation.width) / 2 - child_width; + } + + gtk_widget_size_allocate (child->widget, &child_allocation); + + x -= (child_width + box->spacing); + } + } + } +} diff --git a/gtk/gtkhbox.h b/gtk/gtkhbox.h new file mode 100644 index 000000000..7dfbb3dff --- /dev/null +++ b/gtk/gtkhbox.h @@ -0,0 +1,60 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_HBOX_H__ +#define __GTK_HBOX_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HBOX(obj) GTK_CHECK_CAST (obj, gtk_hbox_get_type (), GtkHBox) +#define GTK_HBOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hbox_get_type (), GtkHBoxClass) +#define GTK_IS_HBOX(obj) GTK_CHECK_TYPE (obj, gtk_hbox_get_type ()) + + +typedef struct _GtkHBox GtkHBox; +typedef struct _GtkHBoxClass GtkHBoxClass; + +struct _GtkHBox +{ + GtkBox box; +}; + +struct _GtkHBoxClass +{ + GtkBoxClass parent_class; +}; + + +guint gtk_hbox_get_type (void); +GtkWidget* gtk_hbox_new (gint homogeneous, + gint spacing); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HBOX_H__ */ diff --git a/gtk/gtkhpaned.c b/gtk/gtkhpaned.c new file mode 100644 index 000000000..23c50961e --- /dev/null +++ b/gtk/gtkhpaned.c @@ -0,0 +1,355 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkhpaned.h" +#include "gtkmain.h" +#include "gtksignal.h" + +static void gtk_hpaned_class_init (GtkHPanedClass *klass); +static void gtk_hpaned_init (GtkHPaned *hpaned); +static void gtk_hpaned_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hpaned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_hpaned_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_hpaned_xor_line (GtkPaned *paned); +static gint gtk_hpaned_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_hpaned_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_hpaned_motion (GtkWidget *widget, + GdkEventMotion *event); + +guint +gtk_hpaned_get_type () +{ + static guint hpaned_type = 0; + + if (!hpaned_type) + { + GtkTypeInfo hpaned_info = + { + "GtkHPaned", + sizeof (GtkHPaned), + sizeof (GtkHPanedClass), + (GtkClassInitFunc) gtk_hpaned_class_init, + (GtkObjectInitFunc) gtk_hpaned_init, + (GtkArgFunc) NULL, + }; + + hpaned_type = gtk_type_unique (gtk_paned_get_type (), &hpaned_info); + } + + return hpaned_type; +} + +static void +gtk_hpaned_class_init (GtkHPanedClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_hpaned_size_request; + widget_class->size_allocate = gtk_hpaned_size_allocate; + widget_class->draw = gtk_hpaned_draw; + widget_class->button_press_event = gtk_hpaned_button_press; + widget_class->button_release_event = gtk_hpaned_button_release; + widget_class->motion_notify_event = gtk_hpaned_motion; +} + +static void +gtk_hpaned_init (GtkHPaned *hpaned) +{ +} + +GtkWidget* +gtk_hpaned_new () +{ + GtkHPaned *hpaned; + + hpaned = gtk_type_new (gtk_hpaned_get_type ()); + + return GTK_WIDGET (hpaned); +} + +static void +gtk_hpaned_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HPANED (widget)); + g_return_if_fail (requisition != NULL); + + paned = GTK_PANED (widget); + requisition->width = 0; + requisition->height = 0; + + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + { + gtk_widget_size_request (paned->child1, &paned->child1->requisition); + + requisition->height = paned->child1->requisition.height; + requisition->width = paned->child1->requisition.width; + } + + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + { + gtk_widget_size_request (paned->child2, &paned->child2->requisition); + + requisition->height = MAX(requisition->height, + paned->child2->requisition.height); + requisition->width += paned->child2->requisition.width; + } + + requisition->width += GTK_CONTAINER (paned)->border_width * 2 + paned->gutter_size; + requisition->height += GTK_CONTAINER (paned)->border_width * 2; +} + +static void +gtk_hpaned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkPaned *paned; + GtkAllocation child1_allocation; + GtkAllocation child2_allocation; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HPANED (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + paned = GTK_PANED (widget); + border_width = GTK_CONTAINER (paned)->border_width; + + if (!paned->position_set) + { + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + paned->child1_size = paned->child1->requisition.width; + else + paned->child1_size = 0; + } + + /* Move the handle first so we don't get extra expose events */ + + paned->handle_xpos = allocation->x + paned->child1_size + border_width + paned->gutter_size / 2 - paned->handle_size / 2; + paned->handle_ypos = allocation->y + allocation->height - border_width - 2*paned->handle_size; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move (paned->handle, paned->handle_xpos, paned->handle_ypos); + gdk_window_raise (paned->handle); + } + + if (GTK_WIDGET_MAPPED (widget)) + { + gdk_window_clear_area (widget->window, + paned->groove_rectangle.x, + paned->groove_rectangle.y, + paned->groove_rectangle.width, + paned->groove_rectangle.height); + } + + child1_allocation.height = child2_allocation.height = allocation->height - border_width * 2; + child1_allocation.width = paned->child1_size; + child1_allocation.x = allocation->x + border_width; + child1_allocation.y = child2_allocation.y = allocation->y + border_width; + + paned->groove_rectangle.x = child1_allocation.x + + child1_allocation.width + paned->gutter_size / 2 - 1; + paned->groove_rectangle.y = allocation->y; + paned->groove_rectangle.width = 2; + paned->groove_rectangle.height = allocation->height; + + child2_allocation.x = paned->groove_rectangle.x + paned->gutter_size / 2 + 1; + child2_allocation.width = allocation->x + allocation->width + - child2_allocation.x - border_width; + + /* Now allocate the childen, making sure, when resizing not to + * overlap the windows */ + if (GTK_WIDGET_MAPPED(widget) && + paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) && + paned->child1->allocation.width < child1_allocation.width) + { + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + gtk_widget_size_allocate (paned->child2, &child2_allocation); + gtk_widget_size_allocate (paned->child1, &child1_allocation); + } + else + { + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + gtk_widget_size_allocate (paned->child1, &child1_allocation); + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + gtk_widget_size_allocate (paned->child2, &child2_allocation); + } +} + +static void +gtk_hpaned_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkPaned *paned; + GdkRectangle child_area; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + paned = GTK_PANED (widget); + border_width = GTK_CONTAINER (paned)->border_width; + + if (paned->child1 && + gtk_widget_intersect (paned->child1, area, &child_area)) + gtk_widget_draw (paned->child1, &child_area); + if (paned->child2 && + gtk_widget_intersect (paned->child2, area, &child_area)) + gtk_widget_draw (paned->child2, &child_area); + + gdk_draw_line (widget->window, + widget->style->dark_gc[widget->state], + widget->allocation.x + border_width + paned->child1_size + paned->gutter_size / 2 - 1, + widget->allocation.y, + widget->allocation.x + border_width + paned->child1_size + paned->gutter_size / 2 - 1, + widget->allocation.y + widget->allocation.height - 1); + gdk_draw_line (widget->window, + widget->style->light_gc[widget->state], + widget->allocation.x + border_width + paned->child1_size + paned->gutter_size / 2, + widget->allocation.y, + widget->allocation.x + border_width + paned->child1_size + paned->gutter_size / 2, + widget->allocation.y + widget->allocation.height - 1); + } +} + +static void +gtk_hpaned_xor_line (GtkPaned *paned) +{ + GtkWidget *widget; + GdkGCValues values; + guint16 xpos; + + widget = GTK_WIDGET(paned); + + if (!paned->xor_gc) + { + values.foreground = widget->style->white; + values.function = GDK_XOR; + values.subwindow_mode = GDK_INCLUDE_INFERIORS; + paned->xor_gc = gdk_gc_new_with_values (widget->window, + &values, + GDK_GC_FOREGROUND | + GDK_GC_FUNCTION | + GDK_GC_SUBWINDOW); + } + + xpos = widget->allocation.x + paned->child1_size + + GTK_CONTAINER(paned)->border_width + paned->gutter_size / 2; + + gdk_draw_line (widget->window, paned->xor_gc, + xpos, + widget->allocation.y, + xpos, + widget->allocation.y + widget->allocation.height - 1); +} + +static gint +gtk_hpaned_button_press (GtkWidget *widget, GdkEventButton *event) +{ + GtkPaned *paned; + + g_return_val_if_fail (widget != NULL,FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget),FALSE); + + paned = GTK_PANED (widget); + + if (!paned->in_drag && + (event->window == paned->handle) && (event->button == 1)) + { + paned->in_drag = TRUE; + /* We need a server grab here, not gtk_grab_add(), since + * we don't want to pass events on to the widget's children */ + gdk_pointer_grab (paned->handle, FALSE, + GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON1_MOTION_MASK + | GDK_BUTTON_RELEASE_MASK, + NULL, NULL, event->time); + paned->child1_size += event->x - paned->handle_size / 2; + paned->child1_size = CLAMP (paned->child1_size, 0, + widget->allocation.width - paned->gutter_size + - 2 * GTK_CONTAINER (paned)->border_width); + gtk_hpaned_xor_line (paned); + } + + return TRUE; +} + +static gint +gtk_hpaned_button_release (GtkWidget *widget, GdkEventButton *event) +{ + GtkPaned *paned; + + g_return_val_if_fail (widget != NULL,FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget),FALSE); + + paned = GTK_PANED (widget); + + if (paned->in_drag && (event->button == 1)) + { + gtk_hpaned_xor_line (paned); + paned->in_drag = FALSE; + paned->position_set = TRUE; + gdk_pointer_ungrab (event->time); + gtk_widget_queue_resize (GTK_WIDGET (paned)); + } + + return TRUE; +} + +static gint +gtk_hpaned_motion (GtkWidget *widget, GdkEventMotion *event) +{ + GtkPaned *paned; + gint x; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget), FALSE); + + if (event->is_hint || event->window != widget->window) + gtk_widget_get_pointer(widget, &x, NULL); + else + x = event->x; + + paned = GTK_PANED (widget); + + if (paned->in_drag) + { + gtk_hpaned_xor_line (paned); + paned->child1_size = x - GTK_CONTAINER (paned)->border_width - paned->gutter_size / 2; + paned->child1_size = CLAMP (paned->child1_size, 0, + widget->allocation.width - paned->gutter_size + - 2 * GTK_CONTAINER (paned)->border_width); + gtk_hpaned_xor_line (paned); + } + + return TRUE; +} diff --git a/gtk/gtkhpaned.h b/gtk/gtkhpaned.h new file mode 100644 index 000000000..0a352e799 --- /dev/null +++ b/gtk/gtkhpaned.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_HPANED_H__ +#define __GTK_HPANED_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HPANED(obj) GTK_CHECK_CAST (obj, gtk_hpaned_get_type (), GtkHPaned) +#define GTK_HPANED_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hpaned_get_type (), GtkHPanedClass) +#define GTK_IS_HPANED(obj) GTK_CHECK_TYPE (obj, gtk_hpaned_get_type ()) + + +typedef struct _GtkHPaned GtkHPaned; +typedef struct _GtkHPanedClass GtkHPanedClass; + +struct _GtkHPaned +{ + GtkPaned paned; +}; + +struct _GtkHPanedClass +{ + GtkPanedClass parent_class; +}; + + +guint gtk_hpaned_get_type (void); +GtkWidget* gtk_hpaned_new (); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HPANED_H__ */ diff --git a/gtk/gtkhruler.c b/gtk/gtkhruler.c new file mode 100644 index 000000000..ab6e69199 --- /dev/null +++ b/gtk/gtkhruler.c @@ -0,0 +1,277 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "gtkhruler.h" + + +#define RULER_HEIGHT 14 +#define MINIMUM_INCR 5 +#define MAXIMUM_SUBDIVIDE 5 +#define MAXIMUM_SCALES 10 + +#define ROUND(x) ((int) ((x) + 0.5)) + + +static void gtk_hruler_class_init (GtkHRulerClass *klass); +static void gtk_hruler_init (GtkHRuler *hruler); +static gint gtk_hruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static void gtk_hruler_draw_ticks (GtkRuler *ruler); +static void gtk_hruler_draw_pos (GtkRuler *ruler); + + +guint +gtk_hruler_get_type () +{ + static guint hruler_type = 0; + + if (!hruler_type) + { + GtkTypeInfo hruler_info = + { + "GtkHRuler", + sizeof (GtkHRuler), + sizeof (GtkHRulerClass), + (GtkClassInitFunc) gtk_hruler_class_init, + (GtkObjectInitFunc) gtk_hruler_init, + (GtkArgFunc) NULL, + }; + + hruler_type = gtk_type_unique (gtk_ruler_get_type (), &hruler_info); + } + + return hruler_type; +} + +static void +gtk_hruler_class_init (GtkHRulerClass *klass) +{ + GtkWidgetClass *widget_class; + GtkRulerClass *ruler_class; + + widget_class = (GtkWidgetClass*) klass; + ruler_class = (GtkRulerClass*) klass; + + widget_class->motion_notify_event = gtk_hruler_motion_notify; + + ruler_class->draw_ticks = gtk_hruler_draw_ticks; + ruler_class->draw_pos = gtk_hruler_draw_pos; +} + +static void +gtk_hruler_init (GtkHRuler *hruler) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (hruler); + widget->requisition.width = widget->style->klass->xthickness * 2 + 1; + widget->requisition.height = widget->style->klass->ythickness * 2 + RULER_HEIGHT; +} + + +GtkWidget* +gtk_hruler_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_hruler_get_type ())); +} + +static gint +gtk_hruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkRuler *ruler; + gint x; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_HRULER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + ruler = GTK_RULER (widget); + + if (event->is_hint) + gdk_window_get_pointer (widget->window, &x, NULL, NULL); + else + x = event->x; + + ruler->position = ruler->lower + ((ruler->upper - ruler->lower) * x) / widget->allocation.width; + + /* Make sure the ruler has been allocated already */ + if (ruler->backing_store != NULL) + gtk_ruler_draw_pos (ruler); + + return FALSE; +} + +static void +gtk_hruler_draw_ticks (GtkRuler *ruler) +{ + GtkWidget *widget; + GdkGC *gc; + gint i; + gint width, height; + gint xthickness; + gint ythickness; + gint length; + gfloat subd_incr; + gfloat step_incr; + gfloat increment; + gfloat start, end, cur; + gchar unit_str[12]; + gint text_height; + gint digit_height; + gint pos; + gint scale; + + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_HRULER (ruler)); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + widget = GTK_WIDGET (ruler); + + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + xthickness = widget->style->klass->xthickness; + ythickness = widget->style->klass->ythickness; + digit_height = widget->style->font->ascent; + + width = widget->allocation.width; + height = widget->allocation.height - ythickness * 2; + gdk_draw_line (ruler->backing_store, gc, + xthickness, + height + ythickness, + widget->allocation.width - xthickness, + height + ythickness); + + if ((ruler->upper - ruler->lower) == 0) + return; + + increment = (gfloat) width * ruler->metric->pixels_per_unit / (ruler->upper - ruler->lower); + + /* determine the scale + * use the maximum extents of the ruler to determine the largest possible + * number to be displayed. calculate the height in pixels of this displayed + * text as for the vertical ruler case. use this height to find a scale + * which leaves sufficient room for drawing the ruler. + */ + scale = ceil (ruler->max_size / ruler->metric->pixels_per_unit); + sprintf (unit_str, "%d", scale); + text_height = strlen (unit_str) * digit_height + 1; + + for (scale = 0; scale < MAXIMUM_SCALES; scale++) + if (ruler->metric->ruler_scale[scale] * increment > 2 * text_height) + break; + + if (scale == MAXIMUM_SCALES) + scale = MAXIMUM_SCALES - 1; + + for (i = 0; i < MAXIMUM_SUBDIVIDE; i++) + { + subd_incr = (gfloat) ruler->metric->ruler_scale[scale] / (gfloat) ruler->metric->subdivide[i]; + step_incr = subd_incr * increment; + if (step_incr <= MINIMUM_INCR) + break; + + start = floor ((ruler->lower / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr; + end = ceil ((ruler->upper / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr; + + length = height / (i + 1) - 1; + if (i > 0) + length -= 2; + + cur = start; + while (cur <= end) + { + pos = ROUND ((cur - (ruler->lower / ruler->metric->pixels_per_unit)) * increment); + + gdk_draw_line (ruler->backing_store, gc, + pos, height + ythickness, pos, + height - length + ythickness); + if (i == 0) + { + sprintf (unit_str, "%d", (int) cur); + gdk_draw_string (ruler->backing_store, widget->style->font, gc, + pos + 2, + ythickness + digit_height - 1, + unit_str); + } + + cur += subd_incr; + } + } + } +} + +static void +gtk_hruler_draw_pos (GtkRuler *ruler) +{ + GtkWidget *widget; + GdkGC *gc; + int i; + gint x, y; + gint width, height; + gint bs_width, bs_height; + gint xthickness; + gint ythickness; + gfloat increment; + + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_HRULER (ruler)); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + widget = GTK_WIDGET (ruler); + + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + xthickness = widget->style->klass->xthickness; + ythickness = widget->style->klass->ythickness; + width = widget->allocation.width; + height = widget->allocation.height - ythickness * 2; + + bs_width = height / 2; + bs_width |= 1; /* make sure it's odd */ + bs_height = bs_width / 2 + 1; + + if ((bs_width > 0) && (bs_height > 0)) + { + /* If a backing store exists, restore the ruler */ + if (ruler->backing_store && ruler->non_gr_exp_gc) + gdk_draw_pixmap (ruler->widget.window, + ruler->non_gr_exp_gc, + ruler->backing_store, + ruler->xsrc, ruler->ysrc, + ruler->xsrc, ruler->ysrc, + bs_width, bs_height); + + increment = (gfloat) width / (ruler->upper - ruler->lower); + + x = ROUND ((ruler->position - ruler->lower) * increment) + (xthickness - bs_width) / 2 - 1; + y = (height + bs_height) / 2 + ythickness; + + for (i = 0; i < bs_height; i++) + gdk_draw_line (widget->window, gc, + x + i, y + i, + x + bs_width - 1 - i, y + i); + + + ruler->xsrc = x; + ruler->ysrc = y; + } + } +} diff --git a/gtk/gtkhruler.h b/gtk/gtkhruler.h new file mode 100644 index 000000000..c4bc74436 --- /dev/null +++ b/gtk/gtkhruler.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_HRULER_H__ +#define __GTK_HRULER_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HRULER(obj) GTK_CHECK_CAST (obj, gtk_hruler_get_type (), GtkHRuler) +#define GTK_HRULER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hruler_get_type (), GtkHRulerClass) +#define GTK_IS_HRULER(obj) GTK_CHECK_TYPE (obj, gtk_hruler_get_type ()) + + +typedef struct _GtkHRuler GtkHRuler; +typedef struct _GtkHRulerClass GtkHRulerClass; + +struct _GtkHRuler +{ + GtkRuler ruler; +}; + +struct _GtkHRulerClass +{ + GtkRulerClass parent_class; +}; + + +guint gtk_hruler_get_type (void); +GtkWidget* gtk_hruler_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HRULER_H__ */ diff --git a/gtk/gtkhscale.c b/gtk/gtkhscale.c new file mode 100644 index 000000000..3bebd30fc --- /dev/null +++ b/gtk/gtkhscale.c @@ -0,0 +1,436 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkhscale.h" +#include "gtksignal.h" +#include "gdk/gdkkeysyms.h" + + +#define SCALE_CLASS(w) GTK_SCALE_CLASS (GTK_OBJECT (w)->klass) +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_hscale_class_init (GtkHScaleClass *klass); +static void gtk_hscale_init (GtkHScale *hscale); +static void gtk_hscale_realize (GtkWidget *widget); +static void gtk_hscale_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_hscale_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_hscale_pos_trough (GtkHScale *hscale, + gint *x, + gint *y, + gint *w, + gint *h); +static void gtk_hscale_draw_slider (GtkRange *range); +static void gtk_hscale_draw_value (GtkScale *scale); +static gint gtk_hscale_trough_keys (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos); + +guint +gtk_hscale_get_type () +{ + static guint hscale_type = 0; + + if (!hscale_type) + { + GtkTypeInfo hscale_info = + { + "GtkHScale", + sizeof (GtkHScale), + sizeof (GtkHScaleClass), + (GtkClassInitFunc) gtk_hscale_class_init, + (GtkObjectInitFunc) gtk_hscale_init, + (GtkArgFunc) NULL, + }; + + hscale_type = gtk_type_unique (gtk_scale_get_type (), &hscale_info); + } + + return hscale_type; +} + +static void +gtk_hscale_class_init (GtkHScaleClass *class) +{ + GtkWidgetClass *widget_class; + GtkRangeClass *range_class; + GtkScaleClass *scale_class; + + widget_class = (GtkWidgetClass*) class; + range_class = (GtkRangeClass*) class; + scale_class = (GtkScaleClass*) class; + + widget_class->realize = gtk_hscale_realize; + widget_class->size_request = gtk_hscale_size_request; + widget_class->size_allocate = gtk_hscale_size_allocate; + + range_class->slider_update = gtk_range_default_hslider_update; + range_class->trough_click = gtk_range_default_htrough_click; + range_class->motion = gtk_range_default_hmotion; + range_class->draw_slider = gtk_hscale_draw_slider; + range_class->trough_keys = gtk_hscale_trough_keys; + + scale_class->draw_value = gtk_hscale_draw_value; +} + +static void +gtk_hscale_init (GtkHScale *hscale) +{ +} + +GtkWidget* +gtk_hscale_new (GtkAdjustment *adjustment) +{ + GtkHScale *hscale; + + hscale = gtk_type_new (gtk_hscale_get_type ()); + + if (!adjustment) + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_range_set_adjustment (GTK_RANGE (hscale), adjustment); + + return GTK_WIDGET (hscale); +} + + +static void +gtk_hscale_realize (GtkWidget *widget) +{ + GtkRange *range; + GdkWindowAttr attributes; + gint attributes_mask; + gint x, y, w, h; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCALE (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + + gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &w, &h); + attributes.x = x; + attributes.y = y; + attributes.width = w; + attributes.height = h; + attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + range->trough = gdk_window_new (widget->window, &attributes, attributes_mask); + + attributes.width = SCALE_CLASS (range)->slider_length; + attributes.height = RANGE_CLASS (range)->slider_width; + attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (widget->window, widget); + gdk_window_set_user_data (range->trough, widget); + gdk_window_set_user_data (range->slider, widget); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); + + gtk_range_slider_update (GTK_RANGE (widget)); + + gdk_window_show (range->slider); + gdk_window_show (range->trough); +} + +static void +gtk_hscale_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkScale *scale; + gint value_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCALE (widget)); + g_return_if_fail (requisition != NULL); + + scale = GTK_SCALE (widget); + + requisition->width = (SCALE_CLASS (scale)->slider_length + + widget->style->klass->xthickness) * 2; + requisition->height = (RANGE_CLASS (scale)->slider_width + + widget->style->klass->ythickness * 2); + + if (scale->draw_value) + { + value_width = gtk_scale_value_width (scale); + + if ((scale->value_pos == GTK_POS_LEFT) || + (scale->value_pos == GTK_POS_RIGHT)) + { + requisition->width += value_width + SCALE_CLASS (scale)->value_spacing; + if (requisition->height < (widget->style->font->ascent + widget->style->font->descent)) + requisition->height = widget->style->font->ascent + widget->style->font->descent; + } + else if ((scale->value_pos == GTK_POS_TOP) || + (scale->value_pos == GTK_POS_BOTTOM)) + { + if (requisition->width < value_width) + requisition->width = value_width; + requisition->height += widget->style->font->ascent + widget->style->font->descent; + } + } +} + +static void +gtk_hscale_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRange *range; + GtkScale *scale; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCALE (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + range = GTK_RANGE (widget); + scale = GTK_SCALE (widget); + + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &width, &height); + + gdk_window_move_resize (range->trough, x, y, width, height); + gtk_range_slider_update (GTK_RANGE (widget)); + } +} + +static void +gtk_hscale_pos_trough (GtkHScale *hscale, + gint *x, + gint *y, + gint *w, + gint *h) +{ + GtkWidget *widget; + GtkScale *scale; + + g_return_if_fail (hscale != NULL); + g_return_if_fail (GTK_IS_HSCALE (hscale)); + g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL)); + + widget = GTK_WIDGET (hscale); + scale = GTK_SCALE (hscale); + + *w = widget->allocation.width; + *h = (RANGE_CLASS (scale)->slider_width + + widget->style->klass->ythickness * 2); + + if (scale->draw_value) + { + *x = 0; + *y = 0; + + switch (scale->value_pos) + { + case GTK_POS_LEFT: + *x += gtk_scale_value_width (scale) + SCALE_CLASS (scale)->value_spacing; + *y = (widget->allocation.height - *h) / 2; + *w -= *x; + break; + case GTK_POS_RIGHT: + *w -= gtk_scale_value_width (scale) + SCALE_CLASS (scale)->value_spacing; + *y = (widget->allocation.height - *h) / 2; + break; + case GTK_POS_TOP: + *y = (widget->style->font->ascent + widget->style->font->descent + + (widget->allocation.height - widget->requisition.height) / 2); + break; + case GTK_POS_BOTTOM: + *y = (widget->allocation.height - widget->requisition.height) / 2; + break; + } + } + else + { + *x = 0; + *y = (widget->allocation.height - *h) / 2; + } + *x += 1; + *w -= 2; +} + +static void +gtk_hscale_draw_slider (GtkRange *range) +{ + GtkStateType state_type; + gint width, height; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_HSCALE (range)); + + if (range->slider) + { + if ((range->in_child == RANGE_CLASS (range)->slider) || + (range->click_child == RANGE_CLASS (range)->slider)) + state_type = GTK_STATE_PRELIGHT; + else + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (GTK_WIDGET (range)->style, range->slider, state_type); + gdk_window_clear (range->slider); + + gdk_window_get_size (range->slider, &width, &height); + gtk_draw_vline (GTK_WIDGET (range)->style, range->slider, + state_type, 1, height - 2, width / 2); + + gtk_draw_shadow (GTK_WIDGET (range)->style, range->slider, + state_type, GTK_SHADOW_OUT, + 0, 0, -1, -1); + } +} + +static void +gtk_hscale_draw_value (GtkScale *scale) +{ + GtkStateType state_type; + gchar buffer[16]; + gint text_width; + gint width, height; + gint x, y; + + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_HSCALE (scale)); + + if (scale->draw_value) + { + gdk_window_get_size (GTK_WIDGET (scale)->window, &width, &height); + gdk_window_clear_area (GTK_WIDGET (scale)->window, 1, 1, width - 2, height - 2); + + sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value); + text_width = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer); + + switch (scale->value_pos) + { + case GTK_POS_LEFT: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); + gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height); + + x -= SCALE_CLASS (scale)->value_spacing + text_width; + y += ((height - + (GTK_WIDGET (scale)->style->font->ascent + + GTK_WIDGET (scale)->style->font->descent)) / 2 + + GTK_WIDGET (scale)->style->font->ascent); + break; + case GTK_POS_RIGHT: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); + gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height); + + x += width + SCALE_CLASS (scale)->value_spacing; + y += ((height - + (GTK_WIDGET (scale)->style->font->ascent + + GTK_WIDGET (scale)->style->font->descent)) / 2 + + GTK_WIDGET (scale)->style->font->ascent); + break; + case GTK_POS_TOP: + gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL); + gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y); + gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); + + x += (width - text_width) / 2; + y -= GTK_WIDGET (scale)->style->font->descent; + break; + case GTK_POS_BOTTOM: + gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL); + gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y); + gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); + + x += (width - text_width) / 2; + y += height + GTK_WIDGET (scale)->style->font->ascent; + break; + } + + state_type = GTK_STATE_NORMAL; + if (!GTK_WIDGET_IS_SENSITIVE (scale)) + state_type = GTK_STATE_INSENSITIVE; + + gtk_draw_string (GTK_WIDGET (scale)->style, + GTK_WIDGET (scale)->window, + state_type, x, y, buffer); + } +} + +static gint +gtk_hscale_trough_keys(GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos) +{ + gint return_val = FALSE; + switch (key->keyval) + { + case GDK_Left: + return_val = TRUE; + if (key->state & GDK_CONTROL_MASK) + *scroll = GTK_SCROLL_PAGE_BACKWARD; + else + *scroll = GTK_SCROLL_STEP_BACKWARD; + break; + case GDK_Right: + return_val = TRUE; + if (key->state & GDK_CONTROL_MASK) + *scroll = GTK_SCROLL_PAGE_FORWARD; + else + *scroll = GTK_SCROLL_STEP_FORWARD; + break; + case GDK_Home: + return_val = TRUE; + *pos = GTK_TROUGH_START; + break; + case GDK_End: + return_val = TRUE; + *pos = GTK_TROUGH_END; + break; + } + return return_val; +} diff --git a/gtk/gtkhscale.h b/gtk/gtkhscale.h new file mode 100644 index 000000000..61ae4fdb3 --- /dev/null +++ b/gtk/gtkhscale.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_HSCALE_H__ +#define __GTK_HSCALE_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HSCALE(obj) GTK_CHECK_CAST (obj, gtk_hscale_get_type (), GtkHScale) +#define GTK_HSCALE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hscale_get_type (), GtkHScaleClass) +#define GTK_IS_HSCALE(obj) GTK_CHECK_TYPE (obj, gtk_hscale_get_type ()) + + +typedef struct _GtkHScale GtkHScale; +typedef struct _GtkHScaleClass GtkHScaleClass; + +struct _GtkHScale +{ + GtkScale scale; +}; + +struct _GtkHScaleClass +{ + GtkScaleClass parent_class; +}; + + +guint gtk_hscale_get_type (void); +GtkWidget* gtk_hscale_new (GtkAdjustment *adjustment); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HSCALE_H__ */ diff --git a/gtk/gtkhscrollbar.c b/gtk/gtkhscrollbar.c new file mode 100644 index 000000000..9b757d406 --- /dev/null +++ b/gtk/gtkhscrollbar.c @@ -0,0 +1,383 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkhscrollbar.h" +#include "gtksignal.h" +#include "gdk/gdkkeysyms.h" + + +#define EPSILON 0.01 + +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_hscrollbar_class_init (GtkHScrollbarClass *klass); +static void gtk_hscrollbar_init (GtkHScrollbar *hscrollbar); +static void gtk_hscrollbar_realize (GtkWidget *widget); +static void gtk_hscrollbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_hscrollbar_draw_step_forw (GtkRange *range); +static void gtk_hscrollbar_draw_step_back (GtkRange *range); +static void gtk_hscrollbar_slider_update (GtkRange *range); +static void gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar); +static gint gtk_hscrollbar_trough_keys (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos); + + +guint +gtk_hscrollbar_get_type () +{ + static guint hscrollbar_type = 0; + + if (!hscrollbar_type) + { + GtkTypeInfo hscrollbar_info = + { + "GtkHScrollbar", + sizeof (GtkHScrollbar), + sizeof (GtkHScrollbarClass), + (GtkClassInitFunc) gtk_hscrollbar_class_init, + (GtkObjectInitFunc) gtk_hscrollbar_init, + (GtkArgFunc) NULL, + }; + + hscrollbar_type = gtk_type_unique (gtk_scrollbar_get_type (), &hscrollbar_info); + } + + return hscrollbar_type; +} + +static void +gtk_hscrollbar_class_init (GtkHScrollbarClass *class) +{ + GtkWidgetClass *widget_class; + GtkRangeClass *range_class; + + widget_class = (GtkWidgetClass*) class; + range_class = (GtkRangeClass*) class; + + widget_class->realize = gtk_hscrollbar_realize; + widget_class->size_allocate = gtk_hscrollbar_size_allocate; + + range_class->draw_step_forw = gtk_hscrollbar_draw_step_forw; + range_class->draw_step_back = gtk_hscrollbar_draw_step_back; + range_class->slider_update = gtk_hscrollbar_slider_update; + range_class->trough_click = gtk_range_default_htrough_click; + range_class->trough_keys = gtk_hscrollbar_trough_keys; + range_class->motion = gtk_range_default_hmotion; +} + +static void +gtk_hscrollbar_init (GtkHScrollbar *hscrollbar) +{ + GtkWidget *widget; + GtkRequisition *requisition; + + widget = GTK_WIDGET (hscrollbar); + GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); + requisition = &widget->requisition; + + requisition->width = (RANGE_CLASS (widget)->min_slider_size + + RANGE_CLASS (widget)->stepper_size + + RANGE_CLASS (widget)->stepper_slider_spacing + + widget->style->klass->xthickness) * 2; + requisition->height = (RANGE_CLASS (widget)->slider_width + + widget->style->klass->ythickness * 2); +} + +GtkWidget* +gtk_hscrollbar_new (GtkAdjustment *adjustment) +{ + GtkHScrollbar *hscrollbar; + + hscrollbar = gtk_type_new (gtk_hscrollbar_get_type ()); + + if (!adjustment) + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_range_set_adjustment (GTK_RANGE (hscrollbar), adjustment); + + return GTK_WIDGET (hscrollbar); +} + + +static void +gtk_hscrollbar_realize (GtkWidget *widget) +{ + GtkRange *range; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y + (widget->allocation.height - widget->requisition.height) / 2; + attributes.width = widget->allocation.width; + attributes.height = widget->requisition.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + range->trough = widget->window; + + attributes.x = widget->style->klass->xthickness; + attributes.y = widget->style->klass->ythickness; + attributes.width = RANGE_CLASS (widget)->stepper_size; + attributes.height = RANGE_CLASS (widget)->stepper_size; + + range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask); + + attributes.x = (widget->allocation.width - + widget->style->klass->xthickness - + RANGE_CLASS (widget)->stepper_size); + + range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask); + + attributes.x = 0; + attributes.y = widget->style->klass->ythickness; + attributes.width = RANGE_CLASS (widget)->min_slider_size; + attributes.height = RANGE_CLASS (widget)->slider_width; + attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); + + gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (widget)); + gtk_range_slider_update (GTK_RANGE (widget)); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (range->trough, widget); + gdk_window_set_user_data (range->slider, widget); + gdk_window_set_user_data (range->step_forw, widget); + gdk_window_set_user_data (range->step_back, widget); + + gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE); + + gdk_window_show (range->slider); + gdk_window_show (range->step_forw); + gdk_window_show (range->step_back); +} + +static void +gtk_hscrollbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRange *range; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + range = GTK_RANGE (widget); + + gdk_window_move_resize (range->trough, + allocation->x, + allocation->y + (allocation->height - widget->requisition.height) / 2, + allocation->width, widget->requisition.height); + gdk_window_move_resize (range->step_back, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + RANGE_CLASS (widget)->stepper_size, + widget->requisition.height - widget->style->klass->ythickness * 2); + gdk_window_move_resize (range->step_forw, + allocation->width - widget->style->klass->xthickness - + RANGE_CLASS (widget)->stepper_size, + widget->style->klass->ythickness, + RANGE_CLASS (widget)->stepper_size, + widget->requisition.height - widget->style->klass->ythickness * 2); + gdk_window_resize (range->slider, + RANGE_CLASS (widget)->min_slider_size, + widget->requisition.height - widget->style->klass->ythickness * 2); + + gtk_range_slider_update (GTK_RANGE (widget)); + } +} + +static void +gtk_hscrollbar_draw_step_forw (GtkRange *range) +{ + GtkStateType state_type; + GtkShadowType shadow_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (range)); + + if (GTK_WIDGET_DRAWABLE (range)) + { + if (range->in_child == RANGE_CLASS (range)->step_forw) + { + if (range->click_child == RANGE_CLASS (range)->step_forw) + state_type = GTK_STATE_ACTIVE; + else + state_type = GTK_STATE_PRELIGHT; + } + else + state_type = GTK_STATE_NORMAL; + + if (range->click_child == RANGE_CLASS (range)->step_forw) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_forw, + state_type, shadow_type, GTK_ARROW_RIGHT, + TRUE, 0, 0, -1, -1); + } +} + +static void +gtk_hscrollbar_draw_step_back (GtkRange *range) +{ + GtkStateType state_type; + GtkShadowType shadow_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (range)); + + if (GTK_WIDGET_DRAWABLE (range)) + { + if (range->in_child == RANGE_CLASS (range)->step_back) + { + if (range->click_child == RANGE_CLASS (range)->step_back) + state_type = GTK_STATE_ACTIVE; + else + state_type = GTK_STATE_PRELIGHT; + } + else + state_type = GTK_STATE_NORMAL; + + if (range->click_child == RANGE_CLASS (range)->step_back) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_back, + state_type, shadow_type, GTK_ARROW_LEFT, + TRUE, 0, 0, -1, -1); + } +} + +static void +gtk_hscrollbar_slider_update (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (range)); + + gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (range)); + gtk_range_default_hslider_update (range); +} + +static void +gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar) +{ + GtkRange *range; + gint step_back_x; + gint step_back_width; + gint step_forw_x; + gint slider_width; + gint slider_height; + gint left, right; + gint width; + + g_return_if_fail (hscrollbar != NULL); + g_return_if_fail (GTK_IS_HSCROLLBAR (hscrollbar)); + + if (GTK_WIDGET_REALIZED (hscrollbar)) + { + range = GTK_RANGE (hscrollbar); + + gdk_window_get_size (range->step_back, &step_back_width, NULL); + gdk_window_get_position (range->step_back, &step_back_x, NULL); + gdk_window_get_position (range->step_forw, &step_forw_x, NULL); + + left = (step_back_x + + step_back_width + + RANGE_CLASS (hscrollbar)->stepper_slider_spacing); + right = step_forw_x - RANGE_CLASS (hscrollbar)->stepper_slider_spacing; + width = right - left; + + if ((range->adjustment->page_size > 0) && + (range->adjustment->lower != range->adjustment->upper)) + { + if (range->adjustment->page_size > + (range->adjustment->upper - range->adjustment->lower)) + range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower; + + width = (width * range->adjustment->page_size / + (range->adjustment->upper - range->adjustment->lower)); + + if (width < RANGE_CLASS (hscrollbar)->min_slider_size) + width = RANGE_CLASS (hscrollbar)->min_slider_size; + } + + gdk_window_get_size (range->slider, &slider_width, &slider_height); + + if (slider_width != width) + gdk_window_resize (range->slider, width, slider_height); + } +} + +static gint +gtk_hscrollbar_trough_keys(GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos) +{ + gint return_val = FALSE; + switch (key->keyval) + { + case GDK_Left: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_BACKWARD; + break; + case GDK_Right: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_FORWARD; + break; + case GDK_Home: + return_val = TRUE; + *pos = GTK_TROUGH_START; + break; + case GDK_End: + return_val = TRUE; + *pos = GTK_TROUGH_END; + break; + } + return return_val; +} diff --git a/gtk/gtkhscrollbar.h b/gtk/gtkhscrollbar.h new file mode 100644 index 000000000..7d6951259 --- /dev/null +++ b/gtk/gtkhscrollbar.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_HSCROLLBAR_H__ +#define __GTK_HSCROLLBAR_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HSCROLLBAR(obj) GTK_CHECK_CAST (obj, gtk_hscrollbar_get_type (), GtkHScrollbar) +#define GTK_HSCROLLBAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hscrollbar_get_type (), GtkHScrollbarClass) +#define GTK_IS_HSCROLLBAR(obj) GTK_CHECK_TYPE (obj, gtk_hscrollbar_get_type ()) + + +typedef struct _GtkHScrollbar GtkHScrollbar; +typedef struct _GtkHScrollbarClass GtkHScrollbarClass; + +struct _GtkHScrollbar +{ + GtkScrollbar scrollbar; +}; + +struct _GtkHScrollbarClass +{ + GtkScrollbarClass parent_class; +}; + + +guint gtk_hscrollbar_get_type (void); +GtkWidget* gtk_hscrollbar_new (GtkAdjustment *adjustment); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HSCROLLBAR_H__ */ diff --git a/gtk/gtkhseparator.c b/gtk/gtkhseparator.c new file mode 100644 index 000000000..5f3a38c20 --- /dev/null +++ b/gtk/gtkhseparator.c @@ -0,0 +1,90 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkhseparator.h" + + +static void gtk_hseparator_class_init (GtkHSeparatorClass *klass); +static void gtk_hseparator_init (GtkHSeparator *hseparator); +static gint gtk_hseparator_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_hseparator_get_type () +{ + static guint hseparator_type = 0; + + if (!hseparator_type) + { + GtkTypeInfo hseparator_info = + { + "GtkHSeparator", + sizeof (GtkHSeparator), + sizeof (GtkHSeparatorClass), + (GtkClassInitFunc) gtk_hseparator_class_init, + (GtkObjectInitFunc) gtk_hseparator_init, + (GtkArgFunc) NULL, + }; + + hseparator_type = gtk_type_unique (gtk_separator_get_type (), &hseparator_info); + } + + return hseparator_type; +} + +static void +gtk_hseparator_class_init (GtkHSeparatorClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->expose_event = gtk_hseparator_expose; +} + +static void +gtk_hseparator_init (GtkHSeparator *hseparator) +{ + GTK_WIDGET (hseparator)->requisition.width = 1; + GTK_WIDGET (hseparator)->requisition.height = GTK_WIDGET (hseparator)->style->klass->ythickness; +} + +GtkWidget* +gtk_hseparator_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_hseparator_get_type ())); +} + + +static gint +gtk_hseparator_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_HSEPARATOR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + gtk_draw_hline (widget->style, widget->window, GTK_STATE_NORMAL, + widget->allocation.x, + widget->allocation.x + widget->allocation.width, + widget->allocation.y + (widget->allocation.height - + widget->style->klass->ythickness) / 2); + + return FALSE; +} diff --git a/gtk/gtkhseparator.h b/gtk/gtkhseparator.h new file mode 100644 index 000000000..990263151 --- /dev/null +++ b/gtk/gtkhseparator.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_HSEPARATOR_H__ +#define __GTK_HSEPARATOR_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_HSEPARATOR(obj) GTK_CHECK_CAST (obj, gtk_hseparator_get_type (), GtkHSeparator) +#define GTK_HSEPARATOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_hseparator_get_type (), GtkHSeparatorClass) +#define GTK_IS_HSEPARATOR(obj) GTK_CHECK_TYPE (obj, gtk_hseparator_get_type ()) + + +typedef struct _GtkHSeparator GtkHSeparator; +typedef struct _GtkHSeparatorClass GtkHSeparatorClass; + +struct _GtkHSeparator +{ + GtkSeparator separator; +}; + +struct _GtkHSeparatorClass +{ + GtkSeparatorClass parent_class; +}; + + +guint gtk_hseparator_get_type (void); +GtkWidget* gtk_hseparator_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_HSEPARATOR_H__ */ diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c new file mode 100644 index 000000000..fddd06a5d --- /dev/null +++ b/gtk/gtkimage.c @@ -0,0 +1,181 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkcontainer.h" +#include "gtkimage.h" + + +static void gtk_image_class_init (GtkImageClass *klass); +static void gtk_image_init (GtkImage *image); +static gint gtk_image_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_image_get_type () +{ + static guint image_type = 0; + + if (!image_type) + { + GtkTypeInfo image_info = + { + "GtkImage", + sizeof (GtkImage), + sizeof (GtkImageClass), + (GtkClassInitFunc) gtk_image_class_init, + (GtkObjectInitFunc) gtk_image_init, + (GtkArgFunc) NULL, + }; + + image_type = gtk_type_unique (gtk_misc_get_type (), &image_info); + } + + return image_type; +} + +static void +gtk_image_class_init (GtkImageClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->expose_event = gtk_image_expose; +} + +static void +gtk_image_init (GtkImage *image) +{ + GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW); + + image->image = NULL; + image->mask = NULL; +} + +GtkWidget* +gtk_image_new (GdkImage *val, + GdkBitmap *mask) +{ + GtkImage *image; + + g_return_val_if_fail (val != NULL, NULL); + + image = gtk_type_new (gtk_image_get_type ()); + + gtk_image_set (image, val, mask); + + return GTK_WIDGET (image); +} + +void +gtk_image_set (GtkImage *image, + GdkImage *val, + GdkBitmap *mask) +{ + g_return_if_fail (image != NULL); + g_return_if_fail (GTK_IS_IMAGE (image)); + + image->image = val; + image->mask = mask; + + if (image->image) + { + GTK_WIDGET (image)->requisition.width = image->image->width + GTK_MISC (image)->xpad * 2; + GTK_WIDGET (image)->requisition.height = image->image->height + GTK_MISC (image)->ypad * 2; + } + else + { + GTK_WIDGET (image)->requisition.width = 0; + GTK_WIDGET (image)->requisition.height = 0; + } + + if (GTK_WIDGET_VISIBLE (image)) + gtk_widget_queue_resize (GTK_WIDGET (image)); +} + +void +gtk_image_get (GtkImage *image, + GdkImage **val, + GdkBitmap **mask) +{ + g_return_if_fail (image != NULL); + g_return_if_fail (GTK_IS_IMAGE (image)); + + if (val) + *val = image->image; + if (mask) + *mask = image->mask; +} + + +static gint +gtk_image_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkImage *image; + GtkMisc *misc; + GdkRectangle area; + gint x, y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + image = GTK_IMAGE (widget); + misc = GTK_MISC (widget); + + x = (widget->allocation.x * (1.0 - misc->xalign) + + (widget->allocation.x + widget->allocation.width + - (widget->requisition.width - misc->xpad * 2)) * + misc->xalign) + 0.5; + y = (widget->allocation.y * (1.0 - misc->yalign) + + (widget->allocation.y + widget->allocation.height + - (widget->requisition.height - misc->ypad * 2)) * + misc->yalign) + 0.5; + + if (image->mask) + { + gdk_gc_set_clip_mask (widget->style->black_gc, image->mask); + gdk_gc_set_clip_origin (widget->style->black_gc, x, y); + } + + area = event->area; + if ((area.x < 0) || (area.y < 0)) + { + area.x = area.y = 0; + area.width = image->image->width; + area.height = image->image->height; + } + + gdk_draw_image (widget->window, + widget->style->black_gc, + image->image, + area.x, area.y, x+area.x, y+area.y, + area.width, area.height); + + if (image->mask) + { + gdk_gc_set_clip_mask (widget->style->black_gc, NULL); + gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0); + } + } + + return FALSE; +} diff --git a/gtk/gtkimage.h b/gtk/gtkimage.h new file mode 100644 index 000000000..d3481d51d --- /dev/null +++ b/gtk/gtkimage.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_IMAGE_H__ +#define __GTK_IMAGE_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_IMAGE(obj) GTK_CHECK_CAST (obj, gtk_image_get_type (), GtkImage) +#define GTK_IMAGE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_image_get_type (), GtkImageClass) +#define GTK_IS_IMAGE(obj) GTK_CHECK_TYPE (obj, gtk_image_get_type ()) + + +typedef struct _GtkImage GtkImage; +typedef struct _GtkImageClass GtkImageClass; + +struct _GtkImage +{ + GtkMisc misc; + + GdkImage *image; + GdkBitmap *mask; +}; + +struct _GtkImageClass +{ + GtkMiscClass parent_class; +}; + + +guint gtk_image_get_type (void); +GtkWidget* gtk_image_new (GdkImage *val, + GdkBitmap *mask); +void gtk_image_set (GtkImage *image, + GdkImage *val, + GdkBitmap *mask); +void gtk_image_get (GtkImage *image, + GdkImage **val, + GdkBitmap **mask); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_IMAGE_H__ */ diff --git a/gtk/gtkinputdialog.c b/gtk/gtkinputdialog.c new file mode 100644 index 000000000..1d412a32e --- /dev/null +++ b/gtk/gtkinputdialog.c @@ -0,0 +1,546 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * gtkinputdialog.c + * + * Copyright 1997 Owen Taylor + * + */ + +#include +#include +#include +#include "gdk/gdkkeysyms.h" +#include "gtkbutton.h" +#include "gtkhbox.h" +#include "gtkhseparator.h" +#include "gtkinputdialog.h" +#include "gtklabel.h" +#include "gtklistitem.h" +#include "gtkmain.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtkoptionmenu.h" +#include "gtkscrolledwindow.h" +#include "gtksignal.h" +#include "gtkvbox.h" + +typedef void (*GtkInputDialogSignal1) (GtkObject *object, + int arg1, + gpointer data); + +enum +{ + ENABLE_DEVICE, + DISABLE_DEVICE, + LAST_SIGNAL +}; + + +#define AXIS_LIST_WIDTH 160 +#define AXIS_LIST_HEIGHT 175 + +/* Forward declarations */ + +static void gtk_input_dialog_marshal_signal1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_input_dialog_class_init (GtkInputDialogClass *klass); +static void gtk_input_dialog_init (GtkInputDialog *inputd); +static GdkDeviceInfo *gtk_input_dialog_get_device_info(guint32 deviceid); +static void gtk_input_dialog_set_device(GtkWidget *widget, gpointer data); +static void gtk_input_dialog_destroy (GtkObject *object); +static void gtk_input_dialog_set_mapping_mode(GtkWidget *w, + gpointer data); +static void gtk_input_dialog_set_axis(GtkWidget *widget, gpointer data); +static void gtk_input_dialog_fill_axes (GtkInputDialog *inputd, + GdkDeviceInfo *info); + +static GtkObjectClass *parent_class = NULL; +static gint input_dialog_signals[LAST_SIGNAL] = { 0 }; + +static void +gtk_input_dialog_marshal_signal1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkInputDialogSignal1 rfunc; + + rfunc = (GtkInputDialogSignal1) func; + (* rfunc) (object, GTK_VALUE_INT(args[0]), func_data); +} + +static GdkDeviceInfo * +gtk_input_dialog_get_device_info(guint32 deviceid) +{ + GList *tmp_list = gdk_input_list_devices(); + while (tmp_list) + { + if (((GdkDeviceInfo *)tmp_list->data)->deviceid == deviceid) + return (GdkDeviceInfo *)tmp_list->data; + tmp_list = tmp_list->next; + } + + return NULL; +} + +guint +gtk_input_dialog_get_type () +{ + static guint input_dialog_type = 0; + + if (!input_dialog_type) + { + GtkTypeInfo input_dialog_info = + { + "GtkInputDialog", + sizeof (GtkInputDialog), + sizeof (GtkInputDialogClass), + (GtkClassInitFunc) gtk_input_dialog_class_init, + (GtkObjectInitFunc) gtk_input_dialog_init, + (GtkArgFunc) NULL, + }; + + input_dialog_type = gtk_type_unique (gtk_dialog_get_type (), + &input_dialog_info); + } + + return input_dialog_type; +} + +static void +gtk_input_dialog_class_init (GtkInputDialogClass *klass) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) klass; + + parent_class = gtk_type_class (gtk_dialog_get_type ()); + + input_dialog_signals[ENABLE_DEVICE] = + gtk_signal_new ("enable_device", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkInputDialogClass, enable_device), + gtk_input_dialog_marshal_signal1, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + input_dialog_signals[DISABLE_DEVICE] = + gtk_signal_new ("disable_device", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkInputDialogClass, disable_device), + gtk_input_dialog_marshal_signal1, + GTK_TYPE_NONE, 1, GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, input_dialog_signals, + LAST_SIGNAL); + + + object_class->destroy = gtk_input_dialog_destroy; + klass->enable_device = NULL; + klass->disable_device = NULL; +} + +static void +gtk_input_dialog_init (GtkInputDialog *inputd) +{ + GtkWidget *vbox; + GtkWidget *util_box; + GtkWidget *label; + GtkWidget *device_menu; + GtkWidget *mapping_menu; + GtkWidget *menuitem; + GtkWidget *optionmenu; + GtkWidget *separator; + + GList *tmp_list; + GList *device_info; + + device_info = gdk_input_list_devices(); + + /* shell and main vbox */ + + gtk_window_set_title (GTK_WINDOW (inputd), "Input"); + + vbox = gtk_vbox_new (FALSE, 4); + gtk_container_border_width(GTK_CONTAINER (vbox), 5); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (inputd)->vbox), vbox, TRUE, TRUE, 0); + + if (g_list_length(device_info) <= 1) /* only core device */ + { + label = gtk_label_new ("No input devices"); + gtk_container_add (GTK_CONTAINER (vbox), label); + + gtk_widget_show (label); + } + else + { + /* menu for selecting device */ + + device_menu = gtk_menu_new (); + + for (tmp_list = device_info; tmp_list; tmp_list = tmp_list->next) { + GdkDeviceInfo *info = (GdkDeviceInfo *)(tmp_list->data); + if (info->deviceid != GDK_CORE_POINTER) + { + menuitem = gtk_menu_item_new_with_label(info->name); + + gtk_menu_append(GTK_MENU(device_menu),menuitem); + gtk_widget_show(menuitem); + gtk_object_set_user_data (GTK_OBJECT (menuitem), inputd); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) gtk_input_dialog_set_device, + (gpointer)((long)info->deviceid)); + } + } + + util_box = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0); + + label = gtk_label_new("Device:"); + gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2); + + optionmenu = gtk_option_menu_new (); + gtk_box_pack_start (GTK_BOX (util_box), optionmenu, TRUE, TRUE, 2); + gtk_widget_show (optionmenu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), device_menu); + + gtk_widget_show (label); + gtk_widget_show (util_box); + + /* Device options */ + + separator = gtk_hseparator_new(); + gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + util_box = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), util_box, FALSE, FALSE, 0); + + /* mapping mode option menu */ + + mapping_menu = gtk_menu_new (); + + menuitem = gtk_menu_item_new_with_label("Disabled"); + gtk_menu_append(GTK_MENU(mapping_menu),menuitem); + gtk_object_set_user_data (GTK_OBJECT (menuitem), inputd); + gtk_widget_show(menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) gtk_input_dialog_set_mapping_mode, + (gpointer)((long)GDK_MODE_DISABLED)); + + menuitem = gtk_menu_item_new_with_label("Screen"); + gtk_menu_append(GTK_MENU(mapping_menu),menuitem); + gtk_object_set_user_data (GTK_OBJECT (menuitem), inputd); + gtk_widget_show(menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) gtk_input_dialog_set_mapping_mode, + (gpointer)((long)GDK_MODE_SCREEN)); + + menuitem = gtk_menu_item_new_with_label("Window"); + gtk_menu_append(GTK_MENU(mapping_menu),menuitem); + gtk_object_set_user_data (GTK_OBJECT (menuitem), inputd); + gtk_widget_show(menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) gtk_input_dialog_set_mapping_mode, + (gpointer)((long)GDK_MODE_WINDOW)); + + label = gtk_label_new("Mode: "); + gtk_box_pack_start (GTK_BOX (util_box), label, FALSE, FALSE, 2); + + inputd->mode_optionmenu = gtk_option_menu_new (); + gtk_box_pack_start (GTK_BOX (util_box), inputd->mode_optionmenu, FALSE, FALSE, 2); + gtk_widget_show (inputd->mode_optionmenu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (inputd->mode_optionmenu), mapping_menu); + + gtk_widget_show(label); + + gtk_widget_show (util_box); + + util_box = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX(vbox), util_box, FALSE, FALSE, 0); + + gtk_widget_show (label); + gtk_widget_show (util_box); + + /* The axis listbox */ + + label = gtk_label_new ("Axes"); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + inputd->axis_listbox = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_set_usize (inputd->axis_listbox, AXIS_LIST_WIDTH, AXIS_LIST_HEIGHT); + gtk_box_pack_start (GTK_BOX (vbox), inputd->axis_listbox, TRUE, TRUE, 0); + gtk_widget_show (inputd->axis_listbox); + + inputd->axis_list = 0; + + gtk_widget_show(label); + + /* ...set_device expects to get input dialog from widget user data */ + gtk_object_set_user_data (GTK_OBJECT (inputd), inputd); + gtk_input_dialog_set_device(GTK_WIDGET(inputd), (gpointer)((long) + ((GdkDeviceInfo *)device_info->data)->deviceid)); + } + + /* buttons */ + + inputd->save_button = gtk_button_new_with_label ("Save"); + GTK_WIDGET_SET_FLAGS (inputd->save_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(inputd)->action_area), + inputd->save_button, TRUE, TRUE, 0); + gtk_widget_show (inputd->save_button); + + inputd->close_button = gtk_button_new_with_label ("Close"); + GTK_WIDGET_SET_FLAGS (inputd->close_button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(inputd)->action_area), + inputd->close_button, TRUE, TRUE, 0); + + gtk_widget_show (inputd->close_button); + gtk_widget_grab_default (inputd->close_button); + + gtk_widget_show (vbox); +} + + +GtkWidget* +gtk_input_dialog_new (void) +{ + GtkInputDialog *inputd; + + inputd = gtk_type_new (gtk_input_dialog_get_type ()); + + return GTK_WIDGET (inputd); +} + +static void +gtk_input_dialog_set_device(GtkWidget *widget, gpointer data) +{ + guint32 deviceid = (guint32)data; + GdkDeviceInfo *info; + + GtkInputDialog *inputd = GTK_INPUT_DIALOG( + gtk_object_get_user_data(GTK_OBJECT(widget))); + + inputd->current_device = deviceid; + info = gtk_input_dialog_get_device_info((guint32)data); + + gtk_input_dialog_fill_axes(inputd, info); + + gtk_option_menu_set_history(GTK_OPTION_MENU(inputd->mode_optionmenu), + info->mode); +} + +static void +gtk_input_dialog_destroy (GtkObject *object) +{ + /* GtkInputDialog *inputd = GTK_INPUT_DIALOG (object); */ + + /* Clean up ? */ + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_input_dialog_set_mapping_mode(GtkWidget *w, + gpointer data) +{ + GtkInputDialog *inputd = GTK_INPUT_DIALOG( + gtk_object_get_user_data(GTK_OBJECT(w))); + GdkDeviceInfo *info = gtk_input_dialog_get_device_info (inputd->current_device); + GdkInputMode old_mode = info->mode; + GdkInputMode mode = (GdkInputMode)data; + + if (mode != old_mode) + { + if (gdk_input_set_mode(inputd->current_device, mode)) + { + if (mode == GDK_MODE_DISABLED) + gtk_signal_emit (GTK_OBJECT (inputd), + input_dialog_signals[DISABLE_DEVICE], + info->deviceid); + else + gtk_signal_emit (GTK_OBJECT (inputd), + input_dialog_signals[ENABLE_DEVICE], + info->deviceid); + } + else + gtk_option_menu_set_history (GTK_OPTION_MENU (inputd->mode_optionmenu), + old_mode); + + /* FIXME: error dialog ? */ + } +} + +static void +gtk_input_dialog_set_axis(GtkWidget *widget, gpointer data) +{ + GdkAxisUse use = (GdkAxisUse)data & 0xFFFF; + GdkAxisUse old_use; + GdkAxisUse *new_axes; + GtkInputDialog *inputd = GTK_INPUT_DIALOG (gtk_object_get_user_data (GTK_OBJECT (widget))); + GdkDeviceInfo *info = gtk_input_dialog_get_device_info (inputd->current_device); + + gint axis = ((gint)data >> 16) - 1; + gint old_axis; + int i; + + new_axes = g_new (GdkAxisUse, info->num_axes); + old_axis = -1; + for (i=0;inum_axes;i++) + { + new_axes[i] = info->axes[i]; + if (info->axes[i] == use) + old_axis = i; + } + + if (axis != -1) + old_use = info->axes[axis]; + else + old_use = GDK_AXIS_IGNORE; + + if (axis == old_axis) + return; + + /* we must always have an x and a y axis */ + if ((axis == -1 && (use == GDK_AXIS_X || use == GDK_AXIS_Y)) || + (old_axis == -1 && (old_use == GDK_AXIS_X || old_use == GDK_AXIS_Y))) + { + gtk_option_menu_set_history ( + GTK_OPTION_MENU (inputd->axis_items[use]), + old_axis + 1); + } + else + { + if (axis != -1) + new_axes[axis] = use; + + if (old_axis != -1) + new_axes[old_axis] = old_use; + + if (old_use != GDK_AXIS_IGNORE) + { + gtk_option_menu_set_history ( + GTK_OPTION_MENU (inputd->axis_items[old_use]), + old_axis + 1); + } + gdk_input_set_axes (info->deviceid, new_axes); + } + + g_free (new_axes); +} + +static void +gtk_input_dialog_fill_axes(GtkInputDialog *inputd, GdkDeviceInfo *info) +{ + static char *axis_use_strings[GDK_AXIS_LAST] = + { + "", + "X", + "Y", + "Pressure", + "X Tilt", + "Y Tilt" + }; + + int i,j; + GtkWidget *list_item; + GtkWidget *menu; + GtkWidget *option_menu; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *label; + + /* remove all the old items */ + if (inputd->axis_list) + { + gtk_widget_hide (inputd->axis_list); /* suppress resizes (or get warnings) */ + gtk_widget_destroy (inputd->axis_list); + } + inputd->axis_list = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (inputd->axis_listbox), inputd->axis_list); + gtk_widget_show (inputd->axis_list); + + gtk_widget_realize (inputd->axis_list); + gdk_window_set_background (inputd->axis_list->window, + &inputd->axis_list->style->white); + + for (i=GDK_AXIS_X;iaxis_list),list_item,FALSE,FALSE,0); + gtk_widget_show (list_item); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add(GTK_CONTAINER (list_item), vbox); + + hbox = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 1); + + /* create the label */ + + label = gtk_label_new(axis_use_strings[i]); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 2); + + /* and the use option menu */ + menu = gtk_menu_new(); + + for (j = -1; j < info->num_axes; j++) + { + char buffer[16]; + GtkWidget *menu_item; + + if (j == -1) + menu_item = gtk_menu_item_new_with_label ("none"); + else + { + sprintf (buffer,"%d",j+1); + menu_item = gtk_menu_item_new_with_label (buffer); + } + gtk_object_set_user_data (GTK_OBJECT (menu_item), inputd); + gtk_signal_connect (GTK_OBJECT (menu_item), "activate", + (GtkSignalFunc) gtk_input_dialog_set_axis, + (gpointer) ((long) (0x10000 * (j + 1) + i))); + gtk_widget_show (menu_item); + gtk_menu_append (GTK_MENU (menu), menu_item); + } + + inputd->axis_items[i] = option_menu = gtk_option_menu_new (); + gtk_box_pack_start (GTK_BOX (hbox), option_menu, FALSE, FALSE, 2); + + gtk_widget_show (option_menu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + for (j = 0; j < info->num_axes; j++) + if (info->axes[j] == (GdkAxisUse) i) + { + gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), j+1); + break; + } + + gtk_widget_show (label); + + gtk_widget_show (hbox); + gtk_widget_show (vbox); + } +} diff --git a/gtk/gtkinputdialog.h b/gtk/gtkinputdialog.h new file mode 100644 index 000000000..93c667f44 --- /dev/null +++ b/gtk/gtkinputdialog.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_INPUTDIALOG_H__ +#define __GTK_INPUTDIALOG_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_INPUT_DIALOG(obj) GTK_CHECK_CAST (obj, gtk_input_dialog_get_type (), GtkInputDialog) +#define GTK_INPUT_DIALOG_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_input_dialog_get_type (), GtkInputDialogClass) +#define GTK_IS_INPUT_DIALOG(obj) GTK_CHECK_TYPE (obj, gtk_input_dialog_get_type ()) + + +typedef struct _GtkInputDialog GtkInputDialog; +typedef struct _GtkInputDialogClass GtkInputDialogClass; + +struct _GtkInputDialog +{ + GtkDialog dialog; + + GtkWidget *axis_list; + GtkWidget *axis_listbox; + GtkWidget *mode_optionmenu; + + GtkWidget *close_button; + GtkWidget *save_button; + + GtkWidget *axis_items[GDK_AXIS_LAST]; + guint32 current_device; +}; + +struct _GtkInputDialogClass +{ + GtkWindowClass parent_class; + + void (* enable_device) (GtkInputDialog *inputd, + guint32 devid, + gpointer *data); + void (* disable_device) (GtkInputDialog *inputd, + guint32 devid, + gpointer *data); +}; + + +guint gtk_input_dialog_get_type (void); +GtkWidget* gtk_input_dialog_new (); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_INPUTDIALOG_H__ */ diff --git a/gtk/gtkitem.c b/gtk/gtkitem.c new file mode 100644 index 000000000..6dd0ec8dd --- /dev/null +++ b/gtk/gtkitem.c @@ -0,0 +1,191 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkitem.h" +#include "gtksignal.h" + + +enum { + SELECT, + DESELECT, + TOGGLE, + LAST_SIGNAL +}; + + +static void gtk_item_class_init (GtkItemClass *klass); +static void gtk_item_init (GtkItem *item); +static void gtk_item_map (GtkWidget *widget); +static void gtk_item_unmap (GtkWidget *widget); +static void gtk_item_realize (GtkWidget *widget); + + +static gint item_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_item_get_type () +{ + static guint item_type = 0; + + if (!item_type) + { + GtkTypeInfo item_info = + { + "GtkItem", + sizeof (GtkItem), + sizeof (GtkItemClass), + (GtkClassInitFunc) gtk_item_class_init, + (GtkObjectInitFunc) gtk_item_init, + (GtkArgFunc) NULL, + }; + + item_type = gtk_type_unique (gtk_bin_get_type (), &item_info); + } + + return item_type; +} + +static void +gtk_item_class_init (GtkItemClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + item_signals[SELECT] = + gtk_signal_new ("select", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkItemClass, select), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + item_signals[DESELECT] = + gtk_signal_new ("deselect", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkItemClass, deselect), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + item_signals[TOGGLE] = + gtk_signal_new ("toggle", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkItemClass, toggle), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, item_signals, LAST_SIGNAL); + + widget_class->activate_signal = item_signals[TOGGLE]; + widget_class->map = gtk_item_map; + widget_class->unmap = gtk_item_unmap; + widget_class->realize = gtk_item_realize; + + class->select = NULL; + class->deselect = NULL; + class->toggle = NULL; +} + +static void +gtk_item_init (GtkItem *item) +{ + GTK_WIDGET_UNSET_FLAGS (item, GTK_NO_WINDOW); +} + +void +gtk_item_select (GtkItem *item) +{ + gtk_signal_emit (GTK_OBJECT (item), item_signals[SELECT]); +} + +void +gtk_item_deselect (GtkItem *item) +{ + gtk_signal_emit (GTK_OBJECT (item), item_signals[DESELECT]); +} + +void +gtk_item_toggle (GtkItem *item) +{ + gtk_signal_emit (GTK_OBJECT (item), item_signals[TOGGLE]); +} + + +static void +gtk_item_map (GtkWidget *widget) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ITEM (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + gdk_window_show (widget->window); + + bin = GTK_BIN (widget); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + !GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_map (bin->child); +} + +static void +gtk_item_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ITEM (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_item_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ITEM (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} diff --git a/gtk/gtkitem.h b/gtk/gtkitem.h new file mode 100644 index 000000000..36cf1ab45 --- /dev/null +++ b/gtk/gtkitem.h @@ -0,0 +1,65 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_ITEM_H__ +#define __GTK_ITEM_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_ITEM(obj) GTK_CHECK_CAST (obj, gtk_item_get_type (), GtkItem) +#define GTK_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_item_get_type (), GtkItemClass) +#define GTK_IS_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_item_get_type ()) + + +typedef struct _GtkItem GtkItem; +typedef struct _GtkItemClass GtkItemClass; + +struct _GtkItem +{ + GtkBin bin; +}; + +struct _GtkItemClass +{ + GtkBinClass parent_class; + + void (* select) (GtkItem *item); + void (* deselect) (GtkItem *item); + void (* toggle) (GtkItem *item); +}; + + +guint gtk_item_get_type (void); +void gtk_item_select (GtkItem *item); +void gtk_item_deselect (GtkItem *item); +void gtk_item_toggle (GtkItem *item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_ITEM_H__ */ diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c new file mode 100644 index 000000000..5cd1f804f --- /dev/null +++ b/gtk/gtklabel.c @@ -0,0 +1,329 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtklabel.h" + + +static void gtk_label_class_init (GtkLabelClass *klass); +static void gtk_label_init (GtkLabel *label); +static void gtk_label_destroy (GtkObject *object); +static void gtk_label_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static gint gtk_label_expose (GtkWidget *widget, + GdkEventExpose *event); + + +static GtkMiscClass *parent_class = NULL; + + +guint +gtk_label_get_type () +{ + static guint label_type = 0; + + if (!label_type) + { + GtkTypeInfo label_info = + { + "GtkLabel", + sizeof (GtkLabel), + sizeof (GtkLabelClass), + (GtkClassInitFunc) gtk_label_class_init, + (GtkObjectInitFunc) gtk_label_init, + (GtkArgFunc) NULL, + }; + + label_type = gtk_type_unique (gtk_misc_get_type (), &label_info); + } + + return label_type; +} + +void +gtk_label_class_init (GtkLabelClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_misc_get_type ()); + + object_class->destroy = gtk_label_destroy; + + widget_class->size_request = gtk_label_size_request; + widget_class->expose_event = gtk_label_expose; +} + +void +gtk_label_init (GtkLabel *label) +{ + GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW); + + label->label = NULL; + label->row = NULL; + label->jtype = GTK_JUSTIFY_CENTER; +} + +GtkWidget* +gtk_label_new (const char *str) +{ + GtkLabel *label; + + g_return_val_if_fail (str != NULL, NULL); + + label = gtk_type_new (gtk_label_get_type ()); + + gtk_label_set (label, str); + + return GTK_WIDGET (label); +} + +void +gtk_label_set (GtkLabel *label, + const char *str) +{ + char* p; + + g_return_if_fail (label != NULL); + g_return_if_fail (GTK_IS_LABEL (label)); + g_return_if_fail (str != NULL); + + if (label->label) + g_free (label->label); + label->label = g_strdup (str); + + if (label->row) + g_slist_free (label->row); + label->row = NULL; + label->row = g_slist_append (label->row, label->label); + p = label->label; + while ((p = strchr(p, '\n'))) + label->row = g_slist_append (label->row, ++p); + + if (GTK_WIDGET_VISIBLE (label)) + { + if (GTK_WIDGET_MAPPED (label)) + gdk_window_clear_area (GTK_WIDGET (label)->window, + GTK_WIDGET (label)->allocation.x, + GTK_WIDGET (label)->allocation.y, + GTK_WIDGET (label)->allocation.width, + GTK_WIDGET (label)->allocation.height); + + gtk_widget_queue_resize (GTK_WIDGET (label)); + } +} + +void +gtk_label_set_justify (GtkLabel *label, GtkJustification jtype) +{ + g_return_if_fail (label != NULL); + g_return_if_fail (GTK_IS_LABEL (label)); + + if ((GtkJustification) label->jtype != jtype) + { + label->jtype = jtype; + + if (GTK_WIDGET_VISIBLE (label)) + { + if (GTK_WIDGET_MAPPED (label)) + gdk_window_clear_area (GTK_WIDGET (label)->window, + GTK_WIDGET (label)->allocation.x, + GTK_WIDGET (label)->allocation.y, + GTK_WIDGET (label)->allocation.width, + GTK_WIDGET (label)->allocation.height); + + gtk_widget_queue_resize (GTK_WIDGET (label)); + } + } +} + +void +gtk_label_get (GtkLabel *label, + char **str) +{ + g_return_if_fail (label != NULL); + g_return_if_fail (GTK_IS_LABEL (label)); + g_return_if_fail (str != NULL); + + *str = label->label; +} + + +static void +gtk_label_destroy (GtkObject *object) +{ + GtkLabel *label; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_LABEL (object)); + + label = GTK_LABEL (object); + + if (GTK_WIDGET (object)->parent && + GTK_WIDGET_MAPPED (object)) + gtk_widget_unmap (GTK_WIDGET (object)); + + g_free (label->label); + g_slist_free (label->row); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_label_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkLabel *label; + GSList *row; + gint width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LABEL (widget)); + g_return_if_fail (requisition != NULL); + + label = GTK_LABEL (widget); + + row = label->row; + width = 0; + while (row) + { + if (row->next) + width = MAX (width, + gdk_text_width (GTK_WIDGET (label)->style->font, row->data, + (gchar*) row->next->data - (gchar*) row->data)); + else + width = MAX (width, gdk_string_width (GTK_WIDGET (label)->style->font, row->data)); + row = row->next; + } + + requisition->width = width + label->misc.xpad * 2; + requisition->height = ((GTK_WIDGET (label)->style->font->ascent + + GTK_WIDGET (label)->style->font->descent + 2) * + g_slist_length(label->row) + + label->misc.ypad * 2); +} + +static gint +gtk_label_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkLabel *label; + GtkMisc *misc; + GSList *row; + gint state; + gint offset; + gint len; + gint maxl; + gint x, y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + label = GTK_LABEL (widget); + misc = GTK_MISC (widget); + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + /* We only draw the label if we have been allocated at least as + * much space as we requested. If we have less space than we + * need to draw the string then we _should_ have asked our + * parent container to resize and a new allocation _should_ + * be forthcoming so there is no reason to redraw (incorrectly) + * here. + */ + if ((widget->allocation.width >= widget->requisition.width) && + (widget->allocation.height >= widget->requisition.height)) + { + maxl = widget->requisition.width - misc->xpad * 2; + x = widget->allocation.x + misc->xpad + + (widget->allocation.width - widget->requisition.width) * misc->xalign + 0.5; + y = (widget->allocation.y * (1.0 - misc->yalign) + + (widget->allocation.y + widget->allocation.height - (widget->requisition.height - + misc->ypad * 2)) * + misc->yalign + widget->style->font->ascent) + 1.5; + + row = label->row; + while (row && row->next) + { + len = (gchar*) row->next->data - (gchar*) row->data; + offset = 0; + if (label->jtype == GTK_JUSTIFY_CENTER) + offset = (maxl - gdk_text_width (widget->style->font, row->data, len)) / 2; + else if (label->jtype == GTK_JUSTIFY_RIGHT) + offset = (maxl - gdk_text_width (widget->style->font, row->data, len)); + if (state == GTK_STATE_INSENSITIVE) + gdk_draw_text (widget->window, widget->style->font, + widget->style->white_gc, + offset + x + 1, y + 1, row->data, len); + + gdk_draw_text (widget->window, widget->style->font, + widget->style->fg_gc[state], + offset + x, y, row->data, len); + row = row->next; + y += widget->style->font->ascent + widget->style->font->descent + 2; + } + + /* COMMENT: we can avoid gdk_text_width() calls here storing in label->row + the widths of the rows calculated in gtk_label_set. + Once we have a wrapping interface we can support GTK_JUSTIFY_FILL. + */ + offset = 0; + if (label->jtype == GTK_JUSTIFY_CENTER) + offset = (maxl - gdk_string_width (widget->style->font, row->data)) / 2; + else if (label->jtype == GTK_JUSTIFY_RIGHT) + offset = (maxl - gdk_string_width (widget->style->font, row->data)); + if (state == GTK_STATE_INSENSITIVE) + gdk_draw_string (widget->window, widget->style->font, + widget->style->white_gc, + offset + x + 1, y + 1, row->data); + + gdk_draw_string (widget->window, widget->style->font, + widget->style->fg_gc[state], + offset + x, y, row->data); + + /* + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_STATE_SELECTED], FALSE, + widget->allocation.x, widget->allocation.y, + widget->allocation.width - 1, widget->allocation.height - 1); + */ + } + else + { + /* + g_print ("gtk_label_expose: allocation too small: %d %d ( %d %d )\n", + widget->allocation.width, widget->allocation.height, + widget->requisition.width, widget->requisition.height); + */ + } + } + + return TRUE; +} + + + + diff --git a/gtk/gtklabel.h b/gtk/gtklabel.h new file mode 100644 index 000000000..81eca4afe --- /dev/null +++ b/gtk/gtklabel.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_LABEL_H__ +#define __GTK_LABEL_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_LABEL(obj) GTK_CHECK_CAST (obj, gtk_label_get_type (), GtkLabel) +#define GTK_LABEL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_label_get_type (), GtkLabelClass) +#define GTK_IS_LABEL(obj) GTK_CHECK_TYPE (obj, gtk_label_get_type ()) + + +typedef struct _GtkLabel GtkLabel; +typedef struct _GtkLabelClass GtkLabelClass; + +struct _GtkLabel +{ + GtkMisc misc; + + char *label; + GSList *row; + guint jtype : 2; +}; + +struct _GtkLabelClass +{ + GtkMiscClass parent_class; +}; + + +guint gtk_label_get_type (void); +GtkWidget* gtk_label_new (const char *str); +void gtk_label_set (GtkLabel *label, + const char *str); +void gtk_label_set_justify (GtkLabel *label, + GtkJustification jtype); +void gtk_label_get (GtkLabel *label, + char **str); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_LABEL_H__ */ diff --git a/gtk/gtklist.c b/gtk/gtklist.c new file mode 100644 index 000000000..7d7d4a66d --- /dev/null +++ b/gtk/gtklist.c @@ -0,0 +1,1007 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtklist.h" +#include "gtklistitem.h" +#include "gtkmain.h" +#include "gtksignal.h" + + +enum { + SELECTION_CHANGED, + SELECT_CHILD, + UNSELECT_CHILD, + LAST_SIGNAL +}; + + +typedef void (*GtkListSignal) (GtkObject *object, + gpointer arg1, + gpointer data); + + +static void gtk_list_class_init (GtkListClass *klass); +static void gtk_list_init (GtkList *list); +static void gtk_list_destroy (GtkObject *object); +static void gtk_list_map (GtkWidget *widget); +static void gtk_list_unmap (GtkWidget *widget); +static void gtk_list_realize (GtkWidget *widget); +static void gtk_list_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_list_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_list_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_list_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_list_button_release (GtkWidget *widget, + GdkEventButton *event); +static void gtk_list_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_list_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_list_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_list_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_list_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + +static void gtk_real_list_select_child (GtkList *list, + GtkWidget *child); +static void gtk_real_list_unselect_child (GtkList *list, + GtkWidget *child); + +static void gtk_list_marshal_signal (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + + +static GtkContainerClass *parent_class = NULL; +static gint list_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_list_get_type () +{ + static guint list_type = 0; + + if (!list_type) + { + GtkTypeInfo list_info = + { + "GtkList", + sizeof (GtkList), + sizeof (GtkListClass), + (GtkClassInitFunc) gtk_list_class_init, + (GtkObjectInitFunc) gtk_list_init, + (GtkArgFunc) NULL, + }; + + list_type = gtk_type_unique (gtk_container_get_type (), &list_info); + } + + return list_type; +} + +static void +gtk_list_class_init (GtkListClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + list_signals[SELECTION_CHANGED] = + gtk_signal_new ("selection_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkListClass, selection_changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + list_signals[SELECT_CHILD] = + gtk_signal_new ("select_child", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkListClass, select_child), + gtk_list_marshal_signal, + GTK_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + list_signals[UNSELECT_CHILD] = + gtk_signal_new ("unselect_child", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkListClass, unselect_child), + gtk_list_marshal_signal, + GTK_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + + gtk_object_class_add_signals (object_class, list_signals, LAST_SIGNAL); + + object_class->destroy = gtk_list_destroy; + + widget_class->map = gtk_list_map; + widget_class->unmap = gtk_list_unmap; + widget_class->realize = gtk_list_realize; + widget_class->draw = gtk_list_draw; + widget_class->expose_event = gtk_list_expose; + widget_class->motion_notify_event = gtk_list_motion_notify; + widget_class->button_press_event = gtk_list_button_press; + widget_class->button_release_event = gtk_list_button_release; + widget_class->size_request = gtk_list_size_request; + widget_class->size_allocate = gtk_list_size_allocate; + + container_class->add = gtk_list_add; + container_class->remove = gtk_list_remove; + container_class->foreach = gtk_list_foreach; + + class->selection_changed = NULL; + class->select_child = gtk_real_list_select_child; + class->unselect_child = gtk_real_list_unselect_child; +} + +static void +gtk_list_init (GtkList *list) +{ + list->children = NULL; + list->selection = NULL; + list->timer = 0; + list->selection_start_pos = 0; + list->selection_end_pos = 0; + list->selection_mode = GTK_SELECTION_SINGLE; + list->scroll_direction = 0; + list->have_grab = FALSE; +} + +GtkWidget* +gtk_list_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_list_get_type ())); +} + +void +gtk_list_insert_items (GtkList *list, + GList *items, + gint position) +{ + GtkWidget *widget; + GList *tmp_list; + GList *last; + gint nchildren; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + if (!items) + return; + + tmp_list = items; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + gtk_widget_set_parent (widget, GTK_WIDGET (list)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + } + + nchildren = g_list_length (list->children); + if ((position < 0) || (position > nchildren)) + position = nchildren; + + if (position == nchildren) + { + if (list->children) + { + tmp_list = g_list_last (list->children); + tmp_list->next = items; + items->prev = tmp_list; + } + else + { + list->children = items; + } + } + else + { + tmp_list = g_list_nth (list->children, position); + last = g_list_last (items); + + if (tmp_list->prev) + tmp_list->prev->next = items; + last->next = tmp_list; + items->prev = tmp_list->prev; + tmp_list->prev = last; + + if (tmp_list == list->children) + list->children = items; + } + + if (list->children && !list->selection && + (list->selection_mode == GTK_SELECTION_BROWSE)) + { + widget = list->children->data; + gtk_list_select_child (list, widget); + } + + if (GTK_WIDGET_VISIBLE (list)) + gtk_widget_queue_resize (GTK_WIDGET (list)); +} + +void +gtk_list_append_items (GtkList *list, + GList *items) +{ + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + gtk_list_insert_items (list, items, -1); +} + +void +gtk_list_prepend_items (GtkList *list, + GList *items) +{ + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + gtk_list_insert_items (list, items, 0); +} + +void +gtk_list_remove_items (GtkList *list, + GList *items) +{ + GtkWidget *widget; + GList *selected_widgets; + GList *tmp_list; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + tmp_list = items; + selected_widgets = NULL; + widget = NULL; + + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + if (widget->state == GTK_STATE_SELECTED) + selected_widgets = g_list_prepend (selected_widgets, widget); + + list->children = g_list_remove (list->children, widget); + + if (GTK_WIDGET_MAPPED (widget)) + gtk_widget_unmap (widget); + + gtk_widget_unparent (widget); + } + + if (selected_widgets) + { + tmp_list = selected_widgets; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + gtk_list_unselect_child (list, widget); + } + + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + + g_list_free (selected_widgets); + + if (list->children && !list->selection && + (list->selection_mode == GTK_SELECTION_BROWSE)) + { + widget = list->children->data; + gtk_list_select_child (list, widget); + } + + if (GTK_WIDGET_VISIBLE (list)) + gtk_widget_queue_resize (GTK_WIDGET (list)); +} + +void +gtk_list_clear_items (GtkList *list, + gint start, + gint end) +{ + GtkWidget *widget; + GList *start_list; + GList *end_list; + GList *tmp_list; + gint nchildren; + gint selection_changed; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + nchildren = g_list_length (list->children); + + if (nchildren > 0) + { + if ((end < 0) || (end > nchildren)) + end = nchildren; + + g_return_if_fail (start < end); + + start_list = g_list_nth (list->children, start); + end_list = g_list_nth (list->children, end); + + if (start_list->prev) + start_list->prev->next = end_list; + if (end_list && end_list->prev) + end_list->prev->next = NULL; + if (end_list) + end_list->prev = start_list->prev; + if (start_list == list->children) + list->children = end_list; + + selection_changed = FALSE; + widget = NULL; + tmp_list = start_list; + + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + if (widget->state == GTK_STATE_SELECTED) + { + selection_changed = TRUE; + list->selection = g_list_remove (list->selection, widget); + } + + /* list->children = g_list_remove (list->children, widget); */ + /* gtk_widget_unparent (widget); */ + + gtk_widget_destroy (widget); + } + + if (list->children && !list->selection && + (list->selection_mode == GTK_SELECTION_BROWSE)) + { + gtk_list_select_child (list, widget); + widget = list->children->data; + } + + if (selection_changed) + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + + gtk_widget_queue_resize (GTK_WIDGET (list)); + } +} + +void +gtk_list_select_item (GtkList *list, + gint item) +{ + GList *tmp_list; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + tmp_list = g_list_nth (list->children, item); + if (tmp_list) + gtk_list_select_child (list, GTK_WIDGET (tmp_list->data)); +} + +void +gtk_list_unselect_item (GtkList *list, + gint item) +{ + GList *tmp_list; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + tmp_list = g_list_nth (list->children, item); + if (tmp_list) + gtk_list_unselect_child (list, GTK_WIDGET (tmp_list->data)); +} + +void +gtk_list_select_child (GtkList *list, + GtkWidget *child) +{ + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECT_CHILD], child); +} + +void +gtk_list_unselect_child (GtkList *list, + GtkWidget *child) +{ + gtk_signal_emit (GTK_OBJECT (list), list_signals[UNSELECT_CHILD], child); +} + +gint +gtk_list_child_position (GtkList *list, + GtkWidget *child) +{ + GList *children; + gint pos; + + g_return_val_if_fail (list != NULL, -1); + g_return_val_if_fail (GTK_IS_LIST (list), -1); + g_return_val_if_fail (child != NULL, -1); + + pos = 0; + children = list->children; + + while (children) + { + if (child == GTK_WIDGET (children->data)) + return pos; + + pos += 1; + children = children->next; + } + + return -1; +} + +void +gtk_list_set_selection_mode (GtkList *list, + GtkSelectionMode mode) +{ + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + + list->selection_mode = mode; +} + + +static void +gtk_list_destroy (GtkObject *object) +{ + GtkList *list; + GtkWidget *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_LIST (object)); + + list = GTK_LIST (object); + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + child->parent = NULL; + gtk_object_unref (GTK_OBJECT (child)); + gtk_widget_destroy (child); + } + + g_list_free (list->children); + g_list_free (list->selection); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_list_map (GtkWidget *widget) +{ + GtkList *list; + GtkWidget *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + list = GTK_LIST (widget); + + gdk_window_show (widget->window); + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } +} + +static void +gtk_list_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_list_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = GDK_EXPOSURE_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gdk_window_set_background (widget->window, &widget->style->white); +} + +static void +gtk_list_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkList *list; + GtkWidget *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + list = GTK_LIST (widget); + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child, area, &child_area)) + gtk_widget_draw (child, &child_area); + } + } +} + +static gint +gtk_list_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkList *list; + GtkWidget *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + list = GTK_LIST (widget); + + child_event = *event; + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child) && + gtk_widget_intersect (child, &event->area, &child_event.area)) + gtk_widget_event (child, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static gint +gtk_list_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + g_print ("gtk_list_motion_notify\n"); + + return FALSE; +} + +static gint +gtk_list_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkList *list; + GtkWidget *item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + list = GTK_LIST (widget); + item = gtk_get_event_widget ((GdkEvent*) event); + + while (!gtk_type_is_a (GTK_WIDGET_TYPE (item), gtk_list_item_get_type ())) + item = item->parent; + + gtk_list_select_child (list, item); + + return FALSE; +} + +static gint +gtk_list_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkList *list; + GtkWidget *item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + list = GTK_LIST (widget); + item = gtk_get_event_widget ((GdkEvent*) event); + + return FALSE; +} + +static void +gtk_list_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkList *list; + GtkWidget *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + g_return_if_fail (requisition != NULL); + + list = GTK_LIST (widget); + requisition->width = 0; + requisition->height = 0; + + children = list->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + gtk_widget_size_request (child, &child->requisition); + + requisition->width = MAX (requisition->width, child->requisition.width); + requisition->height += child->requisition.height; + } + } + + requisition->width += GTK_CONTAINER (list)->border_width * 2; + requisition->height += GTK_CONTAINER (list)->border_width * 2; + + requisition->width = MAX (requisition->width, 1); + requisition->height = MAX (requisition->height, 1); +} + +static void +gtk_list_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkList *list; + GtkWidget *child; + GtkAllocation child_allocation; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST (widget)); + g_return_if_fail (allocation != NULL); + + list = GTK_LIST (widget); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + if (list->children) + { + child_allocation.x = GTK_CONTAINER (list)->border_width; + child_allocation.y = GTK_CONTAINER (list)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + + children = list->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + child_allocation.height = child->requisition.height; + + gtk_widget_size_allocate (child, &child_allocation); + + child_allocation.y += child_allocation.height; + } + } + } +} + +static void +gtk_list_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkList *list; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_LIST (container)); + g_return_if_fail (widget != NULL); + + list = GTK_LIST (container); + + gtk_widget_set_parent (widget, GTK_WIDGET (container)); + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + list->children = g_list_append (list->children, widget); + + if (!list->selection && (list->selection_mode == GTK_SELECTION_BROWSE)) + { + gtk_list_select_child (list, widget); + } + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (widget); +} + +static void +gtk_list_remove (GtkContainer *container, + GtkWidget *widget) +{ + GList *item_list; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_LIST (container)); + g_return_if_fail (widget != NULL); + g_return_if_fail (container == GTK_CONTAINER (widget->parent)); + + + item_list = g_list_alloc (); + item_list->data = widget; + + gtk_list_remove_items (GTK_LIST (container), item_list); + + g_list_free (item_list); +} + +static void +gtk_list_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkList *list; + GtkWidget *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_LIST (container)); + g_return_if_fail (callback != NULL); + + list = GTK_LIST (container); + children = list->children; + + while (children) + { + child = children->data; + children = children->next; + + (* callback) (child, callback_data); + } +} + + +static void +gtk_real_list_select_child (GtkList *list, + GtkWidget *child) +{ + GList *selection; + GList *tmp_list; + GtkWidget *tmp_item; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + g_return_if_fail (child != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (child)); + + switch (list->selection_mode) + { + case GTK_SELECTION_SINGLE: + selection = list->selection; + + while (selection) + { + tmp_item = selection->data; + + if (tmp_item != child) + { + gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item)); + + tmp_list = selection; + selection = selection->next; + + list->selection = g_list_remove_link (list->selection, tmp_list); + + g_list_free (tmp_list); + } + else + selection = selection->next; + } + + if (child->state == GTK_STATE_NORMAL) + { + gtk_list_item_select (GTK_LIST_ITEM (child)); + list->selection = g_list_prepend (list->selection, child); + } + else if (child->state == GTK_STATE_SELECTED) + { + gtk_list_item_deselect (GTK_LIST_ITEM (child)); + list->selection = g_list_remove (list->selection, child); + } + + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + break; + + case GTK_SELECTION_BROWSE: + selection = list->selection; + + while (selection) + { + tmp_item = selection->data; + + if (tmp_item != child) + { + gtk_list_item_deselect (GTK_LIST_ITEM (tmp_item)); + + tmp_list = selection; + selection = selection->next; + + list->selection = g_list_remove_link (list->selection, tmp_list); + + g_list_free (tmp_list); + } + else + selection = selection->next; + } + + if (child->state == GTK_STATE_NORMAL) + { + gtk_list_item_select (GTK_LIST_ITEM (child)); + list->selection = g_list_prepend (list->selection, child); + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + break; + + case GTK_SELECTION_MULTIPLE: + if (child->state == GTK_STATE_NORMAL) + { + gtk_list_item_select (GTK_LIST_ITEM (child)); + list->selection = g_list_prepend (list->selection, child); + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + else if (child->state == GTK_STATE_SELECTED) + { + gtk_list_item_deselect (GTK_LIST_ITEM (child)); + list->selection = g_list_remove (list->selection, child); + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + break; + + case GTK_SELECTION_EXTENDED: + break; + } +} + +static void +gtk_real_list_unselect_child (GtkList *list, + GtkWidget *child) +{ + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_LIST (list)); + g_return_if_fail (child != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (child)); + + switch (list->selection_mode) + { + case GTK_SELECTION_SINGLE: + case GTK_SELECTION_MULTIPLE: + case GTK_SELECTION_BROWSE: + if (child->state == GTK_STATE_SELECTED) + { + gtk_list_item_deselect (GTK_LIST_ITEM (child)); + list->selection = g_list_remove (list->selection, child); + gtk_signal_emit (GTK_OBJECT (list), list_signals[SELECTION_CHANGED]); + } + break; + + case GTK_SELECTION_EXTENDED: + break; + } +} + + +static void +gtk_list_marshal_signal (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkListSignal rfunc; + + rfunc = (GtkListSignal) func; + + (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data); +} diff --git a/gtk/gtklist.h b/gtk/gtklist.h new file mode 100644 index 000000000..3eff261b5 --- /dev/null +++ b/gtk/gtklist.h @@ -0,0 +1,107 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_LIST_H__ +#define __GTK_LIST_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_LIST(obj) GTK_CHECK_CAST (obj, gtk_list_get_type (), GtkList) +#define GTK_LIST_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_list_get_type (), GtkListClass) +#define GTK_IS_LIST(obj) GTK_CHECK_TYPE (obj, gtk_list_get_type ()) + + +typedef struct _GtkList GtkList; +typedef struct _GtkListClass GtkListClass; + +typedef enum +{ + GTK_SELECTION_SINGLE, + GTK_SELECTION_BROWSE, + GTK_SELECTION_MULTIPLE, + GTK_SELECTION_EXTENDED +} GtkSelectionMode; + +struct _GtkList +{ + GtkContainer container; + + GList *children; + GList *selection; + + guint32 timer; + guint16 selection_start_pos; + guint16 selection_end_pos; + guint selection_mode : 2; + guint scroll_direction : 1; + guint have_grab : 1; +}; + +struct _GtkListClass +{ + GtkContainerClass parent_class; + + void (* selection_changed) (GtkList *list); + void (* select_child) (GtkList *list, + GtkWidget *child); + void (* unselect_child) (GtkList *list, + GtkWidget *child); +}; + + +guint gtk_list_get_type (void); +GtkWidget* gtk_list_new (void); +void gtk_list_insert_items (GtkList *list, + GList *items, + gint position); +void gtk_list_append_items (GtkList *list, + GList *items); +void gtk_list_prepend_items (GtkList *list, + GList *items); +void gtk_list_remove_items (GtkList *list, + GList *items); +void gtk_list_clear_items (GtkList *list, + gint start, + gint end); +void gtk_list_select_item (GtkList *list, + gint item); +void gtk_list_unselect_item (GtkList *list, + gint item); +void gtk_list_select_child (GtkList *list, + GtkWidget *child); +void gtk_list_unselect_child (GtkList *list, + GtkWidget *child); +gint gtk_list_child_position (GtkList *list, + GtkWidget *child); +void gtk_list_set_selection_mode (GtkList *list, + GtkSelectionMode mode); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_LIST_H__ */ diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c new file mode 100644 index 000000000..642027025 --- /dev/null +++ b/gtk/gtklistitem.c @@ -0,0 +1,394 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtklabel.h" +#include "gtklistitem.h" +#include "gtklist.h" + +static void gtk_list_item_class_init (GtkListItemClass *klass); +static void gtk_list_item_init (GtkListItem *list_item); +static void gtk_list_item_realize (GtkWidget *widget); +static void gtk_list_item_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_list_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_list_item_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_list_item_draw_focus (GtkWidget *widget); +static gint gtk_list_item_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_list_item_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_list_item_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_list_item_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_real_list_item_select (GtkItem *item); +static void gtk_real_list_item_deselect (GtkItem *item); +static void gtk_real_list_item_toggle (GtkItem *item); + + +static GtkItemClass *parent_class = NULL; + + +guint +gtk_list_item_get_type () +{ + static guint list_item_type = 0; + + if (!list_item_type) + { + GtkTypeInfo list_item_info = + { + "GtkListItem", + sizeof (GtkListItem), + sizeof (GtkListItemClass), + (GtkClassInitFunc) gtk_list_item_class_init, + (GtkObjectInitFunc) gtk_list_item_init, + (GtkArgFunc) NULL, + }; + + list_item_type = gtk_type_unique (gtk_item_get_type (), &list_item_info); + } + + return list_item_type; +} + +static void +gtk_list_item_class_init (GtkListItemClass *class) +{ + GtkWidgetClass *widget_class; + GtkItemClass *item_class; + + widget_class = (GtkWidgetClass*) class; + item_class = (GtkItemClass*) class; + + parent_class = gtk_type_class (gtk_item_get_type ()); + + widget_class->realize = gtk_list_item_realize; + widget_class->size_request = gtk_list_item_size_request; + widget_class->size_allocate = gtk_list_item_size_allocate; + widget_class->draw = gtk_list_item_draw; + widget_class->draw_focus = gtk_list_item_draw_focus; + widget_class->button_press_event = gtk_list_item_button_press; + widget_class->expose_event = gtk_list_item_expose; + widget_class->focus_in_event = gtk_list_item_focus_in; + widget_class->focus_out_event = gtk_list_item_focus_out; + + item_class->select = gtk_real_list_item_select; + item_class->deselect = gtk_real_list_item_deselect; + item_class->toggle = gtk_real_list_item_toggle; +} + +static void +gtk_list_item_init (GtkListItem *list_item) +{ + GTK_WIDGET_SET_FLAGS (list_item, GTK_CAN_FOCUS); +} + +GtkWidget* +gtk_list_item_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_list_item_get_type ())); +} + +GtkWidget* +gtk_list_item_new_with_label (const gchar *label) +{ + GtkWidget *list_item; + GtkWidget *label_widget; + + list_item = gtk_list_item_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (list_item), label_widget); + gtk_widget_show (label_widget); + + return list_item; +} + +void +gtk_list_item_select (GtkListItem *list_item) +{ + gtk_item_select (GTK_ITEM (list_item)); +} + +void +gtk_list_item_deselect (GtkListItem *list_item) +{ + gtk_item_deselect (GTK_ITEM (list_item)); +} + + +static void +gtk_list_item_realize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + + if (GTK_WIDGET_CLASS (parent_class)->realize) + (* GTK_WIDGET_CLASS (parent_class)->realize) (widget); + + gdk_window_set_background (widget->window, &widget->style->white); +} + +static void +gtk_list_item_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + g_return_if_fail (requisition != NULL); + + bin = GTK_BIN (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->xthickness) * 2; + requisition->height = GTK_CONTAINER (widget)->border_width * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += bin->child->requisition.width; + requisition->height += bin->child->requisition.height; + } +} + +static void +gtk_list_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + bin = GTK_BIN (widget); + + if (bin->child) + { + child_allocation.x = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->xthickness); + child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + child_allocation.height = allocation->height - child_allocation.y * 2; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} + +static void +gtk_list_item_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + gtk_style_set_background (widget->style, widget->window, GTK_STATE_INSENSITIVE); + else if (widget->state == GTK_STATE_NORMAL) + gdk_window_set_background (widget->window, &widget->style->white); + else + gtk_style_set_background (widget->style, widget->window, widget->state); + + gdk_window_clear_area (widget->window, area->x, area->y, + area->width, area->height); + + if (bin->child && gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + + gtk_widget_draw_focus (widget); + } +} + +static void +gtk_list_item_draw_focus (GtkWidget *widget) +{ + GdkGC *gc; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + if (GTK_WIDGET_HAS_FOCUS (widget)) + gc = widget->style->black_gc; + else if (!GTK_WIDGET_IS_SENSITIVE (widget)) + gc = widget->style->bg_gc[GTK_STATE_INSENSITIVE]; + else if (widget->state == GTK_STATE_NORMAL) + gc = widget->style->white_gc; + else + gc = widget->style->bg_gc[widget->state]; + + gdk_draw_rectangle (widget->window, gc, FALSE, 0, 0, + widget->allocation.width - 1, + widget->allocation.height - 1); + } +} + +static gint +gtk_list_item_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->type == GDK_BUTTON_PRESS) + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + return FALSE; +} + +static gint +gtk_list_item_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + gdk_window_set_background (widget->window, &widget->style->bg[GTK_STATE_INSENSITIVE]); + else if (widget->state == GTK_STATE_NORMAL) + gdk_window_set_background (widget->window, &widget->style->white); + else + gdk_window_set_background (widget->window, &widget->style->bg[widget->state]); + + gdk_window_clear_area (widget->window, event->area.x, event->area.y, + event->area.width, event->area.height); + + if (bin->child) + { + child_event = *event; + + if (GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + gtk_widget_draw_focus (widget); + } + + return FALSE; +} + +static gint +gtk_list_item_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_list_item_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_LIST_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static void +gtk_real_list_item_select (GtkItem *item) +{ + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (item)); + + if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED) + return; + + gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED); + gtk_widget_queue_draw (GTK_WIDGET (item)); +} + +static void +gtk_real_list_item_deselect (GtkItem *item) +{ + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (item)); + + if (GTK_WIDGET (item)->state == GTK_STATE_NORMAL) + return; + + gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL); + gtk_widget_queue_draw (GTK_WIDGET (item)); +} + +static void +gtk_real_list_item_toggle (GtkItem *item) +{ + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_LIST_ITEM (item)); + + if (GTK_WIDGET (item)->parent && GTK_IS_LIST (GTK_WIDGET (item)->parent)) + gtk_list_select_child (GTK_LIST (GTK_WIDGET (item)->parent), + GTK_WIDGET (item)); + else + { + /* Should we really bother with this bit? A listitem not in a list? + * -Johannes Keukelaar + * yes, always be on the save side! + * -timj + */ + if (GTK_WIDGET (item)->state == GTK_STATE_SELECTED) + gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_NORMAL); + else + gtk_widget_set_state (GTK_WIDGET (item), GTK_STATE_SELECTED); + gtk_widget_queue_draw (GTK_WIDGET (item)); + } +} diff --git a/gtk/gtklistitem.h b/gtk/gtklistitem.h new file mode 100644 index 000000000..4220ae73f --- /dev/null +++ b/gtk/gtklistitem.h @@ -0,0 +1,62 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_LIST_ITEM_H__ +#define __GTK_LIST_ITEM_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_LIST_ITEM(obj) GTK_CHECK_CAST (obj, gtk_list_item_get_type (), GtkListItem) +#define GTK_LIST_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_list_item_get_type (), GtkListItemClass) +#define GTK_IS_LIST_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_list_item_get_type ()) + + +typedef struct _GtkListItem GtkListItem; +typedef struct _GtkListItemClass GtkListItemClass; + +struct _GtkListItem +{ + GtkItem item; +}; + +struct _GtkListItemClass +{ + GtkItemClass parent_class; +}; + + +guint gtk_list_item_get_type (void); +GtkWidget* gtk_list_item_new (void); +GtkWidget* gtk_list_item_new_with_label (const gchar *label); +void gtk_list_item_select (GtkListItem *list_item); +void gtk_list_item_deselect (GtkListItem *list_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_LIST_ITEM_H__ */ diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c new file mode 100644 index 000000000..50d262430 --- /dev/null +++ b/gtk/gtkmain.c @@ -0,0 +1,1129 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gtkbutton.h" +#include "gtkhscrollbar.h" +#include "gtkhseparator.h" +#include "gtkmain.h" +#include "gtkpreview.h" +#include "gtkrc.h" +#include "gtkselection.h" +#include "gtksignal.h" +#include "gtktable.h" +#include "gtktext.h" +#include "gtkvbox.h" +#include "gtkvscrollbar.h" +#include "gtkwidget.h" +#include "gtkwindow.h" + + +/* Private type definitions + */ +typedef struct _GtkInitFunction GtkInitFunction; +typedef struct _GtkTimeoutFunction GtkTimeoutFunction; +typedef struct _GtkIdleFunction GtkIdleFunction; + +struct _GtkInitFunction +{ + GtkFunction function; + gpointer data; +}; + +struct _GtkTimeoutFunction +{ + gint tag; + guint32 start; + guint32 interval; + guint32 originterval; + gint interp; + GtkFunction function; + gpointer data; + GtkDestroyNotify destroy; +}; + +struct _GtkIdleFunction +{ + gint tag; + gint interp; + GtkFunction function; + gpointer data; + GtkDestroyNotify destroy; +}; + + +static void gtk_exit_func (void); +static void gtk_timeout_insert (GtkTimeoutFunction *timeoutf); +static void gtk_handle_current_timeouts (guint32 the_time); +static void gtk_handle_current_idles (); +static void gtk_handle_timeouts (void); +static void gtk_handle_idle (void); +static void gtk_handle_timer (void); +static void gtk_propagate_event (GtkWidget *widget, + GdkEvent *event); +static void gtk_error (char *str); +static void gtk_warning (char *str); +static void gtk_message (char *str); +static void gtk_print (char *str); + + +static int done; +static int initialized = FALSE; +static GdkEvent next_event; +static GdkEvent current_event; +static gint have_event = FALSE; +static gint have_next_event = FALSE; + +static GList *grabs = NULL; /* A list of grabs. The grabbing widget + * is the first one on the list. + */ +static GList *init_functions = NULL; /* A list of init functions. + */ +static GList *timeout_functions = NULL; /* A list of timeout functions sorted by + * when the length of the time interval + * remaining. Therefore, the first timeout + * function to expire is at the head of + * the list and the last to expire is at + * the tail of the list. + */ +static GList *idle_functions = NULL; /* A list of idle functions. + */ + +static GList *current_idles = NULL; +static GList *current_timeouts = NULL; +static GMemChunk *timeout_mem_chunk = NULL; +static GMemChunk *idle_mem_chunk = NULL; + +static GdkVisual *gtk_visual; /* The visual to be used in creating new + * widgets. + */ +static GdkColormap *gtk_colormap; /* The colormap to be used in creating new + * widgets. + */ + + +void +gtk_init (int *argc, + char ***argv) +{ + if (0) + { + g_set_error_handler (gtk_error); + g_set_warning_handler (gtk_warning); + g_set_message_handler (gtk_message); + g_set_print_handler (gtk_print); + } + + /* Initialize "gdk". We simply pass along the 'argc' and 'argv' + * parameters as they contain information that + */ + gdk_init (argc, argv); + + /* Initialize the default visual and colormap to be + * used in creating widgets. (We want to use the system + * defaults so as to be nice to the colormap). + */ + gtk_visual = gdk_visual_get_system (); + gtk_colormap = gdk_colormap_get_system (); + gtk_rc_init (); + + gtk_type_init (); + + /* Register an exit function to make sure we are able to cleanup. + */ + if (ATEXIT (gtk_exit_func)) + g_warning ("unable to register exit function"); + + /* Set the 'initialized' flag. + */ + initialized = TRUE; +} + +void +gtk_exit (int errorcode) +{ + /* Only if "gtk" has been initialized should we de-initialize. + */ + /* de-initialisation is done by the gtk_exit_funct(), + no need to do this here (Alex J.) */ + gdk_exit(errorcode); +} + +gchar* +gtk_set_locale () +{ + return gdk_set_locale (); +} + +void +gtk_main () +{ + GList *tmp_list; + GList *functions; + GtkInitFunction *init; + int old_done; + + tmp_list = functions = init_functions; + init_functions = NULL; + + while (tmp_list) + { + init = tmp_list->data; + tmp_list = tmp_list->next; + + (* init->function) (init->data); + g_free (init); + } + + g_list_free (functions); + + old_done = done; + while (!gtk_main_iteration ()) + ; + done = old_done; +} + +void +gtk_main_quit () +{ + done = TRUE; +} + +gint +gtk_main_iteration () +{ + GdkEvent event_copy; + GtkWidget *event_widget; + GtkWidget *grab_widget; + + done = FALSE; + + /* If this is a recursive call, and there are pending timeouts or + idles, finish them, then return immediately to avoid blocking + in gdk_event_get() */ + if (current_timeouts) + { + gtk_handle_current_timeouts( gdk_time_get()); + return done; + } + if (current_idles) + { + gtk_handle_current_idles(); + return done; + } + + /* If there is a valid event in 'next_event' then copy + * it to 'event' and unset the flag. + */ + if (have_next_event) + { + have_next_event = FALSE; + have_event = TRUE; + current_event = next_event; + } + + /* If we don't have an event then get one. + */ + if (!have_event) + { + /* Handle setting of the "gdk" timer. If there are no + * timeout functions, then the timer is turned off. + * If there are timeout functions, then the timer is + * set to the shortest timeout interval (which is + * the first timeout function). + */ + gtk_handle_timer (); + + have_event = gdk_event_get (¤t_event, NULL, NULL); + } + + /* "gdk_event_get" can return FALSE if the timer goes off + * and no events are pending. Therefore, we should make + * sure that we got an event before continuing. + */ + if (have_event) + { + have_event = FALSE; + + /* If there are any events pending then get the next one. + */ + if (gdk_events_pending () > 0) + have_next_event = gdk_event_get (&next_event, NULL, NULL); + + /* Try to compress enter/leave notify events. These event + * pairs occur when the mouse is dragged quickly across + * a window with many buttons (or through a menu). Instead + * of highlighting and de-highlighting each widget that + * is crossed it is better to simply de-highlight the widget + * which contained the mouse initially and highlight the + * widget which ends up containing the mouse. + */ + if (have_next_event) + if (((current_event.type == GDK_ENTER_NOTIFY) || + (current_event.type == GDK_LEAVE_NOTIFY)) && + ((next_event.type == GDK_ENTER_NOTIFY) || + (next_event.type == GDK_LEAVE_NOTIFY)) && + (next_event.type != current_event.type) && + (next_event.any.window == current_event.any.window)) + return done; + + /* Find the widget which got the event. We store the widget + * in the user_data field of GdkWindow's. + */ + event_widget = gtk_get_event_widget (¤t_event); + + /* If there is a grab in effect... + */ + if (grabs) + { + grab_widget = grabs->data; + + /* If the grab widget is an ancestor of the event widget + * then we send the event to the original event widget. + * This is the key to implementing modality. + */ + if (gtk_widget_is_ancestor (event_widget, grab_widget)) + grab_widget = event_widget; + } + else + { + grab_widget = event_widget; + } + + /* 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 + * 1) these events have no meaning for the grabbing widget + * and 2) redirecting these events to the grabbing widget + * could cause the display to be messed up. + */ + event_copy = current_event; + switch (event_copy.type) + { + case GDK_NOTHING: + break; + + case GDK_DELETE: + if (gtk_widget_event (event_widget, &event_copy)) + gtk_widget_destroy (event_widget); + break; + + case GDK_DESTROY: + gtk_widget_event (event_widget, &event_copy); + gtk_widget_destroy (event_widget); + break; + + case GDK_PROPERTY_NOTIFY: + /* To handle selection INCR transactions, we select + PropertyNotify events on the requestor window and create + a corresponding (fake) GdkWindow so that events get + here. There won't be a widget though, so we have to handle + them specially */ + + if (event_widget == NULL) + { + gtk_selection_incr_event (event_copy.any.window, + &event_copy.property); + break; + } + /* otherwise fall through */ + + case GDK_EXPOSE: + case GDK_FOCUS_CHANGE: + case GDK_CONFIGURE: + case GDK_MAP: + case GDK_UNMAP: + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + case GDK_CLIENT_EVENT: + gtk_widget_event (event_widget, &event_copy); + break; + + case GDK_MOTION_NOTIFY: + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + case GDK_OTHER_EVENT: + case GDK_DRAG_BEGIN: + case GDK_DRAG_REQUEST: + case GDK_DROP_ENTER: + case GDK_DROP_LEAVE: + case GDK_DROP_DATA_AVAIL: + gtk_propagate_event (grab_widget, &event_copy); + break; + + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + if (grab_widget && GTK_WIDGET_IS_SENSITIVE (grab_widget)) + gtk_widget_event (grab_widget, &event_copy); + break; + } + } + else + { + if (gdk_events_pending() == 0) + gtk_handle_idle (); + } + + /* Handle a timeout functions that may have expired. + */ + gtk_handle_timeouts (); + + return done; +} + +gint +gtk_true (void) +{ + return TRUE; +} + +gint +gtk_false (void) +{ + return FALSE; +} + +void +gtk_grab_add (GtkWidget *widget) +{ + /* Place the grab on the front of the list of grabs. + */ + grabs = g_list_prepend (grabs, widget); +} + +void +gtk_grab_remove (GtkWidget *widget) +{ + /* Remove the grab from the list of grabs. + * Note: the grab being removed may be in + * the middle of the list. + */ + grabs = g_list_remove (grabs, widget); +} + +void +gtk_init_add (GtkFunction function, + gpointer data) +{ + GtkInitFunction *init; + + init = g_new (GtkInitFunction, 1); + init->function = function; + init->data = data; + + init_functions = g_list_prepend (init_functions, init); +} + +static gint +gtk_timeout_add_internal (guint32 interval, + gint interp, + GtkFunction function, + gpointer data, + GtkDestroyNotify destroy) +{ + static gint timeout_tag = 1; + GtkTimeoutFunction *timeoutf; + + /* Create a new timeout function structure. + * The start time is the current time. + */ + if (!timeout_mem_chunk) + timeout_mem_chunk = g_mem_chunk_new ("timeout mem chunk", sizeof (GtkTimeoutFunction), + 1024, G_ALLOC_AND_FREE); + + timeoutf = g_chunk_new (GtkTimeoutFunction, timeout_mem_chunk); + + timeoutf->tag = timeout_tag++; + timeoutf->start = gdk_time_get (); + timeoutf->interval = interval; + timeoutf->originterval = interval; + timeoutf->interp = interp; + timeoutf->function = function; + timeoutf->data = data; + timeoutf->destroy = destroy; + + gtk_timeout_insert (timeoutf); + + return timeoutf->tag; +} + +static void +gtk_timeout_destroy (GtkTimeoutFunction *timeoutf) +{ + if (timeoutf->destroy) + (timeoutf->destroy) (timeoutf->data); + g_mem_chunk_free (timeout_mem_chunk, timeoutf); +} + +gint +gtk_timeout_add (guint32 interval, + GtkFunction function, + gpointer data) +{ + return gtk_timeout_add_internal (interval, FALSE, function, data, NULL); +} + +gint +gtk_timeout_add_interp (guint32 interval, + GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify destroy) +{ + return gtk_timeout_add_internal (interval, TRUE, + (GtkFunction) function, + data, destroy); +} + +void +gtk_timeout_remove (gint tag) +{ + GtkTimeoutFunction *timeoutf; + GList *tmp_list; + + /* Remove a timeout function. + * (Which, basically, involves searching the + * list for the tag). + */ + tmp_list = timeout_functions; + while (tmp_list) + { + timeoutf = tmp_list->data; + + if (timeoutf->tag == tag) + { + timeout_functions = g_list_remove_link (timeout_functions, tmp_list); + g_list_free (tmp_list); + gtk_timeout_destroy (timeoutf); + + return; + } + + tmp_list = tmp_list->next; + } + + tmp_list = current_timeouts; + while (tmp_list) + { + timeoutf = tmp_list->data; + + if (timeoutf->tag == tag) + { + current_timeouts = g_list_remove_link (current_timeouts, tmp_list); + g_list_free (tmp_list); + gtk_timeout_destroy (timeoutf); + + return; + } + + tmp_list = tmp_list->next; + } +} + +static gint +gtk_idle_add_internal (gint interp, + GtkFunction function, + gpointer data, + GtkDestroyNotify destroy) +{ + static gint idle_tag = 1; + GtkIdleFunction *idlef; + + if (!idle_mem_chunk) + idle_mem_chunk = g_mem_chunk_new ("idle mem chunk", sizeof (GtkIdleFunction), + 1024, G_ALLOC_AND_FREE); + + idlef = g_chunk_new (GtkIdleFunction, idle_mem_chunk); + + idlef->tag = idle_tag++; + idlef->interp = interp; + idlef->function = function; + idlef->data = data; + idlef->destroy = destroy; + + idle_functions = g_list_append (idle_functions, idlef); + + return idlef->tag; +} + +static void +gtk_idle_destroy (GtkIdleFunction *idlef) +{ + if (idlef->destroy) + idlef->destroy (idlef->data); + g_mem_chunk_free (idle_mem_chunk, idlef); +} + +gint +gtk_idle_add (GtkFunction function, + gpointer data) +{ + return gtk_idle_add_internal (FALSE, function, data, NULL); +} + +gint +gtk_idle_add_interp (GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify destroy) +{ + return gtk_idle_add_internal (TRUE, (GtkFunction)function, data, destroy); +} + +void +gtk_idle_remove (gint tag) +{ + GtkIdleFunction *idlef; + GList *tmp_list; + + tmp_list = idle_functions; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->tag == tag) + { + idle_functions = g_list_remove_link (idle_functions, tmp_list); + g_list_free (tmp_list); + gtk_idle_destroy (idlef); + + return; + } + + tmp_list = tmp_list->next; + } + + tmp_list = current_idles; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->tag == tag) + { + current_idles = g_list_remove_link (current_idles, tmp_list); + g_list_free (tmp_list); + gtk_idle_destroy (idlef); + + return; + } + + tmp_list = tmp_list->next; + } +} + +void +gtk_idle_remove_by_data (gpointer data) +{ + GtkIdleFunction *idlef; + GList *tmp_list; + + tmp_list = idle_functions; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->data == data) + { + idle_functions = g_list_remove_link (idle_functions, tmp_list); + g_list_free (tmp_list); + g_mem_chunk_free (idle_mem_chunk, idlef); + + return; + } + + tmp_list = tmp_list->next; + } + + tmp_list = current_idles; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->data == data) + { + current_idles = g_list_remove_link (current_idles, tmp_list); + g_list_free (tmp_list); + g_mem_chunk_free (idle_mem_chunk, idlef); + + return; + } + + tmp_list = tmp_list->next; + } +} + +void +gtk_get_current_event (GdkEvent *event) +{ + g_assert (event != NULL); + + *event = current_event; +} + +GtkWidget* +gtk_get_event_widget (GdkEvent *event) +{ + GtkWidget *widget; + gdk_window_get_user_data (event->any.window, (void**) &widget); + + return widget; +} + +static void +gtk_exit_func () +{ + if (initialized) + { + initialized = FALSE; + gtk_preview_uninit (); + } +} + +static void +gtk_timeout_insert (GtkTimeoutFunction *timeoutf) +{ + GtkTimeoutFunction *temp; + GList *temp_list; + GList *new_list; + + g_assert (timeoutf != NULL); + + /* Insert the timeout function appropriately. + * Appropriately meaning sort it into the list + * of timeout functions. + */ + temp_list = timeout_functions; + while (temp_list) + { + temp = temp_list->data; + if (timeoutf->interval < temp->interval) + { + new_list = g_list_alloc (); + new_list->data = timeoutf; + new_list->next = temp_list; + new_list->prev = temp_list->prev; + if (temp_list->prev) + temp_list->prev->next = new_list; + temp_list->prev = new_list; + + if (temp_list == timeout_functions) + timeout_functions = new_list; + + return; + } + + temp_list = temp_list->next; + } + + timeout_functions = g_list_append (timeout_functions, timeoutf); +} + +static gint +gtk_invoke_timeout_function (GtkTimeoutFunction *timeoutf) +{ + if (!timeoutf->interp) + return timeoutf->function (timeoutf->data); + else + { + GtkArg args[1]; + gint ret_val = FALSE; + args[0].name = NULL; + args[0].type = GTK_TYPE_BOOL; + args[0].d.pointer_data = &ret_val; + ((GtkCallbackMarshal)timeoutf->function) (NULL, + timeoutf->data, + 0, args); + return ret_val; + } +} + +static void +gtk_handle_current_timeouts (guint32 the_time) +{ + GList *tmp_list; + GtkTimeoutFunction *timeoutf; + + while (current_timeouts) + { + tmp_list = current_timeouts; + timeoutf = tmp_list->data; + + current_timeouts = g_list_remove_link (current_timeouts, tmp_list); + g_list_free (tmp_list); + + if (gtk_invoke_timeout_function (timeoutf) == FALSE) + { + gtk_timeout_destroy (timeoutf); + } + else + { + timeoutf->interval = timeoutf->originterval; + timeoutf->start = the_time; + gtk_timeout_insert (timeoutf); + } + } +} + +/* Utility function - make up for an ommision in glib */ +static GList * +gtk_main_list_concat (GList *list1, GList *list2) +{ + GList *tmp_list; + GList *list; + + if (list2) + { + tmp_list = g_list_last (list1); + if (tmp_list) + tmp_list->next = list2; + else + list1 = list2; + list2->prev = tmp_list; + } + + return list1; +} + +static void +gtk_handle_timeouts () +{ + guint32 the_time; + GList *tmp_list; + GList *tmp_list2; + GList *tmp_list3; + GtkTimeoutFunction *timeoutf; + + /* Caller must already have called gtk_handle_current_timeouts if + * necessary */ + g_assert (current_timeouts == NULL); + + if (timeout_functions) + { + the_time = gdk_time_get (); + + tmp_list = timeout_functions; + while (tmp_list) + { + timeoutf = tmp_list->data; + + if (timeoutf->interval <= (the_time - timeoutf->start)) + { + tmp_list2 = tmp_list; + tmp_list = tmp_list->next; + + timeout_functions = g_list_remove_link (timeout_functions, tmp_list2); + current_timeouts = gtk_main_list_concat (current_timeouts, tmp_list2); + } + else + { + timeoutf->interval -= (the_time - timeoutf->start); + timeoutf->start = the_time; + tmp_list = tmp_list->next; + } + } + + if (current_timeouts) + gtk_handle_current_timeouts(the_time); + } +} + +static gint +gtk_idle_invoke_function (GtkIdleFunction *idlef) +{ + if (!idlef->interp) + return idlef->function (idlef->data); + else + { + GtkArg args[1]; + gint ret_val = FALSE; + args[0].name = NULL; + args[0].type = GTK_TYPE_BOOL; + args[0].d.pointer_data = &ret_val; + ((GtkCallbackMarshal)idlef->function) (NULL, + idlef->data, + 0, args); + return ret_val; + } +} + +static void +gtk_handle_current_idles () +{ + GList *tmp_list; + GtkIdleFunction *idlef; + + while (current_idles) + { + tmp_list = current_idles; + idlef = tmp_list->data; + + current_idles = g_list_remove_link (current_idles, tmp_list); + + if (gtk_idle_invoke_function (idlef) == FALSE) + { + g_list_free (tmp_list); + gtk_idle_destroy (idlef); + } + else + { + idle_functions = gtk_main_list_concat (idle_functions, tmp_list); + } + } +} + +static void +gtk_handle_idle () +{ + GtkIdleFunction *idlef; + GList *tmp_list; + GList *tmp_list2; + + /* Caller must already have called gtk_handle_current_idles if + necessary */ + g_assert (current_idles == NULL); + + if (idle_functions) + { + current_idles = idle_functions; + idle_functions = NULL; + + gtk_handle_current_idles(); + } +} + +static void +gtk_handle_timer () +{ + GtkTimeoutFunction *timeoutf; + + if (idle_functions) + { + gdk_timer_set (0); + gdk_timer_enable (); + } + else if (timeout_functions) + { + timeoutf = timeout_functions->data; + gdk_timer_set (timeoutf->interval); + gdk_timer_enable (); + } + else + { + gdk_timer_set (0); + gdk_timer_disable (); + } +} + +static void +gtk_propagate_event (GtkWidget *widget, + GdkEvent *event) +{ + GtkWidget *parent; + gint handled_event; + gint parent_old_value; + gint old_value; + + g_return_if_fail (widget != NULL); + g_return_if_fail (event != NULL); + + handled_event = FALSE; + + if ((event->type == GDK_KEY_PRESS) || + (event->type == GDK_KEY_RELEASE)) + { + /* Only send key events to window widgets. + * The window widget will in turn pass the + * key event on to the currently focused widget + * for that window. + */ + parent = gtk_widget_get_ancestor (widget, gtk_window_get_type ()); + if (parent && GTK_WIDGET_IS_SENSITIVE (parent)) + { + parent_old_value = GTK_OBJECT_IN_CALL (parent); + GTK_OBJECT_SET_FLAGS (parent, GTK_IN_CALL); + + handled_event = gtk_widget_event (parent, event); + + if (!parent_old_value) + GTK_OBJECT_UNSET_FLAGS (parent, GTK_IN_CALL); + + if (GTK_OBJECT_NEED_DESTROY (parent) && !GTK_OBJECT_IN_CALL (parent)) + { + gtk_object_destroy (GTK_OBJECT (parent)); + return; + } + } + } + + if (!handled_event) + { + old_value = GTK_OBJECT_IN_CALL (widget); + GTK_OBJECT_SET_FLAGS (widget, GTK_IN_CALL); + + /* Other events get propagated up the widget tree + * so that parents can see the button and motion + * events of the children. + */ + parent = widget; + while (parent) + { + parent_old_value = GTK_OBJECT_IN_CALL (parent); + GTK_OBJECT_SET_FLAGS (parent, GTK_IN_CALL); + + handled_event = (!GTK_WIDGET_IS_SENSITIVE (parent) || + gtk_widget_event (parent, event)); + + if (!parent_old_value) + GTK_OBJECT_UNSET_FLAGS (parent, GTK_IN_CALL); + + if (handled_event) + break; + + if (GTK_OBJECT_NEED_DESTROY (parent) && !GTK_OBJECT_IN_CALL (parent)) + { + gtk_object_destroy (GTK_OBJECT (parent)); + break; + } + + parent = parent->parent; + } + + if (!old_value) + GTK_OBJECT_UNSET_FLAGS (widget, GTK_IN_CALL); + + if (GTK_OBJECT_NEED_DESTROY (widget) && !GTK_OBJECT_IN_CALL (widget)) + gtk_object_destroy (GTK_OBJECT (widget)); + } +} + + +static void +gtk_error (char *str) +{ + gtk_print (str); +} + +static void +gtk_warning (char *str) +{ + gtk_print (str); +} + +static void +gtk_message (char *str) +{ + gtk_print (str); +} + +static void +gtk_print (char *str) +{ + static GtkWidget *window = NULL; + static GtkWidget *text; + static int level = 0; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *table; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + GtkWidget *separator; + GtkWidget *button; + + if (level > 0) + { + fputs (str, stdout); + fflush (stdout); + return; + } + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + /* + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) gtk_widget_destroyed, + &window); + */ + gtk_window_set_title (GTK_WINDOW (window), "Messages"); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + table = gtk_table_new (2, 2, FALSE); + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); + gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + text = gtk_text_new (NULL, NULL); + gtk_text_set_editable (GTK_TEXT (text), FALSE); + gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1); + gtk_widget_show (text); + gtk_widget_realize (text); + + hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj); + gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (hscrollbar); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_hide, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + level += 1; + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1); + level -= 1; + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); +} diff --git a/gtk/gtkmain.h b/gtk/gtkmain.h new file mode 100644 index 000000000..9d014e47c --- /dev/null +++ b/gtk/gtkmain.h @@ -0,0 +1,76 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_MAIN_H__ +#define __GTK_MAIN_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Initialization, exit, mainloop and miscellaneous routines + */ +void gtk_init (int *argc, + char ***argv); +void gtk_exit (gint error_code); +gchar* gtk_set_locale (void); +void gtk_main (void); +void gtk_main_quit (void); +gint gtk_main_iteration (void); + +gint gtk_true (void); +gint gtk_false (void); + +void gtk_grab_add (GtkWidget *widget); +void gtk_grab_remove (GtkWidget *widget); + +void gtk_init_add (GtkFunction function, + gpointer data); + +gint gtk_timeout_add (guint32 interval, + GtkFunction function, + gpointer data); +gint gtk_timeout_add_interp (guint32 interval, + GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify notify); +void gtk_timeout_remove (gint tag); + +gint gtk_idle_add (GtkFunction function, + gpointer data); +gint gtk_idle_add_interp (GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify destroy); +void gtk_idle_remove (gint tag); +void gtk_idle_remove_by_data (gpointer data); + +void gtk_get_current_event (GdkEvent *event); +GtkWidget* gtk_get_event_widget (GdkEvent *event); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MAIN_H__ */ diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c new file mode 100644 index 000000000..13fff9023 --- /dev/null +++ b/gtk/gtkmenu.c @@ -0,0 +1,732 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gdk/gdkkeysyms.h" +#include "gtkmain.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtksignal.h" + + +#define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_menu_class_init (GtkMenuClass *klass); +static void gtk_menu_init (GtkMenu *menu); +static void gtk_menu_show (GtkWidget *widget); +static void gtk_menu_map (GtkWidget *widget); +static void gtk_menu_unmap (GtkWidget *widget); +static void gtk_menu_realize (GtkWidget *widget); +static void gtk_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_menu_paint (GtkWidget *widget); +static void gtk_menu_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_menu_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_menu_configure (GtkWidget *widget, + GdkEventConfigure *event); +static gint gtk_menu_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_menu_need_resize (GtkContainer *container); +static void gtk_menu_deactivate (GtkMenuShell *menu_shell); + + +guint +gtk_menu_get_type () +{ + static guint menu_type = 0; + + if (!menu_type) + { + GtkTypeInfo menu_info = + { + "GtkMenu", + sizeof (GtkMenu), + sizeof (GtkMenuClass), + (GtkClassInitFunc) gtk_menu_class_init, + (GtkObjectInitFunc) gtk_menu_init, + (GtkArgFunc) NULL, + }; + + menu_type = gtk_type_unique (gtk_menu_shell_get_type (), &menu_info); + } + + return menu_type; +} + +static void +gtk_menu_class_init (GtkMenuClass *class) +{ + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + GtkMenuShellClass *menu_shell_class; + + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + menu_shell_class = (GtkMenuShellClass*) class; + + widget_class->show = gtk_menu_show; + widget_class->map = gtk_menu_map; + widget_class->unmap = gtk_menu_unmap; + widget_class->realize = gtk_menu_realize; + widget_class->draw = gtk_menu_draw; + widget_class->size_request = gtk_menu_size_request; + widget_class->size_allocate = gtk_menu_size_allocate; + widget_class->expose_event = gtk_menu_expose; + widget_class->configure_event = gtk_menu_configure; + widget_class->key_press_event = gtk_menu_key_press; + + container_class->need_resize = gtk_menu_need_resize; + + menu_shell_class->submenu_placement = GTK_LEFT_RIGHT; + menu_shell_class->deactivate = gtk_menu_deactivate; +} + +static void +gtk_menu_init (GtkMenu *menu) +{ + GTK_WIDGET_SET_FLAGS (menu, GTK_ANCHORED); + + menu->parent_menu_item = NULL; + menu->old_active_menu_item = NULL; + menu->accelerator_table = NULL; + menu->position_func = NULL; + menu->position_func_data = NULL; + + GTK_MENU_SHELL (menu)->menu_flag = TRUE; +} + +GtkWidget* +gtk_menu_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_menu_get_type ())); +} + +void +gtk_menu_append (GtkMenu *menu, + GtkWidget *child) +{ + gtk_menu_shell_append (GTK_MENU_SHELL (menu), child); +} + +void +gtk_menu_prepend (GtkMenu *menu, + GtkWidget *child) +{ + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), child); +} + +void +gtk_menu_insert (GtkMenu *menu, + GtkWidget *child, + gint position) +{ + gtk_menu_shell_insert (GTK_MENU_SHELL (menu), child, position); +} + +void +gtk_menu_popup (GtkMenu *menu, + GtkWidget *parent_menu_shell, + GtkWidget *parent_menu_item, + GtkMenuPositionFunc func, + gpointer data, + gint button, + guint32 activate_time) +{ + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + GTK_MENU_SHELL (menu)->parent_menu_shell = parent_menu_shell; + GTK_MENU_SHELL (menu)->active = TRUE; + GTK_MENU_SHELL (menu)->button = button; + + menu->parent_menu_item = parent_menu_item; + menu->position_func = func; + menu->position_func_data = data; + GTK_MENU_SHELL (menu)->activate_time = activate_time; + + gtk_widget_show (GTK_WIDGET (menu)); + gtk_grab_add (GTK_WIDGET (menu)); +} + +void +gtk_menu_popdown (GtkMenu *menu) +{ + GtkMenuShell *menu_shell; + + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + menu_shell = GTK_MENU_SHELL (menu); + + menu_shell->parent_menu_shell = NULL; + menu_shell->active = FALSE; + + if (menu_shell->active_menu_item) + { + menu->old_active_menu_item = menu_shell->active_menu_item; + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + menu_shell->active_menu_item = NULL; + } + + gtk_widget_hide (GTK_WIDGET (menu)); + gtk_grab_remove (GTK_WIDGET (menu)); +} + +GtkWidget* +gtk_menu_get_active (GtkMenu *menu) +{ + GtkWidget *child; + GList *children; + + g_return_val_if_fail (menu != NULL, NULL); + g_return_val_if_fail (GTK_IS_MENU (menu), NULL); + + if (!menu->old_active_menu_item) + { + child = NULL; + children = GTK_MENU_SHELL (menu)->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_BIN (child)->child) + break; + child = NULL; + } + + menu->old_active_menu_item = child; + } + + return menu->old_active_menu_item; +} + +void +gtk_menu_set_active (GtkMenu *menu, + gint index) +{ + GtkWidget *child; + GList *tmp_list; + + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + tmp_list = g_list_nth (GTK_MENU_SHELL (menu)->children, index); + if (tmp_list) + { + child = tmp_list->data; + if (GTK_BIN (child)->child) + menu->old_active_menu_item = child; + } +} + +void +gtk_menu_set_accelerator_table (GtkMenu *menu, + GtkAcceleratorTable *table) +{ + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + if (menu->accelerator_table) + gtk_accelerator_table_unref (menu->accelerator_table); + + menu->accelerator_table = table; + if (menu->accelerator_table) + gtk_accelerator_table_ref (menu->accelerator_table); +} + + +static void +gtk_menu_show (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); + gtk_widget_map (widget); +} + +static void +gtk_menu_map (GtkWidget *widget) +{ + GtkMenu *menu; + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + GtkAllocation allocation; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + menu = GTK_MENU (widget); + menu_shell = GTK_MENU_SHELL (widget); + GTK_WIDGET_SET_FLAGS (menu_shell, GTK_MAPPED); + GTK_WIDGET_UNSET_FLAGS (menu_shell, GTK_UNMAPPED); + + gtk_widget_size_request (widget, &widget->requisition); + + if (menu_shell->menu_flag) + { + menu_shell->menu_flag = FALSE; + + allocation.x = widget->allocation.x; + allocation.y = widget->allocation.y; + allocation.width = widget->requisition.width; + allocation.height = widget->requisition.height; + + gtk_widget_size_allocate (widget, &allocation); + } + + gdk_window_get_pointer (NULL, &x, &y, NULL); + + if (menu->position_func) + (* menu->position_func) (menu, &x, &y, menu->position_func_data); + else + { + gint screen_width; + gint screen_height; + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + x -= 2; + y -= 2; + + if ((x + widget->requisition.width) > screen_width) + x -= ((x + widget->requisition.width) - screen_width); + if (x < 0) + x = 0; + if ((y + widget->requisition.height) > screen_height) + y -= ((y + widget->requisition.height) - screen_height); + if (y < 0) + y = 0; + } + + gdk_window_move_resize (widget->window, x, y, + widget->requisition.width, + widget->requisition.height); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + gdk_window_show (widget->window); +} + +static void +gtk_menu_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + GTK_WIDGET_SET_FLAGS (widget, GTK_UNMAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_menu_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.window_type = GDK_WINDOW_TEMP; + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_KEY_PRESS_MASK | + GDK_STRUCTURE_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (NULL, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkMenu *menu; + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + gint max_accelerator_size; + gint max_toggle_size; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + g_return_if_fail (requisition != NULL); + + menu = GTK_MENU (widget); + menu_shell = GTK_MENU_SHELL (widget); + + requisition->width = 0; + requisition->height = 0; + + max_accelerator_size = 0; + max_toggle_size = 0; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE; + gtk_widget_size_request (child, &child->requisition); + + requisition->width = MAX (requisition->width, child->requisition.width); + requisition->height += child->requisition.height; + + max_accelerator_size = MAX (max_accelerator_size, GTK_MENU_ITEM (child)->accelerator_size); + max_toggle_size = MAX (max_toggle_size, MENU_ITEM_CLASS (child)->toggle_size); + } + } + + requisition->width += max_toggle_size + max_accelerator_size; + requisition->width += (GTK_CONTAINER (menu)->border_width + + widget->style->klass->xthickness) * 2; + requisition->height += (GTK_CONTAINER (menu)->border_width + + widget->style->klass->ythickness) * 2; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + GTK_MENU_ITEM (child)->accelerator_size = max_accelerator_size; + GTK_MENU_ITEM (child)->toggle_size = max_toggle_size; + } +} + +static void +gtk_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkMenu *menu; + GtkMenuShell *menu_shell; + GtkWidget *child; + GtkAllocation child_allocation; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + g_return_if_fail (allocation != NULL); + + menu = GTK_MENU (widget); + menu_shell = GTK_MENU_SHELL (widget); + + widget->allocation = *allocation; + + if (menu_shell->children) + { + child_allocation.x = (GTK_CONTAINER (menu)->border_width + + widget->style->klass->xthickness); + child_allocation.y = (GTK_CONTAINER (menu)->border_width + + widget->style->klass->ythickness); + child_allocation.width = allocation->width - child_allocation.x * 2; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + child_allocation.height = child->requisition.height; + + gtk_widget_size_allocate (child, &child_allocation); + + child_allocation.y += child_allocation.height; + } + } + } +} + +static void +gtk_menu_paint (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_draw_shadow (widget->style, + widget->window, + GTK_STATE_NORMAL, + GTK_SHADOW_OUT, + 0, 0, + widget->allocation.width, + widget->allocation.height); + } +} + +static void +gtk_menu_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_paint (widget); + + menu_shell = GTK_MENU_SHELL (widget); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child, area, &child_area)) + gtk_widget_draw (child, &child_area); + } + } +} + +static gint +gtk_menu_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (!GTK_WIDGET_UNMAPPED (widget)) + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_paint (widget); + + menu_shell = GTK_MENU_SHELL (widget); + child_event = *event; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child) && + gtk_widget_intersect (child, &event->area, &child_event.area)) + gtk_widget_event (child, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static gint +gtk_menu_configure (GtkWidget *widget, + GdkEventConfigure *event) +{ + GtkAllocation allocation; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_MENU_SHELL (widget)->menu_flag) + { + GTK_MENU_SHELL (widget)->menu_flag = FALSE; + + allocation.x = 0; + allocation.y = 0; + allocation.width = event->width; + allocation.height = event->height; + + gtk_widget_size_allocate (widget, &allocation); + } + + return FALSE; +} + +static gint +gtk_menu_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkAllocation allocation; + GtkAcceleratorTable *table; + GtkMenuShell *menu_shell; + GtkMenuItem *menu_item; + gchar *signame; + int delete; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + delete = ((event->keyval == GDK_Delete) || + (event->keyval == GDK_BackSpace)); + + if (delete || ((event->keyval >= 0x20) && (event->keyval <= 0xFF))) + { + menu_shell = GTK_MENU_SHELL (widget); + menu_item = GTK_MENU_ITEM (menu_shell->active_menu_item); + + if (menu_item && GTK_BIN (menu_item)->child) + { + /* block resizes */ + gtk_container_block_resize (GTK_CONTAINER (widget)); + + table = NULL; + /* if the menu item currently has an accelerator then we'll + * remove it before we do anything else. + */ + if (menu_item->accelerator_signal) + { + signame = gtk_signal_name (menu_item->accelerator_signal); + table = gtk_accelerator_table_find (GTK_OBJECT (widget), + signame, + menu_item->accelerator_key, + menu_item->accelerator_mods); + if (!table) + table = GTK_MENU (widget)->accelerator_table; + gtk_widget_remove_accelerator (GTK_WIDGET (menu_item), + table, signame); + } + + if (!table) + table = GTK_MENU (widget)->accelerator_table; + + /* if we aren't simply deleting the accelerator, then we'll install + * the new one now. + */ + if (!delete) + gtk_widget_install_accelerator (GTK_WIDGET (menu_item), + table, "activate", + toupper (event->keyval), + event->state); + + /* check and see if the menu has changed size. */ + gtk_widget_size_request (widget, &widget->requisition); + + allocation.x = widget->allocation.x; + allocation.y = widget->allocation.y; + allocation.width = widget->requisition.width; + allocation.height = widget->requisition.height; + + if ((allocation.width == widget->allocation.width) && + (allocation.height == widget->allocation.height)) + { + gtk_widget_queue_draw (widget); + } + else + { + gtk_widget_size_allocate (GTK_WIDGET (widget), &allocation); + gtk_menu_map (widget); + } + + /* unblock resizes */ + gtk_container_unblock_resize (GTK_CONTAINER (widget)); + } + } + + return FALSE; +} + +static gint +gtk_menu_need_resize (GtkContainer *container) +{ + GtkAllocation allocation; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU (container), FALSE); + + if (GTK_WIDGET_VISIBLE (container)) + { + GTK_MENU_SHELL (container)->menu_flag = FALSE; + + gtk_widget_size_request (GTK_WIDGET (container), + >K_WIDGET (container)->requisition); + + allocation.x = GTK_WIDGET (container)->allocation.x; + allocation.y = GTK_WIDGET (container)->allocation.y; + allocation.width = GTK_WIDGET (container)->requisition.width; + allocation.height = GTK_WIDGET (container)->requisition.height; + + gtk_widget_size_allocate (GTK_WIDGET (container), &allocation); + } + else + { + GTK_MENU_SHELL (container)->menu_flag = TRUE; + } + + return FALSE; +} + +static void +gtk_menu_deactivate (GtkMenuShell *menu_shell) +{ + GtkMenuShell *parent; + + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU (menu_shell)); + + parent = GTK_MENU_SHELL (menu_shell->parent_menu_shell); + + menu_shell->activate_time = 0; + gtk_menu_popdown (GTK_MENU (menu_shell)); + + if (parent) + gtk_menu_shell_deactivate (parent); +} diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h new file mode 100644 index 000000000..5cd5d28fa --- /dev/null +++ b/gtk/gtkmenu.h @@ -0,0 +1,94 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_MENU_H__ +#define __GTK_MENU_H__ + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MENU(obj) GTK_CHECK_CAST (obj, gtk_menu_get_type (), GtkMenu) +#define GTK_MENU_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_menu_get_type (), GtkMenuClass) +#define GTK_IS_MENU(obj) GTK_CHECK_TYPE (obj, gtk_menu_get_type ()) + + +typedef struct _GtkMenu GtkMenu; +typedef struct _GtkMenuClass GtkMenuClass; + +typedef void (*GtkMenuPositionFunc) (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data); + +struct _GtkMenu +{ + GtkMenuShell menu_shell; + + GList *children; + + GtkWidget *parent_menu_item; + GtkWidget *old_active_menu_item; + + GtkAcceleratorTable *accelerator_table; + GtkMenuPositionFunc position_func; + gpointer position_func_data; +}; + +struct _GtkMenuClass +{ + GtkMenuShellClass parent_class; +}; + + +guint gtk_menu_get_type (void); +GtkWidget* gtk_menu_new (void); +void gtk_menu_append (GtkMenu *menu, + GtkWidget *child); +void gtk_menu_prepend (GtkMenu *menu, + GtkWidget *child); +void gtk_menu_insert (GtkMenu *menu, + GtkWidget *child, + gint position); +void gtk_menu_popup (GtkMenu *menu, + GtkWidget *parent_menu_shell, + GtkWidget *parent_menu_item, + GtkMenuPositionFunc func, + gpointer data, + gint button, + guint32 activate_time); +void gtk_menu_popdown (GtkMenu *menu); +GtkWidget* gtk_menu_get_active (GtkMenu *menu); +void gtk_menu_set_active (GtkMenu *menu, + gint index); +void gtk_menu_set_accelerator_table (GtkMenu *menu, + GtkAcceleratorTable *table); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_H__ */ diff --git a/gtk/gtkmenubar.c b/gtk/gtkmenubar.c new file mode 100644 index 000000000..19f0aa3e7 --- /dev/null +++ b/gtk/gtkmenubar.c @@ -0,0 +1,310 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkmain.h" +#include "gtkmenubar.h" +#include "gtkmenuitem.h" + + +#define BORDER_SPACING 2 +#define CHILD_SPACING 3 + + +static void gtk_menu_bar_class_init (GtkMenuBarClass *klass); +static void gtk_menu_bar_init (GtkMenuBar *menu_bar); +static void gtk_menu_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_menu_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_menu_bar_paint (GtkWidget *widget); +static void gtk_menu_bar_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_menu_bar_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_menu_bar_get_type () +{ + static guint menu_bar_type = 0; + + if (!menu_bar_type) + { + GtkTypeInfo menu_bar_info = + { + "GtkMenuBar", + sizeof (GtkMenuBar), + sizeof (GtkMenuBarClass), + (GtkClassInitFunc) gtk_menu_bar_class_init, + (GtkObjectInitFunc) gtk_menu_bar_init, + (GtkArgFunc) NULL, + }; + + menu_bar_type = gtk_type_unique (gtk_menu_shell_get_type (), &menu_bar_info); + } + + return menu_bar_type; +} + +static void +gtk_menu_bar_class_init (GtkMenuBarClass *class) +{ + GtkWidgetClass *widget_class; + GtkMenuShellClass *menu_shell_class; + + widget_class = (GtkWidgetClass*) class; + menu_shell_class = (GtkMenuShellClass*) class; + + widget_class->draw = gtk_menu_bar_draw; + widget_class->size_request = gtk_menu_bar_size_request; + widget_class->size_allocate = gtk_menu_bar_size_allocate; + widget_class->expose_event = gtk_menu_bar_expose; + + menu_shell_class->submenu_placement = GTK_TOP_BOTTOM; +} + +static void +gtk_menu_bar_init (GtkMenuBar *menu_bar) +{ +} + +GtkWidget* +gtk_menu_bar_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_menu_bar_get_type ())); +} + +void +gtk_menu_bar_append (GtkMenuBar *menu_bar, + GtkWidget *child) +{ + gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), child); +} + +void +gtk_menu_bar_prepend (GtkMenuBar *menu_bar, + GtkWidget *child) +{ + gtk_menu_shell_prepend (GTK_MENU_SHELL (menu_bar), child); +} + +void +gtk_menu_bar_insert (GtkMenuBar *menu_bar, + GtkWidget *child, + gint position) +{ + gtk_menu_shell_insert (GTK_MENU_SHELL (menu_bar), child, position); +} + + +static void +gtk_menu_bar_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkMenuBar *menu_bar; + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + gint nchildren; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_BAR (widget)); + g_return_if_fail (requisition != NULL); + + requisition->width = 0; + requisition->height = 0; + + if (GTK_WIDGET_VISIBLE (widget)) + { + menu_bar = GTK_MENU_BAR (widget); + menu_shell = GTK_MENU_SHELL (widget); + + nchildren = 0; + children = menu_shell->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + GTK_MENU_ITEM (child)->show_submenu_indicator = FALSE; + gtk_widget_size_request (child, &child->requisition); + + requisition->width += child->requisition.width; + requisition->height = MAX (requisition->height, child->requisition.height); + + nchildren += 1; + } + } + + requisition->width += (GTK_CONTAINER (menu_bar)->border_width + + widget->style->klass->xthickness + + BORDER_SPACING) * 2; + requisition->height += (GTK_CONTAINER (menu_bar)->border_width + + widget->style->klass->ythickness + + BORDER_SPACING) * 2; + + if (nchildren > 0) + requisition->width += 2 * CHILD_SPACING * (nchildren - 1); + } +} + +static void +gtk_menu_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkMenuBar *menu_bar; + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + GtkAllocation child_allocation; + guint offset; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_BAR (widget)); + g_return_if_fail (allocation != NULL); + + menu_bar = GTK_MENU_BAR (widget); + menu_shell = GTK_MENU_SHELL (widget); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + if (menu_shell->children) + { + child_allocation.x = (GTK_CONTAINER (menu_bar)->border_width + + widget->style->klass->xthickness + + BORDER_SPACING); + offset = child_allocation.x; /* Window edge to menubar start */ + + child_allocation.y = (GTK_CONTAINER (menu_bar)->border_width + + widget->style->klass->ythickness + + BORDER_SPACING); + child_allocation.height = allocation->height - child_allocation.y * 2; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + /* Support for the right justified help menu */ + if ( (children == NULL) && (GTK_IS_MENU_ITEM(child)) + && (GTK_MENU_ITEM(child)->right_justify)) { + child_allocation.x = allocation->width - + child_allocation.width - CHILD_SPACING - offset; + } + if (GTK_WIDGET_VISIBLE (child)) + { + child_allocation.width = child->requisition.width; + + gtk_widget_size_allocate (child, &child_allocation); + + child_allocation.x += child_allocation.width + CHILD_SPACING * 2; + } + } + } +} + +static void +gtk_menu_bar_paint (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_BAR (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_draw_shadow (widget->style, + widget->window, + GTK_STATE_NORMAL, + GTK_SHADOW_OUT, + 0, 0, + widget->allocation.width, + widget->allocation.height); + } +} + +static void +gtk_menu_bar_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GdkRectangle child_area; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_BAR (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_bar_paint (widget); + + menu_shell = GTK_MENU_SHELL (widget); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child, area, &child_area)) + gtk_widget_draw (child, &child_area); + } + } +} + +static gint +gtk_menu_bar_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GdkEventExpose child_event; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_BAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_bar_paint (widget); + + menu_shell = GTK_MENU_SHELL (widget); + child_event = *event; + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child) && + gtk_widget_intersect (child, &event->area, &child_event.area)) + gtk_widget_event (child, (GdkEvent*) &child_event); + } + } + + return FALSE; +} diff --git a/gtk/gtkmenubar.h b/gtk/gtkmenubar.h new file mode 100644 index 000000000..691e8f36f --- /dev/null +++ b/gtk/gtkmenubar.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_MENU_BAR_H__ +#define __GTK_MENU_BAR_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MENU_BAR(obj) GTK_CHECK_CAST (obj, gtk_menu_bar_get_type (), GtkMenuBar) +#define GTK_MENU_BAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_menu_bar_get_type (), GtkMenuBarClass) +#define GTK_IS_MENU_BAR(obj) GTK_CHECK_TYPE (obj, gtk_menu_bar_get_type ()) + + +typedef struct _GtkMenuBar GtkMenuBar; +typedef struct _GtkMenuBarClass GtkMenuBarClass; + +struct _GtkMenuBar +{ + GtkMenuShell menu_shell; +}; + +struct _GtkMenuBarClass +{ + GtkMenuShellClass parent_class; +}; + + +guint gtk_menu_bar_get_type (void); +GtkWidget* gtk_menu_bar_new (void); +void gtk_menu_bar_append (GtkMenuBar *menu_bar, + GtkWidget *child); +void gtk_menu_bar_prepend (GtkMenuBar *menu_bar, + GtkWidget *child); +void gtk_menu_bar_insert (GtkMenuBar *menu_bar, + GtkWidget *child, + gint position); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_BAR_H__ */ diff --git a/gtk/gtkmenufactory.c b/gtk/gtkmenufactory.c new file mode 100644 index 000000000..d6e9ea684 --- /dev/null +++ b/gtk/gtkmenufactory.c @@ -0,0 +1,541 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkcheckmenuitem.h" +#include "gtkmenu.h" +#include "gtkmenubar.h" +#include "gtkmenufactory.h" +#include "gtkmenuitem.h" +#include "gtksignal.h" + + +enum +{ + CREATE = 1 << 0, + DESTROY = 1 << 1, + CHECK = 1 << 2 +}; + + +static void gtk_menu_factory_create (GtkMenuFactory *factory, + GtkMenuEntry *entry, + GtkWidget *parent, + const char *path); +static void gtk_menu_factory_remove (GtkMenuFactory *factory, + GtkWidget *parent, + const char *path); +static GtkWidget* gtk_menu_factory_make_widget (GtkMenuFactory *factory); +static GtkMenuPath* gtk_menu_factory_get (GtkWidget *parent, + const char *path, + int flags); +static GtkMenuPath* gtk_menu_factory_find_recurse (GtkMenuFactory *factory, + GtkWidget *parent, + const char *path); +static void gtk_menu_factory_parse_accelerator (const char *accelerator, + char *accelerator_key, + guint8 *accelerator_mods); + + +GtkMenuFactory* +gtk_menu_factory_new (GtkMenuFactoryType type) +{ + GtkMenuFactory *factory; + + factory = g_new (GtkMenuFactory, 1); + factory->path = NULL; + factory->type = type; + factory->table = NULL; + factory->widget = NULL; + factory->subfactories = NULL; + + return factory; +} + +void +gtk_menu_factory_destroy (GtkMenuFactory *factory) +{ + GtkMenuFactory *subfactory; + GList *tmp_list; + + g_return_if_fail (factory != NULL); + + if (factory->path) + g_free (factory->path); + + tmp_list = factory->subfactories; + while (tmp_list) + { + subfactory = tmp_list->data; + tmp_list = tmp_list->next; + + gtk_menu_factory_destroy (subfactory); + } +} + +void +gtk_menu_factory_add_entries (GtkMenuFactory *factory, + GtkMenuEntry *entries, + int nentries) +{ + int i; + + g_return_if_fail (factory != NULL); + g_return_if_fail (entries != NULL); + g_return_if_fail (nentries > 0); + + if (!factory->widget) + factory->widget = gtk_menu_factory_make_widget (factory); + + for (i = 0; i < nentries; i++) + gtk_menu_factory_create (factory, &entries[i], factory->widget, entries[i].path); +} + +void +gtk_menu_factory_add_subfactory (GtkMenuFactory *factory, + GtkMenuFactory *subfactory, + const char *path) +{ + g_return_if_fail (factory != NULL); + g_return_if_fail (subfactory != NULL); + g_return_if_fail (path != NULL); + + if (subfactory->path) + g_free (subfactory->path); + subfactory->path = g_strdup (path); + + factory->subfactories = g_list_append (factory->subfactories, subfactory); +} + +void +gtk_menu_factory_remove_paths (GtkMenuFactory *factory, + char **paths, + int npaths) +{ + int i; + + g_return_if_fail (factory != NULL); + g_return_if_fail (paths != NULL); + g_return_if_fail (npaths > 0); + + if (factory->widget) + { + for (i = 0; i < npaths; i++) + gtk_menu_factory_remove (factory, factory->widget, paths[i]); + } +} + +void +gtk_menu_factory_remove_entries (GtkMenuFactory *factory, + GtkMenuEntry *entries, + int nentries) +{ + int i; + + g_return_if_fail (factory != NULL); + g_return_if_fail (entries != NULL); + g_return_if_fail (nentries > 0); + + if (factory->widget) + { + for (i = 0; i < nentries; i++) + gtk_menu_factory_remove (factory, factory->widget, entries[i].path); + } +} + +void +gtk_menu_factory_remove_subfactory (GtkMenuFactory *factory, + GtkMenuFactory *subfactory, + const char *path) +{ + g_return_if_fail (factory != NULL); + g_return_if_fail (subfactory != NULL); + g_return_if_fail (path != NULL); + + g_warning ("FIXME: gtk_menu_factory_remove_subfactory"); +} + +GtkMenuPath* +gtk_menu_factory_find (GtkMenuFactory *factory, + const char *path) +{ + g_return_val_if_fail (factory != NULL, NULL); + g_return_val_if_fail (path != NULL, NULL); + + return gtk_menu_factory_find_recurse (factory, factory->widget, path); +} + + +static void +gtk_menu_factory_create (GtkMenuFactory *factory, + GtkMenuEntry *entry, + GtkWidget *parent, + const char *path) +{ + GtkMenuFactory *subfactory; + GtkMenuPath *menu_path; + GtkWidget *menu; + GList *tmp_list; + char tmp_path[256]; + char accelerator_key; + guint8 accelerator_mods; + char *p; + + g_return_if_fail (factory != NULL); + g_return_if_fail (entry != NULL); + + /* If 'path' is empty, then simply return. + */ + if (!path || path[0] == '\0') + return; + + /* Strip off the next part of the path. + */ + p = strchr (path, '/'); + + /* If this is the last part of the path ('p' is + * NULL), then we create an item. + */ + if (!p) + { + /* Check to see if this item is a separator. + */ + if (strcmp (path, "") == 0) + { + entry->widget = gtk_menu_item_new (); + gtk_container_add (GTK_CONTAINER (parent), entry->widget); + gtk_widget_show (entry->widget); + } + else + { + if (strncmp (path, "", 7) == 0) + menu_path = gtk_menu_factory_get (parent, path + 7, CREATE | CHECK); + else + menu_path = gtk_menu_factory_get (parent, path, CREATE); + entry->widget = menu_path->widget; + + if (strcmp (path, "") == 0) + gtk_widget_hide (entry->widget); + + if (entry->accelerator) + { + gtk_menu_factory_parse_accelerator (entry->accelerator, + &accelerator_key, + &accelerator_mods); + if (!factory->table) + { + factory->table = gtk_accelerator_table_new (); + gtk_accelerator_table_ref (factory->table); + } + + gtk_widget_install_accelerator (menu_path->widget, + factory->table, + "activate", + accelerator_key, + accelerator_mods); + } + + if (entry->callback) + gtk_signal_connect (GTK_OBJECT (menu_path->widget), "activate", + (GtkSignalFunc) entry->callback, + entry->callback_data); + } + } + else + { + strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path)); + tmp_path[(long) p - (long) path] = '\0'; + + menu_path = gtk_menu_factory_get (parent, tmp_path, 0); + if (!menu_path) + { + tmp_list = factory->subfactories; + while (tmp_list) + { + subfactory = tmp_list->data; + tmp_list = tmp_list->next; + + if (subfactory->path && + (strcmp (subfactory->path, tmp_path) == 0)) + { + if (!subfactory->widget) + subfactory->widget = gtk_menu_factory_make_widget (subfactory); + gtk_menu_factory_create (subfactory, entry, subfactory->widget, p + 1); + return; + } + } + + menu_path = gtk_menu_factory_get (parent, tmp_path, CREATE); + } + + entry->widget = menu_path->widget; + menu = GTK_MENU_ITEM (menu_path->widget)->submenu; + + if (!menu) + { + menu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_path->widget), menu); + + if (!factory->table) + { + factory->table = gtk_accelerator_table_new (); + gtk_accelerator_table_ref (factory->table); + } + gtk_menu_set_accelerator_table (GTK_MENU (menu), factory->table); + } + + gtk_menu_factory_create (factory, entry, menu, p + 1); + } +} + +static void +gtk_menu_factory_remove (GtkMenuFactory *factory, + GtkWidget *parent, + const char *path) +{ + GtkMenuFactory *subfactory; + GtkMenuPath *menu_path; + GtkWidget *menu; + GList *tmp_list; + char tmp_path[256]; + char *p; + + if (!path || path[0] == '\0') + return; + + p = strchr (path, '/'); + + if (!p) + { + if (parent) + gtk_menu_factory_get (parent, path, DESTROY); + } + else + { + strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path)); + tmp_path[(long) p - (long) path] = '\0'; + + menu_path = gtk_menu_factory_get (parent, tmp_path, 0); + if (!menu_path) + { + tmp_list = factory->subfactories; + while (tmp_list) + { + subfactory = tmp_list->data; + tmp_list = tmp_list->next; + + if (subfactory->path && + (strcmp (subfactory->path, tmp_path) == 0)) + { + if (!subfactory->widget) + return; + gtk_menu_factory_remove (subfactory, subfactory->widget, p + 1); + } + } + } + else + { + menu = GTK_MENU_ITEM (menu_path->widget)->submenu; + if (menu) + gtk_menu_factory_remove (factory, menu, p + 1); + } + } +} + +static GtkWidget* +gtk_menu_factory_make_widget (GtkMenuFactory *factory) +{ + GtkWidget *widget; + + g_return_val_if_fail (factory != NULL, NULL); + + switch (factory->type) + { + case GTK_MENU_FACTORY_MENU: + widget = gtk_menu_new (); + + if (!factory->table) + { + factory->table = gtk_accelerator_table_new (); + gtk_accelerator_table_ref (factory->table); + } + gtk_menu_set_accelerator_table (GTK_MENU (widget), factory->table); + return widget; + case GTK_MENU_FACTORY_MENU_BAR: + return gtk_menu_bar_new (); + case GTK_MENU_FACTORY_OPTION_MENU: + g_error ("not implemented"); + break; + } + + return NULL; +} + +static GtkMenuPath* +gtk_menu_factory_get (GtkWidget *parent, + const char *path, + int flags) +{ + GtkMenuPath *menu_path; + GList *tmp_list; + + tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent)); + while (tmp_list) + { + menu_path = tmp_list->data; + tmp_list = tmp_list->next; + + if (strcmp (menu_path->path, path) == 0) + { + if (flags & DESTROY) + { + tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent)); + tmp_list = g_list_remove (tmp_list, menu_path); + gtk_object_set_user_data (GTK_OBJECT (parent), tmp_list); + + gtk_widget_destroy (menu_path->widget); + g_free (menu_path->path); + g_free (menu_path); + + return NULL; + } + else + { + return menu_path; + } + } + } + + if (flags & CREATE) + { + menu_path = g_new (GtkMenuPath, 1); + menu_path->path = g_strdup (path); + + if (flags & CHECK) + menu_path->widget = gtk_check_menu_item_new_with_label (path); + else + menu_path->widget = gtk_menu_item_new_with_label (path); + + gtk_container_add (GTK_CONTAINER (parent), menu_path->widget); + gtk_object_set_user_data (GTK_OBJECT (menu_path->widget), NULL); + gtk_widget_show (menu_path->widget); + + tmp_list = gtk_object_get_user_data (GTK_OBJECT (parent)); + tmp_list = g_list_prepend (tmp_list, menu_path); + gtk_object_set_user_data (GTK_OBJECT (parent), tmp_list); + + return menu_path; + } + + return NULL; +} + +static GtkMenuPath* +gtk_menu_factory_find_recurse (GtkMenuFactory *factory, + GtkWidget *parent, + const char *path) +{ + GtkMenuFactory *subfactory; + GtkMenuPath *menu_path; + GtkWidget *menu; + GList *tmp_list; + char tmp_path[256]; + char *p; + + if (!path || path[0] == '\0') + return NULL; + + p = strchr (path, '/'); + + if (!p) + { + if (parent) + return gtk_menu_factory_get (parent, path, 0); + } + else + { + strncpy (tmp_path, path, (unsigned int) ((long) p - (long) path)); + tmp_path[(long) p - (long) path] = '\0'; + + menu_path = gtk_menu_factory_get (parent, tmp_path, 0); + if (!menu_path) + { + tmp_list = factory->subfactories; + while (tmp_list) + { + subfactory = tmp_list->data; + tmp_list = tmp_list->next; + + if (subfactory->path && + (strcmp (subfactory->path, tmp_path) == 0)) + { + if (!subfactory->widget) + return NULL; + return gtk_menu_factory_find_recurse (subfactory, subfactory->widget, p + 1); + } + } + + return NULL; + } + + menu = GTK_MENU_ITEM (menu_path->widget)->submenu; + if (menu) + return gtk_menu_factory_find_recurse (factory, menu, p + 1); + } + + return NULL; +} + +static void +gtk_menu_factory_parse_accelerator (const char *accelerator, + char *accelerator_key, + guint8 *accelerator_mods) +{ + int done; + + g_return_if_fail (accelerator != NULL); + g_return_if_fail (accelerator_key != NULL); + g_return_if_fail (accelerator_mods != NULL); + + *accelerator_key = 0; + *accelerator_mods = 0; + + done = FALSE; + while (!done) + { + if (strncmp (accelerator, "", 7) == 0) + { + accelerator += 7; + *accelerator_mods |= GDK_SHIFT_MASK; + } + else if (strncmp (accelerator, "", 5) == 0) + { + accelerator += 5; + *accelerator_mods |= GDK_MOD1_MASK; + } + else if (strncmp (accelerator, "", 9) == 0) + { + accelerator += 9; + *accelerator_mods |= GDK_CONTROL_MASK; + } + else + { + done = TRUE; + *accelerator_key = accelerator[0]; + } + } +} diff --git a/gtk/gtkmenufactory.h b/gtk/gtkmenufactory.h new file mode 100644 index 000000000..d95fdb775 --- /dev/null +++ b/gtk/gtkmenufactory.h @@ -0,0 +1,88 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_MENU_FACTORY_H__ +#define __GTK_MENU_FACTORY_H__ + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GtkMenuEntry GtkMenuEntry; +typedef struct _GtkMenuPath GtkMenuPath; +typedef struct _GtkMenuFactory GtkMenuFactory; + +typedef void (*GtkMenuCallback) (GtkWidget *widget, + gpointer user_data); + +struct _GtkMenuEntry +{ + char *path; + char *accelerator; + GtkMenuCallback callback; + gpointer callback_data; + GtkWidget *widget; +}; + +struct _GtkMenuPath +{ + char *path; + GtkWidget *widget; +}; + +struct _GtkMenuFactory +{ + char *path; + GtkMenuFactoryType type; + GtkAcceleratorTable *table; + GtkWidget *widget; + GList *subfactories; +}; + + +GtkMenuFactory* gtk_menu_factory_new (GtkMenuFactoryType type); +void gtk_menu_factory_destroy (GtkMenuFactory *factory); +void gtk_menu_factory_add_entries (GtkMenuFactory *factory, + GtkMenuEntry *entries, + int nentries); +void gtk_menu_factory_add_subfactory (GtkMenuFactory *factory, + GtkMenuFactory *subfactory, + const char *path); +void gtk_menu_factory_remove_paths (GtkMenuFactory *factory, + char **paths, + int npaths); +void gtk_menu_factory_remove_entries (GtkMenuFactory *factory, + GtkMenuEntry *entries, + int nentries); +void gtk_menu_factory_remove_subfactory (GtkMenuFactory *factory, + GtkMenuFactory *subfactory, + const char *path); +GtkMenuPath* gtk_menu_factory_find (GtkMenuFactory *factory, + const char *path); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_FACTORY_H__ */ diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c new file mode 100644 index 000000000..f7715fb25 --- /dev/null +++ b/gtk/gtkmenuitem.c @@ -0,0 +1,746 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtksignal.h" + + +#define BORDER_SPACING 3 +#define SELECT_TIMEOUT 20 + +#define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass) + + +enum { + ACTIVATE, + LAST_SIGNAL +}; + + +static void gtk_menu_item_class_init (GtkMenuItemClass *klass); +static void gtk_menu_item_init (GtkMenuItem *menu_item); +static void gtk_menu_item_destroy (GtkObject *object); +static void gtk_menu_item_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_menu_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_menu_item_install_accel (GtkWidget *widget, + const gchar *signal_name, + gchar key, + guint8 modifiers); +static void gtk_menu_item_remove_accel (GtkWidget *widget, + const gchar *signal_name); +static void gtk_menu_item_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_menu_item_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_menu_item_enter (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_menu_item_leave (GtkWidget *widget, + GdkEventCrossing *event); +static void gtk_real_menu_item_select (GtkItem *item); +static void gtk_real_menu_item_deselect (GtkItem *item); +static gint gtk_menu_item_select_timeout (gpointer data); +static void gtk_menu_item_position_menu (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data); + +static GtkItemClass *parent_class; +static gint menu_item_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_menu_item_get_type () +{ + static guint menu_item_type = 0; + + if (!menu_item_type) + { + GtkTypeInfo menu_item_info = + { + "GtkMenuItem", + sizeof (GtkMenuItem), + sizeof (GtkMenuItemClass), + (GtkClassInitFunc) gtk_menu_item_class_init, + (GtkObjectInitFunc) gtk_menu_item_init, + (GtkArgFunc) NULL, + }; + + menu_item_type = gtk_type_unique (gtk_item_get_type (), &menu_item_info); + } + + return menu_item_type; +} + +static void +gtk_menu_item_class_init (GtkMenuItemClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkItemClass *item_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + item_class = (GtkItemClass*) klass; + + parent_class = gtk_type_class (gtk_item_get_type ()); + + menu_item_signals[ACTIVATE] = + gtk_signal_new ("activate", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkMenuItemClass, activate), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, menu_item_signals, LAST_SIGNAL); + + object_class->destroy = gtk_menu_item_destroy; + + widget_class->activate_signal = menu_item_signals[ACTIVATE]; + widget_class->size_request = gtk_menu_item_size_request; + widget_class->size_allocate = gtk_menu_item_size_allocate; + widget_class->install_accelerator = gtk_menu_item_install_accel; + widget_class->remove_accelerator = gtk_menu_item_remove_accel; + widget_class->draw = gtk_menu_item_draw; + widget_class->expose_event = gtk_menu_item_expose; + widget_class->enter_notify_event = gtk_menu_item_enter; + widget_class->leave_notify_event = gtk_menu_item_leave; + + item_class->select = gtk_real_menu_item_select; + item_class->deselect = gtk_real_menu_item_deselect; + + klass->activate = NULL; + + klass->toggle_size = 0; + klass->shift_text = "Shft"; + klass->control_text = "Ctl"; + klass->alt_text = "Alt"; + klass->separator_text = "+"; +} + +static void +gtk_menu_item_init (GtkMenuItem *menu_item) +{ + menu_item->submenu = NULL; + menu_item->accelerator_key = 0; + menu_item->accelerator_mods = 0; + menu_item->accelerator_size = 0; + menu_item->accelerator_signal = 0; + menu_item->toggle_size = 0; + menu_item->show_toggle_indicator = FALSE; + menu_item->show_submenu_indicator = FALSE; + menu_item->submenu_direction = GTK_DIRECTION_RIGHT; + menu_item->submenu_placement = GTK_TOP_BOTTOM; + menu_item->right_justify = FALSE; + + menu_item->timer = 0; +} + +GtkWidget* +gtk_menu_item_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_menu_item_get_type ())); +} + +GtkWidget* +gtk_menu_item_new_with_label (const gchar *label) +{ + GtkWidget *menu_item; + GtkWidget *label_widget; + + menu_item = gtk_menu_item_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (menu_item), label_widget); + gtk_widget_show (label_widget); + + return menu_item; +} + +static void +gtk_menu_item_destroy (GtkObject *object) +{ + GtkMenuItem *menu_item; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (object)); + + menu_item = GTK_MENU_ITEM (object); + + if (menu_item->submenu) + { + gtk_object_unref (GTK_OBJECT (menu_item->submenu)); + /* gtk_widget_destroy (menu_item->submenu); */ + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +void +gtk_menu_item_set_submenu (GtkMenuItem *menu_item, + GtkWidget *submenu) +{ + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (menu_item->submenu) + { + g_return_if_fail (!GTK_WIDGET_VISIBLE (menu_item->submenu)); + gtk_object_unref (GTK_OBJECT (menu_item->submenu)); + } + + menu_item->submenu = submenu; + + if (menu_item->submenu) + gtk_object_ref (GTK_OBJECT (menu_item->submenu)); + + if (GTK_WIDGET (menu_item)->parent) + gtk_widget_queue_resize (GTK_WIDGET (menu_item)); +} + +void +gtk_menu_item_set_placement (GtkMenuItem *menu_item, + GtkSubmenuPlacement placement) +{ + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + menu_item->submenu_placement = placement; +} + +void +gtk_menu_item_accelerator_size (GtkMenuItem *menu_item) +{ + char buf[32]; + + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (menu_item->accelerator_key) + { + gtk_menu_item_accelerator_text (menu_item, buf); + menu_item->accelerator_size = gdk_string_width (GTK_WIDGET (menu_item)->style->font, buf) + 13; + } + else if (menu_item->submenu && menu_item->show_submenu_indicator) + { + menu_item->accelerator_size = 21; + } + else + { + menu_item->accelerator_size = 0; + } +} + +void +gtk_menu_item_accelerator_text (GtkMenuItem *menu_item, + gchar *buffer) +{ + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + if (menu_item->accelerator_key) + { + buffer[0] = '\0'; + if (menu_item->accelerator_mods & GDK_SHIFT_MASK) + { + strcat (buffer, MENU_ITEM_CLASS (menu_item)->shift_text); + strcat (buffer, MENU_ITEM_CLASS (menu_item)->separator_text); + } + if (menu_item->accelerator_mods & GDK_CONTROL_MASK) + { + strcat (buffer, MENU_ITEM_CLASS (menu_item)->control_text); + strcat (buffer, MENU_ITEM_CLASS (menu_item)->separator_text); + } + if (menu_item->accelerator_mods & GDK_MOD1_MASK) + { + strcat (buffer, MENU_ITEM_CLASS (menu_item)->alt_text); + strcat (buffer, MENU_ITEM_CLASS (menu_item)->separator_text); + } + strncat (buffer, &menu_item->accelerator_key, 1); + } +} + +void +gtk_menu_item_configure (GtkMenuItem *menu_item, + gint show_toggle_indicator, + gint show_submenu_indicator) +{ + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + menu_item->show_toggle_indicator = (show_toggle_indicator == TRUE); + menu_item->show_submenu_indicator = (show_submenu_indicator == TRUE); +} + +void +gtk_menu_item_select (GtkMenuItem *menu_item) +{ + gtk_item_select (GTK_ITEM (menu_item)); +} + +void +gtk_menu_item_deselect (GtkMenuItem *menu_item) +{ + gtk_item_deselect (GTK_ITEM (menu_item)); +} + +void +gtk_menu_item_activate (GtkMenuItem *menu_item) +{ + gtk_signal_emit (GTK_OBJECT (menu_item), menu_item_signals[ACTIVATE]); +} + + +static void +gtk_menu_item_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + g_return_if_fail (requisition != NULL); + + bin = GTK_BIN (widget); + + gtk_menu_item_accelerator_size (GTK_MENU_ITEM (widget)); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->xthickness + + BORDER_SPACING) * 2; + requisition->height = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->ythickness) * 2; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &bin->child->requisition); + + requisition->width += bin->child->requisition.width; + requisition->height += bin->child->requisition.height; + } +} + +static void +gtk_menu_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + bin = GTK_BIN (widget); + + if (bin->child) + { + child_allocation.x = (GTK_CONTAINER (widget)->border_width + + widget->style->klass->xthickness + + BORDER_SPACING); + child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + child_allocation.height = allocation->height - child_allocation.y * 2; + child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size; + child_allocation.width -= (GTK_MENU_ITEM (widget)->toggle_size + + GTK_MENU_ITEM (widget)->accelerator_size); + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} + +static gint +gtk_menu_item_install_accel (GtkWidget *widget, + const gchar *signal_name, + gchar key, + guint8 modifiers) +{ + GtkMenuItem *menu_item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (signal_name != NULL, FALSE); + + menu_item = GTK_MENU_ITEM (widget); + + menu_item->accelerator_signal = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (widget)); + if (menu_item->accelerator_signal > 0) + { + menu_item->accelerator_key = key; + menu_item->accelerator_mods = modifiers; + + if (widget->parent) + gtk_widget_queue_resize (widget); + + return TRUE; + } + + return FALSE; +} + +static void +gtk_menu_item_remove_accel (GtkWidget *widget, + const gchar *signal_name) +{ + GtkMenuItem *menu_item; + gint signal_num; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + g_return_if_fail (signal_name != NULL); + + menu_item = GTK_MENU_ITEM (widget); + + signal_num = gtk_signal_lookup (signal_name, GTK_OBJECT_TYPE (widget)); + if (menu_item->accelerator_signal == signal_num) + { + menu_item->accelerator_key = 0; + menu_item->accelerator_mods = 0; + menu_item->accelerator_signal = 0; + + if (GTK_WIDGET_VISIBLE (widget)) + { + gtk_widget_queue_draw (widget); + GTK_MENU_SHELL (widget->parent)->menu_flag = TRUE; + } + else + gtk_container_need_resize (GTK_CONTAINER (widget->parent)); + } +} + +static void +gtk_menu_item_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkMenuItem *menu_item; + GtkStateType state_type; + GtkShadowType shadow_type; + GdkFont *font; + gint width, height; + gint x, y; + char buf[32]; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + menu_item = GTK_MENU_ITEM (widget); + + state_type = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + gtk_style_set_background (widget->style, widget->window, state_type); + gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height); + + x = GTK_CONTAINER (menu_item)->border_width; + y = GTK_CONTAINER (menu_item)->border_width; + width = widget->allocation.width - x * 2; + height = widget->allocation.height - y * 2; + + if ((state_type == GTK_STATE_PRELIGHT) && + (GTK_BIN (menu_item)->child)) + gtk_draw_shadow (widget->style, + widget->window, + GTK_STATE_PRELIGHT, + GTK_SHADOW_OUT, + x, y, width, height); + + if (menu_item->accelerator_key) + { + gtk_menu_item_accelerator_text (menu_item, buf); + + font = widget->style->font; + x = x + width - menu_item->accelerator_size + 13 - 4; + y = y + ((height - (font->ascent + font->descent)) / 2) + font->ascent; + + if (state_type == GTK_STATE_INSENSITIVE) + gdk_draw_string (widget->window, widget->style->font, + widget->style->white_gc, + x + 1, y + 1, buf); + + gdk_draw_string (widget->window, widget->style->font, + widget->style->fg_gc[state_type], + x, y, buf); + } + else if (menu_item->submenu && menu_item->show_submenu_indicator) + { + shadow_type = GTK_SHADOW_OUT; + if (state_type == GTK_STATE_PRELIGHT) + shadow_type = GTK_SHADOW_IN; + + gtk_draw_arrow (widget->style, widget->window, + state_type, shadow_type, GTK_ARROW_RIGHT, FALSE, + x + width - 15, y + height / 2 - 5, 10, 10); + } + else if (!GTK_BIN (menu_item)->child) + { + gtk_draw_hline (widget->style, widget->window, GTK_STATE_NORMAL, + 0, widget->allocation.width, 0); + } + } +} + +static void +gtk_menu_item_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_item_paint (widget, area); + + bin = GTK_BIN (widget); + + if (bin->child) + { + if (gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } + } +} + +static gint +gtk_menu_item_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_menu_item_paint (widget, &event->area); + + bin = GTK_BIN (widget); + + if (bin->child) + { + child_event = *event; + + if (GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static gint +gtk_menu_item_enter (GtkWidget *widget, + GdkEventCrossing *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return gtk_widget_event (widget->parent, (GdkEvent*) event); +} + +static gint +gtk_menu_item_leave (GtkWidget *widget, + GdkEventCrossing *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return gtk_widget_event (widget->parent, (GdkEvent*) event); +} + +static void +gtk_real_menu_item_select (GtkItem *item) +{ + GtkMenuItem *menu_item; + + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (item)); + + menu_item = GTK_MENU_ITEM (item); + + if (menu_item->submenu && !GTK_WIDGET_VISIBLE (menu_item->submenu)) + menu_item->timer = gtk_timeout_add (SELECT_TIMEOUT, gtk_menu_item_select_timeout, menu_item); + + gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT); + gtk_widget_draw (GTK_WIDGET (menu_item), NULL); +} + +static void +gtk_real_menu_item_deselect (GtkItem *item) +{ + GtkMenuItem *menu_item; + + g_return_if_fail (item != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (item)); + + menu_item = GTK_MENU_ITEM (item); + + if (menu_item->submenu) + { + if (menu_item->timer) + gtk_timeout_remove (menu_item->timer); + else + gtk_menu_popdown (GTK_MENU (menu_item->submenu)); + } + + gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL); + gtk_widget_draw (GTK_WIDGET (menu_item), NULL); +} + +static gint +gtk_menu_item_select_timeout (gpointer data) +{ + GtkMenuItem *menu_item; + + menu_item = GTK_MENU_ITEM (data); + menu_item->timer = 0; + + gtk_menu_popup (GTK_MENU (menu_item->submenu), + GTK_WIDGET (menu_item)->parent, + GTK_WIDGET (menu_item), + gtk_menu_item_position_menu, + menu_item, + GTK_MENU_SHELL (GTK_WIDGET (menu_item)->parent)->button, + 0); + + return FALSE; +} + +static void +gtk_menu_item_position_menu (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data) +{ + GtkMenuItem *menu_item; + GtkMenuItem *parent_menu_item; + gint screen_width; + gint screen_height; + gint twidth, theight; + gint tx, ty; + + g_return_if_fail (menu != NULL); + g_return_if_fail (x != NULL); + g_return_if_fail (y != NULL); + + menu_item = GTK_MENU_ITEM (user_data); + + twidth = GTK_WIDGET (menu)->requisition.width; + theight = GTK_WIDGET (menu)->requisition.height; + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + g_return_if_fail (gdk_window_get_origin (GTK_WIDGET (menu_item)->window, &tx, &ty)); + + switch (menu_item->submenu_placement) + { + case GTK_TOP_BOTTOM: + if ((ty + GTK_WIDGET (menu_item)->allocation.height + theight) <= screen_height) + ty += GTK_WIDGET (menu_item)->allocation.height; + else if ((ty - theight) >= 0) + ty -= theight; + else + ty += GTK_WIDGET (menu_item)->allocation.height; + + if ((tx + twidth) > screen_width) + { + tx -= ((tx + twidth) - screen_width); + if (tx < 0) + tx = 0; + } + break; + + case GTK_LEFT_RIGHT: + menu_item->submenu_direction = GTK_DIRECTION_RIGHT; + parent_menu_item = GTK_MENU_ITEM (GTK_MENU (GTK_WIDGET (menu_item)->parent)->parent_menu_item); + if (parent_menu_item) + menu_item->submenu_direction = parent_menu_item->submenu_direction; + + switch (menu_item->submenu_direction) + { + case GTK_DIRECTION_LEFT: + if ((tx - twidth) >= 0) + tx -= twidth; + else + { + menu_item->submenu_direction = GTK_DIRECTION_RIGHT; + tx += GTK_WIDGET (menu_item)->allocation.width - 5; + } + break; + + case GTK_DIRECTION_RIGHT: + if ((tx + GTK_WIDGET (menu_item)->allocation.width + twidth - 5) <= screen_width) + tx += GTK_WIDGET (menu_item)->allocation.width - 5; + else + { + menu_item->submenu_direction = GTK_DIRECTION_LEFT; + tx -= twidth; + } + break; + } + + if ((ty + GTK_WIDGET (menu_item)->allocation.height / 4 + theight) <= screen_height) + ty += GTK_WIDGET (menu_item)->allocation.height / 4; + else + { + ty -= ((ty + theight) - screen_height); + if (ty < 0) + ty = 0; + } + break; + } + + *x = tx; + *y = ty; +} + +void +gtk_menu_item_right_justify(GtkMenuItem *menuitem) +{ + g_return_if_fail (menuitem != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (menuitem)); + + menuitem->right_justify = 1; +} diff --git a/gtk/gtkmenuitem.h b/gtk/gtkmenuitem.h new file mode 100644 index 000000000..da5168109 --- /dev/null +++ b/gtk/gtkmenuitem.h @@ -0,0 +1,98 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_MENU_ITEM_H__ +#define __GTK_MENU_ITEM_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MENU_ITEM(obj) GTK_CHECK_CAST (obj, gtk_menu_item_get_type (), GtkMenuItem) +#define GTK_MENU_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_menu_item_get_type (), GtkMenuItemClass) +#define GTK_IS_MENU_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_menu_item_get_type ()) + + +typedef struct _GtkMenuItem GtkMenuItem; +typedef struct _GtkMenuItemClass GtkMenuItemClass; + +struct _GtkMenuItem +{ + GtkItem item; + + GtkWidget *submenu; + + gint accelerator_signal; + gchar accelerator_key; + guint8 accelerator_mods; + guint16 accelerator_size; + guint16 toggle_size; + + guint show_toggle_indicator : 1; + guint show_submenu_indicator : 1; + guint submenu_placement : 1; + guint submenu_direction : 1; + guint right_justify: 1; + gint timer; +}; + +struct _GtkMenuItemClass +{ + GtkItemClass parent_class; + + gint toggle_size; + + gchar *shift_text; + gchar *control_text; + gchar *alt_text; + gchar *separator_text; + + void (* activate) (GtkMenuItem *menu_item); +}; + + +guint gtk_menu_item_get_type (void); +GtkWidget* gtk_menu_item_new (void); +GtkWidget* gtk_menu_item_new_with_label (const gchar *label); +void gtk_menu_item_set_submenu (GtkMenuItem *menu_item, + GtkWidget *submenu); +void gtk_menu_item_set_placement (GtkMenuItem *menu_item, + GtkSubmenuPlacement placement); +void gtk_menu_item_accelerator_size (GtkMenuItem *menu_item); +void gtk_menu_item_accelerator_text (GtkMenuItem *menu_item, + gchar *buffer); +void gtk_menu_item_configure (GtkMenuItem *menu_item, + gint show_toggle_indicator, + gint show_submenu_indicator); +void gtk_menu_item_select (GtkMenuItem *menu_item); +void gtk_menu_item_deselect (GtkMenuItem *menu_item); +void gtk_menu_item_activate (GtkMenuItem *menu_item); +void gtk_menu_item_right_justify (GtkMenuItem *menu_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_ITEM_H__ */ diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c new file mode 100644 index 000000000..6d3de5a7f --- /dev/null +++ b/gtk/gtkmenushell.c @@ -0,0 +1,633 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkmain.h" +#include "gtkmenuitem.h" +#include "gtkmenushell.h" +#include "gtksignal.h" + + +#define MENU_SHELL_TIMEOUT 500 +#define MENU_SHELL_CLASS(w) GTK_MENU_SHELL_CLASS (GTK_OBJECT (w)->klass) + + +enum { + DEACTIVATE, + LAST_SIGNAL +}; + + +static void gtk_menu_shell_class_init (GtkMenuShellClass *klass); +static void gtk_menu_shell_init (GtkMenuShell *menu_shell); +static void gtk_menu_shell_destroy (GtkObject *object); +static void gtk_menu_shell_map (GtkWidget *widget); +static void gtk_menu_shell_realize (GtkWidget *widget); +static gint gtk_menu_shell_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_menu_shell_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_menu_shell_enter_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_menu_shell_leave_notify (GtkWidget *widget, + GdkEventCrossing *event); +static void gtk_menu_shell_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_menu_shell_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_menu_shell_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +static void gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell); +static gint gtk_menu_shell_is_item (GtkMenuShell *menu_shell, + GtkWidget *child); + + +static GtkContainerClass *parent_class = NULL; +static gint menu_shell_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_menu_shell_get_type () +{ + static guint menu_shell_type = 0; + + if (!menu_shell_type) + { + GtkTypeInfo menu_shell_info = + { + "GtkMenuShell", + sizeof (GtkMenuShell), + sizeof (GtkMenuShellClass), + (GtkClassInitFunc) gtk_menu_shell_class_init, + (GtkObjectInitFunc) gtk_menu_shell_init, + (GtkArgFunc) NULL, + }; + + menu_shell_type = gtk_type_unique (gtk_container_get_type (), &menu_shell_info); + } + + return menu_shell_type; +} + +static void +gtk_menu_shell_class_init (GtkMenuShellClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + container_class = (GtkContainerClass*) klass; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + menu_shell_signals[DEACTIVATE] = + gtk_signal_new ("deactivate", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkMenuShellClass, deactivate), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, menu_shell_signals, LAST_SIGNAL); + + object_class->destroy = gtk_menu_shell_destroy; + + widget_class->map = gtk_menu_shell_map; + widget_class->realize = gtk_menu_shell_realize; + widget_class->button_press_event = gtk_menu_shell_button_press; + widget_class->button_release_event = gtk_menu_shell_button_release; + widget_class->enter_notify_event = gtk_menu_shell_enter_notify; + widget_class->leave_notify_event = gtk_menu_shell_leave_notify; + + container_class->add = gtk_menu_shell_add; + container_class->remove = gtk_menu_shell_remove; + container_class->foreach = gtk_menu_shell_foreach; + + klass->submenu_placement = GTK_TOP_BOTTOM; + klass->deactivate = gtk_real_menu_shell_deactivate; +} + +static void +gtk_menu_shell_init (GtkMenuShell *menu_shell) +{ + menu_shell->children = NULL; + menu_shell->active_menu_item = NULL; + menu_shell->parent_menu_shell = NULL; + menu_shell->active = FALSE; + menu_shell->have_grab = FALSE; + menu_shell->have_xgrab = FALSE; + menu_shell->ignore_leave = FALSE; + menu_shell->button = 0; + menu_shell->menu_flag = 0; + menu_shell->activate_time = 0; +} + +void +gtk_menu_shell_append (GtkMenuShell *menu_shell, + GtkWidget *child) +{ + gtk_menu_shell_insert (menu_shell, child, -1); +} + +void +gtk_menu_shell_prepend (GtkMenuShell *menu_shell, + GtkWidget *child) +{ + gtk_menu_shell_insert (menu_shell, child, 0); +} + +void +gtk_menu_shell_insert (GtkMenuShell *menu_shell, + GtkWidget *child, + gint position) +{ + GList *tmp_list; + GList *new_list; + gint nchildren; + + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + g_return_if_fail (child != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (child)); + + gtk_widget_set_parent (child, GTK_WIDGET (menu_shell)); + + if (GTK_WIDGET_VISIBLE (child->parent)) + { + if (GTK_WIDGET_REALIZED (child->parent) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (child->parent) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + nchildren = g_list_length (menu_shell->children); + if ((position < 0) || (position > nchildren)) + position = nchildren; + + if (position == nchildren) + { + menu_shell->children = g_list_append (menu_shell->children, child); + } + else + { + tmp_list = g_list_nth (menu_shell->children, position); + new_list = g_list_alloc (); + new_list->data = child; + + if (tmp_list->prev) + tmp_list->prev->next = new_list; + new_list->next = tmp_list; + new_list->prev = tmp_list->prev; + tmp_list->prev = new_list; + + if (tmp_list == menu_shell->children) + menu_shell->children = new_list; + } + + if (GTK_WIDGET_VISIBLE (menu_shell)) + gtk_widget_queue_resize (GTK_WIDGET (menu_shell)); +} + +void +gtk_menu_shell_deactivate (GtkMenuShell *menu_shell) +{ + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + + gtk_signal_emit (GTK_OBJECT (menu_shell), menu_shell_signals[DEACTIVATE]); +} + +static void +gtk_menu_shell_destroy (GtkObject *object) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (object)); + + menu_shell = GTK_MENU_SHELL (object); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + child->parent = NULL; + gtk_object_unref (GTK_OBJECT (child)); + gtk_widget_destroy (child); + } + + g_list_free (menu_shell->children); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_menu_shell_map (GtkWidget *widget) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (widget)); + + menu_shell = GTK_MENU_SHELL (widget); + GTK_WIDGET_SET_FLAGS (menu_shell, GTK_MAPPED); + gdk_window_show (widget->window); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } +} + +static void +gtk_menu_shell_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static gint +gtk_menu_shell_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *menu_item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->type != GDK_BUTTON_PRESS) + return FALSE; + + menu_shell = GTK_MENU_SHELL (widget); + + if (menu_shell->parent_menu_shell) + { + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + } + else if (!menu_shell->active || !menu_shell->button) + { + if (!menu_shell->active) + { + gtk_grab_add (GTK_WIDGET (widget)); + menu_shell->have_grab = TRUE; + } + menu_shell->active = TRUE; + + menu_item = gtk_get_event_widget ((GdkEvent*) event); + if (GTK_IS_MENU_ITEM (menu_item) && gtk_menu_shell_is_item (menu_shell, menu_item)) + { + if ((menu_item->parent == widget) && + (menu_item != menu_shell->active_menu_item)) + { + if (menu_shell->active_menu_item) + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + + menu_shell->active_menu_item = menu_item; + gtk_menu_item_set_placement (GTK_MENU_ITEM (menu_shell->active_menu_item), + MENU_SHELL_CLASS (menu_shell)->submenu_placement); + gtk_menu_item_select (GTK_MENU_ITEM (menu_shell->active_menu_item)); + } + } + else if (!menu_shell->button) + { + gtk_menu_shell_deactivate (menu_shell); + } + + if (menu_shell->active) + menu_shell->button = event->button; + } + else + { + widget = gtk_get_event_widget ((GdkEvent*) event); + if (widget == GTK_WIDGET (menu_shell)) + gtk_menu_shell_deactivate (menu_shell); + } + + return TRUE; +} + +static gint +gtk_menu_shell_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *menu_item; + gint deactivate; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + menu_shell = GTK_MENU_SHELL (widget); + if (menu_shell->active) + { + if (menu_shell->button && (event->button != menu_shell->button)) + { + menu_shell->button = 0; + if (menu_shell->parent_menu_shell) + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + return TRUE; + } + + menu_shell->button = 0; + menu_item = gtk_get_event_widget ((GdkEvent*) event); + deactivate = TRUE; + + if ((event->time - menu_shell->activate_time) > MENU_SHELL_TIMEOUT) + { + if (menu_shell->active_menu_item == menu_item) + { + if (GTK_MENU_ITEM (menu_item)->submenu == NULL) + { + gtk_menu_shell_deactivate (menu_shell); + gtk_widget_activate (menu_item); + return TRUE; + } + } + else if (menu_shell->parent_menu_shell) + { + menu_shell->active = TRUE; + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + return TRUE; + } + } + else + deactivate = FALSE; + + if ((!deactivate || (menu_shell->active_menu_item == menu_item)) && + (gdk_pointer_grab (widget->window, TRUE, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK, + NULL, NULL, event->time) == 0)) + { + deactivate = FALSE; + menu_shell->have_xgrab = TRUE; + menu_shell->ignore_leave = TRUE; + } + else + deactivate = TRUE; + + if (deactivate) + gtk_menu_shell_deactivate (menu_shell); + } + + return TRUE; +} + +static gint +gtk_menu_shell_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkMenuShell *menu_shell; + GtkWidget *menu_item; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + menu_shell = GTK_MENU_SHELL (widget); + if (menu_shell->active) + { + menu_item = gtk_get_event_widget ((GdkEvent*) event); + + if (!GTK_WIDGET_IS_SENSITIVE (menu_item)) + return TRUE; + + if ((menu_item->parent == widget) && + (menu_shell->active_menu_item != menu_item) && + GTK_IS_MENU_ITEM (menu_item)) + { + if ((event->detail != GDK_NOTIFY_INFERIOR) && + (GTK_WIDGET_STATE (menu_item) != GTK_STATE_PRELIGHT)) + { + if (menu_shell->active_menu_item) + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + + menu_shell->active_menu_item = menu_item; + gtk_menu_item_set_placement (GTK_MENU_ITEM (menu_shell->active_menu_item), + MENU_SHELL_CLASS (menu_shell)->submenu_placement); + gtk_menu_item_select (GTK_MENU_ITEM (menu_shell->active_menu_item)); + } + } + else if (menu_shell->parent_menu_shell) + { + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + } + } + + return TRUE; +} + +static gint +gtk_menu_shell_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkMenuShell *menu_shell; + GtkMenuItem *menu_item; + GtkWidget *event_widget; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_VISIBLE (widget)) + { + menu_shell = GTK_MENU_SHELL (widget); + event_widget = gtk_get_event_widget ((GdkEvent*) event); + + if (!GTK_IS_MENU_ITEM (event_widget)) + return TRUE; + + menu_item = GTK_MENU_ITEM (event_widget); + + if (!GTK_WIDGET_IS_SENSITIVE (menu_item)) + return TRUE; + + if (menu_shell->ignore_leave) + { + menu_shell->ignore_leave = FALSE; + return TRUE; + } + + if ((menu_shell->active_menu_item == event_widget) && + (menu_item->submenu == NULL)) + { + if ((event->detail != GDK_NOTIFY_INFERIOR) && + (GTK_WIDGET_STATE (menu_item) != GTK_STATE_NORMAL)) + { + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + menu_shell->active_menu_item = NULL; + } + } + else if (menu_shell->parent_menu_shell) + { + gtk_widget_event (menu_shell->parent_menu_shell, (GdkEvent*) event); + } + } + + return TRUE; +} + +static void +gtk_menu_shell_add (GtkContainer *container, + GtkWidget *widget) +{ + gtk_menu_shell_append (GTK_MENU_SHELL (container), widget); +} + +static void +gtk_menu_shell_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkMenuShell *menu_shell; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (container)); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MENU_ITEM (widget)); + + gtk_widget_unparent (widget); + + menu_shell = GTK_MENU_SHELL (container); + menu_shell->children = g_list_remove (menu_shell->children, widget); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); +} + +static void +gtk_menu_shell_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkMenuShell *menu_shell; + GtkWidget *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (container)); + g_return_if_fail (callback != NULL); + + menu_shell = GTK_MENU_SHELL (container); + + children = menu_shell->children; + while (children) + { + child = children->data; + children = children->next; + + (* callback) (child, callback_data); + } +} + + +static void +gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell) +{ + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + + if (menu_shell->active) + { + menu_shell->button = 0; + menu_shell->active = FALSE; + + if (menu_shell->active_menu_item) + { + gtk_menu_item_deselect (GTK_MENU_ITEM (menu_shell->active_menu_item)); + menu_shell->active_menu_item = NULL; + } + + if (menu_shell->have_grab) + { + menu_shell->have_grab = FALSE; + gtk_grab_remove (GTK_WIDGET (menu_shell)); + } + if (menu_shell->have_xgrab) + { + menu_shell->have_xgrab = FALSE; + gdk_pointer_ungrab (GDK_CURRENT_TIME); + } + } +} + +static gint +gtk_menu_shell_is_item (GtkMenuShell *menu_shell, + GtkWidget *child) +{ + GtkMenuShell *parent; + + g_return_val_if_fail (menu_shell != NULL, FALSE); + g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE); + g_return_val_if_fail (child != NULL, FALSE); + + parent = GTK_MENU_SHELL (child->parent); + while (parent && GTK_IS_MENU_SHELL (parent)) + { + if (parent == menu_shell) + return TRUE; + parent = GTK_MENU_SHELL (parent->parent_menu_shell); + } + + return FALSE; +} diff --git a/gtk/gtkmenushell.h b/gtk/gtkmenushell.h new file mode 100644 index 000000000..a468631ed --- /dev/null +++ b/gtk/gtkmenushell.h @@ -0,0 +1,83 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_MENU_SHELL_H__ +#define __GTK_MENU_SHELL_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MENU_SHELL(obj) GTK_CHECK_CAST (obj, gtk_menu_shell_get_type (), GtkMenuShell) +#define GTK_MENU_SHELL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_menu_shell_get_type (), GtkMenuShellClass) +#define GTK_IS_MENU_SHELL(obj) GTK_CHECK_TYPE (obj, gtk_menu_shell_get_type ()) + + +typedef struct _GtkMenuShell GtkMenuShell; +typedef struct _GtkMenuShellClass GtkMenuShellClass; + +struct _GtkMenuShell +{ + GtkContainer container; + + GList *children; + GtkWidget *active_menu_item; + GtkWidget *parent_menu_shell; + + guint active : 1; + guint have_grab : 1; + guint have_xgrab : 1; + guint button : 2; + guint ignore_leave : 1; + guint menu_flag : 1; + + guint32 activate_time; +}; + +struct _GtkMenuShellClass +{ + GtkContainerClass parent_class; + + guint submenu_placement : 1; + + void (*deactivate) (GtkMenuShell *menu_shell); +}; + + +guint gtk_menu_shell_get_type (void); +void gtk_menu_shell_append (GtkMenuShell *menu_shell, + GtkWidget *child); +void gtk_menu_shell_prepend (GtkMenuShell *menu_shell, + GtkWidget *child); +void gtk_menu_shell_insert (GtkMenuShell *menu_shell, + GtkWidget *child, + gint position); +void gtk_menu_shell_deactivate (GtkMenuShell *menu_shell); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_MENU_SHELL_H__ */ diff --git a/gtk/gtkmisc.c b/gtk/gtkmisc.c new file mode 100644 index 000000000..0ef8f0731 --- /dev/null +++ b/gtk/gtkmisc.c @@ -0,0 +1,181 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkcontainer.h" +#include "gtkmisc.h" + + +static void gtk_misc_class_init (GtkMiscClass *klass); +static void gtk_misc_init (GtkMisc *misc); +static void gtk_misc_realize (GtkWidget *widget); + + +guint +gtk_misc_get_type () +{ + static guint misc_type = 0; + + if (!misc_type) + { + GtkTypeInfo misc_info = + { + "GtkMisc", + sizeof (GtkMisc), + sizeof (GtkMiscClass), + (GtkClassInitFunc) gtk_misc_class_init, + (GtkObjectInitFunc) gtk_misc_init, + (GtkArgFunc) NULL, + }; + + misc_type = gtk_type_unique (gtk_widget_get_type (), &misc_info); + } + + return misc_type; +} + +static void +gtk_misc_class_init (GtkMiscClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_misc_realize; +} + +static void +gtk_misc_init (GtkMisc *misc) +{ + GTK_WIDGET_SET_FLAGS (misc, GTK_BASIC); + + misc->xalign = 0.5; + misc->yalign = 0.5; + misc->xpad = 0; + misc->ypad = 0; +} + +void +gtk_misc_set_alignment (GtkMisc *misc, + gfloat xalign, + gfloat yalign) +{ + g_return_if_fail (misc != NULL); + g_return_if_fail (GTK_IS_MISC (misc)); + + if (xalign < 0.0) + xalign = 0.0; + else if (xalign > 1.0) + xalign = 1.0; + + if (yalign < 0.0) + yalign = 0.0; + else if (yalign > 1.0) + yalign = 1.0; + + if ((xalign != misc->xalign) || (yalign != misc->yalign)) + { + misc->xalign = xalign; + misc->yalign = yalign; + + /* clear the area that was allocated before the change + */ + if (GTK_WIDGET_VISIBLE (misc)) + { + GtkWidget *widget; + + widget = GTK_WIDGET (misc); + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + } + + gtk_widget_queue_draw (GTK_WIDGET (misc)); + } +} + +void +gtk_misc_set_padding (GtkMisc *misc, + gint xpad, + gint ypad) +{ + GtkRequisition *requisition; + + g_return_if_fail (misc != NULL); + g_return_if_fail (GTK_IS_MISC (misc)); + + if (xpad < 0) + xpad = 0; + if (ypad < 0) + ypad = 0; + + if ((xpad != misc->xpad) || (ypad != misc->ypad)) + { + requisition = &(GTK_WIDGET (misc)->requisition); + requisition->width -= misc->xpad * 2; + requisition->height -= misc->ypad * 2; + + misc->xpad = xpad; + misc->ypad = ypad; + + requisition->width += misc->xpad * 2; + requisition->height += misc->ypad * 2; + + if (GTK_WIDGET (misc)->parent && GTK_WIDGET_VISIBLE (misc)) + gtk_widget_queue_resize (GTK_WIDGET (misc)); + } +} + +static void +gtk_misc_realize (GtkWidget *widget) +{ + GtkMisc *misc; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_MISC (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + misc = GTK_MISC (widget); + + if (GTK_WIDGET_NO_WINDOW (widget)) + { + widget->window = widget->parent->window; + widget->style = gtk_style_attach (widget->style, widget->window); + } + else + { + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gdk_window_set_back_pixmap (widget->window, NULL, TRUE); + } +} diff --git a/gtk/gtkmisc.h b/gtk/gtkmisc.h new file mode 100644 index 000000000..1bc9cbb93 --- /dev/null +++ b/gtk/gtkmisc.h @@ -0,0 +1,70 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_MISC_H__ +#define __GTK_MISC_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_MISC(obj) GTK_CHECK_CAST (obj, gtk_misc_get_type (), GtkMisc) +#define GTK_MISC_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_misc_get_type (), GtkMiscClass) +#define GTK_IS_MISC(obj) GTK_CHECK_TYPE (obj, gtk_misc_get_type ()) + + +typedef struct _GtkMisc GtkMisc; +typedef struct _GtkMiscClass GtkMiscClass; + +struct _GtkMisc +{ + GtkWidget widget; + + gfloat xalign; + gfloat yalign; + + guint16 xpad; + guint16 ypad; +}; + +struct _GtkMiscClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_misc_get_type (void); +void gtk_misc_set_alignment (GtkMisc *misc, + gfloat xalign, + gfloat yalign); +void gtk_misc_set_padding (GtkMisc *misc, + gint xpad, + gint ypad); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_LABEL_H__ */ diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c new file mode 100644 index 000000000..0b3115034 --- /dev/null +++ b/gtk/gtknotebook.c @@ -0,0 +1,1303 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtknotebook.h" + + +#define CHILD_SPACING 2 +#define TAB_OVERLAP 2 +#define TAB_CURVATURE 1 + + +static void gtk_notebook_class_init (GtkNotebookClass *klass); +static void gtk_notebook_init (GtkNotebook *notebook); +static void gtk_notebook_destroy (GtkObject *object); +static void gtk_notebook_map (GtkWidget *widget); +static void gtk_notebook_unmap (GtkWidget *widget); +static void gtk_notebook_realize (GtkWidget *widget); +static void gtk_notebook_unrealize (GtkWidget *widget); +static void gtk_notebook_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_notebook_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_notebook_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_notebook_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_notebook_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_notebook_button_press (GtkWidget *widget, + GdkEventButton *event); +static void gtk_notebook_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_notebook_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_notebook_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +static void gtk_notebook_switch_page (GtkNotebook *notebook, + GtkNotebookPage *page); +static void gtk_notebook_draw_tab (GtkNotebook *notebook, + GtkNotebookPage *page, + GdkRectangle *area); +static void gtk_notebook_pages_allocate (GtkNotebook *notebook, + GtkAllocation *allocation); +static void gtk_notebook_page_allocate (GtkNotebook *notebook, + GtkNotebookPage *page, + GtkAllocation *allocation); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_notebook_get_type () +{ + static guint notebook_type = 0; + + if (!notebook_type) + { + GtkTypeInfo notebook_info = + { + "GtkNotebook", + sizeof (GtkNotebook), + sizeof (GtkNotebookClass), + (GtkClassInitFunc) gtk_notebook_class_init, + (GtkObjectInitFunc) gtk_notebook_init, + (GtkArgFunc) NULL, + }; + + notebook_type = gtk_type_unique (gtk_container_get_type (), ¬ebook_info); + } + + return notebook_type; +} + +static void +gtk_notebook_class_init (GtkNotebookClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_notebook_destroy; + + widget_class->map = gtk_notebook_map; + widget_class->unmap = gtk_notebook_unmap; + widget_class->realize = gtk_notebook_realize; + widget_class->unrealize = gtk_notebook_unrealize; + widget_class->size_request = gtk_notebook_size_request; + widget_class->size_allocate = gtk_notebook_size_allocate; + widget_class->draw = gtk_notebook_draw; + widget_class->expose_event = gtk_notebook_expose; + widget_class->button_press_event = gtk_notebook_button_press; + + container_class->add = gtk_notebook_add; + container_class->remove = gtk_notebook_remove; + container_class->foreach = gtk_notebook_foreach; +} + +static void +gtk_notebook_init (GtkNotebook *notebook) +{ + notebook->cur_page = NULL; + notebook->children = NULL; + notebook->show_tabs = TRUE; + notebook->show_border = TRUE; + notebook->tab_pos = GTK_POS_TOP; +} + +GtkWidget* +gtk_notebook_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_notebook_get_type ())); +} + +void +gtk_notebook_append_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (child != NULL); + g_return_if_fail (tab_label != NULL); + + gtk_notebook_insert_page (notebook, child, tab_label, -1); +} + +void +gtk_notebook_prepend_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (child != NULL); + g_return_if_fail (tab_label != NULL); + + gtk_notebook_insert_page (notebook, child, tab_label, 0); +} + +void +gtk_notebook_insert_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label, + gint position) +{ + GtkNotebookPage *page; + gint nchildren; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (child != NULL); + g_return_if_fail (tab_label != NULL); + + page = g_new (GtkNotebookPage, 1); + page->child = child; + page->tab_label = tab_label; + page->requisition.width = 0; + page->requisition.height = 0; + page->allocation.x = 0; + page->allocation.y = 0; + page->allocation.width = 0; + page->allocation.height = 0; + + nchildren = g_list_length (notebook->children); + if ((position < 0) || (position > nchildren)) + position = nchildren; + + notebook->children = g_list_insert (notebook->children, page, position); + + if (!notebook->cur_page) + notebook->cur_page = page; + + gtk_widget_show (tab_label); + gtk_widget_set_parent (child, GTK_WIDGET (notebook)); + gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook)); + + if (GTK_WIDGET_VISIBLE (notebook)) + { + if (GTK_WIDGET_REALIZED (notebook) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (notebook) && + !GTK_WIDGET_MAPPED (child) && notebook->cur_page == page) + gtk_widget_map (child); + + if (GTK_WIDGET_REALIZED (notebook) && + !GTK_WIDGET_REALIZED (tab_label)) + gtk_widget_realize (tab_label); + + if (GTK_WIDGET_MAPPED (notebook) && + !GTK_WIDGET_MAPPED (tab_label)) + gtk_widget_map (tab_label); + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (child); +} + +void +gtk_notebook_remove_page (GtkNotebook *notebook, + gint page_num) +{ + GtkNotebookPage *page; + GList *tmp_list; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + tmp_list = g_list_nth (notebook->children, page_num); + if (tmp_list) + { + page = tmp_list->data; + + if (notebook->cur_page == page) + gtk_notebook_prev_page (notebook); + if (notebook->cur_page == page) + notebook->cur_page = NULL; + + notebook->children = g_list_remove_link (notebook->children, tmp_list); + g_list_free (tmp_list); + g_free (page); + } +} + +gint +gtk_notebook_current_page (GtkNotebook *notebook) +{ + GList *children; + gint cur_page; + + g_return_val_if_fail (notebook != NULL, -1); + g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1); + + if (notebook->cur_page) + { + cur_page = 0; + children = notebook->children; + + while (children) + { + if (children->data == notebook->cur_page) + break; + children = children->next; + cur_page += 1; + } + + if (!children) + cur_page = -1; + } + else + { + cur_page = -1; + } + + return cur_page; +} + +void +gtk_notebook_set_page (GtkNotebook *notebook, + gint page_num) +{ + GtkNotebookPage *page; + GList *tmp_list; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + tmp_list = g_list_nth (notebook->children, page_num); + if (tmp_list) + { + page = tmp_list->data; + gtk_notebook_switch_page (notebook, page); + } +} + +void +gtk_notebook_next_page (GtkNotebook *notebook) +{ + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + children = notebook->children; + while (children) + { + page = children->data; + + if (notebook->cur_page == page) + { + children = children->next; + if (!children) + children = notebook->children; + page = children->data; + + gtk_notebook_switch_page (notebook, page); + } + + children = children->next; + } +} + +void +gtk_notebook_prev_page (GtkNotebook *notebook) +{ + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + children = notebook->children; + while (children) + { + page = children->data; + + if (notebook->cur_page == page) + { + children = children->prev; + if (!children) + children = g_list_last (notebook->children); + page = children->data; + + gtk_notebook_switch_page (notebook, page); + } + + children = children->next; + } +} + +void +gtk_notebook_set_tab_pos (GtkNotebook *notebook, + GtkPositionType pos) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + if (notebook->tab_pos != pos) + { + notebook->tab_pos = pos; + + if (GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (GTK_WIDGET (notebook)); + } +} + +void +gtk_notebook_set_show_tabs (GtkNotebook *notebook, + gint show_tabs) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + if (notebook->show_tabs != show_tabs) + { + notebook->show_tabs = show_tabs; + + if (GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (GTK_WIDGET (notebook)); + } +} + +void +gtk_notebook_set_show_border (GtkNotebook *notebook, + gint show_border) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + if (notebook->show_border != show_border) + { + notebook->show_border = show_border; + + if (GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (GTK_WIDGET (notebook)); + } +} + +static void +gtk_notebook_destroy (GtkObject *object) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (object)); + + notebook = GTK_NOTEBOOK (object); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + page->child->parent = NULL; + page->tab_label->parent = NULL; + + gtk_object_unref (GTK_OBJECT (page->child)); + gtk_object_unref (GTK_OBJECT (page->tab_label)); + + gtk_widget_destroy (page->child); + gtk_widget_destroy (page->tab_label); + + g_free (page); + } + + g_list_free (notebook->children); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_notebook_map (GtkWidget *widget) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + gdk_window_show (widget->window); + + notebook = GTK_NOTEBOOK (widget); + + if (notebook->cur_page && + GTK_WIDGET_VISIBLE (notebook->cur_page->child) && + !GTK_WIDGET_MAPPED (notebook->cur_page->child)) + gtk_widget_map (notebook->cur_page->child); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child) && + !GTK_WIDGET_MAPPED (page->tab_label)) + gtk_widget_map (page->tab_label); + } +} + +static void +gtk_notebook_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_notebook_realize (GtkWidget *widget) +{ + GtkNotebook *notebook; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + notebook = GTK_NOTEBOOK (widget); + GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, notebook); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_notebook_unrealize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + gdk_window_destroy (widget->window); + widget->window = NULL; +} + +static void +gtk_notebook_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + gint tab_width; + gint tab_height; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (requisition != NULL); + + notebook = GTK_NOTEBOOK (widget); + widget->requisition.width = 0; + widget->requisition.height = 0; + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + gtk_widget_size_request (page->child, &page->child->requisition); + + widget->requisition.width = MAX (widget->requisition.width, + page->child->requisition.width); + widget->requisition.height = MAX (widget->requisition.height, + page->child->requisition.height); + } + } + + widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2; + widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2; + + if (notebook->show_tabs) + { + widget->requisition.width += GTK_WIDGET (widget)->style->klass->xthickness * 2; + widget->requisition.height += GTK_WIDGET (widget)->style->klass->ythickness * 2; + + tab_width = 0; + tab_height = 0; + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + gtk_widget_size_request (page->tab_label, &page->tab_label->requisition); + + page->requisition.width = (page->tab_label->requisition.width + + (GTK_WIDGET (widget)->style->klass->xthickness + + CHILD_SPACING) * 2); + page->requisition.height = (page->tab_label->requisition.height + + (GTK_WIDGET (widget)->style->klass->ythickness + + CHILD_SPACING) * 2); + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + page->requisition.width -= TAB_OVERLAP; + page->requisition.height -= GTK_WIDGET (widget)->style->klass->ythickness; + + tab_width += page->requisition.width; + tab_height = MAX (tab_height, page->requisition.height); + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + page->requisition.width -= GTK_WIDGET (widget)->style->klass->xthickness; + page->requisition.height -= TAB_OVERLAP; + + tab_width = MAX (tab_width, page->requisition.width); + tab_height += page->requisition.height; + break; + } + } + } + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + if ((notebook->tab_pos == GTK_POS_TOP) || + (notebook->tab_pos == GTK_POS_BOTTOM)) + page->requisition.height = tab_height; + else + page->requisition.width = tab_width; + } + } + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + tab_width += GTK_WIDGET (widget)->style->klass->xthickness; + widget->requisition.width = MAX (widget->requisition.width, tab_width); + widget->requisition.height += tab_height; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + tab_height += GTK_WIDGET (widget)->style->klass->ythickness; + widget->requisition.width += tab_width; + widget->requisition.height = MAX (widget->requisition.height, tab_height); + break; + } + } + else if (notebook->show_border) + { + widget->requisition.width += GTK_WIDGET (widget)->style->klass->xthickness * 2; + widget->requisition.height += GTK_WIDGET (widget)->style->klass->ythickness * 2; + } +} + +static void +gtk_notebook_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GtkAllocation child_allocation; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + notebook = GTK_NOTEBOOK (widget); + if (notebook->children) + { + child_allocation.x = GTK_CONTAINER (widget)->border_width; + child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + child_allocation.height = allocation->height - child_allocation.y * 2; + + if (notebook->show_tabs || notebook->show_border) + { + child_allocation.x += GTK_WIDGET (widget)->style->klass->xthickness; + child_allocation.y += GTK_WIDGET (widget)->style->klass->ythickness; + child_allocation.width -= GTK_WIDGET (widget)->style->klass->xthickness * 2; + child_allocation.height -= GTK_WIDGET (widget)->style->klass->ythickness * 2; + + if (notebook->show_tabs && notebook->children) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + child_allocation.y += notebook->cur_page->requisition.height; + case GTK_POS_BOTTOM: + child_allocation.height -= notebook->cur_page->requisition.height; + break; + case GTK_POS_LEFT: + child_allocation.x += notebook->cur_page->requisition.width; + case GTK_POS_RIGHT: + child_allocation.width -= notebook->cur_page->requisition.width; + break; + } + } + } + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + gtk_widget_size_allocate (page->child, &child_allocation); + } + + if (notebook->show_tabs && notebook->children) + gtk_notebook_pages_allocate (notebook, allocation); + } +} + +static void +gtk_notebook_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + GdkPoint points[6]; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + notebook = GTK_NOTEBOOK (widget); + + gdk_window_clear_area (widget->window, + area->x, area->y, + area->width, area->height); + + if (notebook->show_tabs || notebook->show_border) + { + x = GTK_CONTAINER (widget)->border_width; + y = GTK_CONTAINER (widget)->border_width; + width = widget->allocation.width - x * 2; + height = widget->allocation.height - y * 2; + + if (notebook->show_tabs && notebook->children) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + y += notebook->cur_page->allocation.height; + case GTK_POS_BOTTOM: + height -= notebook->cur_page->allocation.height; + break; + case GTK_POS_LEFT: + x += notebook->cur_page->allocation.width; + case GTK_POS_RIGHT: + width -= notebook->cur_page->allocation.width; + break; + } + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + points[0].x = notebook->cur_page->allocation.x; + points[0].y = y; + points[1].x = x; + points[1].y = y; + points[2].x = x; + points[2].y = y + height - 1; + points[3].x = x + width - 1; + points[3].y = y + height - 1; + points[4].x = x + width - 1; + points[4].y = y; + points[5].x = (notebook->cur_page->allocation.x + + notebook->cur_page->allocation.width - + GTK_WIDGET (notebook)->style->klass->xthickness); + points[5].y = y; + + if (points[5].x == (x + width)) + points[5].x -= 1; + break; + case GTK_POS_BOTTOM: + points[0].x = (notebook->cur_page->allocation.x + + notebook->cur_page->allocation.width - + GTK_WIDGET (notebook)->style->klass->xthickness); + points[0].y = y + height - 1; + points[1].x = x + width - 1; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y; + points[3].x = x; + points[3].y = y; + points[4].x = x; + points[4].y = y + height - 1; + points[5].x = notebook->cur_page->allocation.x; + points[5].y = y + height - 1; + + if (points[0].x == (x + width)) + points[0].x -= 1; + break; + case GTK_POS_LEFT: + points[0].x = x; + points[0].y = (notebook->cur_page->allocation.y + + notebook->cur_page->allocation.height - + GTK_WIDGET (notebook)->style->klass->ythickness); + points[1].x = x; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y + height - 1; + points[3].x = x + width - 1; + points[3].y = y; + points[4].x = x; + points[4].y = y; + points[5].x = x; + points[5].y = notebook->cur_page->allocation.y; + + if (points[0].y == (y + height)) + points[0].y -= 1; + break; + case GTK_POS_RIGHT: + points[0].x = x + width - 1; + points[0].y = notebook->cur_page->allocation.y; + points[1].x = x + width - 1; + points[1].y = y; + points[2].x = x; + points[2].y = y; + points[3].x = x; + points[3].y = y + height - 1; + points[4].x = x + width - 1; + points[4].y = y + height - 1; + points[5].x = x + width - 1; + points[5].y = (notebook->cur_page->allocation.y + + notebook->cur_page->allocation.height - + GTK_WIDGET (notebook)->style->klass->ythickness); + + if (points[5].y == (y + height)) + points[5].y -= 1; + break; + } + + gtk_draw_polygon (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + points, 6, FALSE); + + children = g_list_last (notebook->children); + while (children) + { + page = children->data; + children = children->prev; + + if (notebook->cur_page != page) + gtk_notebook_draw_tab (notebook, page, area); + } + + if (notebook->cur_page) + gtk_notebook_draw_tab (notebook, notebook->cur_page, area); + } + else if (notebook->show_border) + { + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + x, y, width, height); + } + } + } +} + +static void +gtk_notebook_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkNotebook *notebook; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + notebook = GTK_NOTEBOOK (widget); + + gtk_notebook_paint (widget, area); + + if (notebook->cur_page && + gtk_widget_intersect (notebook->cur_page->child, area, &child_area)) + gtk_widget_draw (notebook->cur_page->child, &child_area); + } +} + +static gint +gtk_notebook_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkNotebook *notebook; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + notebook = GTK_NOTEBOOK (widget); + + gtk_notebook_paint (widget, &event->area); + + child_event = *event; + if (notebook->cur_page && GTK_WIDGET_NO_WINDOW (notebook->cur_page->child) && + gtk_widget_intersect (notebook->cur_page->child, &event->area, &child_event.area)) + gtk_widget_event (notebook->cur_page->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static gint +gtk_notebook_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if ((event->type != GDK_BUTTON_PRESS) || + (event->window != widget->window)) + return FALSE; + + notebook = GTK_NOTEBOOK (widget); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child) && + (event->x >= page->allocation.x) && + (event->y >= page->allocation.y) && + (event->x <= (page->allocation.x + page->allocation.width)) && + (event->y <= (page->allocation.y + page->allocation.height))) + { + gtk_notebook_switch_page (notebook, page); + break; + } + } + + return FALSE; +} + +static void +gtk_notebook_add (GtkContainer *container, + GtkWidget *widget) +{ + g_warning ("gtk_notebook_add: use gtk_notebook_{append,prepend}_page instead\n"); +} + +static void +gtk_notebook_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (container)); + g_return_if_fail (widget != NULL); + + notebook = GTK_NOTEBOOK (container); + + children = notebook->children; + while (children) + { + page = children->data; + + if (page->child == widget) + { + gtk_widget_unparent (page->child); + gtk_widget_unparent (page->tab_label); + + notebook->children = g_list_remove_link (notebook->children, children); + g_list_free (children); + g_free (page); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + + break; + } + + children = children->next; + } +} + +static void +gtk_notebook_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (container)); + g_return_if_fail (callback != NULL); + + notebook = GTK_NOTEBOOK (container); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + (* callback) (page->child, callback_data); + } +} + +static void +gtk_notebook_switch_page (GtkNotebook *notebook, + GtkNotebookPage *page) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (page != NULL); + + if (notebook->cur_page != page) + { + if (notebook->cur_page && GTK_WIDGET_MAPPED (notebook->cur_page->child)) + gtk_widget_unmap (notebook->cur_page->child); + + notebook->cur_page = page; + gtk_notebook_pages_allocate (notebook, >K_WIDGET (notebook)->allocation); + + if (GTK_WIDGET_MAPPED (notebook)) + gtk_widget_map (notebook->cur_page->child); + + if (GTK_WIDGET_DRAWABLE (notebook)) + gtk_widget_queue_draw (GTK_WIDGET (notebook)); + } +} + +static void +gtk_notebook_draw_tab (GtkNotebook *notebook, + GtkNotebookPage *page, + GdkRectangle *area) +{ + GdkRectangle child_area; + GdkRectangle page_area; + GtkStateType state_type; + GdkPoint points[6]; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (page != NULL); + g_return_if_fail (area != NULL); + + page_area.x = page->allocation.x; + page_area.y = page->allocation.y; + page_area.width = page->allocation.width; + page_area.height = page->allocation.height; + + if (gdk_rectangle_intersect (&page_area, area, &child_area)) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + points[0].x = page->allocation.x + page->allocation.width - 1; + points[0].y = page->allocation.y + page->allocation.height - 1; + + points[1].x = page->allocation.x + page->allocation.width - 1; + points[1].y = page->allocation.y + TAB_CURVATURE; + + points[2].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[2].y = page->allocation.y; + + points[3].x = page->allocation.x + TAB_CURVATURE; + points[3].y = page->allocation.y; + + points[4].x = page->allocation.x; + points[4].y = page->allocation.y + TAB_CURVATURE; + + points[5].x = page->allocation.x; + points[5].y = page->allocation.y + page->allocation.height - 1; + break; + case GTK_POS_BOTTOM: + points[0].x = page->allocation.x; + points[0].y = page->allocation.y; + + points[1].x = page->allocation.x; + points[1].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[2].x = page->allocation.x + TAB_CURVATURE; + points[2].y = page->allocation.y + page->allocation.height - 1; + + points[3].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[3].y = page->allocation.y + page->allocation.height - 1; + + points[4].x = page->allocation.x + page->allocation.width - 1; + points[4].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[5].x = page->allocation.x + page->allocation.width - 1; + points[5].y = page->allocation.y; + break; + case GTK_POS_LEFT: + points[0].x = page->allocation.x + page->allocation.width - 1; + points[0].y = page->allocation.y; + + points[1].x = page->allocation.x + TAB_CURVATURE; + points[1].y = page->allocation.y; + + points[2].x = page->allocation.x; + points[2].y = page->allocation.y + TAB_CURVATURE; + + points[3].x = page->allocation.x; + points[3].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[4].x = page->allocation.x + TAB_CURVATURE; + points[4].y = page->allocation.y + page->allocation.height - 1; + + points[5].x = page->allocation.x + page->allocation.width - 1; + points[5].y = page->allocation.y + page->allocation.height - 1; + break; + case GTK_POS_RIGHT: + points[0].x = page->allocation.x; + points[0].y = page->allocation.y + page->allocation.height - 1; + + points[1].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[1].y = page->allocation.y + page->allocation.height - 1; + + points[2].x = page->allocation.x + page->allocation.width - 1; + points[2].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[3].x = page->allocation.x + page->allocation.width - 1; + points[3].y = page->allocation.y + TAB_CURVATURE; + + points[4].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[4].y = page->allocation.y; + + points[5].x = page->allocation.x; + points[5].y = page->allocation.y; + break; + } + + if (notebook->cur_page == page) + state_type = GTK_STATE_NORMAL; + else + state_type = GTK_STATE_ACTIVE; + + gtk_draw_polygon (GTK_WIDGET (notebook)->style, + GTK_WIDGET (notebook)->window, + state_type, GTK_SHADOW_OUT, + points, 6, (notebook->cur_page != page)); + + if (gtk_widget_intersect (page->tab_label, area, &child_area)) + gtk_widget_draw (page->tab_label, &child_area); + } +} + +static void +gtk_notebook_pages_allocate (GtkNotebook *notebook, + GtkAllocation *allocation) +{ + GtkNotebookPage *page; + GtkAllocation child_allocation; + GList *children; + + if (notebook->show_tabs && notebook->children) + { + child_allocation.x = GTK_CONTAINER (notebook)->border_width; + child_allocation.y = GTK_CONTAINER (notebook)->border_width; + + switch (notebook->tab_pos) + { + case GTK_POS_BOTTOM: + child_allocation.y = allocation->height - notebook->cur_page->requisition.height; + case GTK_POS_TOP: + child_allocation.height = notebook->cur_page->requisition.height; + break; + case GTK_POS_RIGHT: + child_allocation.x = allocation->width - notebook->cur_page->requisition.width; + case GTK_POS_LEFT: + child_allocation.width = notebook->cur_page->requisition.width; + break; + } + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + child_allocation.width = page->requisition.width + TAB_OVERLAP; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + child_allocation.height = page->requisition.height + TAB_OVERLAP; + break; + } + + gtk_notebook_page_allocate (notebook, page, &child_allocation); + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + child_allocation.x += child_allocation.width - TAB_OVERLAP; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + child_allocation.y += child_allocation.height - TAB_OVERLAP; + break; + } + } + } + } +} + +static void +gtk_notebook_page_allocate (GtkNotebook *notebook, + GtkNotebookPage *page, + GtkAllocation *allocation) +{ + GtkAllocation child_allocation; + gint xthickness, ythickness; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (page != NULL); + g_return_if_fail (allocation != NULL); + + page->allocation = *allocation; + + xthickness = GTK_WIDGET (notebook)->style->klass->xthickness; + ythickness = GTK_WIDGET (notebook)->style->klass->ythickness; + + if (notebook->cur_page != page) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + page->allocation.y += ythickness; + case GTK_POS_BOTTOM: + page->allocation.height -= ythickness; + break; + case GTK_POS_LEFT: + page->allocation.x += xthickness; + case GTK_POS_RIGHT: + page->allocation.width -= xthickness; + break; + } + } + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x * 2; + child_allocation.height = page->allocation.height - child_allocation.y; + child_allocation.x += page->allocation.x; + child_allocation.y += page->allocation.y; + break; + case GTK_POS_BOTTOM: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x * 2; + child_allocation.height = page->allocation.height - child_allocation.y; + child_allocation.x += page->allocation.x; + child_allocation.y = page->allocation.y; + break; + case GTK_POS_LEFT: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x; + child_allocation.height = page->allocation.height - child_allocation.y * 2; + child_allocation.x += page->allocation.x; + child_allocation.y += page->allocation.y; + break; + case GTK_POS_RIGHT: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x; + child_allocation.height = page->allocation.height - child_allocation.y * 2; + child_allocation.x = page->allocation.x; + child_allocation.y += page->allocation.y; + break; + } + + gtk_widget_size_allocate (page->tab_label, &child_allocation); +} diff --git a/gtk/gtknotebook.h b/gtk/gtknotebook.h new file mode 100644 index 000000000..402823b2e --- /dev/null +++ b/gtk/gtknotebook.h @@ -0,0 +1,98 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_NOTEBOOK_H__ +#define __GTK_NOTEBOOK_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_NOTEBOOK(obj) GTK_CHECK_CAST (obj, gtk_notebook_get_type (), GtkNotebook) +#define GTK_NOTEBOOK_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_notebook_get_type (), GtkNotebookClass) +#define GTK_IS_NOTEBOOK(obj) GTK_CHECK_TYPE (obj, gtk_notebook_get_type ()) + + +typedef struct _GtkNotebook GtkNotebook; +typedef struct _GtkNotebookClass GtkNotebookClass; +typedef struct _GtkNotebookPage GtkNotebookPage; + +struct _GtkNotebook +{ + GtkContainer container; + + GtkNotebookPage *cur_page; + GList *children; + + guint show_tabs : 1; + guint show_border : 1; + guint tab_pos : 2; +}; + +struct _GtkNotebookClass +{ + GtkContainerClass parent_class; +}; + +struct _GtkNotebookPage +{ + GtkWidget *child; + GtkWidget *tab_label; + GtkRequisition requisition; + GtkAllocation allocation; +}; + + +guint gtk_notebook_get_type (void); +GtkWidget* gtk_notebook_new (void); +void gtk_notebook_append_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label); +void gtk_notebook_prepend_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label); +void gtk_notebook_insert_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label, + gint position); +void gtk_notebook_remove_page (GtkNotebook *notebook, + gint page_num); +gint gtk_notebook_current_page (GtkNotebook *notebook); +void gtk_notebook_set_page (GtkNotebook *notebook, + gint page_num); +void gtk_notebook_next_page (GtkNotebook *notebook); +void gtk_notebook_prev_page (GtkNotebook *notebook); +void gtk_notebook_set_tab_pos (GtkNotebook *notebook, + GtkPositionType pos); +void gtk_notebook_set_show_tabs (GtkNotebook *notebook, + gint show_tabs); +void gtk_notebook_set_show_border (GtkNotebook *notebook, + gint show_border); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_NOTEBOOK_H__ */ diff --git a/gtk/gtkobject.c b/gtk/gtkobject.c new file mode 100644 index 000000000..ffe487e89 --- /dev/null +++ b/gtk/gtkobject.c @@ -0,0 +1,994 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gtkobject.h" +#include "gtksignal.h" + + +#define OBJECT_DATA_ID_CHUNK 1024 + + +enum { + DESTROY, + LAST_SIGNAL +}; + + +typedef struct _GtkObjectData GtkObjectData; +typedef struct _GtkArgInfo GtkArgInfo; + +struct _GtkObjectData +{ + guint id; + gpointer data; + GtkObjectData *next; +}; + +struct _GtkArgInfo +{ + char *name; + GtkType type; +}; + + +static void gtk_object_class_init (GtkObjectClass *klass); +static void gtk_object_init (GtkObject *object); +static void gtk_object_arg (GtkObject *object, + GtkArg *arg); +static void gtk_real_object_destroy (GtkObject *object); +static void gtk_object_data_init (void); +static GtkObjectData* gtk_object_data_new (void); +static void gtk_object_data_destroy (GtkObjectData *odata); +static guint* gtk_object_data_id_alloc (void); +GtkArg* gtk_object_collect_args (gint *nargs, + va_list args1, + va_list args2); + + +static gint object_signals[LAST_SIGNAL] = { 0 }; + +static gint object_data_init = TRUE; +static GHashTable *object_data_ht = NULL; +static GMemChunk *object_data_mem_chunk = NULL; +static GtkObjectData *object_data_free_list = NULL; +static GSList *object_data_id_list = NULL; +static gint object_data_id_index = 0; + +static GHashTable *arg_info_ht = NULL; + +static const char *user_data_key = "user_data"; + + +/***************************************** + * gtk_object_get_type: + * + * arguments: + * + * results: + * The type identifier for GtkObject's + *****************************************/ + +void +gtk_object_init_type () +{ + GtkType object_type = 0; + GtkTypeInfo object_info = + { + "GtkObject", + sizeof (GtkObject), + sizeof (GtkObjectClass), + (GtkClassInitFunc) gtk_object_class_init, + (GtkObjectInitFunc) gtk_object_init, + (GtkArgFunc) gtk_object_arg, + }; + + object_type = gtk_type_unique (0, &object_info); + g_assert (object_type == GTK_TYPE_OBJECT); +} + +GtkType +gtk_object_get_type () +{ + return GTK_TYPE_OBJECT; +} + +/***************************************** + * gtk_object_class_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_class_init (GtkObjectClass *class) +{ + class->signals = NULL; + class->nsignals = 0; + + gtk_object_add_arg_type ("GtkObject::user_data", GTK_TYPE_POINTER); + gtk_object_add_arg_type ("GtkObject::signal", GTK_TYPE_SIGNAL); + + object_signals[DESTROY] = + gtk_signal_new ("destroy", + GTK_RUN_LAST, + class->type, + GTK_SIGNAL_OFFSET (GtkObjectClass, destroy), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (class, object_signals, LAST_SIGNAL); + + class->destroy = gtk_real_object_destroy; +} + +/***************************************** + * gtk_object_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_init (GtkObject *object) +{ + object->flags = 0; + object->ref_count = 0; + object->object_data = NULL; +} + +/***************************************** + * gtk_object_arg: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_arg (GtkObject *object, + GtkArg *arg) +{ + if (strcmp (arg->name, "user_data") == 0) + { + gtk_object_set_user_data (object, GTK_VALUE_POINTER (*arg)); + } + else if (strncmp (arg->name, "signal", 6) == 0) + { + if ((arg->name[6] != ':') || (arg->name[7] != ':')) + { + g_print ("invalid signal argument: \"%s\"\n", arg->name); + return; + } + + gtk_signal_connect (object, arg->name + 8, + (GtkSignalFunc) GTK_VALUE_SIGNAL (*arg).f, + GTK_VALUE_SIGNAL (*arg).d); + } +} + +/***************************************** + * gtk_object_class_add_signals: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_class_add_signals (GtkObjectClass *class, + gint *signals, + gint nsignals) +{ + gint *new_signals; + gint i; + + g_return_if_fail (class != NULL); + + new_signals = g_new (gint, class->nsignals + nsignals); + for (i = 0; i < class->nsignals; i++) + new_signals[i] = class->signals[i]; + for (i = 0; i < nsignals; i++) + new_signals[class->nsignals + i] = signals[i]; + + class->signals = new_signals; + class->nsignals += nsignals; +} + +/***************************************** + * gtk_object_ref: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_ref (GtkObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + object->ref_count += 1; +} + +/***************************************** + * gtk_object_new: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_unref (GtkObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + if (object->ref_count > 0) + object->ref_count -= 1; +} + +/***************************************** + * gtk_object_new: + * + * arguments: + * + * results: + *****************************************/ + +GtkObject* +gtk_object_new (guint type, + ...) +{ + GtkObject *obj; + GtkArg *args; + gint nargs; + va_list args1; + va_list args2; + + obj = gtk_type_new (type); + + va_start (args1, type); + va_start (args2, type); + + args = gtk_object_collect_args (&nargs, args1, args2); + gtk_object_setv (obj, nargs, args); + g_free (args); + + va_end (args1); + va_end (args2); + + return obj; +} + +/***************************************** + * gtk_object_newv: + * + * arguments: + * + * results: + *****************************************/ + +GtkObject* +gtk_object_newv (guint type, + gint nargs, + GtkArg *args) +{ + gpointer obj; + + obj = gtk_type_new (type); + gtk_object_setv (obj, nargs, args); + + return obj; +} + +/***************************************** + * gtk_object_set: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_set (GtkObject *obj, + ...) +{ + GtkArg *args; + gint nargs; + va_list args1; + va_list args2; + + g_return_if_fail (obj != NULL); + + va_start (args1, obj); + va_start (args2, obj); + + args = gtk_object_collect_args (&nargs, args1, args2); + gtk_object_setv (obj, nargs, args); + g_free (args); + + va_end (args1); + va_end (args2); +} + +/***************************************** + * gtk_object_setv: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_setv (GtkObject *obj, + gint nargs, + GtkArg *args) +{ + guint class_type; + char class_name[1024]; + char *arg_name; + int i; + + g_return_if_fail (obj != NULL); + + for (i = 0; i < nargs; i++) + { + arg_name = strchr (args[i].name, ':'); + if (!arg_name || (arg_name[0] != ':') || (arg_name[1] != ':')) + { + g_print ("invalid arg name: \"%s\"\n", args[i].name); + continue; + } + + strncpy (class_name, args[i].name, (long) (arg_name - args[i].name)); + class_name[(long) (arg_name - args[i].name)] = '\0'; + + args[i].name = arg_name + 2; + + class_type = gtk_type_from_name (class_name); + gtk_type_set_arg (obj, class_type, &args[i]); + } +} + +/***************************************** + * gtk_object_add_arg_type: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_add_arg_type (const char *arg_name, + GtkType arg_type) +{ + GtkArgInfo *info; + + info = g_new (GtkArgInfo, 1); + info->name = g_strdup(arg_name); + info->type = arg_type; + + if (!arg_info_ht) + arg_info_ht = g_hash_table_new (g_string_hash, g_string_equal); + + g_hash_table_insert (arg_info_ht, info->name, info); +} + +/***************************************** + * gtk_object_get_arg_type: + * + * arguments: + * + * results: + *****************************************/ + +GtkType +gtk_object_get_arg_type (const char *arg_name) +{ + GtkArgInfo *info; + char buffer[1024]; + char *t; + + if (!arg_info_ht) + return GTK_TYPE_INVALID; + + t = strchr (arg_name, ':'); + if (!t || (t[0] != ':') || (t[1] != ':')) + { + g_print ("invalid arg name: \"%s\"\n", arg_name); + return GTK_TYPE_INVALID; + } + + t = strchr (t + 2, ':'); + if (t) + { + strncpy (buffer, arg_name, (long) (t - arg_name)); + buffer[(long) (t - arg_name)] = '\0'; + arg_name = buffer; + } + + info = g_hash_table_lookup (arg_info_ht, (gpointer) arg_name); + if (info) + return info->type; + + return GTK_TYPE_INVALID; +} + +/***************************************** + * gtk_object_destroy: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_destroy (GtkObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + if ((object->ref_count > 0) || GTK_OBJECT_IN_CALL (object)) + { + GTK_OBJECT_SET_FLAGS (object, GTK_NEED_DESTROY); + } + else + { + GTK_OBJECT_UNSET_FLAGS (object, GTK_NEED_DESTROY); + GTK_OBJECT_SET_FLAGS (object, GTK_BEING_DESTROYED); + + gtk_signal_emit (object, object_signals[DESTROY]); + } +} + +/***************************************** + * gtk_object_set_data: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_set_data (GtkObject *object, + const gchar *key, + gpointer data) +{ + GtkObjectData *odata; + GtkObjectData *prev; + guint *id; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (key != NULL); + + if (object_data_init) + gtk_object_data_init (); + + id = g_hash_table_lookup (object_data_ht, (gpointer) key); + + if (!data) + { + if (id) + { + prev = NULL; + odata = object->object_data; + + while (odata) + { + if (odata->id == *id) + { + if (prev) + prev->next = odata->next; + if (odata == object->object_data) + object->object_data = odata->next; + + gtk_object_data_destroy (odata); + break; + } + + prev = odata; + odata = odata->next; + } + } + } + else + { + if (!id) + { + id = gtk_object_data_id_alloc (); + g_hash_table_insert (object_data_ht, (gpointer) key, id); + } + + odata = object->object_data; + while (odata) + { + if (odata->id == *id) + { + odata->data = data; + return; + } + + odata = odata->next; + } + + odata = gtk_object_data_new (); + odata->id = *id; + odata->data = data; + + odata->next = object->object_data; + object->object_data = odata; + } +} + +/***************************************** + * gtk_object_get_data: + * + * arguments: + * + * results: + *****************************************/ + +gpointer +gtk_object_get_data (GtkObject *object, + const gchar *key) +{ + GtkObjectData *odata; + guint *id; + + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (GTK_IS_OBJECT (object), NULL); + g_return_val_if_fail (key != NULL, NULL); + + if (object_data_init) + gtk_object_data_init (); + + id = g_hash_table_lookup (object_data_ht, (gpointer) key); + if (id) + { + odata = object->object_data; + while (odata) + { + if (odata->id == *id) + return odata->data; + odata = odata->next; + } + } + + return NULL; +} + +/***************************************** + * gtk_object_remove_data: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_remove_data (GtkObject *object, + const gchar *key) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + g_return_if_fail (key != NULL); + + gtk_object_set_data (object, key, NULL); +} + +/***************************************** + * gtk_object_set_user_data: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_object_set_user_data (GtkObject *object, + gpointer data) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + gtk_object_set_data (object, user_data_key, data); +} + +/***************************************** + * gtk_object_get_user_data: + * + * arguments: + * + * results: + *****************************************/ + +gpointer +gtk_object_get_user_data (GtkObject *object) +{ + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (GTK_IS_OBJECT (object), NULL); + + return gtk_object_get_data (object, user_data_key); +} + +/***************************************** + * gtk_object_check_cast: + * + * arguments: + * + * results: + *****************************************/ + +GtkObject* +gtk_object_check_cast (GtkObject *obj, + GtkType cast_type) +{ + if (obj && obj->klass && !gtk_type_is_a (obj->klass->type, cast_type)) + { + gchar *from_name = gtk_type_name (obj->klass->type); + gchar *to_name = gtk_type_name (cast_type); + + g_warning ("invalid cast from \"%s\" to \"%s\"", + from_name ? from_name : "(unknown)", + to_name ? to_name : "(unknown)"); + } + + return obj; +} + +/***************************************** + * gtk_object_check_class_cast: + * + * arguments: + * + * results: + *****************************************/ + +GtkObjectClass* +gtk_object_check_class_cast (GtkObjectClass *klass, + GtkType cast_type) +{ + if (klass && !gtk_type_is_a (klass->type, cast_type)) + g_warning ("invalid cast from \"%sClass\" to \"%sClass\"", + gtk_type_name (klass->type), + gtk_type_name (cast_type)); + + return klass; +} + +/***************************************** + * gtk_real_object_destroy: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_object_destroy (GtkObject *object) +{ + GtkObjectData *odata; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OBJECT (object)); + + gtk_signal_handlers_destroy (object); + + if (object->object_data) + { + odata = object->object_data; + while (odata->next) + odata = odata->next; + + odata->next = object_data_free_list; + object_data_free_list = object->object_data; + } + + g_free (object); +} + +/***************************************** + * gtk_object_data_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_data_init () +{ + if (object_data_init) + { + object_data_init = FALSE; + + object_data_ht = g_hash_table_new (g_string_hash, g_string_equal); + } +} + +/***************************************** + * gtk_object_data_new: + * + * arguments: + * + * results: + *****************************************/ + +static GtkObjectData* +gtk_object_data_new () +{ + GtkObjectData *odata; + + if (!object_data_mem_chunk) + object_data_mem_chunk = g_mem_chunk_new ("object data mem chunk", + sizeof (GtkObjectData), + 1024, G_ALLOC_AND_FREE); + + odata = g_chunk_new (GtkObjectData, object_data_mem_chunk); + + odata->id = 0; + odata->data = NULL; + odata->next = NULL; + + return odata; +} + +/***************************************** + * gtk_object_data_destroy: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_object_data_destroy (GtkObjectData *odata) +{ + g_return_if_fail (odata != NULL); + + g_mem_chunk_free (object_data_mem_chunk, odata); +} + +/***************************************** + * gtk_object_data_id_alloc: + * + * arguments: + * + * results: + *****************************************/ + +static guint* +gtk_object_data_id_alloc () +{ + static guint next_id = 1; + guint *ids; + + if (!object_data_id_list || + (object_data_id_index == OBJECT_DATA_ID_CHUNK)) + { + ids = g_new (guint, OBJECT_DATA_ID_CHUNK); + object_data_id_index = 0; + object_data_id_list = g_slist_prepend (object_data_id_list, ids); + } + else + { + ids = object_data_id_list->data; + } + + ids[object_data_id_index] = next_id++; + return &ids[object_data_id_index++]; +} + +/***************************************** + * gtk_object_data_id_alloc: + * + * arguments: + * + * results: + *****************************************/ + +GtkArg* +gtk_object_collect_args (gint *nargs, + va_list args1, + va_list args2) +{ + GtkArg *args; + GtkType type; + char *name; + int done; + int i, n; + + n = 0; + done = FALSE; + + while (!done) + { + name = va_arg (args1, char *); + if (!name) + { + done = TRUE; + continue; + } + + type = gtk_object_get_arg_type (name); + + switch (GTK_FUNDAMENTAL_TYPE (type)) + { + case GTK_TYPE_INVALID: + g_print ("invalid arg name: \"%s\" %x\n", name, type); + (void) va_arg (args1, long); + continue; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + case GTK_TYPE_BOOL: + case GTK_TYPE_INT: + case GTK_TYPE_UINT: + case GTK_TYPE_ENUM: + case GTK_TYPE_FLAGS: + (void) va_arg (args1, gint); + break; + case GTK_TYPE_LONG: + case GTK_TYPE_ULONG: + (void) va_arg (args1, glong); + break; + case GTK_TYPE_FLOAT: + (void) va_arg (args1, gfloat); + break; + case GTK_TYPE_STRING: + (void) va_arg (args1, gchar*); + break; + case GTK_TYPE_POINTER: + case GTK_TYPE_BOXED: + (void) va_arg (args1, gpointer); + break; + case GTK_TYPE_SIGNAL: + (void) va_arg (args1, GtkFunction); + (void) va_arg (args1, gpointer); + break; + case GTK_TYPE_FOREIGN: + (void) va_arg (args1, gpointer); + (void) va_arg (args1, GtkDestroyNotify); + break; + case GTK_TYPE_CALLBACK: + (void) va_arg (args1, GtkCallbackMarshal); + (void) va_arg (args1, gpointer); + (void) va_arg (args1, GtkDestroyNotify); + break; + case GTK_TYPE_C_CALLBACK: + (void) va_arg (args1, GtkFunction); + (void) va_arg (args1, gpointer); + break; + case GTK_TYPE_ARGS: + (void) va_arg (args1, gint); + (void) va_arg (args1, GtkArg*); + break; + case GTK_TYPE_OBJECT: + (void) va_arg (args1, GtkObject*); + break; + default: + g_error ("unsupported type %s in args", gtk_type_name (type)); + break; + } + + n += 1; + } + + *nargs = n; + args = NULL; + + if (n > 0) + { + args = g_new0 (GtkArg, n); + + for (i = 0; i < n; i++) + { + args[i].name = va_arg (args2, char *); + args[i].type = gtk_object_get_arg_type (args[i].name); + + switch (GTK_FUNDAMENTAL_TYPE (args[i].type)) + { + case GTK_TYPE_INVALID: + (void) va_arg (args2, long); + i -= 1; + continue; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + GTK_VALUE_CHAR(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_BOOL: + GTK_VALUE_BOOL(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_INT: + GTK_VALUE_INT(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_UINT: + GTK_VALUE_UINT(args[i]) = va_arg (args2, guint); + break; + case GTK_TYPE_ENUM: + GTK_VALUE_ENUM(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_FLAGS: + GTK_VALUE_FLAGS(args[i]) = va_arg (args2, gint); + break; + case GTK_TYPE_LONG: + GTK_VALUE_LONG(args[i]) = va_arg (args2, glong); + break; + case GTK_TYPE_ULONG: + GTK_VALUE_ULONG(args[i]) = va_arg (args2, gulong); + break; + case GTK_TYPE_FLOAT: + GTK_VALUE_FLOAT(args[i]) = va_arg (args2, gfloat); + break; + case GTK_TYPE_STRING: + GTK_VALUE_STRING(args[i]) = va_arg (args2, gchar*); + break; + case GTK_TYPE_POINTER: + GTK_VALUE_POINTER(args[i]) = va_arg (args2, gpointer); + break; + case GTK_TYPE_BOXED: + GTK_VALUE_BOXED(args[i]) = va_arg (args2, gpointer); + break; + case GTK_TYPE_SIGNAL: + GTK_VALUE_SIGNAL(args[i]).f = va_arg (args2, GtkFunction); + GTK_VALUE_SIGNAL(args[i]).d = va_arg (args2, gpointer); + break; + case GTK_TYPE_FOREIGN: + GTK_VALUE_FOREIGN(args[i]).data = va_arg (args2, gpointer); + GTK_VALUE_FOREIGN(args[i]).notify = + va_arg (args2, GtkDestroyNotify); + break; + case GTK_TYPE_CALLBACK: + GTK_VALUE_CALLBACK(args[i]).marshal = + va_arg (args2, GtkCallbackMarshal); + GTK_VALUE_CALLBACK(args[i]).data = va_arg (args2, gpointer); + GTK_VALUE_CALLBACK(args[i]).notify = + va_arg (args2, GtkDestroyNotify); + break; + case GTK_TYPE_C_CALLBACK: + GTK_VALUE_C_CALLBACK(args[i]).func = va_arg (args2, GtkFunction); + GTK_VALUE_C_CALLBACK(args[i]).func_data = + va_arg (args2, gpointer); + break; + case GTK_TYPE_ARGS: + GTK_VALUE_ARGS(args[i]).n_args = va_arg (args2, gint); + GTK_VALUE_ARGS(args[i]).args = va_arg (args2, GtkArg*); + break; + case GTK_TYPE_OBJECT: + GTK_VALUE_OBJECT(args[i]) = va_arg (args2, GtkObject*); + g_assert (GTK_VALUE_OBJECT(args[i]) == NULL || + GTK_CHECK_TYPE (GTK_VALUE_OBJECT(args[i]), + args[i].type)); + break; + default: + g_error ("unsupported type %s in args", + gtk_type_name (args[i].type)); + break; + } + } + } + + return args; +} diff --git a/gtk/gtkobject.h b/gtk/gtkobject.h new file mode 100644 index 000000000..023bbbf0c --- /dev/null +++ b/gtk/gtkobject.h @@ -0,0 +1,250 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_OBJECT_H__ +#define __GTK_OBJECT_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* GtkObject only uses the first 3 bits of the "flags" field. + * They refer to the following flags. + * GtkWidget uses the remaining bits. Though this is a kinda nasty + * break up, it does make the size of GtkWidget smaller. + */ +enum +{ + GTK_NEED_DESTROY = 1 << 0, + GTK_BEING_DESTROYED = 1 << 1, + GTK_IN_CALL = 1 << 2 +}; + + +/* The debugging versions of the casting macros make sure the cast is "ok" + * before proceeding, but they are definately slower than their less + * careful counterparts as they involve no less than 3 function calls. + */ +#ifdef NDEBUG + +#define GTK_CHECK_CAST(obj,cast_type,cast) ((cast*) obj) +#define GTK_CHECK_CLASS_CAST(klass,cast_type,cast) ((cast*) klass) + +#else /* NDEBUG */ + +#define GTK_CHECK_CAST(obj,cast_type,cast) \ + ((cast*) gtk_object_check_cast ((GtkObject*) obj, cast_type)) + +#define GTK_CHECK_CLASS_CAST(klass,cast_type,cast) \ + ((cast*) gtk_object_check_class_cast ((GtkObjectClass*) klass, cast_type)) + +#endif /* NDEBUG */ + + +/* Determines whether 'obj' is a type of 'otype'. + */ +#define GTK_CHECK_TYPE(obj,otype) (gtk_type_is_a (((GtkObject*) obj)->klass->type, otype)) + + +/* Macro for casting a pointer to a GtkObject pointer. + */ +#define GTK_OBJECT(obj) GTK_CHECK_CAST (obj, gtk_object_get_type (), GtkObject) + +/* Macros for extracting various fields from GtkObject and + * GtkObjectClass. + */ +#define GTK_OBJECT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_object_get_type (), GtkObjectClass) +#define GTK_OBJECT_FLAGS(obj) (GTK_OBJECT (obj)->flags) +#define GTK_OBJECT_NEED_DESTROY(obj) (GTK_OBJECT_FLAGS (obj) & GTK_NEED_DESTROY) +#define GTK_OBJECT_BEING_DESTROYED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_BEING_DESTROYED) +#define GTK_OBJECT_IN_CALL(obj) (GTK_OBJECT_FLAGS (obj) & GTK_IN_CALL) +#define GTK_OBJECT_DESTROY(obj) (GTK_OBJECT (obj)->klass->destroy) +#define GTK_OBJECT_TYPE(obj) (GTK_OBJECT (obj)->klass->type) +#define GTK_OBJECT_SIGNALS(obj) (GTK_OBJECT (obj)->klass->signals) +#define GTK_OBJECT_NSIGNALS(obj) (GTK_OBJECT (obj)->klass->signals) + +/* Macro for testing whether "obj" is of type GtkObject. + */ +#define GTK_IS_OBJECT(obj) GTK_CHECK_TYPE (obj, gtk_object_get_type ()) + +/* Macros for setting and clearing bits in the "flags" field of GtkObject. + */ +#define GTK_OBJECT_SET_FLAGS(obj,flag) (GTK_OBJECT_FLAGS (obj) |= (flag)) +#define GTK_OBJECT_UNSET_FLAGS(obj,flag) (GTK_OBJECT_FLAGS (obj) &= ~(flag)) + + +typedef struct _GtkObjectClass GtkObjectClass; + + +/* GtkObject is the base of the object hierarchy. It defines + * the few basic items that all derived classes contain. + */ +struct _GtkObject +{ + /* 32 bits of flags. GtkObject only uses 3 of these bits and + * GtkWidget uses the rest. This is done because structs are + * aligned on 4 or 8 byte boundaries. If bitfields were used + * both here and in GtkWidget much space would be wasted. + */ + guint32 flags; + + /* 16 bit reference count. "gtk_object_destroy" actually only + * destroys an object when its ref count is 0. (Decrementing + * a reference count of 0 is defined as a no-op). + */ + guint16 ref_count; + + /* A pointer to the objects class. This will actually point to + * the derived objects class struct (which will be derived from + * GtkObjectClass). + */ + GtkObjectClass *klass; + + /* The list of signal handlers and other data + * fields for this object. + */ + gpointer object_data; +}; + +/* GtkObjectClass is the base of the class hierarchy. It defines + * the basic necessities for the class mechanism to work. Namely, + * the "type", "signals" and "nsignals" fields. + */ +struct _GtkObjectClass +{ + /* The type identifier for the objects class. There is + * one unique identifier per class. + */ + guint type; + + /* The signals this object class handles. "signals" is an + * array of signal ID's. + */ + gint *signals; + + /* The number of signals listed in "signals". + */ + gint nsignals; + + /* The destroy function for objects. In one way ore another + * this is defined for all objects. If an object class overrides + * this method in order to perform class specific destruction + * then it should still call it after it is finished with its + * own cleanup. (See the destroy function for GtkWidget for + * an example of how to do this). + */ + void (* destroy) (GtkObject *object); +}; + + +/* Get the type identifier for GtkObject's. + */ +guint gtk_object_get_type (void); + +/* Append "signals" to those already defined in "class". + */ +void gtk_object_class_add_signals (GtkObjectClass *klass, + gint *signals, + gint nsignals); + +void gtk_object_ref (GtkObject *object); + +void gtk_object_unref (GtkObject *object); + +GtkObject* gtk_object_new (guint type, + ...); + +GtkObject* gtk_object_newv (guint type, + gint nargs, + GtkArg *args); + +void gtk_object_set (GtkObject *obj, + ...); + +void gtk_object_setv (GtkObject *obj, + gint nargs, + GtkArg *args); + +void gtk_object_add_arg_type (const char *arg_name, + GtkType arg_type); + +GtkType gtk_object_get_arg_type (const char *arg_name); + +/* Emit the "destroy" signal for "object". Normally it is + * permissible to emit a signal for an object instead of + * calling the corresponding convenience routine, however + * "gtk_object_destroy" should be called instead of emitting + * the signal manually as it checks to see if the object is + * currently handling another signal emittion (very likely) + * and sets the GTK_NEED_DESTROY flag which tells the object + * to be destroyed when it is done handling the signal emittion. + */ +void gtk_object_destroy (GtkObject *object); + +/* Set 'data' to the "object_data" field of the object. The + * data is indexed by the "key". If there is already data + * associated with "key" then the new data will replace it. + * If 'data' is NULL then this call is equivalent to + * 'gtk_object_remove_data'. + */ +void gtk_object_set_data (GtkObject *object, + const gchar *key, + gpointer data); + +/* Get the data associated with "key". + */ +gpointer gtk_object_get_data (GtkObject *object, + const gchar *key); + +/* Remove the data associated with "key". This call is + * equivalent to 'gtk_object_set_data' where 'data' is NULL. + */ +void gtk_object_remove_data (GtkObject *object, + const gchar *key); + +/* Set the "user_data" object data field of "object". It should + * be noted that this is no different than calling 'gtk_object_data_add' + * with a key of "user_data". It is merely provided as a convenience. + */ +void gtk_object_set_user_data (GtkObject *object, + gpointer data); + +/* Get the "user_data" object data field of "object". It should + * be noted that this is no different than calling 'gtk_object_data_find' + * with a key of "user_data". It is merely provided as a convenience. + */ +gpointer gtk_object_get_user_data (GtkObject *object); + +GtkObject* gtk_object_check_cast (GtkObject *obj, + GtkType cast_type); + +GtkObjectClass* gtk_object_check_class_cast (GtkObjectClass *klass, + GtkType cast_type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_OBJECT_H__ */ diff --git a/gtk/gtkoptionmenu.c b/gtk/gtkoptionmenu.c new file mode 100644 index 000000000..919aa2669 --- /dev/null +++ b/gtk/gtkoptionmenu.c @@ -0,0 +1,584 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtkoptionmenu.h" +#include "gtksignal.h" + + +#define CHILD_LEFT_SPACING 5 +#define CHILD_RIGHT_SPACING 1 +#define CHILD_TOP_SPACING 1 +#define CHILD_BOTTOM_SPACING 1 +#define OPTION_INDICATOR_WIDTH 12 +#define OPTION_INDICATOR_HEIGHT 8 +#define OPTION_INDICATOR_SPACING 2 + + +static void gtk_option_menu_class_init (GtkOptionMenuClass *klass); +static void gtk_option_menu_init (GtkOptionMenu *option_menu); +static void gtk_option_menu_destroy (GtkObject *object); +static void gtk_option_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_option_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_option_menu_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_option_menu_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_option_menu_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_option_menu_button_press (GtkWidget *widget, + GdkEventButton *event); +static void gtk_option_menu_deactivate (GtkMenuShell *menu_shell, + GtkOptionMenu *option_menu); +static void gtk_option_menu_update_contents (GtkOptionMenu *option_menu); +static void gtk_option_menu_remove_contents (GtkOptionMenu *option_menu); +static void gtk_option_menu_calc_size (GtkOptionMenu *option_menu); +static void gtk_option_menu_position (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data); + + +static GtkButtonClass *parent_class = NULL; + + +guint +gtk_option_menu_get_type () +{ + static guint option_menu_type = 0; + + if (!option_menu_type) + { + GtkTypeInfo option_menu_info = + { + "GtkOptionMenu", + sizeof (GtkOptionMenu), + sizeof (GtkOptionMenuClass), + (GtkClassInitFunc) gtk_option_menu_class_init, + (GtkObjectInitFunc) gtk_option_menu_init, + (GtkArgFunc) NULL, + }; + + option_menu_type = gtk_type_unique (gtk_button_get_type (), &option_menu_info); + } + + return option_menu_type; +} + +static void +gtk_option_menu_class_init (GtkOptionMenuClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkButtonClass *button_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + button_class = (GtkButtonClass*) class; + + parent_class = gtk_type_class (gtk_button_get_type ()); + + object_class->destroy = gtk_option_menu_destroy; + + widget_class->draw = gtk_option_menu_draw; + widget_class->draw_focus = NULL; + widget_class->size_request = gtk_option_menu_size_request; + widget_class->size_allocate = gtk_option_menu_size_allocate; + widget_class->expose_event = gtk_option_menu_expose; + widget_class->button_press_event = gtk_option_menu_button_press; +} + +static void +gtk_option_menu_init (GtkOptionMenu *option_menu) +{ + GTK_WIDGET_UNSET_FLAGS (option_menu, GTK_CAN_FOCUS); + + option_menu->menu = NULL; + option_menu->menu_item = NULL; + option_menu->width = 0; + option_menu->height = 0; +} + +GtkWidget* +gtk_option_menu_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_option_menu_get_type ())); +} + +GtkWidget* +gtk_option_menu_get_menu (GtkOptionMenu *option_menu) +{ + g_return_val_if_fail (option_menu != NULL, NULL); + g_return_val_if_fail (GTK_IS_OPTION_MENU (option_menu), NULL); + + return option_menu->menu; +} + +void +gtk_option_menu_set_menu (GtkOptionMenu *option_menu, + GtkWidget *menu) +{ + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + g_return_if_fail (menu != NULL); + g_return_if_fail (GTK_IS_MENU (menu)); + + gtk_option_menu_remove_menu (option_menu); + + option_menu->menu = menu; + gtk_object_ref (GTK_OBJECT (option_menu->menu)); + + gtk_option_menu_calc_size (option_menu); + + gtk_signal_connect (GTK_OBJECT (option_menu->menu), "deactivate", + (GtkSignalFunc) gtk_option_menu_deactivate, + option_menu); + + if (GTK_WIDGET (option_menu)->parent) + gtk_widget_queue_resize (GTK_WIDGET (option_menu)); + + gtk_option_menu_update_contents (option_menu); +} + +void +gtk_option_menu_remove_menu (GtkOptionMenu *option_menu) +{ + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + if (option_menu->menu) + { + gtk_option_menu_remove_contents (option_menu); + gtk_signal_disconnect_by_data (GTK_OBJECT (option_menu->menu), + option_menu); + + gtk_object_unref (GTK_OBJECT (option_menu->menu)); + option_menu->menu = NULL; + } +} + +void +gtk_option_menu_set_history (GtkOptionMenu *option_menu, + gint index) +{ + GtkWidget *menu_item; + + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + if (option_menu->menu) + { + gtk_menu_set_active (GTK_MENU (option_menu->menu), index); + menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + + if (menu_item != option_menu->menu_item) + { + gtk_option_menu_remove_contents (option_menu); + gtk_option_menu_update_contents (option_menu); + } + } +} + + +static void +gtk_option_menu_destroy (GtkObject *object) +{ + GtkOptionMenu *option_menu; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (object)); + + option_menu = GTK_OPTION_MENU (object); + + gtk_option_menu_remove_contents (option_menu); + if (option_menu->menu) + { + gtk_object_unref (GTK_OBJECT (option_menu->menu)); + gtk_widget_destroy (option_menu->menu); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_option_menu_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkOptionMenu *option_menu; + gint tmp; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (widget)); + g_return_if_fail (requisition != NULL); + + option_menu = GTK_OPTION_MENU (widget); + + requisition->width = ((GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->xthickness) * 2 + + option_menu->width + + OPTION_INDICATOR_WIDTH + + OPTION_INDICATOR_SPACING * 5 + + CHILD_LEFT_SPACING + CHILD_RIGHT_SPACING); + requisition->height = ((GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->ythickness) * 2 + + option_menu->height + + CHILD_TOP_SPACING + CHILD_BOTTOM_SPACING); + + tmp = (requisition->height - option_menu->height + + OPTION_INDICATOR_HEIGHT + OPTION_INDICATOR_SPACING * 2); + requisition->height = MAX (requisition->height, tmp); +} + +static void +gtk_option_menu_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWidget *child; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + child = GTK_BUTTON (widget)->child; + if (child && GTK_WIDGET_VISIBLE (child)) + { + child_allocation.x = (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->xthickness); + child_allocation.y = (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->ythickness); + child_allocation.width = (allocation->width - child_allocation.x * 2 - + OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 5 - + CHILD_LEFT_SPACING - CHILD_RIGHT_SPACING); + child_allocation.height = (allocation->height - child_allocation.y * 2 - + CHILD_TOP_SPACING - CHILD_BOTTOM_SPACING); + child_allocation.x += CHILD_LEFT_SPACING; + child_allocation.y += CHILD_RIGHT_SPACING; + + gtk_widget_size_allocate (child, &child_allocation); + } +} + +static void +gtk_option_menu_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GdkRectangle restrict_area; + GdkRectangle new_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + restrict_area.x = GTK_CONTAINER (widget)->border_width; + restrict_area.y = GTK_CONTAINER (widget)->border_width; + restrict_area.width = widget->allocation.width - restrict_area.x * 2; + restrict_area.height = widget->allocation.height - restrict_area.y * 2; + + if (gdk_rectangle_intersect (area, &restrict_area, &new_area)) + { + gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (widget)); + gdk_window_clear_area (widget->window, + new_area.x, new_area.y, + new_area.width, new_area.height); + + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT, + restrict_area.x, restrict_area.y, + restrict_area.width, restrict_area.height); + + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT, + restrict_area.x + restrict_area.width - restrict_area.x - + OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 4, + restrict_area.y + (restrict_area.height - OPTION_INDICATOR_HEIGHT) / 2, + OPTION_INDICATOR_WIDTH, OPTION_INDICATOR_HEIGHT); + } + } +} + +static void +gtk_option_menu_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkWidget *child; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_option_menu_paint (widget, area); + + child = GTK_BUTTON (widget)->child; + if (child && gtk_widget_intersect (child, area, &child_area)) + gtk_widget_draw (child, &child_area); + } +} + +static gint +gtk_option_menu_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkWidget *child; + GdkEventExpose child_event; + gint remove_child; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + gtk_option_menu_paint (widget, &event->area); + + remove_child = FALSE; + child = GTK_BUTTON (widget)->child; + + if (!child) + { + if (!GTK_OPTION_MENU (widget)->menu) + return FALSE; + gtk_option_menu_update_contents (GTK_OPTION_MENU (widget)); + child = GTK_BUTTON (widget)->child; + if (!child) + return FALSE; + remove_child = TRUE; + } + + child_event = *event; + + if (GTK_WIDGET_NO_WINDOW (child) && + gtk_widget_intersect (child, &event->area, &child_event.area)) + gtk_widget_event (child, (GdkEvent*) &child_event); + + if (remove_child) + gtk_option_menu_remove_contents (GTK_OPTION_MENU (widget)); + } + + return FALSE; +} + +static gint +gtk_option_menu_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkOptionMenu *option_menu; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if ((event->type == GDK_BUTTON_PRESS) && + (event->button == 1)) + { + option_menu = GTK_OPTION_MENU (widget); + gtk_option_menu_remove_contents (option_menu); + gtk_menu_popup (GTK_MENU (option_menu->menu), NULL, NULL, + gtk_option_menu_position, option_menu, + event->button, event->time); + } + + return FALSE; +} + +static void +gtk_option_menu_deactivate (GtkMenuShell *menu_shell, + GtkOptionMenu *option_menu) +{ + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + gtk_option_menu_update_contents (option_menu); +} + +static void +gtk_option_menu_update_contents (GtkOptionMenu *option_menu) +{ + GtkWidget *child; + + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + if (option_menu->menu) + { + gtk_option_menu_remove_contents (option_menu); + + option_menu->menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + if (option_menu->menu_item) + { + child = GTK_BIN (option_menu->menu_item)->child; + if (child) + { + gtk_container_block_resize (GTK_CONTAINER (option_menu)); + if (GTK_WIDGET (option_menu)->state != child->state) + gtk_widget_set_state (child, GTK_WIDGET (option_menu)->state); + gtk_widget_reparent (child, GTK_WIDGET (option_menu)); + gtk_container_unblock_resize (GTK_CONTAINER (option_menu)); + } + + gtk_widget_size_allocate (GTK_WIDGET (option_menu), + &(GTK_WIDGET (option_menu)->allocation)); + + if (GTK_WIDGET_DRAWABLE (option_menu)) + gtk_widget_queue_draw (GTK_WIDGET (option_menu)); + } + } +} + +static void +gtk_option_menu_remove_contents (GtkOptionMenu *option_menu) +{ + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + if (GTK_BUTTON (option_menu)->child) + { + gtk_container_block_resize (GTK_CONTAINER (option_menu)); + if (GTK_WIDGET (option_menu->menu_item)->state != GTK_BUTTON (option_menu)->child->state) + gtk_widget_set_state (GTK_BUTTON (option_menu)->child, + GTK_WIDGET (option_menu->menu_item)->state); + GTK_WIDGET_UNSET_FLAGS (GTK_BUTTON (option_menu)->child, GTK_MAPPED | GTK_REALIZED); + gtk_widget_reparent (GTK_BUTTON (option_menu)->child, option_menu->menu_item); + gtk_container_unblock_resize (GTK_CONTAINER (option_menu)); + option_menu->menu_item = NULL; + } +} + +static void +gtk_option_menu_calc_size (GtkOptionMenu *option_menu) +{ + GtkWidget *child; + GList *children; + + g_return_if_fail (option_menu != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (option_menu)); + + option_menu->width = 0; + option_menu->height = 0; + + if (option_menu->menu) + { + children = GTK_MENU_SHELL (option_menu->menu)->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child)) + { + gtk_widget_size_request (child, &child->requisition); + + option_menu->width = MAX (option_menu->width, child->requisition.width); + option_menu->height = MAX (option_menu->height, child->requisition.height); + } + } + } +} + +static void +gtk_option_menu_position (GtkMenu *menu, + gint *x, + gint *y, + gpointer user_data) +{ + GtkOptionMenu *option_menu; + GtkWidget *active; + GtkWidget *child; + GList *children; + gint shift_menu; + gint screen_width; + gint screen_height; + gint menu_xpos; + gint menu_ypos; + gint width; + gint height; + + g_return_if_fail (user_data != NULL); + g_return_if_fail (GTK_IS_OPTION_MENU (user_data)); + + option_menu = GTK_OPTION_MENU (user_data); + + width = GTK_WIDGET (menu)->allocation.width; + height = GTK_WIDGET (menu)->allocation.height; + + active = gtk_menu_get_active (GTK_MENU (option_menu->menu)); + children = GTK_MENU_SHELL (option_menu->menu)->children; + gdk_window_get_origin (GTK_WIDGET (option_menu)->window, &menu_xpos, &menu_ypos); + + menu_ypos += GTK_WIDGET (option_menu)->allocation.height / 2 - 2; + + if (active != NULL) + menu_ypos -= active->requisition.height / 2; + + while (children) + { + child = children->data; + + if (active == child) + break; + + menu_ypos -= child->allocation.height; + children = children->next; + } + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + shift_menu = FALSE; + if (menu_ypos < 0) + { + menu_ypos = 0; + shift_menu = TRUE; + } + else if ((menu_ypos + height) > screen_height) + { + menu_ypos -= ((menu_ypos + height) - screen_height); + shift_menu = TRUE; + } + + if (shift_menu) + { + if ((menu_xpos + GTK_WIDGET (option_menu)->allocation.width + width) <= screen_width) + menu_xpos += GTK_WIDGET (option_menu)->allocation.width; + else + menu_xpos -= width; + } + + if (menu_xpos < 0) + menu_xpos = 0; + else if ((menu_xpos + width) > screen_width) + menu_xpos -= ((menu_xpos + width) - screen_width); + + *x = menu_xpos; + *y = menu_ypos; +} diff --git a/gtk/gtkoptionmenu.h b/gtk/gtkoptionmenu.h new file mode 100644 index 000000000..bbddf2309 --- /dev/null +++ b/gtk/gtkoptionmenu.h @@ -0,0 +1,71 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_OPTION_MENU_H__ +#define __GTK_OPTION_MENU_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_OPTION_MENU(obj) GTK_CHECK_CAST (obj, gtk_option_menu_get_type (), GtkOptionMenu) +#define GTK_OPTION_MENU_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_option_menu_get_type (), GtkOptionMenuClass) +#define GTK_IS_OPTION_MENU(obj) GTK_CHECK_TYPE (obj, gtk_option_menu_get_type ()) + + +typedef struct _GtkOptionMenu GtkOptionMenu; +typedef struct _GtkOptionMenuClass GtkOptionMenuClass; + +struct _GtkOptionMenu +{ + GtkButton button; + + GtkWidget *menu; + GtkWidget *menu_item; + + guint16 width; + guint16 height; +}; + +struct _GtkOptionMenuClass +{ + GtkButtonClass parent_class; +}; + + +guint gtk_option_menu_get_type (void); +GtkWidget* gtk_option_menu_new (void); +GtkWidget* gtk_option_menu_get_menu (GtkOptionMenu *option_menu); +void gtk_option_menu_set_menu (GtkOptionMenu *option_menu, + GtkWidget *menu); +void gtk_option_menu_remove_menu (GtkOptionMenu *option_menu); +void gtk_option_menu_set_history (GtkOptionMenu *option_menu, + gint index); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_OPTION_MENU_H__ */ diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c new file mode 100644 index 000000000..d6b53db3d --- /dev/null +++ b/gtk/gtkpaned.c @@ -0,0 +1,452 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkpaned.h" + + +static void gtk_paned_class_init (GtkPanedClass *klass); +static void gtk_paned_init (GtkPaned *paned); +static void gtk_paned_destroy (GtkObject *object); +static void gtk_paned_realize (GtkWidget *widget); +static void gtk_paned_map (GtkWidget *widget); +static void gtk_paned_unmap (GtkWidget *widget); +static void gtk_paned_unrealize (GtkWidget *widget); +static gint gtk_paned_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_paned_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_paned_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_paned_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_paned_get_type () +{ + static guint paned_type = 0; + + if (!paned_type) + { + GtkTypeInfo paned_info = + { + "GtkPaned", + sizeof (GtkPaned), + sizeof (GtkPanedClass), + (GtkClassInitFunc) gtk_paned_class_init, + (GtkObjectInitFunc) gtk_paned_init, + (GtkArgFunc) NULL, + }; + + paned_type = gtk_type_unique (gtk_container_get_type (), &paned_info); + } + + return paned_type; +} + +static void +gtk_paned_class_init (GtkPanedClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_paned_destroy; + + widget_class->realize = gtk_paned_realize; + widget_class->map = gtk_paned_map; + widget_class->unmap = gtk_paned_unmap; + widget_class->unrealize = gtk_paned_unrealize; + widget_class->expose_event = gtk_paned_expose; + + container_class->add = gtk_paned_add; + container_class->remove = gtk_paned_remove; + container_class->foreach = gtk_paned_foreach; +} + +static void +gtk_paned_init (GtkPaned *paned) +{ + GTK_WIDGET_SET_FLAGS (paned, GTK_NO_WINDOW); + + paned->child1 = NULL; + paned->child2 = NULL; + paned->handle = NULL; + paned->xor_gc = NULL; + + paned->handle_size = 10; + paned->gutter_size = 6; + paned->position_set = FALSE; + paned->in_drag = FALSE; + + paned->handle_xpos = -1; + paned->handle_ypos = -1; +} + + +static void +gtk_paned_destroy (GtkObject *object) +{ + GtkPaned *paned; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_PANED (object)); + + paned = GTK_PANED (object); + + if (paned->child1) + { + paned->child1->parent = NULL; + gtk_object_unref (GTK_OBJECT (paned->child1)); + gtk_widget_destroy (paned->child1); + } + if (paned->child2) + { + paned->child2->parent = NULL; + gtk_object_unref (GTK_OBJECT (paned->child2)); + gtk_widget_destroy (paned->child2); + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_paned_realize (GtkWidget *widget) +{ + GtkPaned *paned; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + paned = GTK_PANED (widget); + + attributes.x = paned->handle_xpos; + attributes.y = paned->handle_ypos; + attributes.width = paned->handle_size; + attributes.height = paned->handle_size; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.cursor = gdk_cursor_new(GDK_CROSS); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | + GDK_WA_CURSOR; + + paned->handle = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (paned->handle, widget); + gdk_window_show (paned->handle); + gdk_window_raise (paned->handle); + + widget->window = widget->parent->window; + widget->style = gtk_style_attach (widget->style, widget->window); + + gtk_style_set_background (widget->style, paned->handle, GTK_STATE_NORMAL); +} + +static void +gtk_paned_map (GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + paned = GTK_PANED (widget); + + gdk_window_show (paned->handle); + gtk_widget_queue_draw (widget); + + if (paned->child1 && + GTK_WIDGET_VISIBLE (paned->child1) && + !GTK_WIDGET_MAPPED (paned->child1)) + gtk_widget_map (paned->child1); + if (paned->child2 && + GTK_WIDGET_VISIBLE (paned->child2) && + !GTK_WIDGET_MAPPED (paned->child2)) + gtk_widget_map (paned->child2); +} + +static void +gtk_paned_unmap (GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + paned = GTK_PANED (widget); + + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + gdk_window_hide (paned->handle); + + if (paned->child1 && + GTK_WIDGET_VISIBLE (paned->child1) && + GTK_WIDGET_MAPPED (paned->child1)) + gtk_widget_unmap (paned->child1); + if (paned->child2 && + GTK_WIDGET_VISIBLE (paned->child2) && + GTK_WIDGET_MAPPED (paned->child2)) + gtk_widget_unmap (paned->child2); +} + +static void +gtk_paned_unrealize (GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED); + paned = GTK_PANED (widget); + + gtk_style_detach (widget->style); + + if (paned->xor_gc) + gdk_gc_destroy (paned->xor_gc); + if (paned->handle) + gdk_window_destroy (paned->handle); + + paned->handle = NULL; + widget->window = NULL; +} + +static gint +gtk_paned_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkPaned *paned; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + paned = GTK_PANED (widget); + + /* An expose event for the handle */ + if (event->window == paned->handle) + { + gdk_window_set_background (paned->handle, + &widget->style->bg[widget->state]); + gdk_window_clear (paned->handle); + gtk_draw_shadow (widget->style, paned->handle, + GTK_WIDGET_STATE(widget), + GTK_SHADOW_OUT, 0, 0, + paned->handle_size, paned->handle_size); + } + else + { + child_event = *event; + if (paned->child1 && + GTK_WIDGET_NO_WINDOW (paned->child1) && + gtk_widget_intersect (paned->child1, &event->area, &child_event.area)) + gtk_widget_event (paned->child1, (GdkEvent*) &child_event); + + if (paned->child2 && + GTK_WIDGET_NO_WINDOW (paned->child2) && + gtk_widget_intersect (paned->child2, &event->area, &child_event.area)) + gtk_widget_event (paned->child2, (GdkEvent*) &child_event); + + /* redraw the groove if necessary */ + child_event.area = paned->groove_rectangle; + if (gtk_widget_intersect (widget, &event->area, &child_event.area)) + gtk_widget_draw (widget, &child_event.area); + } + } + return FALSE; +} + +void +gtk_paned_add1 (GtkPaned *paned, + GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (!paned->child1) + { + gtk_widget_set_parent (widget, GTK_WIDGET (paned)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + paned->child1 = widget; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned)) + gtk_widget_queue_resize (widget); + } +} + +void +gtk_paned_add2 (GtkPaned *paned, + GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (!paned->child2) + { + gtk_widget_set_parent (widget, GTK_WIDGET (paned)); + + if (GTK_WIDGET_VISIBLE (widget->parent)) + { + if (GTK_WIDGET_REALIZED (widget->parent) && + !GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent) && + !GTK_WIDGET_MAPPED (widget)) + gtk_widget_map (widget); + } + + paned->child2 = widget; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned)) + gtk_widget_queue_resize (widget); + } +} + +static void +gtk_paned_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_PANED (container)); + g_return_if_fail (widget != NULL); + + paned = GTK_PANED (container); + + if (!paned->child1) + gtk_paned_add1 (GTK_PANED (container),widget); + else if (!paned->child2) + gtk_paned_add2 (GTK_PANED (container),widget); +} + +static void +gtk_paned_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkPaned *paned; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_PANED (container)); + g_return_if_fail (widget != NULL); + + paned = GTK_PANED (container); + + if (paned->child1 == widget) + { + gtk_widget_unparent (widget); + + paned->child1 = NULL; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } + else if (paned->child2 == widget) + { + gtk_widget_unparent (widget); + + paned->child2 = NULL; + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + } +} + +static void +gtk_paned_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkPaned *paned; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_PANED (container)); + g_return_if_fail (callback != NULL); + + paned = GTK_PANED (container); + + if (paned->child1) + (* callback) (paned->child1, callback_data); + if (paned->child2) + (* callback) (paned->child2, callback_data); +} + +void +gtk_paned_handle_size (GtkPaned *paned, guint16 size) +{ + gint x,y; + + if (paned->handle) + { + gdk_window_get_geometry (paned->handle, &x, &y, NULL, NULL, NULL); + gdk_window_move_resize (paned->handle, + x + paned->handle_size / 2 - size / 2, + y + paned->handle_size / 2 - size / 2, + size, size); + } + + paned->handle_size = size; +} + +void +gtk_paned_gutter_size (GtkPaned *paned, guint16 size) +{ + paned->gutter_size = size; + + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (paned))) + gtk_widget_queue_resize (GTK_WIDGET (paned)); +} diff --git a/gtk/gtkpaned.h b/gtk/gtkpaned.h new file mode 100644 index 000000000..1b25263b0 --- /dev/null +++ b/gtk/gtkpaned.h @@ -0,0 +1,78 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_PANED_H__ +#define __GTK_PANED_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_PANED(obj) GTK_CHECK_CAST (obj, gtk_paned_get_type (), GtkPaned) +#define GTK_PANED_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_paned_get_type (), GtkPanedClass) +#define GTK_IS_PANED(obj) GTK_CHECK_TYPE (obj, gtk_paned_get_type ()) + + +typedef struct _GtkPaned GtkPaned; +typedef struct _GtkPanedClass GtkPanedClass; + +struct _GtkPaned +{ + GtkContainer container; + + GtkWidget *child1; + GtkWidget *child2; + + GdkWindow *handle; + GdkRectangle groove_rectangle; + GdkGC *xor_gc; + + guint16 handle_size; + guint16 gutter_size; + + gint child1_size; + guint position_set : 1; + guint in_drag : 1; + + gint16 handle_xpos; + gint16 handle_ypos; +}; + +struct _GtkPanedClass +{ + GtkContainerClass parent_class; +}; + + +guint gtk_paned_get_type (void); +void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child); +void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child); +void gtk_paned_handle_size (GtkPaned *paned, guint16 size); +void gtk_paned_gutter_size (GtkPaned *paned, guint16 size); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_PANED_H__ */ diff --git a/gtk/gtkpixmap.c b/gtk/gtkpixmap.c new file mode 100644 index 000000000..ae640f81f --- /dev/null +++ b/gtk/gtkpixmap.c @@ -0,0 +1,176 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkcontainer.h" +#include "gtkpixmap.h" + + +static void gtk_pixmap_class_init (GtkPixmapClass *klass); +static void gtk_pixmap_init (GtkPixmap *pixmap); +static gint gtk_pixmap_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_pixmap_get_type () +{ + static guint pixmap_type = 0; + + if (!pixmap_type) + { + GtkTypeInfo pixmap_info = + { + "GtkPixmap", + sizeof (GtkPixmap), + sizeof (GtkPixmapClass), + (GtkClassInitFunc) gtk_pixmap_class_init, + (GtkObjectInitFunc) gtk_pixmap_init, + (GtkArgFunc) NULL, + }; + + pixmap_type = gtk_type_unique (gtk_misc_get_type (), &pixmap_info); + } + + return pixmap_type; +} + +static void +gtk_pixmap_class_init (GtkPixmapClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->expose_event = gtk_pixmap_expose; +} + +static void +gtk_pixmap_init (GtkPixmap *pixmap) +{ + GTK_WIDGET_SET_FLAGS (pixmap, GTK_NO_WINDOW); + + pixmap->pixmap = NULL; + pixmap->mask = NULL; +} + +GtkWidget* +gtk_pixmap_new (GdkPixmap *val, + GdkBitmap *mask) +{ + GtkPixmap *pixmap; + + g_return_val_if_fail (val != NULL, NULL); + + pixmap = gtk_type_new (gtk_pixmap_get_type ()); + + gtk_pixmap_set (pixmap, val, mask); + + return GTK_WIDGET (pixmap); +} + +void +gtk_pixmap_set (GtkPixmap *pixmap, + GdkPixmap *val, + GdkBitmap *mask) +{ + gint width; + gint height; + + g_return_if_fail (pixmap != NULL); + g_return_if_fail (GTK_IS_PIXMAP (pixmap)); + g_return_if_fail (val != NULL); + + pixmap->pixmap = val; + pixmap->mask = mask; + + if (pixmap->pixmap) + { + gdk_window_get_size (pixmap->pixmap, &width, &height); + GTK_WIDGET (pixmap)->requisition.width = width + GTK_MISC (pixmap)->xpad * 2; + GTK_WIDGET (pixmap)->requisition.height = height + GTK_MISC (pixmap)->ypad * 2; + } + else + { + GTK_WIDGET (pixmap)->requisition.width = 0; + GTK_WIDGET (pixmap)->requisition.height = 0; + } + + if (GTK_WIDGET_VISIBLE (pixmap)) + gtk_widget_queue_resize (GTK_WIDGET (pixmap)); +} + +void +gtk_pixmap_get (GtkPixmap *pixmap, + GdkPixmap **val, + GdkBitmap **mask) +{ + g_return_if_fail (pixmap != NULL); + g_return_if_fail (GTK_IS_PIXMAP (pixmap)); + + if (val) + *val = pixmap->pixmap; + if (mask) + *mask = pixmap->mask; +} + + +static gint +gtk_pixmap_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkPixmap *pixmap; + GtkMisc *misc; + gint x, y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PIXMAP (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + pixmap = GTK_PIXMAP (widget); + misc = GTK_MISC (widget); + + x = (widget->allocation.x * (1.0 - misc->xalign) + + (widget->allocation.x + widget->allocation.width + - (widget->requisition.width - misc->xpad * 2)) * + misc->xalign) + 0.5; + y = (widget->allocation.y * (1.0 - misc->yalign) + + (widget->allocation.y + widget->allocation.height + - (widget->requisition.height - misc->ypad * 2)) * + misc->yalign) + 0.5; + + if (pixmap->mask) + { + gdk_gc_set_clip_mask (widget->style->black_gc, pixmap->mask); + gdk_gc_set_clip_origin (widget->style->black_gc, x, y); + } + + gdk_draw_pixmap (widget->window, + widget->style->black_gc, + pixmap->pixmap, + 0, 0, x, y, -1, -1); + + if (pixmap->mask) + { + gdk_gc_set_clip_mask (widget->style->black_gc, NULL); + gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0); + } + } + + return FALSE; +} diff --git a/gtk/gtkpixmap.h b/gtk/gtkpixmap.h new file mode 100644 index 000000000..970d4f40f --- /dev/null +++ b/gtk/gtkpixmap.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_PIXMAP_H__ +#define __GTK_PIXMAP_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_PIXMAP(obj) GTK_CHECK_CAST (obj, gtk_pixmap_get_type (), GtkPixmap) +#define GTK_PIXMAP_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_pixmap_get_type (), GtkPixmapClass) +#define GTK_IS_PIXMAP(obj) GTK_CHECK_TYPE (obj, gtk_pixmap_get_type ()) + + +typedef struct _GtkPixmap GtkPixmap; +typedef struct _GtkPixmapClass GtkPixmapClass; + +struct _GtkPixmap +{ + GtkMisc misc; + + GdkPixmap *pixmap; + GdkBitmap *mask; +}; + +struct _GtkPixmapClass +{ + GtkMiscClass parent_class; +}; + + +guint gtk_pixmap_get_type (void); +GtkWidget* gtk_pixmap_new (GdkPixmap *pixmap, + GdkBitmap *mask); +void gtk_pixmap_set (GtkPixmap *pixmap, + GdkPixmap *val, + GdkBitmap *mask); +void gtk_pixmap_get (GtkPixmap *pixmap, + GdkPixmap **val, + GdkBitmap **mask); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_PIXMAP_H__ */ diff --git a/gtk/gtkpreview.c b/gtk/gtkpreview.c new file mode 100644 index 000000000..4246a321a --- /dev/null +++ b/gtk/gtkpreview.c @@ -0,0 +1,1571 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include "gdk/gdkx.h" +#include "gtkpreview.h" +#include "gtksignal.h" + + +#define IMAGE_SIZE 256 +#define PREVIEW_CLASS(w) GTK_PREVIEW_CLASS (GTK_OBJECT (w)->klass) +#define COLOR_COMPOSE(r,g,b) (lookup_red[r] | lookup_green[g] | lookup_blue[b]) + + +typedef struct _GtkPreviewProp GtkPreviewProp; +typedef void (*GtkTransferFunc) (guchar *dest, guchar *src, gint count); + +struct _GtkPreviewProp +{ + guint16 ref_count; + guint16 nred_shades; + guint16 ngreen_shades; + guint16 nblue_shades; + guint16 ngray_shades; +}; + + +static void gtk_preview_class_init (GtkPreviewClass *klass); +static void gtk_preview_init (GtkPreview *preview); +static void gtk_preview_destroy (GtkObject *object); +static void gtk_preview_realize (GtkWidget *widget); +static void gtk_preview_unrealize (GtkWidget *widget); +static gint gtk_preview_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_preview_make_buffer (GtkPreview *preview); +static void gtk_preview_get_visuals (GtkPreviewClass *klass); +static void gtk_preview_get_cmaps (GtkPreviewClass *klass); +static void gtk_preview_dither_init (GtkPreviewClass *klass); +static void gtk_fill_lookup_array (gulong *array, + int depth, + int shift, + int prec); +static void gtk_trim_cmap (GtkPreviewClass *klass); +static void gtk_create_8_bit (GtkPreviewClass *klass); + +static void gtk_color_8 (guchar *src, + guchar *data, + gint x, + gint y, + gulong width); +static void gtk_color_16 (guchar *src, + guchar *data, + gulong width); +static void gtk_color_24 (guchar *src, + guchar *data, + gulong width); +static void gtk_grayscale_8 (guchar *src, + guchar *data, + gint x, + gint y, + gulong width); +static void gtk_grayscale_16 (guchar *src, + guchar *data, + gulong width); +static void gtk_grayscale_24 (guchar *src, + guchar *data, + gulong width); + +static gint gtk_get_preview_prop (guint *nred, + guint *nblue, + guint *ngreen, + guint *ngray); +static void gtk_set_preview_prop (guint nred, + guint ngreen, + guint nblue, + guint ngray); + +/* transfer functions: + * destination byte order/source bpp/destination bpp + */ +static void gtk_lsbmsb_1_1 (guchar *dest, + guchar *src, + gint count); +static void gtk_lsb_2_2 (guchar *dest, + guchar *src, + gint count); +static void gtk_msb_2_2 (guchar *dest, + guchar *src, + gint count); +static void gtk_lsb_3_3 (guchar *dest, + guchar *src, + gint count); +static void gtk_msb_3_3 (guchar *dest, + guchar *src, + gint count); +static void gtk_lsb_3_4 (guchar *dest, + guchar *src, + gint count); +static void gtk_msb_3_4 (guchar *dest, + guchar *src, + gint count); + + +static GtkWidgetClass *parent_class = NULL; +static GtkPreviewClass *preview_class = NULL; +static GtkPreviewInfo *preview_info = NULL; +static gint install_cmap = FALSE; + + +guint +gtk_preview_get_type () +{ + static guint preview_type = 0; + + if (!preview_type) + { + GtkTypeInfo preview_info = + { + "GtkPreview", + sizeof (GtkPreview), + sizeof (GtkPreviewClass), + (GtkClassInitFunc) gtk_preview_class_init, + (GtkObjectInitFunc) gtk_preview_init, + (GtkArgFunc) NULL, + }; + + preview_type = gtk_type_unique (gtk_widget_get_type (), &preview_info); + } + + return preview_type; +} + +static void +gtk_preview_class_init (GtkPreviewClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + preview_class = klass; + + object_class->destroy = gtk_preview_destroy; + + widget_class->realize = gtk_preview_realize; + widget_class->unrealize = gtk_preview_unrealize; + widget_class->expose_event = gtk_preview_expose; + + if (preview_info) + klass->info = *preview_info; + else + { + klass->info.visual = NULL; + klass->info.cmap = NULL; + + klass->info.color_pixels = NULL; + klass->info.gray_pixels = NULL; + klass->info.reserved_pixels = NULL; + + klass->info.lookup_red = NULL; + klass->info.lookup_green = NULL; + klass->info.lookup_blue = NULL; + + klass->info.dither_red = NULL; + klass->info.dither_green = NULL; + klass->info.dither_blue = NULL; + klass->info.dither_gray = NULL; + klass->info.dither_matrix = NULL; + + klass->info.nred_shades = 6; + klass->info.ngreen_shades = 6; + klass->info.nblue_shades = 4; + klass->info.ngray_shades = 24; + klass->info.nreserved = 0; + + klass->info.bpp = 0; + klass->info.cmap_alloced = FALSE; + klass->info.gamma = 1.0; + } + + klass->image = NULL; + + gtk_preview_get_visuals (klass); + gtk_preview_get_cmaps (klass); + gtk_preview_dither_init (klass); +} + +static void +gtk_preview_init (GtkPreview *preview) +{ + GTK_WIDGET_SET_FLAGS (preview, GTK_BASIC); + + preview->buffer = NULL; + preview->buffer_width = 0; + preview->buffer_height = 0; + preview->expand = FALSE; +} + +void +gtk_preview_uninit () +{ + GtkPreviewProp *prop; + GdkAtom property; + + if (preview_class && !install_cmap && + (preview_class->info.visual->type != GDK_VISUAL_TRUE_COLOR) && + (preview_class->info.visual->type != GDK_VISUAL_DIRECT_COLOR)) + { + property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE); + + if (gdk_property_get (NULL, property, property, + 0, sizeof (GtkPreviewProp), FALSE, + NULL, NULL, NULL, (guchar**) &prop)) + { + prop->ref_count = ntohs (prop->ref_count) - 1; + if (prop->ref_count == 0) + { + gdk_property_delete (NULL, property); + } + else + { + prop->ref_count = htons (prop->ref_count); + gdk_property_change (NULL, property, property, 16, + GDK_PROP_MODE_REPLACE, + (guchar*) prop, 5); + } + } + } +} + +GtkWidget* +gtk_preview_new (GtkPreviewType type) +{ + GtkPreview *preview; + + preview = gtk_type_new (gtk_preview_get_type ()); + preview->type = type; + + return GTK_WIDGET (preview); +} + +void +gtk_preview_size (GtkPreview *preview, + gint width, + gint height) +{ + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + + if ((width != GTK_WIDGET (preview)->requisition.width) || + (height != GTK_WIDGET (preview)->requisition.height)) + { + GTK_WIDGET (preview)->requisition.width = width; + GTK_WIDGET (preview)->requisition.height = height; + + if (preview->buffer) + g_free (preview->buffer); + preview->buffer = NULL; + } +} + +void +gtk_preview_put (GtkPreview *preview, + GdkWindow *window, + GdkGC *gc, + gint srcx, + gint srcy, + gint destx, + gint desty, + gint width, + gint height) +{ + GtkWidget *widget; + GdkImage *image; + GdkRectangle r1, r2, r3; + GtkTransferFunc transfer_func; + guchar *image_mem; + guchar *src, *dest; + gint x, xe, x2; + gint y, ye, y2; + guint dest_rowstride; + guint src_bpp; + guint dest_bpp; + gint i; + + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + g_return_if_fail (window != NULL); + + if (!preview->buffer) + return; + + widget = GTK_WIDGET (preview); + + r1.x = srcx; + r1.y = srcy; + r1.width = preview->buffer_width; + r1.height = preview->buffer_height; + + r2.x = destx; + r2.y = desty; + r2.width = width; + r2.height = height; + + if (!gdk_rectangle_intersect (&r1, &r2, &r3)) + return; + + x2 = r3.x + r3.width; + y2 = r3.y + r3.height; + + if (!preview_class->image) + preview_class->image = gdk_image_new (GDK_IMAGE_FASTEST, + preview_class->info.visual, + IMAGE_SIZE, IMAGE_SIZE); + image = preview_class->image; + src_bpp = preview_class->info.bpp; + + image_mem = image->mem; + dest_bpp = image->bpp; + dest_rowstride = image->bpl; + + transfer_func = NULL; + + switch (dest_bpp) + { + case 1: + switch (src_bpp) + { + case 1: + transfer_func = gtk_lsbmsb_1_1; + break; + } + break; + case 2: + switch (src_bpp) + { + case 2: + if (image->byte_order == GDK_MSB_FIRST) + transfer_func = gtk_msb_2_2; + else + transfer_func = gtk_lsb_2_2; + break; + case 3: + break; + } + break; + case 3: + switch (src_bpp) + { + case 3: + if (image->byte_order == GDK_MSB_FIRST) + transfer_func = gtk_msb_3_3; + else + transfer_func = gtk_lsb_3_3; + break; + } + break; + case 4: + switch (src_bpp) + { + case 3: + if (image->byte_order == GDK_MSB_FIRST) + transfer_func = gtk_msb_3_4; + else + transfer_func = gtk_lsb_3_4; + break; + } + break; + } + + if (!transfer_func) + { + g_warning ("unsupported byte order/src bpp/dest bpp combination: %s:%d:%d", + (image->byte_order == GDK_MSB_FIRST) ? "msb" : "lsb", src_bpp, dest_bpp); + return; + } + + for (y = r3.y; y < y2; y += IMAGE_SIZE) + { + for (x = r3.x; x < x2; x += IMAGE_SIZE) + { + xe = x + IMAGE_SIZE; + if (xe > x2) + xe = x2; + + ye = y + IMAGE_SIZE; + if (ye > y2) + ye = y2; + + for (i = y; i < ye; i++) + { + src = preview->buffer + (((gulong) (i - r1.y) * (gulong) preview->buffer_width) + + (x - r1.x)) * (gulong) src_bpp; + dest = image_mem + ((gulong) (i - y) * dest_rowstride); + + if (xe > x) + (* transfer_func) (dest, src, xe - x); + } + + gdk_draw_image (window, gc, + image, 0, 0, x, y, + xe - x, ye - y); + gdk_flush (); + } + } +} + +void +gtk_preview_put_row (GtkPreview *preview, + guchar *src, + guchar *dest, + gint x, + gint y, + gint w) +{ + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + g_return_if_fail (src != NULL); + g_return_if_fail (dest != NULL); + + switch (preview->type) + { + case GTK_PREVIEW_COLOR: + switch (preview_class->info.visual->depth) + { + case 8: + gtk_color_8 (src, dest, x, y, w); + break; + case 15: + case 16: + gtk_color_16 (src, dest, w); + break; + case 24: + case 32: + gtk_color_24 (src, dest, w); + break; + } + break; + case GTK_PREVIEW_GRAYSCALE: + switch (preview_class->info.visual->depth) + { + case 8: + gtk_grayscale_8 (src, dest, x, y, w); + break; + case 15: + case 16: + gtk_grayscale_16 (src, dest, w); + break; + case 24: + case 32: + gtk_grayscale_24 (src, dest, w); + break; + } + break; + } +} + +void +gtk_preview_draw_row (GtkPreview *preview, + guchar *data, + gint x, + gint y, + gint w) +{ + guchar *dest; + + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + g_return_if_fail (data != NULL); + + if ((w <= 0) || (y < 0)) + return; + + g_return_if_fail (data != NULL); + + gtk_preview_make_buffer (preview); + + if (y >= preview->buffer_height) + return; + + switch (preview->type) + { + case GTK_PREVIEW_COLOR: + switch (preview_class->info.visual->depth) + { + case 8: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x); + gtk_color_8 (data, dest, x, y, w); + break; + case 15: + case 16: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2; + gtk_color_16 (data, dest, w); + break; + case 24: + case 32: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3; + gtk_color_24 (data, dest, w); + break; + } + break; + case GTK_PREVIEW_GRAYSCALE: + switch (preview_class->info.visual->depth) + { + case 8: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x); + gtk_grayscale_8 (data, dest, x, y, w); + break; + case 15: + case 16: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2; + gtk_grayscale_16 (data, dest, w); + break; + case 24: + case 32: + dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3; + gtk_grayscale_24 (data, dest, w); + break; + } + break; + } +} + +void +gtk_preview_set_expand (GtkPreview *preview, + gint expand) +{ + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + + preview->expand = (expand != FALSE); +} + +void +gtk_preview_set_gamma (double _gamma) +{ + g_return_if_fail (preview_class == NULL); + + if (!preview_info) + { + preview_info = g_new0 (GtkPreviewInfo, 1); + preview_info->nred_shades = 6; + preview_info->ngreen_shades = 6; + preview_info->nblue_shades = 4; + preview_info->ngray_shades = 24; + } + + preview_info->gamma = _gamma; +} + +void +gtk_preview_set_color_cube (guint nred_shades, + guint ngreen_shades, + guint nblue_shades, + guint ngray_shades) +{ + g_return_if_fail (preview_class == NULL); + + if (!preview_info) + { + preview_info = g_new0 (GtkPreviewInfo, 1); + preview_info->gamma = 1.0; + } + + preview_info->nred_shades = nred_shades; + preview_info->ngreen_shades = ngreen_shades; + preview_info->nblue_shades = nblue_shades; + preview_info->ngray_shades = ngray_shades; +} + +void +gtk_preview_set_install_cmap (gint _install_cmap) +{ + /* g_return_if_fail (preview_class == NULL); */ + + install_cmap = _install_cmap; +} + +void +gtk_preview_set_reserved (gint nreserved) +{ + if (!preview_info) + preview_info = g_new0 (GtkPreviewInfo, 1); + + preview_info->nreserved = nreserved; +} + +GdkVisual* +gtk_preview_get_visual () +{ + if (!preview_class) + preview_class = gtk_type_class (gtk_preview_get_type ()); + + return preview_class->info.visual; +} + +GdkColormap* +gtk_preview_get_cmap () +{ + if (!preview_class) + preview_class = gtk_type_class (gtk_preview_get_type ()); + + return preview_class->info.cmap; +} + +GtkPreviewInfo* +gtk_preview_get_info () +{ + if (!preview_class) + preview_class = gtk_type_class (gtk_preview_get_type ()); + + return &preview_class->info; +} + + +static void +gtk_preview_destroy (GtkObject *object) +{ + GtkPreview *preview; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_PREVIEW (object)); + + preview = GTK_PREVIEW (object); + if (preview->buffer) + g_free (preview->buffer); + preview->type = (GtkPreviewType) -1; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_preview_realize (GtkWidget *widget) +{ + GtkPreview *preview; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PREVIEW (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + preview = GTK_PREVIEW (widget); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_preview_unrealize (GtkWidget *widget) +{ + GtkPreview *preview; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PREVIEW (widget)); + + preview = GTK_PREVIEW (widget); + + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +} + +static gint +gtk_preview_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkPreview *preview; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + preview = GTK_PREVIEW (widget); + + gtk_preview_put (GTK_PREVIEW (widget), + widget->window, widget->style->black_gc, + (widget->allocation.width - preview->buffer_width) / 2, + (widget->allocation.height - preview->buffer_height) / 2, + event->area.x, event->area.y, + event->area.width, event->area.height); + } + + return FALSE; +} + +static void +gtk_preview_make_buffer (GtkPreview *preview) +{ + GtkWidget *widget; + gint width; + gint height; + + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_PREVIEW (preview)); + + widget = GTK_WIDGET (preview); + + if (preview->expand && + (widget->allocation.width != 0) && + (widget->allocation.height != 0)) + { + width = widget->allocation.width; + height = widget->allocation.height; + } + else + { + width = widget->requisition.width; + height = widget->requisition.height; + } + + if (!preview->buffer || + (preview->buffer_width != width) || + (preview->buffer_height != height)) + { + if (preview->buffer) + g_free (preview->buffer); + + preview->buffer_width = width; + preview->buffer_height = height; + + preview->buffer = g_new0 (guchar, + preview->buffer_width * + preview->buffer_height * + preview_class->info.bpp); + } +} + +static void +gtk_preview_get_visuals (GtkPreviewClass *klass) +{ + static GdkVisualType types[] = + { + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_TRUE_COLOR, + GDK_VISUAL_DIRECT_COLOR, + GDK_VISUAL_PSEUDO_COLOR + }; + static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8 }; + static gint nvisual_types = sizeof (types) / sizeof (types[0]); + + int i; + + g_return_if_fail (klass != NULL); + + if (!klass->info.visual) + for (i = 0; i < nvisual_types; i++) + if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i]))) + { + if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) || + (klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR)) + { + klass->info.lookup_red = g_new (gulong, 256); + klass->info.lookup_green = g_new (gulong, 256); + klass->info.lookup_blue = g_new (gulong, 256); + + gtk_fill_lookup_array (klass->info.lookup_red, + klass->info.visual->depth, + klass->info.visual->red_shift, + 8 - klass->info.visual->red_prec); + gtk_fill_lookup_array (klass->info.lookup_green, + klass->info.visual->depth, + klass->info.visual->green_shift, + 8 - klass->info.visual->green_prec); + gtk_fill_lookup_array (klass->info.lookup_blue, + klass->info.visual->depth, + klass->info.visual->blue_shift, + 8 - klass->info.visual->blue_prec); + } + break; + } + + if (!klass->info.visual) + { + g_warning ("unable to find a suitable visual for color image display.\n"); + return; + } + + switch (klass->info.visual->depth) + { + case 8: + klass->info.bpp = 1; + break; + case 15: + case 16: + klass->info.bpp = 2; + break; + case 24: + case 32: + klass->info.bpp = 3; + break; + } +} + +static void +gtk_preview_get_cmaps (GtkPreviewClass *klass) +{ + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->info.visual != NULL); + + if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) && + (klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR)) + { + if (install_cmap) + { + klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE); + klass->info.cmap_alloced = install_cmap; + + gtk_trim_cmap (klass); + gtk_create_8_bit (klass); + } + else + { + guint nred; + guint ngreen; + guint nblue; + guint ngray; + gint set_prop; + + klass->info.cmap = gdk_colormap_get_system (); + + set_prop = TRUE; + if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray)) + { + set_prop = FALSE; + + klass->info.nred_shades = nred; + klass->info.ngreen_shades = ngreen; + klass->info.nblue_shades = nblue; + klass->info.ngray_shades = ngray; + + if (klass->info.nreserved) + { + klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved); + if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, + klass->info.reserved_pixels, + klass->info.nreserved)) + { + g_free (klass->info.reserved_pixels); + klass->info.reserved_pixels = NULL; + } + } + } + else + { + gtk_trim_cmap (klass); + } + + gtk_create_8_bit (klass); + + if (set_prop) + gtk_set_preview_prop (klass->info.nred_shades, + klass->info.ngreen_shades, + klass->info.nblue_shades, + klass->info.ngray_shades); + } + } + else + { + if (klass->info.visual == gdk_visual_get_system ()) + klass->info.cmap = gdk_colormap_get_system (); + else + klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE); + klass->info.cmap_alloced = TRUE; + + klass->info.nred_shades = 0; + klass->info.ngreen_shades = 0; + klass->info.nblue_shades = 0; + klass->info.ngray_shades = 0; + } +} + +static void +gtk_preview_dither_init (GtkPreviewClass *klass) +{ + int i, j, k; + unsigned char low_shade, high_shade; + unsigned short index; + long red_mult, green_mult; + double red_matrix_width; + double green_matrix_width; + double blue_matrix_width; + double gray_matrix_width; + double red_colors_per_shade; + double green_colors_per_shade; + double blue_colors_per_shade; + double gray_colors_per_shade; + gulong *gray_pixels; + gint shades_r, shades_g, shades_b, shades_gray; + GtkDitherInfo *red_ordered_dither; + GtkDitherInfo *green_ordered_dither; + GtkDitherInfo *blue_ordered_dither; + GtkDitherInfo *gray_ordered_dither; + guchar ***dither_matrix; + guchar DM[8][8] = + { + { 0, 32, 8, 40, 2, 34, 10, 42 }, + { 48, 16, 56, 24, 50, 18, 58, 26 }, + { 12, 44, 4, 36, 14, 46, 6, 38 }, + { 60, 28, 52, 20, 62, 30, 54, 22 }, + { 3, 35, 11, 43, 1, 33, 9, 41 }, + { 51, 19, 59, 27, 49, 17, 57, 25 }, + { 15, 47, 7, 39, 13, 45, 5, 37 }, + { 63, 31, 55, 23, 61, 29, 53, 21 } + }; + + if (klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR) + return; + + shades_r = klass->info.nred_shades; + shades_g = klass->info.ngreen_shades; + shades_b = klass->info.nblue_shades; + shades_gray = klass->info.ngray_shades; + + red_mult = shades_g * shades_b; + green_mult = shades_b; + + red_colors_per_shade = 255.0 / (shades_r - 1); + red_matrix_width = red_colors_per_shade / 64; + + green_colors_per_shade = 255.0 / (shades_g - 1); + green_matrix_width = green_colors_per_shade / 64; + + blue_colors_per_shade = 255.0 / (shades_b - 1); + blue_matrix_width = blue_colors_per_shade / 64; + + gray_colors_per_shade = 255.0 / (shades_gray - 1); + gray_matrix_width = gray_colors_per_shade / 64; + + /* alloc the ordered dither arrays for accelerated dithering */ + + klass->info.dither_red = g_new (GtkDitherInfo, 256); + klass->info.dither_green = g_new (GtkDitherInfo, 256); + klass->info.dither_blue = g_new (GtkDitherInfo, 256); + klass->info.dither_gray = g_new (GtkDitherInfo, 256); + + red_ordered_dither = klass->info.dither_red; + green_ordered_dither = klass->info.dither_green; + blue_ordered_dither = klass->info.dither_blue; + gray_ordered_dither = klass->info.dither_gray; + + dither_matrix = g_new (guchar**, 8); + for (i = 0; i < 8; i++) + { + dither_matrix[i] = g_new (guchar*, 8); + for (j = 0; j < 8; j++) + dither_matrix[i][j] = g_new (guchar, 65); + } + + klass->info.dither_matrix = dither_matrix; + + /* setup the ordered_dither_matrices */ + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + for (k = 0; k <= 64; k++) + dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0; + + /* setup arrays containing three bytes of information for red, green, & blue */ + /* the arrays contain : + * 1st byte: low end shade value + * 2nd byte: high end shade value + * 3rd & 4th bytes: ordered dither matrix index + */ + + gray_pixels = klass->info.gray_pixels; + + for (i = 0; i < 256; i++) + { + + /* setup the red information */ + { + low_shade = (unsigned char) (i / red_colors_per_shade); + if (low_shade == (shades_r - 1)) + low_shade--; + high_shade = low_shade + 1; + + index = (unsigned short) + (((double) i - low_shade * red_colors_per_shade) / + red_matrix_width); + + low_shade *= red_mult; + high_shade *= red_mult; + + red_ordered_dither[i].s[1] = index; + red_ordered_dither[i].c[0] = low_shade; + red_ordered_dither[i].c[1] = high_shade; + } + + + /* setup the green information */ + { + low_shade = (unsigned char) (i / green_colors_per_shade); + if (low_shade == (shades_g - 1)) + low_shade--; + high_shade = low_shade + 1; + + index = (unsigned short) + (((double) i - low_shade * green_colors_per_shade) / + green_matrix_width); + + low_shade *= green_mult; + high_shade *= green_mult; + + green_ordered_dither[i].s[1] = index; + green_ordered_dither[i].c[0] = low_shade; + green_ordered_dither[i].c[1] = high_shade; + } + + + /* setup the blue information */ + { + low_shade = (unsigned char) (i / blue_colors_per_shade); + if (low_shade == (shades_b - 1)) + low_shade--; + high_shade = low_shade + 1; + + index = (unsigned short) + (((double) i - low_shade * blue_colors_per_shade) / + blue_matrix_width); + + blue_ordered_dither[i].s[1] = index; + blue_ordered_dither[i].c[0] = low_shade; + blue_ordered_dither[i].c[1] = high_shade; + } + + + /* setup the gray information */ + { + low_shade = (unsigned char) (i / gray_colors_per_shade); + if (low_shade == (shades_gray - 1)) + low_shade--; + high_shade = low_shade + 1; + + index = (unsigned short) + (((double) i - low_shade * gray_colors_per_shade) / + gray_matrix_width); + + gray_ordered_dither[i].s[1] = index; + gray_ordered_dither[i].c[0] = gray_pixels[low_shade]; + gray_ordered_dither[i].c[1] = gray_pixels[high_shade]; + } + } +} + +static void +gtk_fill_lookup_array (gulong *array, + int depth, + int shift, + int prec) +{ + double one_over_gamma; + double ind; + int val; + int i; + + if (preview_class->info.gamma != 0.0) + one_over_gamma = 1.0 / preview_class->info.gamma; + else + one_over_gamma = 1.0; + + for (i = 0; i < 256; i++) + { + if (one_over_gamma == 1.0) + array[i] = ((i >> prec) << shift); + else + { + ind = (double) i / 255.0; + val = (int) (255 * pow (ind, one_over_gamma)); + array[i] = ((val >> prec) << shift); + } + } +} + +static void +gtk_trim_cmap (GtkPreviewClass *klass) +{ + gulong pixels[256]; + guint nred; + guint ngreen; + guint nblue; + guint ngray; + guint nreserved; + guint total; + guint tmp; + gint success; + + nred = klass->info.nred_shades; + ngreen = klass->info.ngreen_shades; + nblue = klass->info.nblue_shades; + ngray = klass->info.ngray_shades; + nreserved = klass->info.nreserved; + + success = FALSE; + while (!success) + { + total = nred * ngreen * nblue + ngray + nreserved; + + if (total <= 256) + { + if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2)) + success = TRUE; + else + { + success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total); + if (success) + { + if (nreserved > 0) + { + klass->info.reserved_pixels = g_new (gulong, nreserved); + memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved); + gdk_colors_free (klass->info.cmap, &pixels[nreserved], + total - nreserved, 0); + } + else + { + gdk_colors_free (klass->info.cmap, pixels, total, 0); + } + } + } + } + + if (!success) + { + if ((nblue >= nred) && (nblue >= ngreen)) + nblue = nblue - 1; + else if ((nred >= ngreen) && (nred >= nblue)) + nred = nred - 1; + else + { + tmp = log (ngray) / log (2); + + if (ngreen >= tmp) + ngreen = ngreen - 1; + else + ngray -= 1; + } + } + } + + if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2)) + { + g_print ("Unable to allocate sufficient colormap entries.\n"); + g_print ("Try exiting other color intensive applications.\n"); + return; + } + + /* If any of the shade values has changed, issue a warning */ + if ((nred != klass->info.nred_shades) || + (ngreen != klass->info.ngreen_shades) || + (nblue != klass->info.nblue_shades) || + (ngray != klass->info.ngray_shades)) + { + g_print ("Not enough colors to satisfy requested color cube.\n"); + g_print ("Reduced color cube shades from\n"); + g_print ("[%d of Red, %d of Green, %d of Blue, %d of Gray] ==> [%d of Red, %d of Green, %d of Blue, %d of Gray]\n", + klass->info.nred_shades, klass->info.ngreen_shades, + klass->info.nblue_shades, klass->info.ngray_shades, + nred, ngreen, nblue, ngray); + } + + klass->info.nred_shades = nred; + klass->info.ngreen_shades = ngreen; + klass->info.nblue_shades = nblue; + klass->info.ngray_shades = ngray; +} + +static void +gtk_create_8_bit (GtkPreviewClass *klass) +{ + unsigned int r, g, b; + unsigned int rv, gv, bv; + unsigned int dr, dg, db, dgray; + GdkColor color; + gulong *pixels; + double one_over_gamma; + int i; + + if (!klass->info.color_pixels) + klass->info.color_pixels = g_new (gulong, 256); + + if (!klass->info.gray_pixels) + klass->info.gray_pixels = g_new (gulong, 256); + + if (klass->info.gamma != 0.0) + one_over_gamma = 1.0 / klass->info.gamma; + else + one_over_gamma = 1.0; + + dr = klass->info.nred_shades - 1; + dg = klass->info.ngreen_shades - 1; + db = klass->info.nblue_shades - 1; + dgray = klass->info.ngray_shades - 1; + + pixels = klass->info.color_pixels; + + for (r = 0, i = 0; r <= dr; r++) + for (g = 0; g <= dg; g++) + for (b = 0; b <= db; b++, i++) + { + rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr); + gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg); + bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db); + color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257; + color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257; + color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257; + + if (!gdk_color_alloc (klass->info.cmap, &color)) + { + g_error ("could not initialize 8-bit combined colormap"); + return; + } + + pixels[i] = color.pixel; + } + + pixels = klass->info.gray_pixels; + + for (i = 0; i < (int) klass->info.ngray_shades; i++) + { + color.red = (i * klass->info.visual->colormap_size) / dgray; + color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257; + color.green = color.red; + color.blue = color.red; + + if (!gdk_color_alloc (klass->info.cmap, &color)) + { + g_error ("could not initialize 8-bit combined colormap"); + return; + } + + pixels[i] = color.pixel; + } +} + + +static void +gtk_color_8 (guchar *src, + guchar *dest, + gint x, + gint y, + gulong width) +{ + gulong *colors; + GtkDitherInfo *dither_red; + GtkDitherInfo *dither_green; + GtkDitherInfo *dither_blue; + GtkDitherInfo r, g, b; + guchar **dither_matrix; + guchar *matrix; + + colors = preview_class->info.color_pixels; + dither_red = preview_class->info.dither_red; + dither_green = preview_class->info.dither_green; + dither_blue = preview_class->info.dither_blue; + dither_matrix = preview_class->info.dither_matrix[y & 0x7]; + + while (width--) + { + r = dither_red[src[0]]; + g = dither_green[src[1]]; + b = dither_blue[src[2]]; + src += 3; + + matrix = dither_matrix[x++ & 0x7]; + *dest++ = colors[(r.c[matrix[r.s[1]]] + + g.c[matrix[g.s[1]]] + + b.c[matrix[b.s[1]]])]; + } +} + +static void +gtk_color_16 (guchar *src, + guchar *dest, + gulong width) +{ + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + gulong val; + + lookup_red = preview_class->info.lookup_red; + lookup_green = preview_class->info.lookup_green; + lookup_blue = preview_class->info.lookup_blue; + + while (width--) + { + val = COLOR_COMPOSE (src[0], src[1], src[2]); + dest[0] = val; + dest[1] = val >> 8; + dest += 2; + src += 3; + } +} + +static void +gtk_color_24 (guchar *src, + guchar *dest, + gulong width) +{ + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + gulong val; + + lookup_red = preview_class->info.lookup_red; + lookup_green = preview_class->info.lookup_green; + lookup_blue = preview_class->info.lookup_blue; + + while (width--) + { + val = COLOR_COMPOSE (src[0], src[1], src[2]); + dest[0] = val; + dest[1] = val >> 8; + dest[2] = val >> 16; + dest += 3; + src += 3; + } +} + +static void +gtk_grayscale_8 (guchar *src, + guchar *dest, + gint x, + gint y, + gulong width) +{ + GtkDitherInfo *dither_gray; + GtkDitherInfo gray; + guchar **dither_matrix; + guchar *matrix; + + dither_gray = preview_class->info.dither_gray; + dither_matrix = preview_class->info.dither_matrix[y & 0x7]; + + while (width--) + { + gray = dither_gray[*src++]; + matrix = dither_matrix[x++ & 0x7]; + *dest++ = gray.c[matrix[gray.s[1]]]; + } +} + +static void +gtk_grayscale_16 (guchar *src, + guchar *dest, + gulong width) +{ + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + gulong val; + + lookup_red = preview_class->info.lookup_red; + lookup_green = preview_class->info.lookup_green; + lookup_blue = preview_class->info.lookup_blue; + + while (width--) + { + val = COLOR_COMPOSE (*src, *src, *src); + dest[0] = val; + dest[1] = val >> 8; + dest += 2; + src += 1; + } +} + +static void +gtk_grayscale_24 (guchar *src, + guchar *dest, + gulong width) +{ + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + gulong val; + + lookup_red = preview_class->info.lookup_red; + lookup_green = preview_class->info.lookup_green; + lookup_blue = preview_class->info.lookup_blue; + + while (width--) + { + val = COLOR_COMPOSE (*src, *src, *src); + dest[0] = val; + dest[1] = val >> 8; + dest[2] = val >> 16; + dest += 3; + src += 1; + } +} + + +static gint +gtk_get_preview_prop (guint *nred, + guint *ngreen, + guint *nblue, + guint *ngray) +{ + GtkPreviewProp *prop; + GdkAtom property; + + property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE); + + if (gdk_property_get (NULL, property, property, + 0, sizeof (GtkPreviewProp), FALSE, + NULL, NULL, NULL, (guchar**) &prop)) + { + *nred = ntohs (prop->nred_shades); + *ngreen = ntohs (prop->ngreen_shades); + *nblue = ntohs (prop->nblue_shades); + *ngray = ntohs (prop->ngray_shades); + + prop->ref_count = htons (ntohs (prop->ref_count) + 1); + gdk_property_change (NULL, property, property, 16, + GDK_PROP_MODE_REPLACE, + (guchar*) prop, 5); + + return TRUE; + } + + return FALSE; +} + +static void +gtk_set_preview_prop (guint nred, + guint ngreen, + guint nblue, + guint ngray) +{ + GtkPreviewProp prop; + GdkAtom property; + + property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE); + + prop.ref_count = htons (1); + prop.nred_shades = htons (nred); + prop.ngreen_shades = htons (ngreen); + prop.nblue_shades = htons (nblue); + prop.ngray_shades = htons (ngray); + + gdk_property_change (NULL, property, property, 16, + GDK_PROP_MODE_REPLACE, + (guchar*) &prop, 5); +} + + +static void +gtk_lsbmsb_1_1 (guchar *dest, + guchar *src, + gint count) +{ + memcpy (dest, src, count); +} + +static void +gtk_lsb_2_2 (guchar *dest, + guchar *src, + gint count) +{ + memcpy (dest, src, count * 2); +} + +static void +gtk_msb_2_2 (guchar *dest, + guchar *src, + gint count) +{ + while (count--) + { + dest[0] = src[1]; + dest[1] = src[0]; + dest += 2; + src += 2; + } +} + +static void +gtk_lsb_3_3 (guchar *dest, + guchar *src, + gint count) +{ + memcpy (dest, src, count * 3); +} + +static void +gtk_msb_3_3 (guchar *dest, + guchar *src, + gint count) +{ + while (count--) + { + dest[0] = src[2]; + dest[1] = src[1]; + dest[2] = src[0]; + dest += 3; + src += 3; + } +} + +static void +gtk_lsb_3_4 (guchar *dest, + guchar *src, + gint count) +{ + while (count--) + { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest += 4; + src += 3; + } +} + +static void +gtk_msb_3_4 (guchar *dest, + guchar *src, + gint count) +{ + while (count--) + { + dest[1] = src[2]; + dest[2] = src[1]; + dest[3] = src[0]; + dest += 4; + src += 3; + } +} diff --git a/gtk/gtkpreview.h b/gtk/gtkpreview.h new file mode 100644 index 000000000..2fe6ad5e0 --- /dev/null +++ b/gtk/gtkpreview.h @@ -0,0 +1,144 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_PREVIEW_H__ +#define __GTK_PREVIEW_H__ + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_PREVIEW(obj) GTK_CHECK_CAST (obj, gtk_preview_get_type (), GtkPreview) +#define GTK_PREVIEW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_preview_get_type (), GtkPreviewClass) +#define GTK_IS_PREVIEW(obj) GTK_CHECK_TYPE (obj, gtk_preview_get_type ()) + + +typedef struct _GtkPreview GtkPreview; +typedef struct _GtkPreviewInfo GtkPreviewInfo; +typedef union _GtkDitherInfo GtkDitherInfo; +typedef struct _GtkPreviewClass GtkPreviewClass; + +struct _GtkPreview +{ + GtkWidget widget; + + guchar *buffer; + guint16 buffer_width; + guint16 buffer_height; + + guint type : 1; + guint expand : 1; +}; + +struct _GtkPreviewInfo +{ + GdkVisual *visual; + GdkColormap *cmap; + + gulong *color_pixels; + gulong *gray_pixels; + gulong *reserved_pixels; + + gulong *lookup_red; + gulong *lookup_green; + gulong *lookup_blue; + + GtkDitherInfo *dither_red; + GtkDitherInfo *dither_green; + GtkDitherInfo *dither_blue; + GtkDitherInfo *dither_gray; + guchar ***dither_matrix; + + guint nred_shades; + guint ngreen_shades; + guint nblue_shades; + guint ngray_shades; + guint nreserved; + + guint bpp; + gint cmap_alloced; + gdouble gamma; +}; + +union _GtkDitherInfo +{ + gushort s[2]; + guchar c[4]; +}; + +struct _GtkPreviewClass +{ + GtkWidgetClass parent_class; + + GtkPreviewInfo info; + + GdkImage *image; +}; + + +guint gtk_preview_get_type (void); +void gtk_preview_uninit (void); +GtkWidget* gtk_preview_new (GtkPreviewType type); +void gtk_preview_size (GtkPreview *preview, + gint width, + gint height); +void gtk_preview_put (GtkPreview *preview, + GdkWindow *window, + GdkGC *gc, + gint srcx, + gint srcy, + gint destx, + gint desty, + gint width, + gint height); +void gtk_preview_put_row (GtkPreview *preview, + guchar *src, + guchar *dest, + gint x, + gint y, + gint w); +void gtk_preview_draw_row (GtkPreview *preview, + guchar *data, + gint x, + gint y, + gint w); +void gtk_preview_set_expand (GtkPreview *preview, + gint expand); + +void gtk_preview_set_gamma (double gamma); +void gtk_preview_set_color_cube (guint nred_shades, + guint ngreen_shades, + guint nblue_shades, + guint ngray_shades); +void gtk_preview_set_install_cmap (gint install_cmap); +void gtk_preview_set_reserved (gint nreserved); +GdkVisual* gtk_preview_get_visual (void); +GdkColormap* gtk_preview_get_cmap (void); +GtkPreviewInfo* gtk_preview_get_info (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_PREVIEW_H__ */ diff --git a/gtk/gtkprogressbar.c b/gtk/gtkprogressbar.c new file mode 100644 index 000000000..8db560ba0 --- /dev/null +++ b/gtk/gtkprogressbar.c @@ -0,0 +1,259 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkprogressbar.h" + + +#define MIN_WIDTH 200 +#define MIN_HEIGHT 20 + + +static void gtk_progress_bar_class_init (GtkProgressBarClass *klass); +static void gtk_progress_bar_init (GtkProgressBar *pbar); +static void gtk_progress_bar_realize (GtkWidget *widget); +static void gtk_progress_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_progress_bar_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_progress_bar_make_pixmap (GtkProgressBar *pbar); +static void gtk_progress_bar_paint (GtkProgressBar *pbar); + + +guint +gtk_progress_bar_get_type () +{ + static guint progress_bar_type = 0; + + if (!progress_bar_type) + { + GtkTypeInfo progress_bar_info = + { + "GtkProgressBar", + sizeof (GtkProgressBar), + sizeof (GtkProgressBarClass), + (GtkClassInitFunc) gtk_progress_bar_class_init, + (GtkObjectInitFunc) gtk_progress_bar_init, + (GtkArgFunc) NULL, + }; + + progress_bar_type = gtk_type_unique (gtk_widget_get_type (), &progress_bar_info); + } + + return progress_bar_type; +} + +static void +gtk_progress_bar_class_init (GtkProgressBarClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_progress_bar_realize; + widget_class->size_allocate = gtk_progress_bar_size_allocate; + widget_class->expose_event = gtk_progress_bar_expose; +} + +static void +gtk_progress_bar_init (GtkProgressBar *pbar) +{ + GTK_WIDGET_SET_FLAGS (pbar, GTK_BASIC); + + GTK_WIDGET (pbar)->requisition.width = MIN_WIDTH; + GTK_WIDGET (pbar)->requisition.height = MIN_HEIGHT; + pbar->offscreen_pixmap = NULL; + pbar->percentage = 0; +} + + +GtkWidget* +gtk_progress_bar_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_progress_bar_get_type ())); +} + +void +gtk_progress_bar_update (GtkProgressBar *pbar, + gfloat percentage) +{ + g_return_if_fail (pbar != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); + + if (percentage < 0.0) + percentage = 0.0; + else if (percentage > 1.0) + percentage = 1.0; + + if (pbar->percentage != percentage) + { + pbar->percentage = percentage; + gtk_progress_bar_paint (pbar); + gtk_widget_queue_draw (GTK_WIDGET (pbar)); + } +} + +static void +gtk_progress_bar_realize (GtkWidget *widget) +{ + GtkProgressBar *pbar; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (widget)); + + pbar = GTK_PROGRESS_BAR (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_EXPOSURE_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, pbar); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); + + gtk_progress_bar_make_pixmap (pbar); +} + +static void +gtk_progress_bar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gtk_progress_bar_make_pixmap (GTK_PROGRESS_BAR (widget)); + } +} + +static gint +gtk_progress_bar_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkProgressBar *pbar; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PROGRESS_BAR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + pbar = GTK_PROGRESS_BAR (widget); + + gdk_draw_pixmap (widget->window, + widget->style->black_gc, + pbar->offscreen_pixmap, + 0, 0, 0, 0, + widget->allocation.width, + widget->allocation.height); + } + + return FALSE; +} + +static void +gtk_progress_bar_make_pixmap (GtkProgressBar *pbar) +{ + GtkWidget *widget; + + g_return_if_fail (pbar != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); + + if (GTK_WIDGET_REALIZED (pbar)) + { + widget = GTK_WIDGET (pbar); + + if (pbar->offscreen_pixmap) + gdk_pixmap_destroy (pbar->offscreen_pixmap); + + pbar->offscreen_pixmap = gdk_pixmap_new (widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + + gtk_progress_bar_paint (pbar); + } +} + +static void +gtk_progress_bar_paint (GtkProgressBar *pbar) +{ + GtkWidget *widget; + int amount; + + g_return_if_fail (pbar != NULL); + g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); + + if (pbar->offscreen_pixmap) + { + widget = GTK_WIDGET (pbar); + + gtk_draw_shadow (widget->style, + pbar->offscreen_pixmap, + GTK_STATE_NORMAL, GTK_SHADOW_IN, 0, 0, + widget->allocation.width, + widget->allocation.height); + + gdk_draw_rectangle (pbar->offscreen_pixmap, + widget->style->bg_gc[GTK_STATE_ACTIVE], TRUE, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + widget->allocation.width - widget->style->klass->xthickness * 2, + widget->allocation.height - widget->style->klass->ythickness * 2); + + + amount = pbar->percentage * (widget->allocation.width - widget->style->klass->xthickness * 2); + if (amount > 0) + { + gdk_draw_rectangle (pbar->offscreen_pixmap, + widget->style->bg_gc[GTK_STATE_PRELIGHT], TRUE, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + amount, + widget->allocation.height - widget->style->klass->ythickness * 2); + + gtk_draw_shadow (widget->style, + pbar->offscreen_pixmap, + GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + amount, + widget->allocation.height - widget->style->klass->ythickness * 2); + } + } +} diff --git a/gtk/gtkprogressbar.h b/gtk/gtkprogressbar.h new file mode 100644 index 000000000..e831dfb97 --- /dev/null +++ b/gtk/gtkprogressbar.h @@ -0,0 +1,64 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_PROGRESS_BAR_H__ +#define __GTK_PROGRESS_BAR_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_PROGRESS_BAR(obj) GTK_CHECK_CAST (obj, gtk_progress_bar_get_type (), GtkProgressBar) +#define GTK_PROGRESS_BAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_progress_bar_get_type (), GtkProgressBarClass) +#define GTK_IS_PROGRESS_BAR(obj) GTK_CHECK_TYPE (obj, gtk_progress_bar_get_type ()) + + +typedef struct _GtkProgressBar GtkProgressBar; +typedef struct _GtkProgressBarClass GtkProgressBarClass; + +struct _GtkProgressBar +{ + GtkWidget widget; + + GdkPixmap *offscreen_pixmap; + gfloat percentage; +}; + +struct _GtkProgressBarClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_progress_bar_get_type (void); +GtkWidget* gtk_progress_bar_new (void); +void gtk_progress_bar_update (GtkProgressBar *pbar, + gfloat percentage); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_PROGRESS_BAR_H__ */ diff --git a/gtk/gtkradiobutton.c b/gtk/gtkradiobutton.c new file mode 100644 index 000000000..0c52836e9 --- /dev/null +++ b/gtk/gtkradiobutton.c @@ -0,0 +1,321 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtklabel.h" +#include "gtkradiobutton.h" +#include "gtksignal.h" + + +#define CHECK_BUTTON_CLASS(w) GTK_CHECK_BUTTON_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_radio_button_class_init (GtkRadioButtonClass *klass); +static void gtk_radio_button_init (GtkRadioButton *radio_button); +static void gtk_radio_button_destroy (GtkObject *object); +static void gtk_radio_button_clicked (GtkButton *button); +static void gtk_radio_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area); + + +static GtkCheckButtonClass *parent_class = NULL; + + +guint +gtk_radio_button_get_type () +{ + static guint radio_button_type = 0; + + if (!radio_button_type) + { + GtkTypeInfo radio_button_info = + { + "GtkRadioButton", + sizeof (GtkRadioButton), + sizeof (GtkRadioButtonClass), + (GtkClassInitFunc) gtk_radio_button_class_init, + (GtkObjectInitFunc) gtk_radio_button_init, + (GtkArgFunc) NULL, + }; + + radio_button_type = gtk_type_unique (gtk_check_button_get_type (), &radio_button_info); + } + + return radio_button_type; +} + +static void +gtk_radio_button_class_init (GtkRadioButtonClass *class) +{ + GtkObjectClass *object_class; + GtkButtonClass *button_class; + GtkCheckButtonClass *check_button_class; + + object_class = (GtkObjectClass*) class; + button_class = (GtkButtonClass*) class; + check_button_class = (GtkCheckButtonClass*) class; + + parent_class = gtk_type_class (gtk_check_button_get_type ()); + + object_class->destroy = gtk_radio_button_destroy; + + button_class->clicked = gtk_radio_button_clicked; + + check_button_class->draw_indicator = gtk_radio_button_draw_indicator; +} + +static void +gtk_radio_button_init (GtkRadioButton *radio_button) +{ + radio_button->group = NULL; +} + +GtkWidget* +gtk_radio_button_new (GSList *group) +{ + GtkRadioButton *radio_button; + GtkRadioButton *tmp_button; + GSList *tmp_list; + + radio_button = gtk_type_new (gtk_radio_button_get_type ()); + + tmp_list = group; + radio_button->group = g_slist_prepend (group, radio_button); + + if (tmp_list) + { + while (tmp_list) + { + tmp_button = tmp_list->data; + tmp_list = tmp_list->next; + + tmp_button->group = radio_button->group; + } + } + else + { + GTK_TOGGLE_BUTTON (radio_button)->active = TRUE; + gtk_widget_set_state (GTK_WIDGET (radio_button), GTK_STATE_ACTIVE); + } + + return GTK_WIDGET (radio_button); +} + +GtkWidget* +gtk_radio_button_new_with_label (GSList *group, + const gchar *label) +{ + GtkWidget *radio_button; + GtkWidget *label_widget; + + radio_button = gtk_radio_button_new (group); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (radio_button), label_widget); + gtk_widget_show (label_widget); + + return radio_button; +} + +GtkWidget* +gtk_radio_button_new_from_widget (GtkRadioButton *group) +{ + GSList *l = NULL; + if (group) + l = gtk_radio_button_group (group); + return gtk_radio_button_new (l); +} + + +GtkWidget* +gtk_radio_button_new_with_label_from_widget (GtkRadioButton *group, + const gchar *label) +{ + GSList *l = NULL; + if (group) + l = gtk_radio_button_group (group); + return gtk_radio_button_new_with_label (l, label); +} + +GSList* +gtk_radio_button_group (GtkRadioButton *radio_button) +{ + g_return_val_if_fail (radio_button != NULL, NULL); + g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_button), NULL); + + return radio_button->group; +} + + +static void +gtk_radio_button_destroy (GtkObject *object) +{ + GtkRadioButton *radio_button; + GtkRadioButton *tmp_button; + GSList *tmp_list; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_RADIO_BUTTON (object)); + + radio_button = GTK_RADIO_BUTTON (object); + + radio_button->group = g_slist_remove (radio_button->group, radio_button); + tmp_list = radio_button->group; + + while (tmp_list) + { + tmp_button = tmp_list->data; + tmp_list = tmp_list->next; + + tmp_button->group = radio_button->group; + } + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_radio_button_clicked (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkRadioButton *radio_button; + GtkToggleButton *tmp_button; + GtkStateType new_state; + GSList *tmp_list; + gint toggled; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_RADIO_BUTTON (button)); + + radio_button = GTK_RADIO_BUTTON (button); + toggle_button = GTK_TOGGLE_BUTTON (button); + toggled = FALSE; + + if (toggle_button->active) + { + tmp_button = NULL; + tmp_list = radio_button->group; + + while (tmp_list) + { + tmp_button = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_button->active && (tmp_button != toggle_button)) + break; + + tmp_button = NULL; + } + + if (!tmp_button) + { + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + } + else + { + toggled = TRUE; + toggle_button->active = !toggle_button->active; + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + } + } + else + { + toggled = TRUE; + toggle_button->active = !toggle_button->active; + + tmp_list = radio_button->group; + while (tmp_list) + { + tmp_button = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_button->active && (tmp_button != toggle_button)) + { + gtk_button_clicked (GTK_BUTTON (tmp_button)); + break; + } + } + + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + } + + if (GTK_WIDGET_STATE (button) != new_state) + gtk_widget_set_state (GTK_WIDGET (button), new_state); + if (toggled) + gtk_toggle_button_toggled (toggle_button); + gtk_widget_queue_draw (GTK_WIDGET (button)); +} + +static void +gtk_radio_button_draw_indicator (GtkCheckButton *check_button, + GdkRectangle *area) +{ + GtkWidget *widget; + GtkButton *button; + GtkToggleButton *toggle_button; + GtkStateType state_type; + GtkShadowType shadow_type; + GdkPoint pts[4]; + gint width, height; + gint x, y; + + g_return_if_fail (check_button != NULL); + g_return_if_fail (GTK_IS_RADIO_BUTTON (check_button)); + + if (GTK_WIDGET_VISIBLE (check_button) && GTK_WIDGET_MAPPED (check_button)) + { + widget = GTK_WIDGET (check_button); + button = GTK_BUTTON (check_button); + toggle_button = GTK_TOGGLE_BUTTON (check_button); + + state_type = GTK_WIDGET_STATE (widget); + if ((state_type != GTK_STATE_NORMAL) && + (state_type != GTK_STATE_PRELIGHT)) + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (widget->style, widget->window, state_type); + gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height); + + x = CHECK_BUTTON_CLASS (widget)->indicator_spacing + GTK_CONTAINER (widget)->border_width; + y = (widget->allocation.height - CHECK_BUTTON_CLASS (widget)->indicator_size) / 2; + width = CHECK_BUTTON_CLASS (widget)->indicator_size; + height = CHECK_BUTTON_CLASS (widget)->indicator_size; + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + shadow_type = GTK_SHADOW_IN; + else if ((GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) && toggle_button->active) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + pts[0].x = x + width / 2; + pts[0].y = y; + pts[1].x = x + width; + pts[1].y = y + height / 2; + pts[2].x = pts[0].x; + pts[2].y = y + height; + pts[3].x = x; + pts[3].y = pts[1].y; + + gdk_draw_polygon (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], + TRUE, pts, 4); + gtk_draw_diamond (widget->style, widget->window, + GTK_WIDGET_STATE (widget), shadow_type, + x, y, width, height); + } +} diff --git a/gtk/gtkradiobutton.h b/gtk/gtkradiobutton.h new file mode 100644 index 000000000..bf346c27e --- /dev/null +++ b/gtk/gtkradiobutton.h @@ -0,0 +1,69 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_RADIO_BUTTON_H__ +#define __GTK_RADIO_BUTTON_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_RADIO_BUTTON(obj) GTK_CHECK_CAST (obj, gtk_radio_button_get_type (), GtkRadioButton) +#define GTK_RADIO_BUTTON_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_radio_button_get_type (), GtkRadioButtonClass) +#define GTK_IS_RADIO_BUTTON(obj) GTK_CHECK_TYPE (obj, gtk_radio_button_get_type ()) + + +typedef struct _GtkRadioButton GtkRadioButton; +typedef struct _GtkRadioButtonClass GtkRadioButtonClass; + +struct _GtkRadioButton +{ + GtkCheckButton check_button; + + GSList *group; +}; + +struct _GtkRadioButtonClass +{ + GtkCheckButtonClass parent_class; +}; + + +guint gtk_radio_button_get_type (void); +GtkWidget* gtk_radio_button_new (GSList *group); +GtkWidget* gtk_radio_button_new_from_widget (GtkRadioButton *group); +GtkWidget* gtk_radio_button_new_with_label (GSList *group, + const gchar *label); +GtkWidget* gtk_radio_button_new_interp (GtkRadioButton *group); +GtkWidget* gtk_radio_button_new_with_label_interp + (GtkRadioButton *group, + const gchar *label); +GSList* gtk_radio_button_group (GtkRadioButton *radio_button); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RADIO_BUTTON_H__ */ diff --git a/gtk/gtkradiomenuitem.c b/gtk/gtkradiomenuitem.c new file mode 100644 index 000000000..edfcff673 --- /dev/null +++ b/gtk/gtkradiomenuitem.c @@ -0,0 +1,240 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtklabel.h" +#include "gtkradiomenuitem.h" + + +static void gtk_radio_menu_item_class_init (GtkRadioMenuItemClass *klass); +static void gtk_radio_menu_item_init (GtkRadioMenuItem *radio_menu_item); +static void gtk_radio_menu_item_activate (GtkMenuItem *menu_item); +static void gtk_radio_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area); + + +guint +gtk_radio_menu_item_get_type () +{ + static guint radio_menu_item_type = 0; + + if (!radio_menu_item_type) + { + GtkTypeInfo radio_menu_item_info = + { + "GtkRadioMenuItem", + sizeof (GtkRadioMenuItem), + sizeof (GtkRadioMenuItemClass), + (GtkClassInitFunc) gtk_radio_menu_item_class_init, + (GtkObjectInitFunc) gtk_radio_menu_item_init, + (GtkArgFunc) NULL, + }; + + radio_menu_item_type = gtk_type_unique (gtk_check_menu_item_get_type (), &radio_menu_item_info); + } + + return radio_menu_item_type; +} + +GtkWidget* +gtk_radio_menu_item_new (GSList *group) +{ + GtkRadioMenuItem *radio_menu_item; + GtkRadioMenuItem *tmp_menu_item; + GSList *tmp_list; + + radio_menu_item = gtk_type_new (gtk_radio_menu_item_get_type ()); + + tmp_list = group; + radio_menu_item->group = g_slist_prepend (group, radio_menu_item); + + if (tmp_list) + { + while (tmp_list) + { + tmp_menu_item = tmp_list->data; + tmp_list = tmp_list->next; + + tmp_menu_item->group = radio_menu_item->group; + } + } + else + { + GTK_CHECK_MENU_ITEM (radio_menu_item)->active = TRUE; + } + + return GTK_WIDGET (radio_menu_item); +} + +GtkWidget* +gtk_radio_menu_item_new_with_label (GSList *group, + const gchar *label) +{ + GtkWidget *radio_menu_item; + GtkWidget *label_widget; + + radio_menu_item = gtk_radio_menu_item_new (group); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (radio_menu_item), label_widget); + gtk_widget_show (label_widget); + + return radio_menu_item; +} + +GSList* +gtk_radio_menu_item_group (GtkRadioMenuItem *radio_menu_item) +{ + g_return_val_if_fail (radio_menu_item != NULL, NULL); + g_return_val_if_fail (GTK_IS_RADIO_MENU_ITEM (radio_menu_item), NULL); + + return radio_menu_item->group; +} + + +static void +gtk_radio_menu_item_class_init (GtkRadioMenuItemClass *klass) +{ + GtkMenuItemClass *menu_item_class; + GtkCheckMenuItemClass *check_menu_item_class; + + menu_item_class = (GtkMenuItemClass*) klass; + check_menu_item_class = (GtkCheckMenuItemClass*) klass; + + menu_item_class->activate = gtk_radio_menu_item_activate; + + check_menu_item_class->draw_indicator = gtk_radio_menu_item_draw_indicator; +} + +static void +gtk_radio_menu_item_init (GtkRadioMenuItem *radio_menu_item) +{ + radio_menu_item->group = NULL; +} + +static void +gtk_radio_menu_item_activate (GtkMenuItem *menu_item) +{ + GtkRadioMenuItem *radio_menu_item; + GtkCheckMenuItem *check_menu_item; + GtkCheckMenuItem *tmp_menu_item; + GSList *tmp_list; + gint toggled; + + g_return_if_fail (menu_item != NULL); + g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (menu_item)); + + radio_menu_item = GTK_RADIO_MENU_ITEM (menu_item); + check_menu_item = GTK_CHECK_MENU_ITEM (menu_item); + toggled = FALSE; + + if (check_menu_item->active) + { + tmp_menu_item = NULL; + tmp_list = radio_menu_item->group; + + while (tmp_list) + { + tmp_menu_item = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_menu_item->active && (tmp_menu_item != check_menu_item)) + break; + + tmp_menu_item = NULL; + } + + if (tmp_menu_item) + { + toggled = TRUE; + check_menu_item->active = !check_menu_item->active; + } + } + else + { + toggled = TRUE; + check_menu_item->active = !check_menu_item->active; + + tmp_list = radio_menu_item->group; + while (tmp_list) + { + tmp_menu_item = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_menu_item->active && (tmp_menu_item != check_menu_item)) + { + gtk_menu_item_activate (GTK_MENU_ITEM (tmp_menu_item)); + break; + } + } + } + + if (toggled) + gtk_check_menu_item_toggled (check_menu_item); + gtk_widget_queue_draw (GTK_WIDGET (radio_menu_item)); +} + +static void +gtk_radio_menu_item_draw_indicator (GtkCheckMenuItem *check_menu_item, + GdkRectangle *area) +{ + GtkWidget *widget; + GtkStateType state_type; + GtkShadowType shadow_type; + GdkPoint pts[4]; + gint width, height; + gint x, y; + + g_return_if_fail (check_menu_item != NULL); + g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (check_menu_item)); + + if (GTK_WIDGET_DRAWABLE (check_menu_item)) + { + widget = GTK_WIDGET (check_menu_item); + + width = 8; + height = 8; + x = (GTK_CONTAINER (check_menu_item)->border_width + + widget->style->klass->xthickness + 2); + y = (widget->allocation.height - height) / 2; + + gdk_window_clear_area (widget->window, x, y, width, height); + + if (check_menu_item->active || + (GTK_WIDGET_STATE (check_menu_item) == GTK_STATE_PRELIGHT)) + { + state_type = GTK_WIDGET_STATE (widget); + shadow_type = GTK_SHADOW_IN; + + pts[0].x = x + width / 2; + pts[0].y = y; + pts[1].x = x + width; + pts[1].y = y + height / 2; + pts[2].x = pts[0].x; + pts[2].y = y + height; + pts[3].x = x; + pts[3].y = pts[1].y; + + gdk_draw_polygon (widget->window, + widget->style->bg_gc[state_type], + TRUE, pts, 4); + gtk_draw_diamond (widget->style, widget->window, + state_type, shadow_type, + x, y, width, height); + } + } +} diff --git a/gtk/gtkradiomenuitem.h b/gtk/gtkradiomenuitem.h new file mode 100644 index 000000000..28abafc6b --- /dev/null +++ b/gtk/gtkradiomenuitem.h @@ -0,0 +1,64 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_RADIO_MENU_ITEM_H__ +#define __GTK_RADIO_MENU_ITEM_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_RADIO_MENU_ITEM(obj) GTK_CHECK_CAST (obj, gtk_radio_menu_item_get_type (), GtkRadioMenuItem) +#define GTK_RADIO_MENU_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_radio_menu_item_get_type (), GtkRadioMenuItemClass) +#define GTK_IS_RADIO_MENU_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_radio_menu_item_get_type ()) + + +typedef struct _GtkRadioMenuItem GtkRadioMenuItem; +typedef struct _GtkRadioMenuItemClass GtkRadioMenuItemClass; + +struct _GtkRadioMenuItem +{ + GtkCheckMenuItem check_menu_item; + + GSList *group; +}; + +struct _GtkRadioMenuItemClass +{ + GtkCheckMenuItemClass parent_class; +}; + + +guint gtk_radio_menu_item_get_type (void); +GtkWidget* gtk_radio_menu_item_new (GSList *group); +GtkWidget* gtk_radio_menu_item_new_with_label (GSList *group, + const gchar *label); +GSList* gtk_radio_menu_item_group (GtkRadioMenuItem *radio_menu_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RADIO_MENU_ITEM_H__ */ diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c new file mode 100644 index 000000000..f00bbf683 --- /dev/null +++ b/gtk/gtkrange.c @@ -0,0 +1,1369 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkmain.h" +#include "gtkrange.h" +#include "gtksignal.h" + + +#define SCROLL_TIMER_LENGTH 20 +#define SCROLL_INITIAL_DELAY 100 +#define SCROLL_DELAY_LENGTH 300 + +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_range_class_init (GtkRangeClass *klass); +static void gtk_range_init (GtkRange *range); +static void gtk_range_destroy (GtkObject *object); +static void gtk_range_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_range_draw_focus (GtkWidget *widget); +static void gtk_range_unrealize (GtkWidget *widget); +static gint gtk_range_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_range_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_range_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_range_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_range_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_range_enter_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_range_leave_notify (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_range_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_range_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static void gtk_real_range_draw_trough (GtkRange *range); +static void gtk_real_range_draw_slider (GtkRange *range); +static gint gtk_real_range_timer (GtkRange *range); +static gint gtk_range_scroll (GtkRange *range); + +static void gtk_range_add_timer (GtkRange *range); +static void gtk_range_remove_timer (GtkRange *range); + +static void gtk_range_adjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); + +static void gtk_range_trough_hdims (GtkRange *range, + gint *left, + gint *right); +static void gtk_range_trough_vdims (GtkRange *range, + gint *top, + gint *bottom); + +static GtkWidgetClass *parent_class = NULL; + + +guint +gtk_range_get_type () +{ + static guint range_type = 0; + + if (!range_type) + { + GtkTypeInfo range_info = + { + "GtkRange", + sizeof (GtkRange), + sizeof (GtkRangeClass), + (GtkClassInitFunc) gtk_range_class_init, + (GtkObjectInitFunc) gtk_range_init, + (GtkArgFunc) NULL, + }; + + range_type = gtk_type_unique (gtk_widget_get_type (), &range_info); + } + + return range_type; +} + +static void +gtk_range_class_init (GtkRangeClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = gtk_range_destroy; + + widget_class->draw = gtk_range_draw; + widget_class->draw_focus = gtk_range_draw_focus; + widget_class->unrealize = gtk_range_unrealize; + widget_class->expose_event = gtk_range_expose; + widget_class->button_press_event = gtk_range_button_press; + widget_class->button_release_event = gtk_range_button_release; + widget_class->motion_notify_event = gtk_range_motion_notify; + widget_class->key_press_event = gtk_range_key_press; + widget_class->enter_notify_event = gtk_range_enter_notify; + widget_class->leave_notify_event = gtk_range_leave_notify; + widget_class->focus_in_event = gtk_range_focus_in; + widget_class->focus_out_event = gtk_range_focus_out; + + class->slider_width = 11; + class->stepper_size = 11; + class->stepper_slider_spacing = 1; + class->min_slider_size = 7; + class->trough = 1; + class->slider = 2; + class->step_forw = 3; + class->step_back = 4; + class->draw_background = NULL; + class->draw_trough = gtk_real_range_draw_trough; + class->draw_slider = gtk_real_range_draw_slider; + class->draw_step_forw = NULL; + class->draw_step_back = NULL; + class->trough_click = NULL; + class->trough_keys = NULL; + class->motion = NULL; + class->timer = gtk_real_range_timer; +} + +static void +gtk_range_init (GtkRange *range) +{ + range->trough = NULL; + range->slider = NULL; + range->step_forw = NULL; + range->step_back = NULL; + + range->x_click_point = 0; + range->y_click_point = 0; + range->button = 0; + range->digits = -1; + range->policy = GTK_UPDATE_CONTINUOUS; + range->scroll_type = GTK_SCROLL_NONE; + range->in_child = 0; + range->click_child = 0; + range->need_timer = FALSE; + range->timer = 0; + range->old_value = 0.0; + range->old_lower = 0.0; + range->old_upper = 0.0; + range->old_page_size = 0.0; + range->adjustment = NULL; +} + +GtkAdjustment* +gtk_range_get_adjustment (GtkRange *range) +{ + g_return_val_if_fail (range != NULL, NULL); + g_return_val_if_fail (GTK_IS_RANGE (range), NULL); + + return range->adjustment; +} + +void +gtk_range_set_update_policy (GtkRange *range, + GtkUpdateType policy) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + range->policy = policy; +} + +void +gtk_range_set_adjustment (GtkRange *range, + GtkAdjustment *adjustment) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->adjustment) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment), (gpointer) range); + gtk_object_unref (GTK_OBJECT (range->adjustment)); + } + + range->adjustment = adjustment; + gtk_object_ref (GTK_OBJECT (range->adjustment)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) gtk_range_adjustment_changed, + (gpointer) range); + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) gtk_range_adjustment_value_changed, + (gpointer) range); + + range->old_value = adjustment->value; + range->old_lower = adjustment->lower; + range->old_upper = adjustment->upper; + range->old_page_size = adjustment->page_size; + + gtk_range_adjustment_changed (range->adjustment, (gpointer) range); +} + +void +gtk_range_draw_background (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->trough && RANGE_CLASS (range)->draw_background) + (* RANGE_CLASS (range)->draw_background) (range); +} + +void +gtk_range_draw_trough (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->trough && RANGE_CLASS (range)->draw_trough) + (* RANGE_CLASS (range)->draw_trough) (range); +} + +void +gtk_range_draw_slider (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->slider && RANGE_CLASS (range)->draw_slider) + (* RANGE_CLASS (range)->draw_slider) (range); +} + +void +gtk_range_draw_step_forw (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->step_forw && RANGE_CLASS (range)->draw_step_forw) + (* RANGE_CLASS (range)->draw_step_forw) (range); +} + +void +gtk_range_draw_step_back (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->step_back && RANGE_CLASS (range)->draw_step_back) + (* RANGE_CLASS (range)->draw_step_back) (range); +} + +void +gtk_range_slider_update (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (RANGE_CLASS (range)->slider_update) + (* RANGE_CLASS (range)->slider_update) (range); +} + +gint +gtk_range_trough_click (GtkRange *range, + gint x, + gint y) +{ + g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); + g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); + + if (RANGE_CLASS (range)->trough_click) + return (* RANGE_CLASS (range)->trough_click) (range, x, y); + + return GTK_TROUGH_NONE; +} + +void +gtk_range_default_hslider_update (GtkRange *range) +{ + gint left; + gint right; + gint x; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (GTK_WIDGET_REALIZED (range)) + { + gtk_range_trough_hdims (range, &left, &right); + x = left; + + if (range->adjustment->value < range->adjustment->lower) + { + range->adjustment->value = range->adjustment->lower; + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else if (range->adjustment->value > range->adjustment->upper) + { + range->adjustment->value = range->adjustment->upper; + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + + if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size)) + x += ((right - left) * (range->adjustment->value - range->adjustment->lower) / + (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); + + if (x < left) + x = left; + else if (x > right) + x = right; + + gdk_window_move (range->slider, x, GTK_WIDGET (range)->style->klass->ythickness); + } +} + +void +gtk_range_default_vslider_update (GtkRange *range) +{ + gint top; + gint bottom; + gint y; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (GTK_WIDGET_REALIZED (range)) + { + gtk_range_trough_vdims (range, &top, &bottom); + y = top; + + if (range->adjustment->value < range->adjustment->lower) + { + range->adjustment->value = range->adjustment->lower; + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else if (range->adjustment->value > range->adjustment->upper) + { + range->adjustment->value = range->adjustment->upper; + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + + if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size)) + y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) / + (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size)); + + if (y < top) + y = top; + else if (y > bottom) + y = bottom; + + gdk_window_move (range->slider, GTK_WIDGET (range)->style->klass->ythickness, y); + } +} + +gint +gtk_range_default_htrough_click (GtkRange *range, + gint x, + gint y) +{ + gint xthickness; + gint ythickness; + gint trough_width; + gint trough_height; + gint slider_x; + + g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); + g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); + + xthickness = GTK_WIDGET (range)->style->klass->xthickness; + ythickness = GTK_WIDGET (range)->style->klass->ythickness; + + if ((x > xthickness) && (y > ythickness)) + { + gdk_window_get_size (range->trough, &trough_width, &trough_height); + + if ((x < (trough_width - xthickness) && (y < (trough_height - ythickness)))) + { + gdk_window_get_position (range->slider, &slider_x, NULL); + + if (x < slider_x) + return GTK_TROUGH_START; + else + return GTK_TROUGH_END; + } + } + + return GTK_TROUGH_NONE; +} + +gint +gtk_range_default_vtrough_click (GtkRange *range, + gint x, + gint y) +{ + gint xthickness; + gint ythickness; + gint trough_width; + gint trough_height; + gint slider_y; + + g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE); + g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE); + + xthickness = GTK_WIDGET (range)->style->klass->xthickness; + ythickness = GTK_WIDGET (range)->style->klass->ythickness; + + if ((x > xthickness) && (y > ythickness)) + { + gdk_window_get_size (range->trough, &trough_width, &trough_height); + + if ((x < (trough_width - xthickness) && (y < (trough_height - ythickness)))) + { + gdk_window_get_position (range->slider, NULL, &slider_y); + + if (y < slider_y) + return GTK_TROUGH_START; + else + return GTK_TROUGH_END; + } + } + + return GTK_TROUGH_NONE; +} + +void +gtk_range_default_hmotion (GtkRange *range, + gint xdelta, + gint ydelta) +{ + gdouble old_value; + gint left, right; + gint slider_x, slider_y; + gint new_pos; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + range = GTK_RANGE (range); + + gdk_window_get_position (range->slider, &slider_x, &slider_y); + gtk_range_trough_hdims (range, &left, &right); + + if (left == right) + return; + + new_pos = slider_x + xdelta; + + if (new_pos < left) + new_pos = left; + else if (new_pos > right) + new_pos = right; + + old_value = range->adjustment->value; + range->adjustment->value = ((range->adjustment->upper - + range->adjustment->lower - + range->adjustment->page_size) * + (new_pos - left) / (right - left) + + range->adjustment->lower); + + if (range->digits >= 0) + { + char buffer[64]; + + sprintf (buffer, "%0.*f", range->digits, range->adjustment->value); + sscanf (buffer, "%f", &range->adjustment->value); + } + + if (old_value != range->adjustment->value) + { + if (range->policy == GTK_UPDATE_CONTINUOUS) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + + if (range->policy == GTK_UPDATE_DELAYED) + { + gtk_range_remove_timer (range); + range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, + (GtkFunction) RANGE_CLASS (range)->timer, + (gpointer) range); + } + } + } +} + +void +gtk_range_default_vmotion (GtkRange *range, + gint xdelta, + gint ydelta) +{ + gdouble old_value; + gint top, bottom; + gint slider_x, slider_y; + gint new_pos; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + range = GTK_RANGE (range); + + gdk_window_get_position (range->slider, &slider_x, &slider_y); + gtk_range_trough_vdims (range, &top, &bottom); + + if (bottom == top) + return; + + new_pos = slider_y + ydelta; + + if (new_pos < top) + new_pos = top; + else if (new_pos > bottom) + new_pos = bottom; + + old_value = range->adjustment->value; + range->adjustment->value = ((range->adjustment->upper - + range->adjustment->lower - + range->adjustment->page_size) * + (new_pos - top) / (bottom - top) + + range->adjustment->lower); + + if (range->digits >= 0) + { + char buffer[64]; + + sprintf (buffer, "%0.*f", range->digits, range->adjustment->value); + sscanf (buffer, "%f", &range->adjustment->value); + } + + if (old_value != range->adjustment->value) + { + if (range->policy == GTK_UPDATE_CONTINUOUS) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + + if (range->policy == GTK_UPDATE_DELAYED) + { + gtk_range_remove_timer (range); + range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, + (GtkFunction) RANGE_CLASS (range)->timer, + (gpointer) range); + } + } + } +} + +gfloat +gtk_range_calc_value (GtkRange *range, + gint position) +{ + return 0.0; +} + + +static void +gtk_range_destroy (GtkObject *object) +{ + GtkRange *range; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_RANGE (object)); + + range = GTK_RANGE (object); + + if (range->adjustment) + gtk_object_unref (GTK_OBJECT (range->adjustment)); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_range_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkRange *range; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RANGE (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + range = GTK_RANGE (widget); + + gtk_range_draw_background (range); + gtk_range_draw_trough (range); + gtk_range_draw_slider (range); + gtk_range_draw_step_forw (range); + gtk_range_draw_step_back (range); + } +} + +static void +gtk_range_draw_focus (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RANGE (widget)); + + if (GTK_WIDGET_DRAWABLE (widget)) + gtk_range_draw_trough (GTK_RANGE (widget)); +} + +static void +gtk_range_unrealize (GtkWidget *widget) +{ + GtkRange *range; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RANGE (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + gtk_style_detach (widget->style); + + if (range->slider) + gdk_window_destroy (range->slider); + if (range->trough) + gdk_window_destroy (range->trough); + if (range->step_forw) + gdk_window_destroy (range->step_forw); + if (range->step_back) + gdk_window_destroy (range->step_back); + if (widget->window) + gdk_window_destroy (widget->window); + + range->slider = NULL; + range->trough = NULL; + range->step_forw = NULL; + range->step_back = NULL; + widget->window = NULL; +} + +static gint +gtk_range_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkRange *range; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + if (event->window == range->trough) + { + gtk_range_draw_trough (range); + } + else if (event->window == widget->window) + { + gtk_range_draw_background (range); + } + else if (event->window == range->slider) + { + gtk_range_draw_slider (range); + } + else if (event->window == range->step_forw) + { + gtk_range_draw_step_forw (range); + } + else if (event->window == range->step_back) + { + gtk_range_draw_step_back (range); + } + return FALSE; +} + +static gint +gtk_range_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkRange *range; + gint trough_part; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + range = GTK_RANGE (widget); + if (!range->button) + { + gtk_grab_add (widget); + + range->button = event->button; + range->x_click_point = event->x; + range->y_click_point = event->y; + + if (event->window == range->trough) + { + range->click_child = RANGE_CLASS (range)->trough; + + trough_part = gtk_range_trough_click (range, event->x, event->y); + + range->scroll_type = GTK_SCROLL_NONE; + if (trough_part == GTK_TROUGH_START) + range->scroll_type = GTK_SCROLL_PAGE_BACKWARD; + else if (trough_part == GTK_TROUGH_END) + range->scroll_type = GTK_SCROLL_PAGE_FORWARD; + + if (range->scroll_type != GTK_SCROLL_NONE) + { + gtk_range_scroll (range); + gtk_range_add_timer (range); + } + } + else if (event->window == range->slider) + { + range->click_child = RANGE_CLASS (range)->slider; + range->scroll_type = GTK_SCROLL_NONE; + } + else if (event->window == range->step_forw) + { + range->click_child = RANGE_CLASS (range)->step_forw; + range->scroll_type = GTK_SCROLL_STEP_FORWARD; + + gtk_range_scroll (range); + gtk_range_add_timer (range); + gtk_range_draw_step_forw (range); + } + else if (event->window == range->step_back) + { + range->click_child = RANGE_CLASS (range)->step_back; + range->scroll_type = GTK_SCROLL_STEP_BACKWARD; + + gtk_range_scroll (range); + gtk_range_add_timer (range); + gtk_range_draw_step_back (range); + } + } + + return FALSE; +} + +static gint +gtk_range_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkRange *range; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + if (range->button == event->button) + { + gtk_grab_remove (widget); + + range->button = 0; + range->x_click_point = -1; + range->y_click_point = -1; + + if (range->click_child == RANGE_CLASS (range)->slider) + { + if (range->policy == GTK_UPDATE_DELAYED) + gtk_range_remove_timer (range); + + if ((range->policy != GTK_UPDATE_CONTINUOUS) && + (range->old_value != range->adjustment->value)) + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else if ((range->click_child == RANGE_CLASS (range)->trough) || + (range->click_child == RANGE_CLASS (range)->step_forw) || + (range->click_child == RANGE_CLASS (range)->step_back)) + { + gtk_range_remove_timer (range); + + if ((range->policy != GTK_UPDATE_CONTINUOUS) && + (range->old_value != range->adjustment->value)) + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + + if (range->click_child == RANGE_CLASS (range)->step_forw) + { + range->click_child = 0; + gtk_range_draw_step_forw (range); + } + else if (range->click_child == RANGE_CLASS (range)->step_back) + { + range->click_child = 0; + gtk_range_draw_step_back (range); + } + } + + range->click_child = 0; + } + + return FALSE; +} + +static gint +gtk_range_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkRange *range; + GdkModifierType mods; + gint x, y, mask; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + if (range->click_child == RANGE_CLASS (range)->slider) + { + x = event->x; + y = event->y; + + if (event->is_hint || (event->window != range->slider)) + gdk_window_get_pointer (range->slider, &x, &y, &mods); + + switch (range->button) + { + case 1: + mask = GDK_BUTTON1_MASK; + break; + case 2: + mask = GDK_BUTTON2_MASK; + break; + case 3: + mask = GDK_BUTTON3_MASK; + break; + default: + mask = 0; + break; + } + + if (mods & mask) + { + if (RANGE_CLASS (range)->motion) + (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point); + } + } + + return FALSE; +} + +static gint +gtk_range_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkRange *range; + gint return_val; + GtkScrollType scroll = GTK_SCROLL_NONE; + GtkTroughType pos = GTK_TROUGH_NONE; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + return_val = FALSE; + + if (RANGE_CLASS (range)->trough_keys) + return_val = (* RANGE_CLASS (range)->trough_keys) (range, event, &scroll, &pos); + + if (return_val) + { + if (scroll != GTK_SCROLL_NONE) + { + range->scroll_type = scroll; + gtk_range_scroll (range); + if (range->old_value != range->adjustment->value) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + switch (range->scroll_type) + { + case GTK_SCROLL_STEP_BACKWARD: + gtk_range_draw_step_back (range); + break; + case GTK_SCROLL_STEP_FORWARD: + gtk_range_draw_step_forw (range); + break; + } + } + } + if (pos != GTK_TROUGH_NONE) + { + if (pos == GTK_TROUGH_START) + range->adjustment->value = range->adjustment->lower; + else + range->adjustment->value = + range->adjustment->upper - range->adjustment->page_size; + + if (range->old_value != range->adjustment->value) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), + "value_changed"); + + gtk_range_slider_update (range); + gtk_range_draw_background (range); + } + } + } + return return_val; +} + +static gint +gtk_range_enter_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkRange *range; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + if (event->window == range->trough) + { + range->in_child = RANGE_CLASS (range)->trough; + } + else if (event->window == range->slider) + { + range->in_child = RANGE_CLASS (range)->slider; + + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_slider (range); + } + else if (event->window == range->step_forw) + { + range->in_child = RANGE_CLASS (range)->step_forw; + + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_step_forw (range); + } + else if (event->window == range->step_back) + { + range->in_child = RANGE_CLASS (range)->step_back; + + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_step_back (range); + } + + return FALSE; +} + +static gint +gtk_range_leave_notify (GtkWidget *widget, + GdkEventCrossing *event) +{ + GtkRange *range; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + range->in_child = 0; + + if (event->window == range->trough) + { + } + else if (event->window == range->slider) + { + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_slider (range); + } + else if (event->window == range->step_forw) + { + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_step_forw (range); + } + else if (event->window == range->step_back) + { + if ((range->click_child == 0) || + (range->click_child == RANGE_CLASS (range)->trough)) + gtk_range_draw_step_back (range); + } + + return FALSE; +} + +static gint +gtk_range_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static gint +gtk_range_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + return FALSE; +} + +static void +gtk_real_range_draw_trough (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->trough) + { + gtk_draw_shadow (GTK_WIDGET (range)->style, range->trough, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + 0, 0, -1, -1); + + if (GTK_WIDGET_HAS_FOCUS (range)) + gdk_draw_rectangle (GTK_WIDGET (range)->window, + GTK_WIDGET (range)->style->black_gc, + FALSE, 0, 0, + GTK_WIDGET (range)->allocation.width - 1, + GTK_WIDGET (range)->allocation.height - 1); + else if (range->trough != GTK_WIDGET (range)->window) + gdk_draw_rectangle (GTK_WIDGET (range)->window, + GTK_WIDGET (range)->style->bg_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, + GTK_WIDGET (range)->allocation.width - 1, + GTK_WIDGET (range)->allocation.height - 1); + } +} + +static void +gtk_real_range_draw_slider (GtkRange *range) +{ + GtkStateType state_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->slider) + { + if ((range->in_child == RANGE_CLASS (range)->slider) || + (range->click_child == RANGE_CLASS (range)->slider)) + state_type = GTK_STATE_PRELIGHT; + else + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (GTK_WIDGET (range)->style, range->slider, state_type); + gdk_window_clear (range->slider); + + gtk_draw_shadow (GTK_WIDGET (range)->style, range->slider, + state_type, GTK_SHADOW_OUT, + 0, 0, -1, -1); + } +} + +static gint +gtk_real_range_timer (GtkRange *range) +{ + gint return_val; + + g_return_val_if_fail (range != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (range), FALSE); + + return_val = TRUE; + if (range->click_child == RANGE_CLASS (range)->slider) + { + if (range->policy == GTK_UPDATE_DELAYED) + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + return_val = FALSE; + } + else + { + if (!range->timer) + { + return_val = FALSE; + if (range->need_timer) + range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH, + (GtkFunction) RANGE_CLASS (range)->timer, + (gpointer) range); + else + return FALSE; + range->need_timer = FALSE; + } + + if (gtk_range_scroll (range)) + return return_val; + } + + return return_val; +} + +static gint +gtk_range_scroll (GtkRange *range) +{ + gfloat new_value; + gint return_val; + + g_return_val_if_fail (range != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (range), FALSE); + + new_value = range->adjustment->value; + return_val = TRUE; + + switch (range->scroll_type) + { + case GTK_SCROLL_NONE: + break; + + case GTK_SCROLL_STEP_BACKWARD: + new_value -= range->adjustment->step_increment; + if (new_value <= range->adjustment->lower) + { + new_value = range->adjustment->lower; + return_val = FALSE; + range->timer = 0; + } + break; + + case GTK_SCROLL_STEP_FORWARD: + new_value += range->adjustment->step_increment; + if (new_value >= (range->adjustment->upper - range->adjustment->page_size)) + { + new_value = range->adjustment->upper - range->adjustment->page_size; + return_val = FALSE; + range->timer = 0; + } + break; + + case GTK_SCROLL_PAGE_BACKWARD: + new_value -= range->adjustment->page_increment; + if (new_value <= range->adjustment->lower) + { + new_value = range->adjustment->lower; + return_val = FALSE; + range->timer = 0; + } + break; + + case GTK_SCROLL_PAGE_FORWARD: + new_value += range->adjustment->page_increment; + if (new_value >= (range->adjustment->upper - range->adjustment->page_size)) + { + new_value = range->adjustment->upper - range->adjustment->page_size; + return_val = FALSE; + range->timer = 0; + } + break; + } + + if (new_value != range->adjustment->value) + { + range->adjustment->value = new_value; + + if ((range->policy == GTK_UPDATE_CONTINUOUS) || + (!return_val && (range->policy == GTK_UPDATE_DELAYED))) + { + gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed"); + } + else + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + } + } + + return return_val; +} + + +static void +gtk_range_add_timer (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (!range->timer) + { + range->need_timer = TRUE; + range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY, + (GtkFunction) RANGE_CLASS (range)->timer, + (gpointer) range); + } +} + +static void +gtk_range_remove_timer (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_RANGE (range)); + + if (range->timer) + { + gtk_timeout_remove (range->timer); + range->timer = 0; + } + range->need_timer = FALSE; +} + +static void +gtk_range_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkRange *range; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + range = GTK_RANGE (data); + + if (((range->old_lower != adjustment->lower) || + (range->old_upper != adjustment->upper) || + (range->old_page_size != adjustment->page_size)) && + (range->old_value == adjustment->value)) + { + if ((adjustment->lower == adjustment->upper) || + (range->old_lower == (range->old_upper - range->old_page_size))) + { + adjustment->value = adjustment->lower; + gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed"); + } + } + + if ((range->old_value != adjustment->value) || + (range->old_lower != adjustment->lower) || + (range->old_upper != adjustment->upper) || + (range->old_page_size != adjustment->page_size)) + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + + range->old_value = adjustment->value; + range->old_lower = adjustment->lower; + range->old_upper = adjustment->upper; + range->old_page_size = adjustment->page_size; + } +} + +static void +gtk_range_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkRange *range; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + range = GTK_RANGE (data); + + if (range->old_value != adjustment->value) + { + gtk_range_slider_update (range); + gtk_range_draw_background (range); + + range->old_value = adjustment->value; + } +} + + +static void +gtk_range_trough_hdims (GtkRange *range, + gint *left, + gint *right) +{ + gint trough_width; + gint slider_length; + gint tmp_width; + gint tleft; + gint tright; + + g_return_if_fail (range != NULL); + + gdk_window_get_size (range->trough, &trough_width, NULL); + gdk_window_get_size (range->slider, &slider_length, NULL); + + tleft = GTK_WIDGET (range)->style->klass->xthickness; + tright = trough_width - slider_length - GTK_WIDGET (range)->style->klass->xthickness; + + if (range->step_back) + { + gdk_window_get_size (range->step_back, &tmp_width, NULL); + tleft += (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing); + } + + if (range->step_forw) + { + gdk_window_get_size (range->step_forw, &tmp_width, NULL); + tright -= (tmp_width + RANGE_CLASS (range)->stepper_slider_spacing); + } + + if (left) + *left = tleft; + if (right) + *right = tright; +} + +static void +gtk_range_trough_vdims (GtkRange *range, + gint *top, + gint *bottom) +{ + gint trough_height; + gint slider_length; + gint tmp_height; + gint ttop; + gint tbottom; + + g_return_if_fail (range != NULL); + + gdk_window_get_size (range->trough, NULL, &trough_height); + gdk_window_get_size (range->slider, NULL, &slider_length); + + ttop = GTK_WIDGET (range)->style->klass->xthickness; + tbottom = trough_height - slider_length - GTK_WIDGET (range)->style->klass->ythickness; + + if (range->step_back) + { + gdk_window_get_size (range->step_back, NULL, &tmp_height); + ttop += (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing); + } + + if (range->step_forw) + { + gdk_window_get_size (range->step_forw, NULL, &tmp_height); + tbottom -= (tmp_height + RANGE_CLASS (range)->stepper_slider_spacing); + } + + if (top) + *top = ttop; + if (bottom) + *bottom = tbottom; +} diff --git a/gtk/gtkrange.h b/gtk/gtkrange.h new file mode 100644 index 000000000..47ff50a36 --- /dev/null +++ b/gtk/gtkrange.h @@ -0,0 +1,144 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_RANGE_H__ +#define __GTK_RANGE_H__ + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_RANGE(obj) GTK_CHECK_CAST (obj, gtk_range_get_type (), GtkRange) +#define GTK_RANGE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_range_get_type (), GtkRangeClass) +#define GTK_IS_RANGE(obj) GTK_CHECK_TYPE (obj, gtk_range_get_type ()) + + +typedef struct _GtkRange GtkRange; +typedef struct _GtkRangeClass GtkRangeClass; + +struct _GtkRange +{ + GtkWidget widget; + + GdkWindow *trough; + GdkWindow *slider; + GdkWindow *step_forw; + GdkWindow *step_back; + + gint16 x_click_point; + gint16 y_click_point; + + guint8 button; + gint8 digits; + guint policy : 2; + guint scroll_type : 3; + guint in_child : 3; + guint click_child : 3; + guint need_timer : 1; + + guint32 timer; + + gfloat old_value; + gfloat old_lower; + gfloat old_upper; + gfloat old_page_size; + + GtkAdjustment *adjustment; +}; + +struct _GtkRangeClass +{ + GtkWidgetClass parent_class; + + gint slider_width; + gint stepper_size; + gint stepper_slider_spacing; + gint min_slider_size; + + guint8 trough; + guint8 slider; + guint8 step_forw; + guint8 step_back; + + void (* draw_background) (GtkRange *range); + void (* draw_trough) (GtkRange *range); + void (* draw_slider) (GtkRange *range); + void (* draw_step_forw) (GtkRange *range); + void (* draw_step_back) (GtkRange *range); + void (* slider_update) (GtkRange *range); + gint (* trough_click) (GtkRange *range, + gint x, + gint y); + gint (* trough_keys) (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *trough); + void (* motion) (GtkRange *range, + gint xdelta, + gint ydelta); + gint (* timer) (GtkRange *range); +}; + + +guint gtk_range_get_type (void); +GtkAdjustment* gtk_range_get_adjustment (GtkRange *range); +void gtk_range_set_update_policy (GtkRange *range, + GtkUpdateType policy); +void gtk_range_set_adjustment (GtkRange *range, + GtkAdjustment *adjustment); + +void gtk_range_draw_background (GtkRange *range); +void gtk_range_draw_trough (GtkRange *range); +void gtk_range_draw_slider (GtkRange *range); +void gtk_range_draw_step_forw (GtkRange *range); +void gtk_range_draw_step_back (GtkRange *range); +void gtk_range_slider_update (GtkRange *range); +gint gtk_range_trough_click (GtkRange *range, + gint x, + gint y); + +void gtk_range_default_hslider_update (GtkRange *range); +void gtk_range_default_vslider_update (GtkRange *range); +gint gtk_range_default_htrough_click (GtkRange *range, + gint x, + gint y); +gint gtk_range_default_vtrough_click (GtkRange *range, + gint x, + gint y); +void gtk_range_default_hmotion (GtkRange *range, + gint xdelta, + gint ydelta); +void gtk_range_default_vmotion (GtkRange *range, + gint xdelta, + gint ydelta); +gfloat gtk_range_calc_value (GtkRange *range, + gint position); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RANGE_H__ */ diff --git a/gtk/gtkrc.c b/gtk/gtkrc.c new file mode 100644 index 000000000..86bc20121 --- /dev/null +++ b/gtk/gtkrc.c @@ -0,0 +1,1489 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include "gtkrc.h" + + +enum { + TOKEN_EOF, + TOKEN_LEFT_CURLY, + TOKEN_RIGHT_CURLY, + TOKEN_LEFT_BRACE, + TOKEN_RIGHT_BRACE, + TOKEN_EQUAL_SIGN, + TOKEN_COMMA, + TOKEN_INTEGER, + TOKEN_FLOAT, + TOKEN_STRING, + TOKEN_SYMBOL, + TOKEN_ACTIVE, + TOKEN_BASE, + TOKEN_BG, + TOKEN_BG_PIXMAP, + TOKEN_FG, + TOKEN_FONT, + TOKEN_FONTSET, + TOKEN_INSENSITIVE, + TOKEN_NORMAL, + TOKEN_PIXMAP_PATH, + TOKEN_PRELIGHT, + TOKEN_SELECTED, + TOKEN_STYLE, + TOKEN_TEXT, + TOKEN_WIDGET, + TOKEN_WIDGET_CLASS +}; + +enum { + PARSE_OK, + PARSE_ERROR, + PARSE_SYNTAX +}; + +enum { + PARSE_START, + PARSE_COMMENT, + PARSE_STRING, + PARSE_SYMBOL, + PARSE_NUMBER +}; + + +typedef struct _GtkRcStyle GtkRcStyle; +typedef struct _GtkRcSet GtkRcSet; + +struct _GtkRcStyle +{ + int initialize; + char *name; + char *font_name; + char *fontset_name; + char *bg_pixmap_name[5]; + GtkStyle *style; +}; + +struct _GtkRcSet +{ + char *set; + GtkRcStyle *rc_style; +}; + + +static guint gtk_rc_style_hash (const char *name); +static gint gtk_rc_style_compare (const char *a, + const char *b); +static GtkRcStyle* gtk_rc_style_find (const char *name); +static GtkRcStyle* gtk_rc_styles_match (GSList *sets, + const char *path); +static gint gtk_rc_style_match (const char *set, + const char *path); +static void gtk_rc_style_init (GtkRcStyle *rc_style); +static gint gtk_rc_get_token (void); +static gint gtk_rc_simple_token (char ch); +static gint gtk_rc_symbol_token (const char *sym); +static gint gtk_rc_get_next_token (void); +static gint gtk_rc_peek_next_token (void); +static gint gtk_rc_parse_statement (void); +static gint gtk_rc_parse_style (void); +static gint gtk_rc_parse_style_option (GtkRcStyle *rc_style); +static gint gtk_rc_parse_base (GtkStyle *style); +static gint gtk_rc_parse_bg (GtkStyle *style); +static gint gtk_rc_parse_fg (GtkStyle *style); +static gint gtk_rc_parse_bg_pixmap (GtkRcStyle *rc_style); +static gint gtk_rc_parse_font (GtkRcStyle *rc_style); +static gint gtk_rc_parse_fontset (GtkRcStyle *rc_style); +static gint gtk_rc_parse_state (GtkStateType *state); +static gint gtk_rc_parse_color (GdkColor *color); +static gint gtk_rc_parse_pixmap_path (void); +static void gtk_rc_parse_pixmap_path_string (gchar *pix_path); +static char* gtk_rc_find_pixmap_in_path (gchar *pixmap_file); +static gint gtk_rc_parse_widget_style (void); +static gint gtk_rc_parse_widget_class_style (void); +static char* gtk_rc_widget_path (GtkWidget *widget); +static char* gtk_rc_widget_class_path (GtkWidget *widget); + + +static struct +{ + char *name; + int token; +} symbols[] = + { + { "ACTIVE", TOKEN_ACTIVE }, + { "base", TOKEN_BASE }, + { "bg", TOKEN_BG }, + { "bg_pixmap", TOKEN_BG_PIXMAP }, + { "fg", TOKEN_FG }, + { "font", TOKEN_FONT }, + { "fontset", TOKEN_FONTSET }, + { "INSENSITIVE", TOKEN_INSENSITIVE }, + { "NORMAL", TOKEN_NORMAL }, + { "pixmap_path", TOKEN_PIXMAP_PATH }, + { "PRELIGHT", TOKEN_PRELIGHT }, + { "SELECTED", TOKEN_SELECTED }, + { "style", TOKEN_STYLE }, + { "text", TOKEN_TEXT }, + { "widget", TOKEN_WIDGET }, + { "widget_class", TOKEN_WIDGET_CLASS }, + }; + +static int nsymbols = sizeof (symbols) / sizeof (symbols[0]); + +static struct +{ + char ch; + int token; +} simple_tokens[] = + { + { '{', TOKEN_LEFT_CURLY }, + { '}', TOKEN_RIGHT_CURLY }, + { '[', TOKEN_LEFT_BRACE }, + { ']', TOKEN_RIGHT_BRACE }, + { '=', TOKEN_EQUAL_SIGN }, + { ',', TOKEN_COMMA }, + }; + +static int nsimple_tokens = sizeof (simple_tokens) / sizeof (simple_tokens[0]); + +static FILE *input_fp = NULL; +static char *buffer = NULL; +static char *tokenbuf = NULL; +static int position = 0; +static int linenum = 1; +static int buffer_size = 1024; +static int tokenbuf_size = 1024; + +static int done; +static int cur_token; +static int next_token; + +static char *token_str; +static double token_float; +static int token_int; + +static GHashTable *rc_style_ht = NULL; +static GSList *widget_sets = NULL; +static GSList *widget_class_sets = NULL; + +#define GTK_RC_MAX_PIXMAP_PATHS 128 +static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS]; + + +void +gtk_rc_init () +{ + rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash, + (GCompareFunc) gtk_rc_style_compare); +} + +void +gtk_rc_parse (const char *filename) +{ + input_fp = fopen (filename, "r"); + if (!input_fp) + return; + + buffer = g_new (char, buffer_size + tokenbuf_size); + tokenbuf = buffer + buffer_size; + position = 0; + linenum = 1; + + cur_token = -1; + next_token = -1; + done = FALSE; + + while (!done) + { + if (gtk_rc_parse_statement () != PARSE_OK) + { + g_warning ("rc file parse error: \"%s\" line %d", + filename, linenum); + done = TRUE; + } + } + + fclose (input_fp); + + g_free (buffer); + + buffer = NULL; + tokenbuf = NULL; + position = 0; + linenum = 1; +} + +GtkStyle* +gtk_rc_get_style (GtkWidget *widget) +{ + GtkRcStyle *rc_style; + char *path; + + if (widget_sets) + { + path = gtk_rc_widget_path (widget); + if (path) + { + rc_style = gtk_rc_styles_match (widget_sets, path); + g_free (path); + + if (rc_style) + { + gtk_rc_style_init (rc_style); + return rc_style->style; + } + } + } + + if (widget_class_sets) + { + path = gtk_rc_widget_class_path (widget); + if (path) + { + rc_style = gtk_rc_styles_match (widget_class_sets, path); + g_free (path); + + if (rc_style) + { + gtk_rc_style_init (rc_style); + return rc_style->style; + } + } + } + + return widget->style; +} + +void +gtk_rc_add_widget_name_style (GtkStyle *style, + const char *pattern) +{ + GtkRcStyle *rc_style; + GtkRcSet *rc_set; + int i; + + gtk_style_ref (style); + + rc_style = g_new (GtkRcStyle, 1); + rc_style->initialize = FALSE; + rc_style->name = NULL; + rc_style->font_name = NULL; + rc_style->fontset_name = NULL; + + for (i = 0; i < 5; i++) + rc_style->bg_pixmap_name[i] = NULL; + + rc_style->style = style; + + rc_set = g_new (GtkRcSet, 1); + rc_set->set = g_strdup (pattern); + rc_set->rc_style = rc_style; + + widget_sets = g_slist_append (widget_sets, rc_set); +} + +void +gtk_rc_add_widget_class_style (GtkStyle *style, + const char *pattern) +{ + GtkRcStyle *rc_style; + GtkRcSet *rc_set; + int i; + + gtk_style_ref (style); + + rc_style = g_new (GtkRcStyle, 1); + rc_style->initialize = FALSE; + rc_style->name = NULL; + rc_style->font_name = NULL; + rc_style->fontset_name = NULL; + + for (i = 0; i < 5; i++) + rc_style->bg_pixmap_name[i] = NULL; + + rc_style->style = style; + + rc_set = g_new (GtkRcSet, 1); + rc_set->set = g_strdup (pattern); + rc_set->rc_style = rc_style; + + widget_class_sets = g_slist_append (widget_class_sets, rc_set); +} + + +static guint +gtk_rc_style_hash (const char *name) +{ + guint result; + + result = 0; + while (*name) + result += (result << 3) + *name++; + + return result; +} + +static gint +gtk_rc_style_compare (const char *a, + const char *b) +{ + return (strcmp (a, b) == 0); +} + +static GtkRcStyle* +gtk_rc_style_find (const char *name) +{ + GtkRcStyle *rc_style; + + rc_style = g_hash_table_lookup (rc_style_ht, (gpointer) name); + + return rc_style; +} + +static GtkRcStyle* +gtk_rc_styles_match (GSList *sets, + const char *path) +{ + GtkRcSet *rc_set; + + while (sets) + { + rc_set = sets->data; + sets = sets->next; + + if (gtk_rc_style_match (rc_set->set, path)) + return rc_set->rc_style; + } + + return NULL; +} + +static gint +gtk_rc_style_match (const char *set, + const char *path) +{ + char ch; + + while (1) + { + ch = *set++; + if (ch == '\0') + return (*path == '\0'); + + switch (ch) + { + case '*': + while (*set == '*') + set++; + + ch = *set++; + if (ch == '\0') + return TRUE; + + while (*path) + { + while (*path && (ch != *path)) + path++; + + if (!(*path)) + return FALSE; + + path++; + if (gtk_rc_style_match (set, path)) + return TRUE; + } + break; + + case '?': + break; + + default: + if (ch == *path) + path++; + else + return FALSE; + break; + } + } + + return TRUE; +} + +static void +gtk_rc_style_init (GtkRcStyle *rc_style) +{ + GdkFont *old_font; + gint i; + + if (rc_style->initialize) + { + rc_style->initialize = FALSE; + + if (rc_style->fontset_name) + { + old_font = rc_style->style->font; + rc_style->style->font = gdk_fontset_load (rc_style->fontset_name); + if (rc_style->style->font) + gdk_fontset_free (old_font); + else + rc_style->style->font = old_font; + } + else if (rc_style->font_name) + { + old_font = rc_style->style->font; + rc_style->style->font = gdk_font_load (rc_style->font_name); + if (rc_style->style->font) + gdk_font_free (old_font); + else + rc_style->style->font = old_font; + } + + for (i = 0; i < 5; i++) + if (rc_style->bg_pixmap_name[i]) + { + if (strcmp (rc_style->bg_pixmap_name[i], "") == 0) + rc_style->style->bg_pixmap[i] = (GdkPixmap*) GDK_PARENT_RELATIVE; + else + rc_style->style->bg_pixmap[i] = gdk_pixmap_create_from_xpm (NULL, NULL, + &rc_style->style->bg[i], + rc_style->bg_pixmap_name[i]); + } + } +} + +static gint +gtk_rc_get_token () +{ + int tokenpos; + int state; + int count; + int token; + int hex_number = FALSE; + int float_number = FALSE; + char ch; + + tokenpos = 0; + state = PARSE_START; + + while (1) + { + if (position >= (buffer_size - 1)) + position = 0; + if (!position || (buffer[position] == '\0')) + { + count = fread (buffer, sizeof (char), buffer_size - 1, input_fp); + if ((count == 0) && feof (input_fp)) + return TOKEN_EOF; + buffer[count] = '\0'; + } + + ch = buffer[position++]; + if (ch == '\n') + linenum += 1; + + switch (state) + { + case PARSE_START: + token = gtk_rc_simple_token (ch); + + if (token) + return token; + else if (ch == '#') + state = PARSE_COMMENT; + else if (ch == '"') + state = PARSE_STRING; + else if ((ch == ' ') || (ch == '\t') || (ch == '\n')) + break; + else if (ch == '.') + { + hex_number = FALSE; + float_number = TRUE; + tokenbuf[tokenpos++] = ch; + state = PARSE_NUMBER; + } + else if ((ch == '$') || (ch == '#')) + { + hex_number = TRUE; + float_number = FALSE; + state = PARSE_NUMBER; + } + else if (isdigit (ch)) + { + hex_number = FALSE; + float_number = FALSE; + tokenbuf[tokenpos++] = ch; + state = PARSE_NUMBER; + } + else + { + tokenbuf[tokenpos++] = ch; + state = PARSE_SYMBOL; + } + break; + + case PARSE_COMMENT: + if (ch == '\n') + state = PARSE_START; + break; + + case PARSE_STRING: + if (ch != '"') + { + tokenbuf[tokenpos++] = ch; + } + else + { + tokenbuf[tokenpos] = '\0'; + token_str = tokenbuf; + return TOKEN_STRING; + } + break; + + case PARSE_SYMBOL: + if ((ch != ' ') && (ch != '\t') && (ch != '\n') && + (gtk_rc_simple_token (ch) == 0)) + { + tokenbuf[tokenpos++] = ch; + } + else + { + position -= 1; + tokenbuf[tokenpos] = '\0'; + token_str = tokenbuf; + return gtk_rc_symbol_token (tokenbuf); + } + break; + + case PARSE_NUMBER: + if (isdigit (ch) || (hex_number && isxdigit (ch))) + { + tokenbuf[tokenpos++] = ch; + } + else if (!hex_number && !float_number && (ch == '.')) + { + float_number = TRUE; + tokenbuf[tokenpos++] = ch; + } + else if (!float_number && + (ch == 'x') && (tokenpos == 1) && + (tokenbuf[0] == '0')) + { + hex_number = TRUE; + tokenpos = 0; + } + else + { + position -= 1; + tokenbuf[tokenpos] = '\0'; + if (float_number) + { + sscanf (tokenbuf, "%lf", &token_float); + return TOKEN_FLOAT; + } + else + { + sscanf (tokenbuf, (hex_number ? "%x" : "%d"), &token_int); + return TOKEN_INTEGER; + } + } + break; + } + } +} + +static gint +gtk_rc_simple_token (char ch) +{ + gint i; + + for (i = 0; i < nsimple_tokens; i++) + if (simple_tokens[i].ch == ch) + return simple_tokens[i].token; + + return 0; +} + +static gint +gtk_rc_symbol_token (const char *sym) +{ + gint i; + + for (i = 0; i < nsymbols; i++) + if (strcmp (symbols[i].name, sym) == 0) + return symbols[i].token; + + return TOKEN_STRING; +} + +static gint +gtk_rc_get_next_token () +{ + if (next_token != -1) + { + cur_token = next_token; + next_token = -1; + } + else + { + cur_token = gtk_rc_get_token (); + } + + return cur_token; +} + +static gint +gtk_rc_peek_next_token () +{ + if (next_token == -1) + next_token = gtk_rc_get_token (); + + return next_token; +} + +static gint +gtk_rc_parse_statement () +{ + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + { + done = TRUE; + return PARSE_OK; + } + + error = gtk_rc_parse_style (); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_pixmap_path (); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_widget_style (); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_widget_class_style (); + + return error; +} + +static gint +gtk_rc_parse_style () +{ + GtkRcStyle *rc_style; + GtkRcStyle *parent_style; + gint token; + gint error; + gint insert; + gint i; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_STYLE) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + insert = FALSE; + rc_style = g_hash_table_lookup (rc_style_ht, token_str); + + if (!rc_style) + { + insert = TRUE; + rc_style = g_new (GtkRcStyle, 1); + rc_style->initialize = TRUE; + rc_style->name = g_strdup (token_str); + rc_style->font_name = NULL; + rc_style->fontset_name = NULL; + + for (i = 0; i < 5; i++) + rc_style->bg_pixmap_name[i] = NULL; + + rc_style->style = gtk_style_new (); + gtk_style_ref (rc_style->style); + } + + token = gtk_rc_peek_next_token (); + if (token == TOKEN_EQUAL_SIGN) + { + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + { + if (insert) + { + gtk_style_unref (rc_style->style); + g_free (rc_style); + } + return PARSE_ERROR; + } + + parent_style = g_hash_table_lookup (rc_style_ht, token_str); + if (parent_style) + { + for (i = 0; i < 5; i++) + { + rc_style->style->fg[i] = parent_style->style->fg[i]; + rc_style->style->bg[i] = parent_style->style->bg[i]; + rc_style->style->light[i] = parent_style->style->light[i]; + rc_style->style->dark[i] = parent_style->style->dark[i]; + rc_style->style->mid[i] = parent_style->style->mid[i]; + rc_style->style->text[i] = parent_style->style->text[i]; + rc_style->style->base[i] = parent_style->style->base[i]; + } + + rc_style->style->black = parent_style->style->black; + rc_style->style->white = parent_style->style->white; + + if (rc_style->fontset_name) + { + g_free (rc_style->fontset_name); + rc_style->fontset_name = g_strdup (parent_style->fontset_name); + } + else if (rc_style->font_name) + { + g_free (rc_style->font_name); + rc_style->font_name = g_strdup (parent_style->font_name); + } + + for (i = 0; i < 5; i++) + { + if (rc_style->bg_pixmap_name[i]) + g_free (rc_style->bg_pixmap_name[i]); + rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]); + } + } + } + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_LEFT_CURLY)) + { + if (insert) + { + gtk_style_unref (rc_style->style); + g_free (rc_style); + } + return PARSE_ERROR; + } + + while (1) + { + error = gtk_rc_parse_style_option (rc_style); + if (error == PARSE_SYNTAX) + break; + if (error == PARSE_ERROR) + { + if (insert) + { + gtk_style_unref (rc_style->style); + g_free (rc_style); + } + return error; + } + } + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_RIGHT_CURLY)) + { + if (insert) + { + if (rc_style->fontset_name) + g_free (rc_style->fontset_name); + else if (rc_style->font_name) + g_free (rc_style->font_name); + + for (i = 0; i < 5; i++) + if (rc_style->bg_pixmap_name[i]) + g_free (rc_style->bg_pixmap_name[i]); + + gtk_style_unref (rc_style->style); + g_free (rc_style); + } + return PARSE_ERROR; + } + + if (insert) + g_hash_table_insert (rc_style_ht, rc_style->name, rc_style); + + return PARSE_OK; +} + +static gint +gtk_rc_parse_style_option (GtkRcStyle *rc_style) +{ + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + + error = gtk_rc_parse_base (rc_style->style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_bg (rc_style->style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_fg (rc_style->style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_bg_pixmap (rc_style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_font (rc_style); + if (error != PARSE_SYNTAX) + return error; + + error = gtk_rc_parse_fontset (rc_style); + + return error; +} + +static gint +gtk_rc_parse_base (GtkStyle *style) +{ + GtkStateType state; + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_BASE) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + error = gtk_rc_parse_state (&state); + if (error != PARSE_OK) + return error; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + error = gtk_rc_parse_color (&style->base[state]); + + return error; +} + +static gint +gtk_rc_parse_bg (GtkStyle *style) +{ + GtkStateType state; + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_BG) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + error = gtk_rc_parse_state (&state); + if (error != PARSE_OK) + return error; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + error = gtk_rc_parse_color (&style->bg[state]); + + return error; +} + +static gint +gtk_rc_parse_fg (GtkStyle *style) +{ + GtkStateType state; + gint token; + gint error; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_FG) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + error = gtk_rc_parse_state (&state); + if (error != PARSE_OK) + return error; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + error = gtk_rc_parse_color (&style->fg[state]); + + return error; +} + +static gint +gtk_rc_parse_bg_pixmap (GtkRcStyle *rc_style) +{ + GtkStateType state; + gint token; + gint error; + gchar *pixmap_file; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_BG_PIXMAP) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + error = gtk_rc_parse_state (&state); + if (error != PARSE_OK) + return error; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + if (strcmp (token_str, "")) + pixmap_file = gtk_rc_find_pixmap_in_path (token_str); + else + pixmap_file = g_strdup(token_str); + + if (pixmap_file) + { + if (rc_style->bg_pixmap_name[state]) + g_free (rc_style->bg_pixmap_name[state]); + rc_style->bg_pixmap_name[state] = pixmap_file; + } + + return PARSE_OK; +} + +static char* +gtk_rc_find_pixmap_in_path (gchar *pixmap_file) +{ + gint i; + FILE *fp; + gchar *buf; + + for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++) + { + buf = g_malloc (strlen (pixmap_path[i]) + strlen (pixmap_file) + 2); + sprintf (buf, "%s%c%s", pixmap_path[i], '/', pixmap_file); + + fp = fopen (buf, "r"); + if (fp) + { + fclose (fp); + return buf; + } + + g_free (buf); + } + + g_warning ("Unable to locate image file in pixmap_path: \"%s\" line %d", + pixmap_file, linenum); + + return NULL; +} + +static gint +gtk_rc_parse_font (GtkRcStyle *rc_style) +{ + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_FONT) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + if (rc_style->font_name) + g_free (rc_style->font_name); + rc_style->font_name = g_strdup (token_str); + + return PARSE_OK; +} + +static gint +gtk_rc_parse_fontset (GtkRcStyle *rc_style) +{ + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_FONTSET) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_EQUAL_SIGN)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + if (rc_style->fontset_name) + g_free (rc_style->fontset_name); + rc_style->fontset_name = g_strdup (token_str); + + return PARSE_OK; +} + +static gint +gtk_rc_parse_state (GtkStateType *state) +{ + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_LEFT_BRACE) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (token == TOKEN_ACTIVE) + *state = GTK_STATE_ACTIVE; + else if (token == TOKEN_INSENSITIVE) + *state = GTK_STATE_INSENSITIVE; + else if (token == TOKEN_NORMAL) + *state = GTK_STATE_NORMAL; + else if (token == TOKEN_PRELIGHT) + *state = GTK_STATE_PRELIGHT; + else if (token == TOKEN_SELECTED) + *state = GTK_STATE_SELECTED; + else + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_RIGHT_BRACE)) + return PARSE_ERROR; + + return PARSE_OK; +} + +static gint +gtk_rc_parse_color (GdkColor *color) +{ + gint token; + gint length; + gint temp; + gchar buf[9]; + gint i, j; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + + switch (token) + { + case TOKEN_LEFT_CURLY: + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || ((token != TOKEN_INTEGER) && (token != TOKEN_FLOAT))) + return PARSE_ERROR; + + if (token == TOKEN_FLOAT) + token_int = token_float * 65535.0; + if (token_int < 0) + token_int = 0; + if (token_int > 65535) + token_int = 65535; + + color->red = token_int; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_COMMA)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || ((token != TOKEN_INTEGER) && (token != TOKEN_FLOAT))) + return PARSE_ERROR; + + if (token == TOKEN_FLOAT) + token_int = token_float * 65535.0; + if (token_int < 0) + token_int = 0; + if (token_int > 65535) + token_int = 65535; + + color->green = token_int; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_COMMA)) + return PARSE_ERROR; + + token = gtk_rc_get_next_token (); + if (!token || ((token != TOKEN_INTEGER) && (token != TOKEN_FLOAT))) + return PARSE_ERROR; + + if (token == TOKEN_FLOAT) + token_int = token_float * 65535.0; + if (token_int < 0) + token_int = 0; + if (token_int > 65535) + token_int = 65535; + + color->blue = token_int; + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_RIGHT_CURLY)) + return PARSE_ERROR; + break; + + case TOKEN_STRING: + token = gtk_rc_get_next_token (); + + if (token_str[0] != '#') + return PARSE_ERROR; + + length = strlen (token_str) - 1; + if (((length % 3) != 0) || (length > 12)) + return PARSE_ERROR; + length /= 3; + + for (i = 0, j = 1; i < length; i++, j++) + buf[i] = token_str[j]; + buf[i] = '\0'; + + sscanf (buf, "%x", &temp); + color->red = temp; + + for (i = 0; i < length; i++, j++) + buf[i] = token_str[j]; + buf[i] = '\0'; + + sscanf (buf, "%x", &temp); + color->green = temp; + + for (i = 0; i < length; i++, j++) + buf[i] = token_str[j]; + buf[i] = '\0'; + + sscanf (buf, "%x", &temp); + color->blue = temp; + + if (length == 1) + { + color->red *= 4369; + color->green *= 4369; + color->blue *= 4369; + } + else if (length == 2) + { + color->red *= 257; + color->green *= 257; + color->blue *= 257; + } + else if (length == 3) + { + color->red *= 16; + color->green *= 16; + color->blue *= 16; + } + break; + + default: + return PARSE_SYNTAX; + } + + return PARSE_OK; +} + +static gint +gtk_rc_parse_pixmap_path () +{ + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_PIXMAP_PATH) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + gtk_rc_parse_pixmap_path_string(token_str); + + return PARSE_OK; +} + +static void gtk_rc_parse_pixmap_path_string(gchar *pix_path) +{ + gchar *buf; + gint end_offset; + gint start_offset = 0; + gint path_len; + gint path_num; + + /* free the old one, or just add to the old one ? */ + for (path_num=0; pixmap_path[path_num]; path_num++) + { + g_free(pixmap_path[path_num]); + pixmap_path[path_num] = NULL; + } + + path_num = 0; + + path_len = strlen(pix_path); + + buf = g_strdup(pix_path); + + for(end_offset = 0; end_offset <= path_len; end_offset++) + { + if ( (buf[end_offset] == ':') || (end_offset == path_len) ) + { + buf[end_offset] = '\0'; + pixmap_path[path_num] = g_strdup(buf + start_offset); + path_num++; + pixmap_path[path_num] = NULL; + start_offset = end_offset + 1; + g_free(buf); + buf = g_strdup(pix_path); + } + } + g_free(buf); +} + +static gint +gtk_rc_parse_widget_style () +{ + GtkRcSet *rc_set; + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_WIDGET) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + rc_set = g_new (GtkRcSet, 1); + rc_set->set = g_strdup (token_str); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STYLE)) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + rc_set->rc_style = gtk_rc_style_find (token_str); + if (!rc_set->rc_style) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + widget_sets = g_slist_append (widget_sets, rc_set); + + return PARSE_OK; +} + +static gint +gtk_rc_parse_widget_class_style () +{ + GtkRcSet *rc_set; + gint token; + + token = gtk_rc_peek_next_token (); + if (!token) + return PARSE_ERROR; + if (token != TOKEN_WIDGET_CLASS) + return PARSE_SYNTAX; + token = gtk_rc_get_next_token (); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + return PARSE_ERROR; + + rc_set = g_new (GtkRcSet, 1); + rc_set->set = g_strdup (token_str); + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STYLE)) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + token = gtk_rc_get_next_token (); + if (!token || (token != TOKEN_STRING)) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + rc_set->rc_style = gtk_rc_style_find (token_str); + if (!rc_set->rc_style) + { + g_free (rc_set->set); + g_free (rc_set); + return PARSE_ERROR; + } + + widget_class_sets = g_slist_append (widget_class_sets, rc_set); + + return PARSE_OK; +} + +static char* +gtk_rc_widget_path (GtkWidget *widget) +{ + GtkWidget *tmp_widget; + char *path; + char *name; + int pathlength; + int namelength; + + path = NULL; + pathlength = 0; + + tmp_widget = widget; + while (tmp_widget) + { + name = gtk_widget_get_name (tmp_widget); + pathlength += strlen (name); + + tmp_widget = tmp_widget->parent; + + if (tmp_widget) + pathlength += 1; + } + + path = g_new (char, pathlength + 1); + path[pathlength] = '\0'; + + tmp_widget = widget; + while (tmp_widget) + { + name = gtk_widget_get_name (tmp_widget); + namelength = strlen (name); + + strncpy (&path[pathlength - namelength], name, namelength); + pathlength -= namelength; + + tmp_widget = tmp_widget->parent; + + if (tmp_widget) + { + pathlength -= 1; + path[pathlength] = '.'; + } + } + + return path; +} + +static char* +gtk_rc_widget_class_path (GtkWidget *widget) +{ + GtkWidget *tmp_widget; + char *path; + char *name; + int pathlength; + int namelength; + + path = NULL; + pathlength = 0; + + tmp_widget = widget; + while (tmp_widget) + { + name = gtk_type_name (GTK_WIDGET_TYPE (tmp_widget)); + pathlength += strlen (name); + + tmp_widget = tmp_widget->parent; + + if (tmp_widget) + pathlength += 1; + } + + path = g_new (char, pathlength + 1); + path[pathlength] = '\0'; + + tmp_widget = widget; + while (tmp_widget) + { + name = gtk_type_name (GTK_WIDGET_TYPE (tmp_widget)); + namelength = strlen (name); + + strncpy (&path[pathlength - namelength], name, namelength); + pathlength -= namelength; + + tmp_widget = tmp_widget->parent; + + if (tmp_widget) + { + pathlength -= 1; + path[pathlength] = '.'; + } + } + + return path; +} diff --git a/gtk/gtkrc.h b/gtk/gtkrc.h new file mode 100644 index 000000000..8c761bb9e --- /dev/null +++ b/gtk/gtkrc.h @@ -0,0 +1,45 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_RC_H__ +#define __GTK_RC_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +void gtk_rc_init (void); +void gtk_rc_parse (const char *filename); +GtkStyle* gtk_rc_get_style (GtkWidget *widget); +void gtk_rc_add_widget_name_style (GtkStyle *style, + const char *pattern); +void gtk_rc_add_widget_class_style (GtkStyle *style, + const char *pattern); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RC_H__ */ diff --git a/gtk/gtkruler.c b/gtk/gtkruler.c new file mode 100644 index 000000000..dad0e11f6 --- /dev/null +++ b/gtk/gtkruler.c @@ -0,0 +1,305 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkruler.h" + + +static void gtk_ruler_class_init (GtkRulerClass *klass); +static void gtk_ruler_init (GtkRuler *ruler); +static void gtk_ruler_realize (GtkWidget *widget); +static void gtk_ruler_unrealize (GtkWidget *widget); +static void gtk_ruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_ruler_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_ruler_make_pixmap (GtkRuler *ruler); + + +static GtkRulerMetric ruler_metrics[] = +{ + {"Pixels", "Pi", 1.0, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, + {"Inches", "In", 72.0, { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }, { 1, 2, 4, 8, 16 }}, + {"Centimeters", "Cn", 28.35, { 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000 }, { 1, 5, 10, 50, 100 }}, +}; + + +guint +gtk_ruler_get_type () +{ + static guint ruler_type = 0; + + if (!ruler_type) + { + GtkTypeInfo ruler_info = + { + "GtkRuler", + sizeof (GtkRuler), + sizeof (GtkRulerClass), + (GtkClassInitFunc) gtk_ruler_class_init, + (GtkObjectInitFunc) gtk_ruler_init, + (GtkArgFunc) NULL, + }; + + ruler_type = gtk_type_unique (gtk_widget_get_type (), &ruler_info); + } + + return ruler_type; +} + +static void +gtk_ruler_class_init (GtkRulerClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + widget_class->realize = gtk_ruler_realize; + widget_class->unrealize = gtk_ruler_unrealize; + widget_class->size_allocate = gtk_ruler_size_allocate; + widget_class->expose_event = gtk_ruler_expose; + + class->draw_ticks = NULL; + class->draw_pos = NULL; +} + +static void +gtk_ruler_init (GtkRuler *ruler) +{ + ruler->backing_store = NULL; + ruler->non_gr_exp_gc = NULL; + ruler->xsrc = 0; + ruler->ysrc = 0; + ruler->slider_size = 0; + ruler->lower = 0; + ruler->upper = 0; + ruler->position = 0; + ruler->max_size = 0; + + gtk_ruler_set_metric (ruler, GTK_PIXELS); +} + +void +gtk_ruler_set_metric (GtkRuler *ruler, + GtkMetricType metric) +{ + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_RULER (ruler)); + + ruler->metric = &ruler_metrics[metric]; + + if (GTK_WIDGET_DRAWABLE (ruler)) + gtk_widget_queue_draw (GTK_WIDGET (ruler)); +} + +void +gtk_ruler_set_range (GtkRuler *ruler, + gfloat lower, + gfloat upper, + gfloat position, + gfloat max_size) +{ + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_RULER (ruler)); + + ruler->lower = lower; + ruler->upper = upper; + ruler->position = position; + ruler->max_size = max_size; + + if (GTK_WIDGET_DRAWABLE (ruler)) + gtk_widget_queue_draw (GTK_WIDGET (ruler)); +} + +void +gtk_ruler_draw_ticks (GtkRuler *ruler) +{ + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_RULER (ruler)); + + if (GTK_RULER_CLASS (GTK_OBJECT (ruler)->klass)->draw_ticks) + (* GTK_RULER_CLASS (GTK_OBJECT (ruler)->klass)->draw_ticks) (ruler); +} + +void +gtk_ruler_draw_pos (GtkRuler *ruler) +{ + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_RULER (ruler)); + + if (GTK_RULER_CLASS (GTK_OBJECT (ruler)->klass)->draw_pos) + (* GTK_RULER_CLASS (GTK_OBJECT (ruler)->klass)->draw_pos) (ruler); +} + + +static void +gtk_ruler_realize (GtkWidget *widget) +{ + GtkRuler *ruler; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RULER (widget)); + + ruler = GTK_RULER (widget); + GTK_WIDGET_SET_FLAGS (ruler, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, ruler); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); + + gtk_ruler_make_pixmap (ruler); +} + +static void +gtk_ruler_unrealize (GtkWidget *widget) +{ + GtkRuler *ruler; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RULER (widget)); + + ruler = GTK_RULER (widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + gdk_window_destroy (widget->window); + widget->window = NULL; + + if (ruler->backing_store) + gdk_pixmap_destroy (ruler->backing_store); + if (ruler->non_gr_exp_gc) + gdk_gc_destroy (ruler->non_gr_exp_gc); + + ruler->backing_store = NULL; + ruler->non_gr_exp_gc = NULL; +} + +static void +gtk_ruler_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRuler *ruler; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_RULER (widget)); + + ruler = GTK_RULER (widget); + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gtk_ruler_make_pixmap (ruler); + } +} + +static gint +gtk_ruler_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkRuler *ruler; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RULER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + ruler = GTK_RULER (widget); + + gdk_draw_rectangle (ruler->backing_store, + widget->style->bg_gc[GTK_STATE_NORMAL], + TRUE, 0, 0, + widget->allocation.width, + widget->allocation.height); + + gtk_ruler_draw_ticks (ruler); + + gtk_draw_shadow (widget->style, ruler->backing_store, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, 0, 0, + widget->allocation.width, + widget->allocation.height); + + gdk_draw_pixmap (widget->window, + ruler->non_gr_exp_gc, + ruler->backing_store, + 0, 0, 0, 0, + widget->allocation.width, + widget->allocation.height); + + gtk_ruler_draw_pos (ruler); + } + + return FALSE; +} + +static void +gtk_ruler_make_pixmap (GtkRuler *ruler) +{ + GtkWidget *widget; + gint width; + gint height; + + widget = GTK_WIDGET (ruler); + + if (ruler->backing_store) + { + gdk_window_get_size (ruler->backing_store, &width, &height); + if ((width == widget->allocation.width) && + (height == widget->allocation.height)) + return; + + gdk_pixmap_destroy (ruler->backing_store); + } + + ruler->backing_store = gdk_pixmap_new (widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + + ruler->xsrc = 0; + ruler->ysrc = 0; + + if (!ruler->non_gr_exp_gc) + { + ruler->non_gr_exp_gc = gdk_gc_new (widget->window); + gdk_gc_set_exposures (ruler->non_gr_exp_gc, FALSE); + } +} diff --git a/gtk/gtkruler.h b/gtk/gtkruler.h new file mode 100644 index 000000000..c74b20321 --- /dev/null +++ b/gtk/gtkruler.h @@ -0,0 +1,91 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_RULER_H__ +#define __GTK_RULER_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_RULER(obj) GTK_CHECK_CAST (obj, gtk_ruler_get_type (), GtkRuler) +#define GTK_RULER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_ruler_get_type (), GtkRulerClass) +#define GTK_IS_RULER(obj) GTK_CHECK_TYPE (obj, gtk_ruler_get_type ()) + + +typedef struct _GtkRuler GtkRuler; +typedef struct _GtkRulerClass GtkRulerClass; +typedef struct _GtkRulerMetric GtkRulerMetric; + +struct _GtkRuler +{ + GtkWidget widget; + + GdkPixmap *backing_store; + GdkGC *non_gr_exp_gc; + GtkRulerMetric *metric; + gint xsrc, ysrc; + gint slider_size; + + gfloat lower; + gfloat upper; + gfloat position; + gfloat max_size; +}; + +struct _GtkRulerClass +{ + GtkWidgetClass parent_class; + + void (* draw_ticks) (GtkRuler *ruler); + void (* draw_pos) (GtkRuler *ruler); +}; + +struct _GtkRulerMetric +{ + gchar *metric_name; + gchar *abbrev; + gfloat pixels_per_unit; + gfloat ruler_scale[10]; + gint subdivide[5]; /* five possible modes of subdivision */ +}; + + +guint gtk_ruler_get_type (void); +void gtk_ruler_set_metric (GtkRuler *ruler, + GtkMetricType metric); +void gtk_ruler_set_range (GtkRuler *ruler, + gfloat lower, + gfloat upper, + gfloat position, + gfloat max_size); +void gtk_ruler_draw_ticks (GtkRuler *ruler); +void gtk_ruler_draw_pos (GtkRuler *ruler); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_RULER_H__ */ diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c new file mode 100644 index 000000000..ba2f18616 --- /dev/null +++ b/gtk/gtkscale.c @@ -0,0 +1,229 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkcontainer.h" +#include "gtkscale.h" + + +#define SCALE_CLASS(w) GTK_SCALE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_scale_class_init (GtkScaleClass *klass); +static void gtk_scale_init (GtkScale *scale); +static void gtk_scale_destroy (GtkObject *object); +static void gtk_scale_draw_background (GtkRange *range); + + +static GtkRangeClass *parent_class = NULL; + + +guint +gtk_scale_get_type () +{ + static guint scale_type = 0; + + if (!scale_type) + { + GtkTypeInfo scale_info = + { + "GtkScale", + sizeof (GtkScale), + sizeof (GtkScaleClass), + (GtkClassInitFunc) gtk_scale_class_init, + (GtkObjectInitFunc) gtk_scale_init, + (GtkArgFunc) NULL, + }; + + scale_type = gtk_type_unique (gtk_range_get_type (), &scale_info); + } + + return scale_type; +} + +static void +gtk_scale_class_init (GtkScaleClass *class) +{ + GtkObjectClass *object_class; + GtkRangeClass *range_class; + + object_class = (GtkObjectClass*) class; + range_class = (GtkRangeClass*) class; + + parent_class = gtk_type_class (gtk_range_get_type ()); + + object_class->destroy = gtk_scale_destroy; + + range_class->draw_background = gtk_scale_draw_background; + + class->slider_length = 31; + class->value_spacing = 2; + class->draw_value = NULL; +} + +static void +gtk_scale_init (GtkScale *scale) +{ + GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS); + GTK_RANGE (scale)->digits = 1; + scale->draw_value = TRUE; + scale->value_pos = GTK_POS_TOP; +} + +void +gtk_scale_set_digits (GtkScale *scale, + gint digits) +{ + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_SCALE (scale)); + + if (GTK_RANGE (scale)->digits != digits) + { + GTK_RANGE (scale)->digits = digits; + + if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale)) + gtk_widget_queue_resize (GTK_WIDGET (scale)); + } +} + +void +gtk_scale_set_draw_value (GtkScale *scale, + gint draw_value) +{ + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_SCALE (scale)); + + if (scale->draw_value != draw_value) + { + scale->draw_value = (draw_value != 0); + + if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale)) + gtk_widget_queue_resize (GTK_WIDGET (scale)); + } +} + +void +gtk_scale_set_value_pos (GtkScale *scale, + GtkPositionType pos) +{ + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_SCALE (scale)); + + if (scale->value_pos != pos) + { + scale->value_pos = pos; + + if (GTK_WIDGET_VISIBLE (scale) && GTK_WIDGET_MAPPED (scale)) + gtk_widget_queue_resize (GTK_WIDGET (scale)); + } +} + +gint +gtk_scale_value_width (GtkScale *scale) +{ + GtkRange *range; + gchar buffer[128]; + gfloat value; + gint temp; + gint return_val; + gint digits; + gint i, j; + + g_return_val_if_fail (scale != NULL, 0); + g_return_val_if_fail (GTK_IS_SCALE (scale), 0); + + return_val = 0; + if (scale->draw_value) + { + range = GTK_RANGE (scale); + + value = ABS (range->adjustment->lower); + if (value == 0) value = 1; + digits = log10 (value) + 1; + if (digits > 13) + digits = 13; + + i = 0; + if (range->adjustment->lower < 0) + buffer[i++] = '-'; + for (j = 0; j < digits; j++) + buffer[i++] = '0'; + if (GTK_RANGE (scale)->digits) + buffer[i++] = '.'; + for (j = 0; j < GTK_RANGE (scale)->digits; j++) + buffer[i++] = '0'; + buffer[i] = '\0'; + + return_val = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer); + + value = ABS (range->adjustment->upper); + if (value == 0) value = 1; + digits = log10 (value) + 1; + if (digits > 13) + digits = 13; + + i = 0; + if (range->adjustment->lower < 0) + buffer[i++] = '-'; + for (j = 0; j < digits; j++) + buffer[i++] = '0'; + if (GTK_RANGE (scale)->digits) + buffer[i++] = '.'; + for (j = 0; j < GTK_RANGE (scale)->digits; j++) + buffer[i++] = '0'; + buffer[i] = '\0'; + + temp = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer); + return_val = MAX (return_val, temp); + } + + return return_val; +} + +void +gtk_scale_draw_value (GtkScale *scale) +{ + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_SCALE (scale)); + + if (SCALE_CLASS (scale)->draw_value) + (* SCALE_CLASS (scale)->draw_value) (scale); +} + + +static void +gtk_scale_destroy (GtkObject *object) +{ + GtkRange *range; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_SCALE (object)); + + range = GTK_RANGE (object); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_scale_draw_background (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_SCALE (range)); + + gtk_scale_draw_value (GTK_SCALE (range)); +} diff --git a/gtk/gtkscale.h b/gtk/gtkscale.h new file mode 100644 index 000000000..6fe2e4925 --- /dev/null +++ b/gtk/gtkscale.h @@ -0,0 +1,75 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_SCALE_H__ +#define __GTK_SCALE_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_SCALE(obj) GTK_CHECK_CAST (obj, gtk_scale_get_type (), GtkScale) +#define GTK_SCALE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_scale_get_type (), GtkScaleClass) +#define GTK_IS_SCALE(obj) GTK_CHECK_TYPE (obj, gtk_scale_get_type ()) + + +typedef struct _GtkScale GtkScale; +typedef struct _GtkScaleClass GtkScaleClass; + +struct _GtkScale +{ + GtkRange range; + + guint draw_value : 1; + guint value_pos : 2; +}; + +struct _GtkScaleClass +{ + GtkRangeClass parent_class; + + gint slider_length; + gint value_spacing; + + void (* draw_value) (GtkScale *scale); +}; + + +guint gtk_scale_get_type (void); +void gtk_scale_set_digits (GtkScale *scale, + gint digits); +void gtk_scale_set_draw_value (GtkScale *scale, + gint draw_value); +void gtk_scale_set_value_pos (GtkScale *scale, + GtkPositionType pos); +gint gtk_scale_value_width (GtkScale *scale); + +void gtk_scale_draw_value (GtkScale *scale); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SCALE_H__ */ diff --git a/gtk/gtkscrollbar.c b/gtk/gtkscrollbar.c new file mode 100644 index 000000000..3f5088b44 --- /dev/null +++ b/gtk/gtkscrollbar.c @@ -0,0 +1,54 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkscrollbar.h" + +static void gtk_scrollbar_class_init (GtkScrollbarClass *klass); +static void gtk_scrollbar_init (GtkScrollbar *scrollbar); + +guint +gtk_scrollbar_get_type () +{ + static guint scrollbar_type = 0; + + if (!scrollbar_type) + { + GtkTypeInfo scrollbar_info = + { + "GtkScrollbar", + sizeof (GtkScrollbar), + sizeof (GtkScrollbarClass), + (GtkClassInitFunc) gtk_scrollbar_class_init, + (GtkObjectInitFunc) gtk_scrollbar_init, + (GtkArgFunc) NULL, + }; + + scrollbar_type = gtk_type_unique (gtk_range_get_type (), &scrollbar_info); + } + + return scrollbar_type; +} + +static void +gtk_scrollbar_class_init (GtkScrollbarClass *class) +{ +} + +static void +gtk_scrollbar_init (GtkScrollbar *scrollbar) +{ +} diff --git a/gtk/gtkscrollbar.h b/gtk/gtkscrollbar.h new file mode 100644 index 000000000..14aadad1a --- /dev/null +++ b/gtk/gtkscrollbar.h @@ -0,0 +1,58 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_SCROLLBAR_H__ +#define __GTK_SCROLLBAR_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_SCROLLBAR(obj) GTK_CHECK_CAST (obj, gtk_scrollbar_get_type (), GtkScrollbar) +#define GTK_SCROLLBAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_scrollbar_get_type (), GtkScrollbarClass) +#define GTK_IS_SCROLLBAR(obj) GTK_CHECK_TYPE (obj, gtk_scrollbar_get_type ()) + + +typedef struct _GtkScrollbar GtkScrollbar; +typedef struct _GtkScrollbarClass GtkScrollbarClass; + +struct _GtkScrollbar +{ + GtkRange range; +}; + +struct _GtkScrollbarClass +{ + GtkRangeClass parent_class; +}; + + +guint gtk_scrollbar_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SCROLLBAR_H__ */ diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c new file mode 100644 index 000000000..79cc67aaf --- /dev/null +++ b/gtk/gtkscrolledwindow.c @@ -0,0 +1,510 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkscrolledwindow.h" +#include "gtksignal.h" + + +#define SCROLLBAR_SPACING 5 + + +static void gtk_scrolled_window_class_init (GtkScrolledWindowClass *klass); +static void gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window); +static void gtk_scrolled_window_destroy (GtkObject *object); +static void gtk_scrolled_window_map (GtkWidget *widget); +static void gtk_scrolled_window_unmap (GtkWidget *widget); +static void gtk_scrolled_window_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_scrolled_window_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_scrolled_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_scrolled_window_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_scrolled_window_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_scrolled_window_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +static void gtk_scrolled_window_viewport_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment, + gpointer data); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_scrolled_window_get_type () +{ + static guint scrolled_window_type = 0; + + if (!scrolled_window_type) + { + GtkTypeInfo scrolled_window_info = + { + "GtkScrolledWindow", + sizeof (GtkScrolledWindow), + sizeof (GtkScrolledWindowClass), + (GtkClassInitFunc) gtk_scrolled_window_class_init, + (GtkObjectInitFunc) gtk_scrolled_window_init, + (GtkArgFunc) NULL, + }; + + scrolled_window_type = gtk_type_unique (gtk_container_get_type (), &scrolled_window_info); + } + + return scrolled_window_type; +} + +static void +gtk_scrolled_window_class_init (GtkScrolledWindowClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_scrolled_window_destroy; + + widget_class->map = gtk_scrolled_window_map; + widget_class->unmap = gtk_scrolled_window_unmap; + widget_class->draw = gtk_scrolled_window_draw; + widget_class->size_request = gtk_scrolled_window_size_request; + widget_class->size_allocate = gtk_scrolled_window_size_allocate; + + container_class->add = gtk_scrolled_window_add; + container_class->remove = gtk_scrolled_window_remove; + container_class->foreach = gtk_scrolled_window_foreach; +} + +static void +gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window) +{ + GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW); + + scrolled_window->hscrollbar = NULL; + scrolled_window->vscrollbar = NULL; + scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS; + scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS; +} + +GtkWidget* +gtk_scrolled_window_new (GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment) +{ + GtkScrolledWindow *scrolled_window; + + scrolled_window = gtk_type_new (gtk_scrolled_window_get_type ()); + + scrolled_window->viewport = gtk_viewport_new (hadjustment, vadjustment); + hadjustment = gtk_viewport_get_hadjustment (GTK_VIEWPORT (scrolled_window->viewport)); + vadjustment = gtk_viewport_get_vadjustment (GTK_VIEWPORT (scrolled_window->viewport)); + + gtk_signal_connect (GTK_OBJECT (hadjustment), "changed", + (GtkSignalFunc) gtk_scrolled_window_adjustment_changed, + (gpointer) scrolled_window); + gtk_signal_connect (GTK_OBJECT (vadjustment), "changed", + (GtkSignalFunc) gtk_scrolled_window_adjustment_changed, + (gpointer) scrolled_window); + + scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment); + scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment); + + gtk_widget_set_parent (scrolled_window->viewport, GTK_WIDGET (scrolled_window)); + gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window)); + gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window)); + + gtk_widget_show (scrolled_window->viewport); + gtk_widget_show (scrolled_window->hscrollbar); + gtk_widget_show (scrolled_window->vscrollbar); + + return GTK_WIDGET (scrolled_window); +} + +GtkAdjustment* +gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window) +{ + g_return_val_if_fail (scrolled_window != NULL, NULL); + g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL); + + return gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)); +} + +GtkAdjustment* +gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window) +{ + g_return_val_if_fail (scrolled_window != NULL, NULL); + g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL); + + return gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)); +} + +void +gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window, + GtkPolicyType hscrollbar_policy, + GtkPolicyType vscrollbar_policy) +{ + g_return_if_fail (scrolled_window != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window)); + + if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) || + (scrolled_window->vscrollbar_policy != vscrollbar_policy)) + { + scrolled_window->hscrollbar_policy = hscrollbar_policy; + scrolled_window->vscrollbar_policy = vscrollbar_policy; + + if (GTK_WIDGET (scrolled_window)->parent) + gtk_widget_queue_resize (GTK_WIDGET (scrolled_window)); + } +} + + +static void +gtk_scrolled_window_destroy (GtkObject *object) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (object)); + + scrolled_window = GTK_SCROLLED_WINDOW (object); + + gtk_widget_destroy (scrolled_window->viewport); + gtk_widget_destroy (scrolled_window->hscrollbar); + gtk_widget_destroy (scrolled_window->vscrollbar); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_scrolled_window_map (GtkWidget *widget) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + + if (!GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + if (GTK_WIDGET_VISIBLE (scrolled_window->viewport) && + !GTK_WIDGET_MAPPED (scrolled_window->viewport)) + gtk_widget_map (scrolled_window->viewport); + + if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) && + !GTK_WIDGET_MAPPED (scrolled_window->hscrollbar)) + gtk_widget_map (scrolled_window->hscrollbar); + + if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) && + !GTK_WIDGET_MAPPED (scrolled_window->vscrollbar)) + gtk_widget_map (scrolled_window->vscrollbar); + } +} + +static void +gtk_scrolled_window_unmap (GtkWidget *widget) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + + if (GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + if (GTK_WIDGET_MAPPED (scrolled_window->viewport)) + gtk_widget_unmap (scrolled_window->viewport); + + if (GTK_WIDGET_MAPPED (scrolled_window->hscrollbar)) + gtk_widget_unmap (scrolled_window->hscrollbar); + + if (GTK_WIDGET_MAPPED (scrolled_window->vscrollbar)) + gtk_widget_unmap (scrolled_window->vscrollbar); + } +} + +static void +gtk_scrolled_window_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkScrolledWindow *scrolled_window; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + if (gtk_widget_intersect (scrolled_window->viewport, area, &child_area)) + gtk_widget_draw (scrolled_window->viewport, &child_area); + + if (gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area)) + gtk_widget_draw (scrolled_window->hscrollbar, &child_area); + + if (gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area)) + gtk_widget_draw (scrolled_window->vscrollbar, &child_area); + } +} + +static void +gtk_scrolled_window_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkScrolledWindow *scrolled_window; + gint extra_height; + gint extra_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + g_return_if_fail (requisition != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + requisition->width = 0; + requisition->height = 0; + + if (GTK_WIDGET_VISIBLE (scrolled_window->viewport)) + { + gtk_widget_size_request (scrolled_window->viewport, &scrolled_window->viewport->requisition); + + requisition->width += scrolled_window->viewport->requisition.width; + requisition->height += scrolled_window->viewport->requisition.height; + } + + extra_width = 0; + extra_height = 0; + + if ((scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC) || + GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar)) + { + gtk_widget_size_request (scrolled_window->hscrollbar, + &scrolled_window->hscrollbar->requisition); + + requisition->width = MAX (requisition->width, scrolled_window->hscrollbar->requisition.width); + extra_height = SCROLLBAR_SPACING + scrolled_window->hscrollbar->requisition.height; + } + + if ((scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC) || + GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar)) + { + gtk_widget_size_request (scrolled_window->vscrollbar, + &scrolled_window->vscrollbar->requisition); + + requisition->height = MAX (requisition->height, scrolled_window->vscrollbar->requisition.height); + extra_width = SCROLLBAR_SPACING + scrolled_window->vscrollbar->requisition.width; + } + + requisition->width += GTK_CONTAINER (widget)->border_width * 2 + extra_width; + requisition->height += GTK_CONTAINER (widget)->border_width * 2 + extra_height; +} + +static void +gtk_scrolled_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkScrolledWindow *scrolled_window; + GtkAllocation viewport_allocation; + GtkAllocation child_allocation; + guint previous_hvis; + guint previous_vvis; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget)); + g_return_if_fail (allocation != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (widget); + widget->allocation = *allocation; + + gtk_scrolled_window_viewport_allocate (widget, &viewport_allocation); + + gtk_container_disable_resize (GTK_CONTAINER (scrolled_window)); + + if (GTK_WIDGET_VISIBLE (scrolled_window->viewport)) + { + do { + gtk_scrolled_window_viewport_allocate (widget, &viewport_allocation); + + child_allocation.x = viewport_allocation.x + allocation->x; + child_allocation.y = viewport_allocation.y + allocation->y; + child_allocation.width = viewport_allocation.width; + child_allocation.height = viewport_allocation.height; + + previous_hvis = GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar); + previous_vvis = GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar); + + gtk_widget_size_allocate (scrolled_window->viewport, &child_allocation); + } while ((previous_hvis != GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar)) || + (previous_vvis != GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))); + } + + if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar)) + { + child_allocation.x = viewport_allocation.x; + child_allocation.y = viewport_allocation.y + viewport_allocation.height + SCROLLBAR_SPACING; + child_allocation.width = viewport_allocation.width; + child_allocation.height = scrolled_window->hscrollbar->requisition.height; + child_allocation.x += allocation->x; + child_allocation.y += allocation->y; + + gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation); + } + + if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar)) + { + child_allocation.x = viewport_allocation.x + viewport_allocation.width + SCROLLBAR_SPACING; + child_allocation.y = viewport_allocation.y; + child_allocation.width = scrolled_window->vscrollbar->requisition.width; + child_allocation.height = viewport_allocation.height; + child_allocation.x += allocation->x; + child_allocation.y += allocation->y; + + gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation); + } + + gtk_container_enable_resize (GTK_CONTAINER (scrolled_window)); +} + +static void +gtk_scrolled_window_add (GtkContainer *container, + GtkWidget *widget) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container)); + g_return_if_fail (widget != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (container); + gtk_container_add (GTK_CONTAINER (scrolled_window->viewport), widget); +} + +static void +gtk_scrolled_window_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container)); + g_return_if_fail (widget != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (container); + gtk_container_remove (GTK_CONTAINER (scrolled_window->viewport), widget); +} + +static void +gtk_scrolled_window_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container)); + g_return_if_fail (callback != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (container); + + (* callback) (scrolled_window->viewport, callback_data); +} + +static void +gtk_scrolled_window_viewport_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkScrolledWindow *scrolled_window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (allocation != NULL); + + scrolled_window = GTK_SCROLLED_WINDOW (widget); + + allocation->x = GTK_CONTAINER (widget)->border_width; + allocation->y = GTK_CONTAINER (widget)->border_width; + allocation->width = widget->allocation.width - allocation->x * 2; + allocation->height = widget->allocation.height - allocation->y * 2; + + if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar)) + allocation->width -= scrolled_window->vscrollbar->requisition.width + SCROLLBAR_SPACING; + if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar)) + allocation->height -= scrolled_window->hscrollbar->requisition.height + SCROLLBAR_SPACING; +} + +static void +gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkScrolledWindow *scrolled_win; + GtkWidget *scrollbar; + gint hide_scrollbar; + gint policy; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + + scrolled_win = GTK_SCROLLED_WINDOW (data); + + if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar))) + { + scrollbar = scrolled_win->hscrollbar; + policy = scrolled_win->hscrollbar_policy; + } + else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar))) + { + scrollbar = scrolled_win->vscrollbar; + policy = scrolled_win->vscrollbar_policy; + } + else + { + g_warning ("could not determine which adjustment scrollbar received change signal for"); + return; + } + + if (policy == GTK_POLICY_AUTOMATIC) + { + hide_scrollbar = FALSE; + + if ((adjustment->upper - adjustment->lower) <= adjustment->page_size) + hide_scrollbar = TRUE; + + if (hide_scrollbar) + { + if (GTK_WIDGET_VISIBLE (scrollbar)) + gtk_widget_hide (scrollbar); + } + else + { + if (!GTK_WIDGET_VISIBLE (scrollbar)) + gtk_widget_show (scrollbar); + } + } +} diff --git a/gtk/gtkscrolledwindow.h b/gtk/gtkscrolledwindow.h new file mode 100644 index 000000000..34a01ef6c --- /dev/null +++ b/gtk/gtkscrolledwindow.h @@ -0,0 +1,74 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_SCROLLED_WINDOW_H__ +#define __GTK_SCROLLED_WINDOW_H__ + + +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_SCROLLED_WINDOW(obj) GTK_CHECK_CAST (obj, gtk_scrolled_window_get_type (), GtkScrolledWindow) +#define GTK_SCROLLED_WINDOW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_scrolled_window_get_type (), GtkScrolledWindowClass) +#define GTK_IS_SCROLLED_WINDOW(obj) GTK_CHECK_TYPE (obj, gtk_scrolled_window_get_type ()) + + +typedef struct _GtkScrolledWindow GtkScrolledWindow; +typedef struct _GtkScrolledWindowClass GtkScrolledWindowClass; + +struct _GtkScrolledWindow +{ + GtkContainer container; + + GtkWidget *viewport; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + + guint8 hscrollbar_policy; + guint8 vscrollbar_policy; +}; + +struct _GtkScrolledWindowClass +{ + GtkContainerClass parent_class; +}; + + +guint gtk_scrolled_window_get_type (void); +GtkWidget* gtk_scrolled_window_new (GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +GtkAdjustment* gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window); +GtkAdjustment* gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window); +void gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window, + GtkPolicyType hscrollbar_policy, + GtkPolicyType vscrollbar_policy); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SCROLLED_WINDOW_H__ */ diff --git a/gtk/gtkselection.c b/gtk/gtkselection.c new file mode 100644 index 000000000..ca6f5742f --- /dev/null +++ b/gtk/gtkselection.c @@ -0,0 +1,1388 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* This file implements most of the work of the ICCM selection protocol. + * The code was written after an intensive study of the equivalent part + * of John Ousterhout's Tk toolkit, and does many things in much the + * same way. + * + * The one thing in the ICCM that isn't fully supported here (or in Tk) + * is side effects targets. For these to be handled properly, MULTIPLE + * targets need to be done in the order specified. This cannot be + * guaranteed with the way we do things, since if we are doing INCR + * transfers, the order will depend on the timing of the requestor. + * + * By Owen Taylor 8/16/97 + */ + +/* Terminology note: when not otherwise specified, the term "incr" below + * refers to the _sending_ part of the INCR protocol. The receiving + * portion is referred to just as "retrieval". (Terminology borrowed + * from Tk, because there is no good opposite to "retrieval" in English. + * "send" can't be made into a noun gracefully and we're already using + * "emission" for something else ....) + */ + +/* The MOTIF entry widget seems to ask for the TARGETS target, then + (regardless of the reply) ask for the TEXT target. It's slightly + possible though that it somehow thinks we are responding negatively + to the TARGETS request, though I don't really think so ... */ + +#include +#include +/* we need this for gdk_window_lookup() */ +#include "gtkmain.h" +#include "gtkselection.h" +#include "gtksignal.h" + +/* #define DEBUG_SELECTION */ + +/* Maximum size of a sent chunk, in bytes. Also the default size of + our buffers */ +#define GTK_SELECTION_MAX_SIZE 4000 + +enum { + INCR, + MULTIPLE, + TARGETS, + TIMESTAMP, + LAST_ATOM +}; + +typedef struct _GtkSelectionInfo GtkSelectionInfo; +typedef struct _GtkIncrConversion GtkIncrConversion; +typedef struct _GtkIncrInfo GtkIncrInfo; +typedef struct _GtkRetrievalInfo GtkRetrievalInfo; +typedef struct _GtkSelectionHandler GtkSelectionHandler; + +struct _GtkSelectionInfo +{ + GdkAtom selection; + GtkWidget *widget; /* widget that owns selection */ + guint32 time; /* time used to acquire selection */ +}; + +struct _GtkIncrConversion +{ + GdkAtom target; /* Requested target */ + GdkAtom property; /* Property to store in */ + GtkSelectionData data; /* The data being supplied */ + gint offset; /* Current offset in sent selection. + * -1 => All done + * -2 => Only the final (empty) portion + * left to send */ +}; + +struct _GtkIncrInfo +{ + GtkWidget *widget; /* Selection owner */ + GdkWindow *requestor; /* Requestor window - we create a GdkWindow + so we can receive events */ + GdkAtom selection; /* Selection we're sending */ + + GtkIncrConversion *conversions; /* Information about requested conversions - + * With MULTIPLE requests (benighted 1980's + * hardware idea), there can be more than + * one */ + gint num_conversions; + gint num_incrs; /* number of remaining INCR style transactions */ + guint32 idle_time; +}; + + +struct _GtkRetrievalInfo +{ + GtkWidget *widget; + GdkAtom selection; /* Selection being retrieved. */ + GdkAtom target; /* Form of selection that we requested */ + guint32 idle_time; /* Number of seconds since we last heard + from selection owner */ + guchar *buffer; /* Buffer in which to accumulate results */ + gint offset; /* Current offset in buffer, -1 indicates + not yet started */ +}; + +struct _GtkSelectionHandler +{ + GdkAtom selection; /* selection thats handled */ + GdkAtom target; /* target thats handled */ + GtkSelectionFunction function; /* callback function */ + GtkRemoveFunction remove_func; /* called when callback is removed */ + gpointer data; /* callback data */ +}; + +/* Local Functions */ +static void gtk_selection_init (void); +static gint gtk_selection_incr_timeout (GtkIncrInfo *info); +static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info); +static void gtk_selection_retrieval_report (GtkRetrievalInfo *info, + GdkAtom type, gint format, + guchar *buffer, gint length); +static GtkSelectionHandler *gtk_selection_find_handler (GtkWidget *widget, + GdkAtom selection, + GdkAtom target); +static void gtk_selection_default_handler (GtkWidget *widget, + GtkSelectionData *data); + +/* Local Data */ +static gint initialize = TRUE; +static GList *current_retrievals = NULL; +static GList *current_incrs = NULL; +static GList *current_selections = NULL; + +static GdkAtom gtk_selection_atoms[LAST_ATOM]; +static const char *gtk_selection_handler_key = "selection_handlers"; + +/************************************************************* + * gtk_selection_owner_set: + * Claim ownership of a selection. + * arguments: + * widget: new selection owner + * selection: which selection + * time: time (use GDK_CURRENT_TIME only if necessary) + * + * results: + *************************************************************/ + +gint +gtk_selection_owner_set (GtkWidget *widget, + GdkAtom selection, + guint32 time) +{ + GList *tmp_list; + GtkWidget *old_owner; + GtkSelectionInfo *selection_info; + GdkWindow *window; + + if (widget == NULL) + window = NULL; + else + { + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + window = widget->window; + } + + tmp_list = current_selections; + while (tmp_list) + { + selection_info = (GtkSelectionInfo *)tmp_list->data; + + if (selection_info->selection == selection) + break; + + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL) + selection_info = NULL; + else + if (selection_info->widget == widget) + return TRUE; + + if (gdk_selection_owner_set (window, selection, time, TRUE)) + { + old_owner = NULL; + + if (widget == NULL) + { + if (selection_info) + { + old_owner = selection_info->widget; + current_selections = g_list_remove_link (current_selections, + tmp_list); + g_list_free (tmp_list); + g_free (selection_info); + } + } + else + { + if (selection_info == NULL) + { + selection_info = g_new (GtkSelectionInfo, 1); + selection_info->selection = selection; + selection_info->widget = widget; + selection_info->time = time; + current_selections = g_list_append (current_selections, + selection_info); + } + else + { + old_owner = selection_info->widget; + selection_info->widget = widget; + selection_info->time = time; + } + } + /* If another widget in the application lost the selection, + * send it a GDK_SELECTION_CLEAR event, unless we're setting + * the owner to None, in which case an event will be sent */ + if (old_owner && (widget != NULL)) + { + GdkEventSelection event; + + event.type = GDK_SELECTION_CLEAR; + event.window = old_owner->window; + event.selection = selection; + event.time = time; + + gtk_widget_event (widget, (GdkEvent *) &event); + } + return TRUE; + } + else + return FALSE; +} + +/************************************************************* + * gtk_selection_add_handler: + * Add a handler for a specified selection/target pair + * + * arguments: + * widget: The widget the handler applies to + * selection: + * target: + * format: Format in which this handler will return data + * function: Callback function (can be NULL) + * data: User data for callback + * + * results: + *************************************************************/ + +void +gtk_selection_add_handler (GtkWidget *widget, + GdkAtom selection, + GdkAtom target, + GtkSelectionFunction function, + GtkRemoveFunction remove_func, + gpointer data) +{ + GList *selection_handlers; + GList *tmp_list; + GtkSelectionHandler *handler; + + g_return_if_fail (widget != NULL); + if (initialize) + gtk_selection_init (); + + selection_handlers = gtk_object_get_data (GTK_OBJECT (widget), + gtk_selection_handler_key); + + /* Reuse old handler structure, if present */ + tmp_list = selection_handlers; + while (tmp_list) + { + handler = (GtkSelectionHandler *)tmp_list->data; + if ((handler->selection == selection) && (handler->target == target)) + { + if (handler->remove_func) + (*handler->remove_func)(handler->data); + if (function) + { + handler->function = function; + handler->remove_func = remove_func; + handler->data = data; + } + else + { + selection_handlers = g_list_remove_link (selection_handlers, + tmp_list); + g_list_free (tmp_list); + g_free (handler); + } + return; + } + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL && function) + { + handler = g_new (GtkSelectionHandler, 1); + handler->selection = selection; + handler->target = target; + handler->function = function; + handler->remove_func = remove_func; + handler->data = data; + selection_handlers = g_list_append (selection_handlers, handler); + } + + gtk_object_set_data (GTK_OBJECT (widget), gtk_selection_handler_key, + selection_handlers); +} + +/************************************************************* + * gtk_selection_remove_all: + * Removes all handlers and unsets ownership of all + * selections for a widget. Called when widget is being + * destroyed + * + * arguments: + * widget: The widget + * results: + *************************************************************/ + +void +gtk_selection_remove_all (GtkWidget *widget) +{ + GList *tmp_list; + GList *next; + GtkSelectionInfo *selection_info; + GList *selection_handlers; + GtkSelectionHandler *handler; + + /* Remove pending requests/incrs for this widget */ + + tmp_list = current_incrs; + while (tmp_list) + { + next = tmp_list->next; + if (((GtkIncrInfo *)tmp_list->data)->widget == widget) + { + current_incrs = g_list_remove_link (current_incrs, tmp_list); + /* structure will be freed in timeout */ + g_list_free (tmp_list); + } + tmp_list = next; + } + + tmp_list = current_retrievals; + while (tmp_list) + { + next = tmp_list->next; + if (((GtkRetrievalInfo *)tmp_list->data)->widget == widget) + { + current_retrievals = g_list_remove_link (current_retrievals, + tmp_list); + /* structure will be freed in timeout */ + g_list_free (tmp_list); + } + tmp_list = next; + } + + /* Disclaim ownership of any selections */ + + tmp_list = current_selections; + while (tmp_list) + { + next = tmp_list->next; + selection_info = (GtkSelectionInfo *)tmp_list->data; + + if (selection_info->widget == widget) + { + gdk_selection_owner_set (NULL, + selection_info->selection, + GDK_CURRENT_TIME, FALSE); + current_selections = g_list_remove_link (current_selections, + tmp_list); + g_list_free (tmp_list); + g_free (selection_info); + } + + tmp_list = next; + } + + /* Now remove all handlers */ + + selection_handlers = gtk_object_get_data (GTK_OBJECT (widget), + gtk_selection_handler_key); + + tmp_list = selection_handlers; + while (tmp_list) + { + next = tmp_list->next; + handler = (GtkSelectionHandler *)tmp_list->data; + + if (handler->remove_func) + (*handler->remove_func)(handler->data); + + g_free (handler); + + tmp_list = next; + } + + g_list_free (selection_handlers); +} + +/************************************************************* + * gtk_selection_convert: + * Request the contents of a selection. When received, + * a "selection_received" signal will be generated. + * + * arguments: + * widget: The widget which acts as requestor + * selection: Which selection to get + * target: Form of information desired (e.g., STRING) + * time: Time of request (usually of triggering event) + * In emergency, you could use GDK_CURRENT_TIME + * + * results: + * TRUE if requested succeeded. FALSE if we could not process + * request. (e.g., there was already a request in process for + * this widget). + *************************************************************/ + +gint +gtk_selection_convert (GtkWidget *widget, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + GtkRetrievalInfo *info; + GList *tmp_list; + GdkWindow *owner_window; + + g_return_val_if_fail (widget != NULL, FALSE); + + if (initialize) + gtk_selection_init (); + + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + /* Check to see if there are already any retrievals in progress for + this widget. If we changed GDK to use the selection for the + window property in which to store the retrieved information, then + we could support multiple retrievals for different selections. + This might be useful for DND. */ + + tmp_list = current_retrievals; + while (tmp_list) + { + info = (GtkRetrievalInfo *)tmp_list->data; + if (info->widget == widget) + return FALSE; + tmp_list = tmp_list->next; + } + + info = g_new (GtkRetrievalInfo, 1); + + info->widget = widget; + info->selection = selection; + info->target = target; + info->buffer = NULL; + info->offset = -1; + + /* Check if this process has current owner. If so, call handler + procedure directly to avoid deadlocks with INCR. */ + + owner_window = gdk_selection_owner_get (selection); + + if (owner_window != NULL) + { + GtkWidget *owner_widget; + GtkSelectionHandler *handler; + GtkSelectionData selection_data; + + selection_data.selection = selection; + selection_data.target = target; + selection_data.data = NULL; + selection_data.length = -1; + + gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget); + + if (owner_widget != NULL) + { + handler = gtk_selection_find_handler (owner_widget, selection, target); + if (handler) + (* handler->function)(owner_widget, + &selection_data, + handler->data); + else /* try the default handler */ + gtk_selection_default_handler (owner_widget, + &selection_data); + + gtk_selection_retrieval_report (info, + selection_data.type, + selection_data.format, + selection_data.data, + selection_data.length); + + g_free (selection_data.data); + + g_free (info); + return TRUE; + } + } + + /* Otherwise, we need to go through X */ + + current_retrievals = g_list_append (current_retrievals, info); + gdk_selection_convert (widget->window, selection, target, time); + gtk_timeout_add (1000, (GtkFunction) gtk_selection_retrieval_timeout, info); + + return TRUE; +} + +/************************************************************* + * gtk_selection_data_set: + * Store new data into a GtkSelectionData object. Should + * _only_ by called from a selection handler callback. + * Null terminates the stored data. + * arguments: + * type: the type of selection data + * format: format (number of bits in a unit) + * data: pointer to the data (will be copied) + * length: length of the data + * results: + *************************************************************/ + +void +gtk_selection_data_set (GtkSelectionData *selection_data, + GdkAtom type, + gint format, + guchar *data, + gint length) +{ + if (selection_data->data) + g_free (selection_data->data); + + selection_data->type = type; + selection_data->format = format; + + if (data) + { + selection_data->data = g_new (guchar, length+1); + memcpy (selection_data->data, data, length); + selection_data->data[length] = 0; + } + else + selection_data->data = NULL; + + selection_data->length = length; +} + +/************************************************************* + * gtk_selection_init: + * Initialize local variables + * arguments: + * + * results: + *************************************************************/ + +static void +gtk_selection_init (void) +{ + gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE); + gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE); + gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE); + gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE); +} + +/************************************************************* + * gtk_selection_clear: + * Handler for "selection_clear_event" + * arguments: + * widget: + * event: + * results: + *************************************************************/ + +gint +gtk_selection_clear (GtkWidget *widget, + GdkEventSelection *event) +{ + /* FIXME: there can be a problem if we change the selection + via gtk_selection_owner_set after another client claims + the selection, but before we get the notification event. + Tk filters based on serial #'s, which aren't retained by + GTK. Filtering based on time's will be inherently + somewhat unreliable. */ + + GList *tmp_list; + GtkSelectionInfo *selection_info; + + tmp_list = current_selections; + while (tmp_list) + { + selection_info = (GtkSelectionInfo *)tmp_list->data; + + if ((selection_info->selection == event->selection) && + (selection_info->widget == widget)) + break; + + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL || selection_info->time > event->time) + return TRUE; + + current_selections = g_list_remove_link (current_selections, tmp_list); + g_list_free (tmp_list); + g_free (selection_info); + + return TRUE; +} + + +/************************************************************* + * gtk_selection_request: + * Handler for "selection_request_event" + * arguments: + * widget: + * event: + * results: + *************************************************************/ + +gint +gtk_selection_request (GtkWidget *widget, + GdkEventSelection *event) +{ + GtkIncrInfo *info; + GtkSelectionHandler *handler; + GList *tmp_list; + guchar *mult_atoms; + int i; + + /* Check if we own selection */ + + tmp_list = current_selections; + while (tmp_list) + { + GtkSelectionInfo *selection_info = (GtkSelectionInfo *)tmp_list->data; + + if ((selection_info->selection == event->selection) && + (selection_info->widget == widget)) + break; + + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL) + return FALSE; + + info = g_new(GtkIncrInfo, 1); + + info->widget = widget; + info->selection = event->selection; + info->num_incrs = 0; + + /* Create GdkWindow structure for the requestor */ + + info->requestor = gdk_window_lookup (event->requestor); + if (!info->requestor) + info->requestor = gdk_window_foreign_new (event->requestor); + + /* Determine conversions we need to perform */ + + if (event->target == gtk_selection_atoms[MULTIPLE]) + { + GdkAtom type; + gint format; + gint length; + + mult_atoms = NULL; + if (!gdk_property_get (info->requestor, event->property, GDK_SELECTION_TYPE_ATOM, + 0, GTK_SELECTION_MAX_SIZE, FALSE, + &type, &format, &length, &mult_atoms) || + type != GDK_SELECTION_TYPE_ATOM || format != 8*sizeof(GdkAtom)) + { + gdk_selection_send_notify (event->requestor, event->selection, + event->target, GDK_NONE, event->time); + g_free (mult_atoms); + g_free (info); + return TRUE; + } + + info->num_conversions = length / (2*sizeof (GdkAtom)); + info->conversions = g_new (GtkIncrConversion, info->num_conversions); + + for (i=0; inum_conversions; i++) + { + info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i]; + info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1]; + } + } + else /* only a single conversion */ + { + info->conversions = g_new (GtkIncrConversion, 1); + info->num_conversions = 1; + info->conversions[0].target = event->target; + info->conversions[0].property = event->property; + mult_atoms = (guchar *)info->conversions; + } + + /* Loop through conversions and determine which of these are big + enough to require doing them via INCR */ + for (i=0; inum_conversions; i++) + { + GtkSelectionData data; + gint items; + + data.selection = event->selection; + data.target = info->conversions[i].target; + data.data = NULL; + data.length = -1; + +#ifdef DEBUG_SELECTION + g_print("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)\n", + event->selection, info->conversions[i].target, + gdk_atom_name(info->conversions[i].target), + event->requestor, event->property); +#endif + + handler = gtk_selection_find_handler (widget, event->selection, + info->conversions[i].target); + if (handler) + (* handler->function)(widget, &data, handler->data); + else + gtk_selection_default_handler (widget, &data); + + if (data.length < 0) + { + ((GdkAtom *)mult_atoms)[2*i+1] = GDK_NONE; + info->conversions[i].property = GDK_NONE; + continue; + } + + g_return_val_if_fail ((data.format >= 8) + && (data.format % 8 == 0), FALSE) + + items = (data.length + data.format/8 - 1) / (data.format/8); + + if (data.length > GTK_SELECTION_MAX_SIZE) + { + /* Sending via INCR */ + + info->conversions[i].offset = 0; + info->conversions[i].data = data; + info->num_incrs++; + + gdk_property_change (info->requestor, + info->conversions[i].property, + gtk_selection_atoms[INCR], + 8*sizeof (GdkAtom), + GDK_PROP_MODE_REPLACE, + (guchar *)&items, 1); + } + else + { + info->conversions[i].offset = -1; + + gdk_property_change (info->requestor, + info->conversions[i].property, + data.type, + data.format, + GDK_PROP_MODE_REPLACE, + data.data, items); + + g_free (data.data); + } + } + + /* If we have some INCR's, we need to send the rest of the data in + a callback */ + + if (info->num_incrs > 0) + { + /* FIXME: this could be dangerous if window doesn't still + exist */ + +#ifdef DEBUG_SELECTION + g_print("Starting INCR...\n"); +#endif + + gdk_window_set_events (info->requestor, + gdk_window_get_events (info->requestor) | + GDK_PROPERTY_CHANGE_MASK); + current_incrs = g_list_append (current_incrs, info); + gtk_timeout_add (1000, (GtkFunction)gtk_selection_incr_timeout, info); + } + + /* If it was a MULTIPLE request, set the property to indicate which + conversions succeeded */ + if (event->target == gtk_selection_atoms[MULTIPLE]) + { + gdk_property_change (info->requestor, event->property, + GDK_SELECTION_TYPE_ATOM, 8*sizeof(GdkAtom), + GDK_PROP_MODE_REPLACE, + mult_atoms, info->num_conversions); + g_free (mult_atoms); + } + + gdk_selection_send_notify (event->requestor, event->selection, event->target, + event->property, event->time); + + if (info->num_incrs == 0) + { + g_free (info->conversions); + g_free (info); + } + + return TRUE; +} + +/************************************************************* + * gtk_selection_incr_event: + * Called whenever an PropertyNotify event occurs for an + * GdkWindow with user_data == NULL. These will be notifications + * that a window we are sending the selection to via the + * INCR protocol has deleted a property and is ready for + * more data. + * + * arguments: + * window: the requestor window + * event: the property event structure + * + * results: + *************************************************************/ + +gint +gtk_selection_incr_event (GdkWindow *window, + GdkEventProperty *event) +{ + GList *tmp_list; + GtkIncrInfo *info; + gint num_bytes; + guchar *buffer; + + int i; + + if (event->state != GDK_PROPERTY_DELETE) + return FALSE; + +#ifdef DEBUG_SELECTION + g_print("PropertyDelete, property %ld\n", event->atom); +#endif + + /* Now find the appropriate ongoing INCR */ + tmp_list = current_incrs; + while (tmp_list) + { + info = (GtkIncrInfo *)tmp_list->data; + if (info->requestor == event->window) + break; + + tmp_list = tmp_list->next; + } + + if (tmp_list == NULL) + return FALSE; + + /* Find out which target this is for */ + for (i=0; inum_conversions; i++) + { + if (info->conversions[i].property == event->atom && + info->conversions[i].offset != -1) + { + info->idle_time = 0; + + if (info->conversions[i].offset == -2) /* only the last 0-length + piece*/ + { + num_bytes = 0; + buffer = NULL; + } + else + { + num_bytes = info->conversions[i].data.length - + info->conversions[i].offset; + buffer = info->conversions[i].data.data + + info->conversions[i].offset; + + if (num_bytes > GTK_SELECTION_MAX_SIZE) + { + num_bytes = GTK_SELECTION_MAX_SIZE; + info->conversions[i].offset += GTK_SELECTION_MAX_SIZE; + } + else + info->conversions[i].offset = -2; + } +#ifdef DEBUG_SELECTION + g_print("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld\n", + num_bytes, info->conversions[i].offset, + GDK_WINDOW_XWINDOW(info->requestor), event->atom); +#endif + gdk_property_change (info->requestor, event->atom, + info->conversions[i].data.type, + info->conversions[i].data.format, + GDK_PROP_MODE_REPLACE, + buffer, + (num_bytes + info->conversions[i].data.format/8 - 1) / + (info->conversions[i].data.format/8)); + + if (info->conversions[i].offset == -2) + { + g_free (info->conversions[i].data.data); + info->conversions[i].data.data = NULL; + } + + if (num_bytes == 0) + { + info->num_incrs--; + info->conversions[i].offset = -1; + } + } + break; + } + + /* Check if we're finished with all the targets */ + + if (info->num_incrs == 0) + { + current_incrs = g_list_remove_link (current_incrs, tmp_list); + g_list_free (tmp_list); + /* Let the timeout free it */ + } + + return TRUE; +} + +/************************************************************* + * gtk_selection_incr_timeout: + * Timeout callback for the sending portion of the INCR + * protocol + * arguments: + * info: Information about this incr + * results: + *************************************************************/ + +static gint +gtk_selection_incr_timeout (GtkIncrInfo *info) +{ + GList *tmp_list; + + /* Determine if retrieval has finished by checking if it still in + list of pending retrievals */ + + tmp_list = current_incrs; + while (tmp_list) + { + if (info == (GtkIncrInfo *)tmp_list->data) + break; + tmp_list = tmp_list->next; + } + + /* If retrieval is finished */ + if (!tmp_list || info->idle_time >= 5) + { + if (tmp_list && info->idle_time >= 5) + { + current_incrs = g_list_remove_link (current_incrs, tmp_list); + g_list_free (tmp_list); + } + + g_free (info->conversions); + /* FIXME: we should check if requestor window is still in use, + and if not, remove it? */ + + g_free (info); + + return FALSE; /* remove timeout */ + } + else + { + info->idle_time++; + + return TRUE; /* timeout will happen again */ + } +} + +/************************************************************* + * gtk_selection_notify: + * Handler for "selection_notify_event" signals on windows + * where a retrieval is currently in process. The selection + * owner has responded to our conversion request. + * arguments: + * widget: Widget getting signal + * event: Selection event structure + * info: Information about this retrieval + * results: + * was event handled? + *************************************************************/ + +gint +gtk_selection_notify (GtkWidget *widget, + GdkEventSelection *event) +{ + GList *tmp_list; + GtkRetrievalInfo *info; + guchar *buffer; + gint length; + GdkAtom type; + gint format; + +#ifdef DEBUG_SELECTION + g_print("Initial receipt of selection %ld, target %ld (property = %ld)\n", + event->selection, event->target, event->property); +#endif + + tmp_list = current_retrievals; + while (tmp_list) + { + info = (GtkRetrievalInfo *)tmp_list->data; + if (info->widget == widget && info->selection == event->selection) + break; + tmp_list = tmp_list->next; + } + + if (!tmp_list) /* no retrieval in progress */ + return FALSE; + + if (event->property == GDK_NONE) + { + current_retrievals = g_list_remove_link (current_retrievals, tmp_list); + g_list_free (tmp_list); + /* structure will be freed in timeout */ + gtk_selection_retrieval_report (info, + GDK_NONE, 0, NULL, -1); + + return TRUE; + } + + length = gdk_selection_property_get (widget->window, &buffer, + &type, &format); + + if (type == gtk_selection_atoms[INCR]) + { + /* The remainder of the selection will come through PropertyNotify + events */ + + info->idle_time = 0; + info->offset = 0; /* Mark as OK to proceed */ + gdk_window_set_events (widget->window, + gdk_window_get_events (widget->window) + | GDK_PROPERTY_CHANGE_MASK); + } + else + { + /* We don't delete the info structure - that will happen in timeout */ + current_retrievals = g_list_remove_link (current_retrievals, tmp_list); + g_list_free (tmp_list); + + info->offset = length; + gtk_selection_retrieval_report (info, + type, format, + buffer, length); + } + + gdk_property_delete (widget->window, event->property); + + g_free (buffer); + + return TRUE; +} + +/************************************************************* + * gtk_selection_property_notify: + * Handler for "property_notify_event" signals on windows + * where a retrieval is currently in process. The selection + * owner has added more data. + * arguments: + * widget: Widget getting signal + * event: Property event structure + * info: Information about this retrieval + * results: + * was event handled? + *************************************************************/ + +gint +gtk_selection_property_notify (GtkWidget *widget, + GdkEventProperty *event) +{ + GList *tmp_list; + GtkRetrievalInfo *info; + guchar *new_buffer; + int length; + GdkAtom type; + gint format; + + if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */ + (event->atom != gdk_selection_property)) /* not the right property */ + return FALSE; + +#ifdef DEBUG_SELECTION + g_print("PropertyNewValue, property %ld\n", + event->atom); +#endif + + tmp_list = current_retrievals; + while (tmp_list) + { + info = (GtkRetrievalInfo *)tmp_list->data; + if (info->widget == widget) + break; + tmp_list = tmp_list->next; + } + + if (!tmp_list) /* No retrieval in progress */ + return FALSE; + + if (info->offset < 0) /* We haven't got the SelectionNotify + for this retrieval yet */ + return FALSE; + + info->idle_time = 0; + + length = gdk_selection_property_get (widget->window, &new_buffer, + &type, &format); + gdk_property_delete (widget->window, event->atom); + + /* We could do a lot better efficiency-wise by paying attention to + what length was sent in the initial INCR transaction, instead of + doing memory allocation at every step. But its only guaranteed to + be a _lower bound_ (pretty useless!) */ + + if (length == 0 || type == GDK_NONE) /* final zero length portion */ + { + /* Info structure will be freed in timeout */ + current_retrievals = g_list_remove_link (current_retrievals, tmp_list); + g_list_free (tmp_list); + gtk_selection_retrieval_report (info, + type, format, + (type == GDK_NONE) ? NULL : info->buffer, + (type == GDK_NONE) ? -1 : info->offset); + } + else /* append on newly arrived data */ + { + if (!info->buffer) + { +#ifdef DEBUG_SELECTION + g_print("Start - Adding %d bytes at offset 0\n", + length); +#endif + info->buffer = new_buffer; + info->offset = length; + } + else + { + +#ifdef DEBUG_SELECTION + g_print("Appending %d bytes at offset %d\n", + length,info->offset); +#endif + /* We copy length+1 bytes to preserve guaranteed null termination */ + info->buffer = g_realloc (info->buffer, info->offset+length+1); + memcpy (info->buffer + info->offset, new_buffer, length+1); + info->offset += length; + g_free (new_buffer); + } + } + + return TRUE; +} + +/************************************************************* + * gtk_selection_retrieval_timeout: + * Timeout callback while receiving a selection. + * arguments: + * info: Information about this retrieval + * results: + *************************************************************/ + +static gint +gtk_selection_retrieval_timeout (GtkRetrievalInfo *info) +{ + GList *tmp_list; + + /* Determine if retrieval has finished by checking if it still in + list of pending retrievals */ + + tmp_list = current_retrievals; + while (tmp_list) + { + if (info == (GtkRetrievalInfo *)tmp_list->data) + break; + tmp_list = tmp_list->next; + } + + /* If retrieval is finished */ + if (!tmp_list || info->idle_time >= 5) + { + if (tmp_list && info->idle_time >= 5) + { + current_retrievals = g_list_remove_link (current_retrievals, tmp_list); + g_list_free (tmp_list); + gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1); + } + + g_free (info->buffer); + g_free (info); + + return FALSE; /* remove timeout */ + } + else + { + info->idle_time++; + + return TRUE; /* timeout will happen again */ + } + +} + +/************************************************************* + * gtk_selection_retrieval_report: + * Emits a "selection_received" signal. + * arguments: + * info: information about the retrieval that completed + * buffer: buffer containing data (NULL => errror) + * results: + *************************************************************/ + +static void +gtk_selection_retrieval_report (GtkRetrievalInfo *info, + GdkAtom type, gint format, + guchar *buffer, gint length) +{ + GtkSelectionData data; + + data.selection = info->selection; + data.target = info->target; + data.type = type; + data.format = format; + + data.length = length; + data.data = buffer; + + gtk_signal_emit_by_name (GTK_OBJECT(info->widget), + "selection_received", &data); +} + +/************************************************************* + * gtk_selection_find_handler: + * Find handler for specified widget/selection/target + * arguments: + * widget: + * selection: + * target: + * results: + *************************************************************/ + +static GtkSelectionHandler * +gtk_selection_find_handler (GtkWidget *widget, + GdkAtom selection, + GdkAtom target) +{ + GList *tmp_list; + GtkSelectionHandler *handler; + + g_return_val_if_fail (widget != NULL, FALSE); + + tmp_list = gtk_object_get_data (GTK_OBJECT (widget), + gtk_selection_handler_key); + + while (tmp_list) + { + handler = (GtkSelectionHandler *)tmp_list->data; + if ((handler->selection == selection) && (handler->target == target)) + return handler; + tmp_list = tmp_list->next; + } + + return NULL; +} + + +/************************************************************* + * gtk_selection_default_handler: + * Handles some default targets that exist for any widget + * If it can't fit results into buffer, returns -1. This + * won't happen in any conceivable case, since it would + * require 1000 selection targets! + * + * arguments: + * widget: selection owner + * selection: selection requested + * target: target requested + * buffer: buffer to write results into + * length: size of buffer + * type: type atom + * format: length of type's units in bits + * + * results: + * Number of bytes written to buffer, -1 if error + *************************************************************/ + +static void +gtk_selection_default_handler (GtkWidget *widget, + GtkSelectionData *data) +{ + if (data->target == gtk_selection_atoms[TIMESTAMP]) + { + /* Time which was used to obtain selection */ + GList *tmp_list; + GtkSelectionInfo *selection_info; + + tmp_list = current_selections; + while (tmp_list) + { + selection_info = (GtkSelectionInfo *)tmp_list->data; + if ((selection_info->widget == widget) && + (selection_info->selection == data->selection)) + { + gtk_selection_data_set (data, + GDK_SELECTION_TYPE_INTEGER, + sizeof (guint32)*8, + (guchar *)&selection_info->time, + sizeof (guint32)); + return; + } + + tmp_list = tmp_list->next; + } + + data->length = -1; + } + else if (data->target == gtk_selection_atoms[TARGETS]) + { + /* List of all targets supported for this widget/selection pair */ + GdkAtom *p; + gint count; + GList *tmp_list; + GtkSelectionHandler *handler; + + count = 3; + tmp_list = gtk_object_get_data (GTK_OBJECT(widget), + gtk_selection_handler_key); + while (tmp_list) + { + handler = (GtkSelectionHandler *)tmp_list->data; + + if (handler->selection == data->selection) + count++; + + tmp_list = tmp_list->next; + } + + data->type = GDK_SELECTION_TYPE_ATOM; + data->format = 8*sizeof (GdkAtom); + data->length = count*sizeof (GdkAtom); + + p = g_new (GdkAtom, count); + data->data = (guchar *)p; + + *p++ = gtk_selection_atoms[TIMESTAMP]; + *p++ = gtk_selection_atoms[TARGETS]; + *p++ = gtk_selection_atoms[MULTIPLE]; + + tmp_list = gtk_object_get_data (GTK_OBJECT(widget), + gtk_selection_handler_key); + while (tmp_list) + { + handler = (GtkSelectionHandler *)tmp_list->data; + + if (handler->selection == data->selection) + *p++ = handler->target; + + tmp_list = tmp_list->next; + } + } + else + { + data->length = -1; + } +} diff --git a/gtk/gtkselection.h b/gtk/gtkselection.h new file mode 100644 index 000000000..18f3dc4b5 --- /dev/null +++ b/gtk/gtkselection.h @@ -0,0 +1,91 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_SELECTION_H__ +#define __GTK_SELECTION_H__ + + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _GtkSelectionData GtkSelectioData; + +/* a callback function that provides the selection. Arguments are: + widget: selection owner + offset: offset into selection + buffer: buffer into which to store selection + length: length of buffer + bytes_after: (sizeof(selection) - offset - length ) (return) + data: callback data */ + +typedef void (*GtkSelectionFunction) (GtkWidget *widget, + GtkSelectionData *selection_data, + gpointer data); + +/* Public interface */ + +gint gtk_selection_owner_set (GtkWidget *widget, + GdkAtom selection, + guint32 time); +void gtk_selection_add_handler (GtkWidget *widget, + GdkAtom selection, + GdkAtom target, + GtkSelectionFunction function, + GtkRemoveFunction remove_func, + gpointer data); +gint gtk_selection_convert (GtkWidget *widget, + GdkAtom selection, + GdkAtom target, + guint32 time); + + +void gtk_selection_data_set (GtkSelectionData *selection_data, + GdkAtom type, + gint format, + guchar *data, + gint length); + +/* Called when a widget is destroyed */ + +void gtk_selection_remove_all (GtkWidget *widget); + +/* Event handlers */ + +gint gtk_selection_clear (GtkWidget *widget, + GdkEventSelection *event); +gint gtk_selection_request (GtkWidget *widget, + GdkEventSelection *event); +gint gtk_selection_incr_event (GdkWindow *window, + GdkEventProperty *event); +gint gtk_selection_notify (GtkWidget *widget, + GdkEventSelection *event); +gint gtk_selection_property_notify (GtkWidget *widget, + GdkEventProperty *event); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SELECTION_H__ */ diff --git a/gtk/gtkseparator.c b/gtk/gtkseparator.c new file mode 100644 index 000000000..6ad41ad5b --- /dev/null +++ b/gtk/gtkseparator.c @@ -0,0 +1,57 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkseparator.h" + + +static void gtk_separator_class_init (GtkSeparatorClass *klass); +static void gtk_separator_init (GtkSeparator *separator); + + +guint +gtk_separator_get_type () +{ + static guint separator_type = 0; + + if (!separator_type) + { + GtkTypeInfo separator_info = + { + "GtkSeparator", + sizeof (GtkSeparator), + sizeof (GtkSeparatorClass), + (GtkClassInitFunc) gtk_separator_class_init, + (GtkObjectInitFunc) gtk_separator_init, + (GtkArgFunc) NULL, + }; + + separator_type = gtk_type_unique (gtk_widget_get_type (), &separator_info); + } + + return separator_type; +} + +static void +gtk_separator_class_init (GtkSeparatorClass *class) +{ +} + +static void +gtk_separator_init (GtkSeparator *separator) +{ + GTK_WIDGET_SET_FLAGS (separator, GTK_NO_WINDOW | GTK_BASIC); +} diff --git a/gtk/gtkseparator.h b/gtk/gtkseparator.h new file mode 100644 index 000000000..bfccd337a --- /dev/null +++ b/gtk/gtkseparator.h @@ -0,0 +1,58 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_SEPARATOR_H__ +#define __GTK_SEPARATOR_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_SEPARATOR(obj) GTK_CHECK_CAST (obj, gtk_separator_get_type (), GtkSeparator) +#define GTK_SEPARATOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_separator_get_type (), GtkSeparatorClass) +#define GTK_IS_SEPARATOR(obj) GTK_CHECK_TYPE (obj, gtk_separator_get_type ()) + + +typedef struct _GtkSeparator GtkSeparator; +typedef struct _GtkSeparatorClass GtkSeparatorClass; + +struct _GtkSeparator +{ + GtkWidget widget; +}; + +struct _GtkSeparatorClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_separator_get_type (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SEPARATOR_H__ */ diff --git a/gtk/gtksignal.c b/gtk/gtksignal.c new file mode 100644 index 000000000..65efdb991 --- /dev/null +++ b/gtk/gtksignal.c @@ -0,0 +1,1322 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtksignal.h" + + +#define MAX_PARAMS 20 +#define DONE 1 +#define RESTART 2 + +#define GTK_RUN_TYPE(x) ((x) & GTK_RUN_MASK) + + +typedef struct _GtkSignal GtkSignal; +typedef struct _GtkSignalInfo GtkSignalInfo; +typedef struct _GtkHandler GtkHandler; +typedef struct _GtkHandlerInfo GtkHandlerInfo; +typedef struct _GtkEmission GtkEmission; + +typedef void (*GtkSignalMarshaller0) (GtkObject *object, + gpointer data); + +struct _GtkSignalInfo +{ + gchar *name; + gint object_type; + gint signal_type; +}; + +struct _GtkSignal +{ + GtkSignalInfo info; + gint function_offset; + GtkSignalRunType run_type; + GtkSignalMarshaller marshaller; + GtkType return_val; + GtkType *params; + gint nparams; +}; + +struct _GtkHandler +{ + guint16 id; + guint signal_type : 13; + guint object_signal : 1; + guint blocked : 1; + guint after : 1; + guint no_marshal : 1; + GtkSignalFunc func; + gpointer func_data; + GtkSignalDestroy destroy_func; + GtkHandler *next; +}; + +struct _GtkHandlerInfo +{ + GtkObject *object; + GtkSignalMarshaller marshaller; + GtkArg *params; + GtkType *param_types; + GtkType return_val; + GtkSignalRunType run_type; + gint nparams; + gint signal_type; +}; + +struct _GtkEmission +{ + GtkObject *object; + gint signal_type; +}; + + +static void gtk_signal_init (void); +static guint gtk_signal_hash (gint *key); +static gint gtk_signal_compare (gint *a, + gint *b); +static guint gtk_signal_info_hash (GtkSignalInfo *a); +static gint gtk_signal_info_compare (GtkSignalInfo *a, + GtkSignalInfo *b); +static GtkHandler* gtk_signal_handler_new (void); +static void gtk_signal_handler_destroy (GtkHandler *handler); +static void gtk_signal_handler_insert (GtkObject *object, + GtkHandler *handler); +static gint gtk_signal_real_emit (GtkObject *object, + gint signal_type, + va_list args); +static GtkHandler* gtk_signal_get_handlers (GtkObject *object, + gint signal_type); +static gint gtk_signal_connect_by_type (GtkObject *object, + gint signal_type, + gint object_signal, + GtkSignalFunc func, + gpointer func_data, + GtkSignalDestroy destroy_func, + gint after, + gint no_marshal); +static GtkEmission* gtk_emission_new (void); +static void gtk_emission_destroy (GtkEmission *emission); +static void gtk_emission_add (GList **emissions, + GtkObject *object, + gint signal_type); +static void gtk_emission_remove (GList **emissions, + GtkObject *object, + gint signal_type); +static gint gtk_emission_check (GList *emissions, + GtkObject *object, + gint signal_type); +static gint gtk_handlers_run (GtkHandler *handlers, + GtkHandlerInfo *info, + gint after); +static void gtk_params_get (GtkArg *params, + gint nparams, + GtkType *param_types, + GtkType return_val, + va_list args); + + +static gint initialize = TRUE; +static GHashTable *signal_hash_table = NULL; +static GHashTable *signal_info_hash_table = NULL; +static gint next_signal = 1; +static gint next_handler_id = 1; + +static const char *handler_key = "signal_handlers"; + +static GMemChunk *handler_mem_chunk = NULL; +static GMemChunk *emission_mem_chunk = NULL; + +static GList *current_emissions = NULL; +static GList *stop_emissions = NULL; +static GList *restart_emissions = NULL; + +static GtkSignalMarshal marshal = NULL; +static GtkSignalDestroy destroy = NULL; + + +gint +gtk_signal_new (const gchar *name, + GtkSignalRunType run_type, + gint object_type, + gint function_offset, + GtkSignalMarshaller marshaller, + GtkType return_val, + gint nparams, + ...) +{ + GtkType *params; + GtkSignal *signal; + GtkSignalInfo info; + gint *type; + gint i; + va_list args; + + g_return_val_if_fail (name != NULL, 0); + g_return_val_if_fail (marshaller != NULL, 0); + g_return_val_if_fail (nparams < 10, 0); + + if (initialize) + gtk_signal_init (); + + info.name = (char*)name; + info.object_type = object_type; + + type = g_hash_table_lookup (signal_info_hash_table, &info); + if (type) + { + g_warning ("signal \"%s\" already exists in the \"%s\" class ancestry\n", + name, gtk_type_name (object_type)); + return 0; + } + + signal = g_new (GtkSignal, 1); + signal->info.name = g_strdup(name); + signal->info.object_type = object_type; + signal->info.signal_type = next_signal++; + signal->function_offset = function_offset; + signal->run_type = run_type; + signal->marshaller = marshaller; + signal->return_val = return_val; + signal->params = NULL; + signal->nparams = nparams; + + g_hash_table_insert (signal_hash_table, &signal->info.signal_type, signal); + g_hash_table_insert (signal_info_hash_table, &signal->info, &signal->info.signal_type); + + if (nparams > 0) + { + signal->params = g_new (GtkType, nparams); + params = signal->params; + + va_start (args, nparams); + + for (i = 0; i < nparams; i++) + params[i] = va_arg (args, GtkType); + + va_end (args); + } + + return signal->info.signal_type; +} + +gint +gtk_signal_lookup (const gchar *name, + gint object_type) +{ + GtkSignalInfo info; + gint *type; + + g_return_val_if_fail (name != NULL, 0); + + if (initialize) + gtk_signal_init (); + + info.name = (char*)name; + + while (object_type) + { + info.object_type = object_type; + + type = g_hash_table_lookup (signal_info_hash_table, &info); + if (type) + return *type; + + object_type = gtk_type_parent (object_type); + } + + return 0; +} + +gchar* +gtk_signal_name (gint signal_num) +{ + GtkSignal *signal; + + signal = g_hash_table_lookup (signal_hash_table, &signal_num); + if (signal) + return signal->info.name; + + return NULL; +} + +gint +gtk_signal_emit (GtkObject *object, + gint signal_type, + ...) +{ + gint return_val; + + va_list args; + + g_return_val_if_fail (object != NULL, FALSE); + + if (initialize) + gtk_signal_init (); + + va_start (args, signal_type); + + return_val = gtk_signal_real_emit (object, signal_type, args); + + va_end (args); + + return return_val; +} + +gint +gtk_signal_emit_by_name (GtkObject *object, + const gchar *name, + ...) +{ + gint return_val; + gint type; + va_list args; + + g_return_val_if_fail (object != NULL, FALSE); + + if (initialize) + gtk_signal_init (); + + return_val = TRUE; + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + + if (type) + { + va_start (args, name); + + return_val = gtk_signal_real_emit (object, type, args); + + va_end (args); + } + + return return_val; +} + +void +gtk_signal_emit_stop (GtkObject *object, + gint signal_type) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (signal_type >= 1); + + if (initialize) + gtk_signal_init (); + + if (gtk_emission_check (current_emissions, object, signal_type)) + gtk_emission_add (&stop_emissions, object, signal_type); +} + +void +gtk_signal_emit_stop_by_name (GtkObject *object, + const gchar *name) +{ + gint type; + + g_return_if_fail (object != NULL); + g_return_if_fail (name != NULL); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (type) + gtk_signal_emit_stop (object, type); +} + +gint +gtk_signal_connect (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, FALSE, + func, func_data, NULL, + FALSE, FALSE); +} + +gint +gtk_signal_connect_after (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, FALSE, + func, func_data, NULL, + TRUE, FALSE); +} + +gint +gtk_signal_connect_interp (GtkObject *object, + gchar *name, + GtkCallbackMarshal func, + gpointer func_data, + GtkDestroyNotify destroy_func, + gint after) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, FALSE, + (GtkSignalFunc) func, func_data, + destroy_func, after, TRUE); +} + +gint +gtk_signal_connect_object (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, TRUE, + func, slot_object, NULL, + FALSE, FALSE); +} + +gint +gtk_signal_connect_object_after (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object) +{ + gint type; + + g_return_val_if_fail (object != NULL, 0); + + if (initialize) + gtk_signal_init (); + + type = gtk_signal_lookup (name, GTK_OBJECT_TYPE (object)); + if (!type) + { + g_warning ("could not find signal type \"%s\" in the \"%s\" class ancestry", + name, gtk_type_name (GTK_OBJECT_TYPE (object))); + return 0; + } + + return gtk_signal_connect_by_type (object, type, TRUE, + func, slot_object, NULL, + TRUE, FALSE); +} + +void +gtk_signal_disconnect (GtkObject *object, + gint anid) +{ + GtkHandler *tmp; + GtkHandler *prev; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + prev = NULL; + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->id == anid) + { + if (prev) + prev->next = tmp->next; + else + gtk_object_set_data (object, handler_key, tmp->next); + gtk_signal_handler_destroy (tmp); + return; + } + + prev = tmp; + tmp = tmp->next; + } + + g_warning ("could not find handler (%d)", anid); +} + +void +gtk_signal_disconnect_by_data (GtkObject *object, + gpointer data) +{ + GtkHandler *start; + GtkHandler *tmp; + GtkHandler *prev; + gint found_one; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + prev = NULL; + start = gtk_object_get_data (object, handler_key); + tmp = start; + found_one = FALSE; + + while (tmp) + { + if (tmp->func_data == data) + { + found_one = TRUE; + + if (prev) + prev->next = tmp->next; + else + start = tmp->next; + + gtk_signal_handler_destroy (tmp); + + if (prev) + { + tmp = prev->next; + } + else + { + prev = NULL; + tmp = start; + } + } + else + { + prev = tmp; + tmp = tmp->next; + } + } + + gtk_object_set_data (object, handler_key, start); + + if (!found_one) + g_warning ("could not find handler containing data (0x%0lX)", (long) data); +} + +void +gtk_signal_handler_block (GtkObject *object, + gint anid) +{ + GtkHandler *tmp; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->id == anid) + { + tmp->blocked = TRUE; + return; + } + + tmp = tmp->next; + } + + g_warning ("could not find handler (%d)", anid); +} + +void +gtk_signal_handler_block_by_data (GtkObject *object, + gpointer data) +{ + GtkHandler *tmp; + gint found_one; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + found_one = FALSE; + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->func_data == data) + { + tmp->blocked = TRUE; + found_one = TRUE; + } + + tmp = tmp->next; + } + + if (!found_one) + g_warning ("could not find handler containing data (0x%0lX)", (long) data); +} + +void +gtk_signal_handler_unblock (GtkObject *object, + gint anid) +{ + GtkHandler *tmp; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->id == anid) + { + tmp->blocked = FALSE; + return; + } + + tmp = tmp->next; + } + + g_warning ("could not find handler (%d)", anid); +} + +void +gtk_signal_handler_unblock_by_data (GtkObject *object, + gpointer data) +{ + GtkHandler *tmp; + gint found_one; + + g_return_if_fail (object != NULL); + + if (initialize) + gtk_signal_init (); + + found_one = FALSE; + tmp = gtk_object_get_data (object, handler_key); + + while (tmp) + { + if (tmp->func_data == data) + { + tmp->blocked = FALSE; + found_one = TRUE; + } + + tmp = tmp->next; + } + + if (!found_one) + g_warning ("could not find handler containing data (0x%0lX)", (long) data); +} + +void +gtk_signal_handlers_destroy (GtkObject *object) +{ + GtkHandler *list; + GtkHandler *handler; + + list = gtk_object_get_data (object, handler_key); + if (list) + { + while (list) + { + handler = list->next; + gtk_signal_handler_destroy (list); + list = handler; + } + + gtk_object_remove_data (object, handler_key); + } +} + +void +gtk_signal_default_marshaller (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *params) +{ + GtkSignalMarshaller0 rfunc; + + rfunc = (GtkSignalMarshaller0) func; + + (* rfunc) (object, func_data); +} + +void +gtk_signal_set_funcs (GtkSignalMarshal marshal_func, + GtkSignalDestroy destroy_func) +{ + marshal = marshal_func; + destroy = destroy_func; +} + + +static void +gtk_signal_init () +{ + if (initialize) + { + initialize = FALSE; + signal_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_hash, + (GCompareFunc) gtk_signal_compare); + signal_info_hash_table = g_hash_table_new ((GHashFunc) gtk_signal_info_hash, + (GCompareFunc) gtk_signal_info_compare); + } +} + +static guint +gtk_signal_hash (gint *key) +{ + return (guint) *key; +} + +static gint +gtk_signal_compare (gint *a, + gint *b) +{ + return (*a == *b); +} + +static guint +gtk_signal_info_hash (GtkSignalInfo *a) +{ + return (g_string_hash (a->name) + a->object_type); +} + +static gint +gtk_signal_info_compare (GtkSignalInfo *a, + GtkSignalInfo *b) +{ + return ((a->object_type == b->object_type) && + g_string_equal (a->name, b->name)); +} + +static GtkHandler* +gtk_signal_handler_new () +{ + GtkHandler *handler; + + if (!handler_mem_chunk) + handler_mem_chunk = g_mem_chunk_new ("handler mem chunk", sizeof (GtkHandler), + 1024, G_ALLOC_AND_FREE); + + handler = g_chunk_new (GtkHandler, handler_mem_chunk); + + handler->id = 0; + handler->signal_type = 0; + handler->object_signal = FALSE; + handler->blocked = FALSE; + handler->after = FALSE; + handler->no_marshal = FALSE; + handler->func = NULL; + handler->func_data = NULL; + handler->destroy_func = NULL; + handler->next = NULL; + + return handler; +} + +static void +gtk_signal_handler_destroy (GtkHandler *handler) +{ + if (!handler->func && destroy) + (* destroy) (handler->func_data); + else if (handler->destroy_func) + (* handler->destroy_func) (handler->func_data); + g_mem_chunk_free (handler_mem_chunk, handler); +} + +static void +gtk_signal_handler_insert (GtkObject *object, + GtkHandler *handler) +{ + GtkHandler *start; + GtkHandler *tmp; + GtkHandler *prev; + + start = gtk_object_get_data (object, handler_key); + if (!start) + { + gtk_object_set_data (object, handler_key, handler); + } + else + { + prev = NULL; + tmp = start; + + while (tmp) + { + if (tmp->signal_type < handler->signal_type) + { + if (prev) + prev->next = handler; + else + gtk_object_set_data (object, handler_key, handler); + handler->next = tmp; + break; + } + + if (!tmp->next) + { + tmp->next = handler; + break; + } + + prev = tmp; + tmp = tmp->next; + } + } +} + +static gint +gtk_signal_real_emit (GtkObject *object, + gint signal_type, + va_list args) +{ + gint old_value; + GtkSignal *signal; + GtkHandler *handlers; + GtkHandlerInfo info; + guchar **signal_func_offset; + gint being_destroyed; + GtkArg params[MAX_PARAMS]; + + g_return_val_if_fail (object != NULL, FALSE); + g_return_val_if_fail (signal_type >= 1, TRUE); + + being_destroyed = GTK_OBJECT_BEING_DESTROYED (object); + if (!GTK_OBJECT_NEED_DESTROY (object)) + { + signal = g_hash_table_lookup (signal_hash_table, &signal_type); + g_return_val_if_fail (signal != NULL, TRUE); + g_return_val_if_fail (gtk_type_is_a (GTK_OBJECT_TYPE (object), signal->info.object_type), TRUE); + + if ((signal->run_type & GTK_RUN_NO_RECURSE) && + gtk_emission_check (current_emissions, object, signal_type)) + { + gtk_emission_add (&restart_emissions, object, signal_type); + return TRUE; + } + + old_value = GTK_OBJECT_IN_CALL (object); + GTK_OBJECT_SET_FLAGS (object, GTK_IN_CALL); + + gtk_params_get (params, signal->nparams, signal->params, signal->return_val, args); + + gtk_emission_add (¤t_emissions, object, signal_type); + + restart: + if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST) + { + signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset); + if (*signal_func_offset) + (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset, NULL, params); + if (GTK_OBJECT_NEED_DESTROY (object)) + goto done; + } + + info.object = object; + info.marshaller = signal->marshaller; + info.params = params; + info.param_types = signal->params; + info.return_val = signal->return_val; + info.nparams = signal->nparams; + info.run_type = signal->run_type; + info.signal_type = signal_type; + + handlers = gtk_signal_get_handlers (object, signal_type); + switch (gtk_handlers_run (handlers, &info, FALSE)) + { + case DONE: + goto done; + case RESTART: + goto restart; + } + + if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST) + { + signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset); + if (*signal_func_offset) + (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset, NULL, params); + if (being_destroyed || GTK_OBJECT_NEED_DESTROY (object)) + goto done; + } + + switch (gtk_handlers_run (handlers, &info, TRUE)) + { + case DONE: + goto done; + case RESTART: + goto restart; + } + + done: + gtk_emission_remove (¤t_emissions, object, signal_type); + + if (signal->run_type & GTK_RUN_NO_RECURSE) + gtk_emission_remove (&restart_emissions, object, signal_type); + + if (!being_destroyed && !old_value) + GTK_OBJECT_UNSET_FLAGS (object, GTK_IN_CALL); + } + + if (!being_destroyed && GTK_OBJECT_NEED_DESTROY (object) && !GTK_OBJECT_IN_CALL (object)) + { + gtk_object_destroy (object); + return FALSE; + } + + return TRUE; +} + +static GtkHandler* +gtk_signal_get_handlers (GtkObject *object, + gint signal_type) +{ + GtkHandler *handlers; + + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (signal_type >= 1, NULL); + + handlers = gtk_object_get_data (object, handler_key); + + while (handlers) + { + if (handlers->signal_type == signal_type) + return handlers; + handlers = handlers->next; + } + + return NULL; +} + +static gint +gtk_signal_connect_by_type (GtkObject *object, + gint signal_type, + gint object_signal, + GtkSignalFunc func, + gpointer func_data, + GtkSignalDestroy destroy_func, + gint after, + gint no_marshal) +{ + GtkHandler *handler; + gint *object_signals; + gint nsignals; + gint found_it; + gint i; + + g_return_val_if_fail (object != NULL, 0); + g_return_val_if_fail (object->klass != NULL, 0); + g_return_val_if_fail (object->klass->signals != NULL, 0); + + /* Search through the signals for this object and make + * sure the one we are adding is valid. If it isn't then + * issue a warning and return. + */ + object_signals = object->klass->signals; + nsignals = object->klass->nsignals; + found_it = FALSE; + + for (i = 0; i < nsignals; i++) + if (object_signals[i] == signal_type) + { + found_it = TRUE; + break; + } + + if (!found_it) + { + g_warning ("could not find signal (%d) in object's list of signals", signal_type); + return 0; + } + + handler = gtk_signal_handler_new (); + handler->id = next_handler_id++; + handler->signal_type = signal_type; + handler->object_signal = object_signal; + handler->func = func; + handler->func_data = func_data; + handler->destroy_func = destroy_func; + + if (after) + handler->after = TRUE; + handler->no_marshal = no_marshal; + + gtk_signal_handler_insert (object, handler); + return handler->id; +} + +static GtkEmission* +gtk_emission_new () +{ + GtkEmission *emission; + + if (!emission_mem_chunk) + emission_mem_chunk = g_mem_chunk_new ("emission mem chunk", sizeof (GtkEmission), + 1024, G_ALLOC_AND_FREE); + + emission = g_chunk_new (GtkEmission, emission_mem_chunk); + + emission->object = NULL; + emission->signal_type = 0; + + return emission; +} + +static void +gtk_emission_destroy (GtkEmission *emission) +{ + g_mem_chunk_free (emission_mem_chunk, emission); +} + +static void +gtk_emission_add (GList **emissions, + GtkObject *object, + gint signal_type) +{ + GtkEmission *emission; + + g_return_if_fail (emissions != NULL); + g_return_if_fail (object != NULL); + + emission = gtk_emission_new (); + emission->object = object; + emission->signal_type = signal_type; + + *emissions = g_list_prepend (*emissions, emission); +} + +static void +gtk_emission_remove (GList **emissions, + GtkObject *object, + gint signal_type) +{ + GtkEmission *emission; + GList *tmp; + + g_return_if_fail (emissions != NULL); + g_return_if_fail (object != NULL); + + tmp = *emissions; + while (tmp) + { + emission = tmp->data; + + if ((emission->object == object) && + (emission->signal_type == signal_type)) + { + gtk_emission_destroy (emission); + *emissions = g_list_remove_link (*emissions, tmp); + g_list_free (tmp); + break; + } + + tmp = tmp->next; + } +} + +static gint +gtk_emission_check (GList *emissions, + GtkObject *object, + gint signal_type) +{ + GtkEmission *emission; + GList *tmp; + + g_return_val_if_fail (object != NULL, FALSE); + + tmp = emissions; + while (tmp) + { + emission = tmp->data; + tmp = tmp->next; + + if ((emission->object == object) && + (emission->signal_type == signal_type)) + return TRUE; + } + return FALSE; +} + +static gint +gtk_handlers_run (GtkHandler *handlers, + GtkHandlerInfo *info, + gint after) +{ + while (handlers && (handlers->signal_type == info->signal_type)) + { + if (!handlers->blocked && (handlers->after == after)) + { + if (handlers->func) + { + if (handlers->no_marshal) + (* (GtkCallbackMarshal)handlers->func) (info->object, + handlers->func_data, + info->nparams, + info->params); + else if (handlers->object_signal) + (* info->marshaller) (GTK_OBJECT (handlers->func_data), + handlers->func, + handlers->func_data, + info->params); + else + (* info->marshaller) (info->object, + handlers->func, + handlers->func_data, + info->params); + } + else if (marshal) + (* marshal) (info->object, + handlers->func_data, + info->nparams, + info->params, + info->param_types, + info->return_val); + + if (GTK_OBJECT_NEED_DESTROY (info->object)) + return DONE; + else if (gtk_emission_check (stop_emissions, info->object, info->signal_type)) + { + gtk_emission_remove (&stop_emissions, info->object, info->signal_type); + + if (info->run_type & GTK_RUN_NO_RECURSE) + gtk_emission_remove (&restart_emissions, info->object, info->signal_type); + return DONE; + } + else if ((info->run_type & GTK_RUN_NO_RECURSE) && + gtk_emission_check (restart_emissions, info->object, info->signal_type)) + { + gtk_emission_remove (&restart_emissions, info->object, info->signal_type); + return RESTART; + } + } + + handlers = handlers->next; + } + + return 0; +} + +static void +gtk_params_get (GtkArg *params, + gint nparams, + GtkType *param_types, + GtkType return_val, + va_list args) +{ + int i; + + for (i = 0; i < nparams; i++) + { + if (param_types[i] != GTK_TYPE_NONE) + { + params[i].type = param_types[i]; + params[i].name = NULL; + } + + switch (GTK_FUNDAMENTAL_TYPE (param_types[i])) + { + case GTK_TYPE_INVALID: + break; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + GTK_VALUE_CHAR(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_BOOL: + GTK_VALUE_BOOL(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_INT: + GTK_VALUE_INT(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_UINT: + GTK_VALUE_UINT(params[i]) = va_arg (args, guint); + break; + case GTK_TYPE_ENUM: + GTK_VALUE_ENUM(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_FLAGS: + GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_LONG: + GTK_VALUE_LONG(params[i]) = va_arg (args, glong); + break; + case GTK_TYPE_ULONG: + GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong); + break; + case GTK_TYPE_FLOAT: + GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat); + break; + case GTK_TYPE_STRING: + GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*); + break; + case GTK_TYPE_POINTER: + GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer); + break; + case GTK_TYPE_BOXED: + GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer); + break; + case GTK_TYPE_SIGNAL: + GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction); + GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer); + break; + case GTK_TYPE_FOREIGN: + GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer); + GTK_VALUE_FOREIGN(params[i]).notify = + va_arg (args, GtkDestroyNotify); + break; + case GTK_TYPE_CALLBACK: + GTK_VALUE_CALLBACK(params[i]).marshal = + va_arg (args, GtkCallbackMarshal); + GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer); + GTK_VALUE_CALLBACK(params[i]).notify = + va_arg (args, GtkDestroyNotify); + break; + case GTK_TYPE_C_CALLBACK: + GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction); + GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer); + break; + case GTK_TYPE_ARGS: + GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, int); + GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*); + break; + case GTK_TYPE_OBJECT: + GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*); + g_assert (GTK_VALUE_OBJECT(params[i]) == NULL || + GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]), + params[i].type)); + break; + default: + g_error ("unsupported type %s in signal arg", + gtk_type_name (params[i].type)); + break; + } + } + + if (return_val != GTK_TYPE_NONE) + { + params[i].type = return_val; + params[i].name = NULL; + } + + switch (GTK_FUNDAMENTAL_TYPE (return_val)) + { + case GTK_TYPE_INVALID: + break; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + params[i].d.pointer_data = va_arg (args, gchar*); + break; + case GTK_TYPE_BOOL: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_INT: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_UINT: + params[i].d.pointer_data = va_arg (args, guint*); + break; + case GTK_TYPE_ENUM: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_FLAGS: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_LONG: + params[i].d.pointer_data = va_arg (args, glong*); + break; + case GTK_TYPE_ULONG: + params[i].d.pointer_data = va_arg (args, gulong*); + break; + case GTK_TYPE_FLOAT: + params[i].d.pointer_data = va_arg (args, gfloat*); + break; + case GTK_TYPE_STRING: + params[i].d.pointer_data = va_arg (args, gchar**); + break; + case GTK_TYPE_POINTER: + params[i].d.pointer_data = va_arg (args, gpointer*); + break; + case GTK_TYPE_BOXED: + params[i].d.pointer_data = va_arg (args, gpointer*); + break; + case GTK_TYPE_OBJECT: + params[i].d.pointer_data = va_arg (args, GtkObject**); + break; + case GTK_TYPE_SIGNAL: + case GTK_TYPE_FOREIGN: + case GTK_TYPE_CALLBACK: + case GTK_TYPE_C_CALLBACK: + case GTK_TYPE_ARGS: + default: + g_error ("unsupported type %s in signal return", + gtk_type_name (return_val)); + break; + } +} diff --git a/gtk/gtksignal.h b/gtk/gtksignal.h new file mode 100644 index 000000000..68ff99902 --- /dev/null +++ b/gtk/gtksignal.h @@ -0,0 +1,124 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_SIGNAL_H__ +#define __GTK_SIGNAL_H__ + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#ifdef offsetof +#define GTK_SIGNAL_OFFSET(t, f) ((int) offsetof (t, f)) +#else /* offsetof */ +#define GTK_SIGNAL_OFFSET(t, f) ((int) ((char*) &((t*) 0)->f)) +#endif /* offsetof */ + +#define GTK_SIGNAL_FUNC(f) ((GtkSignalFunc) f) + + +typedef void (*GtkSignalFunc) (void); +typedef void (*GtkSignalMarshaller) (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +typedef void (*GtkSignalMarshal) (GtkObject *object, + gpointer data, + gint nparams, + GtkArg *args, + GtkType *arg_types, + GtkType return_type); +typedef void (*GtkSignalDestroy) (gpointer data); + + +gint gtk_signal_new (const gchar *name, + GtkSignalRunType run_type, + gint object_type, + gint function_offset, + GtkSignalMarshaller marshaller, + GtkType return_val, + gint nparams, + ...); +gint gtk_signal_lookup (const gchar *name, + gint object_type); +gchar* gtk_signal_name (gint signal_num); +gint gtk_signal_emit (GtkObject *object, + gint signal_type, + ...); +gint gtk_signal_emit_by_name (GtkObject *object, + const gchar *name, + ...); +void gtk_signal_emit_stop (GtkObject *object, + gint signal_type); +void gtk_signal_emit_stop_by_name (GtkObject *object, + const gchar *name); +gint gtk_signal_connect (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data); +gint gtk_signal_connect_after (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + gpointer func_data); +gint gtk_signal_connect_object (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object); +gint gtk_signal_connect_object_after (GtkObject *object, + const gchar *name, + GtkSignalFunc func, + GtkObject *slot_object); +gint gtk_signal_connect_interp (GtkObject *object, + gchar *name, + GtkCallbackMarshal func, + gpointer data, + GtkDestroyNotify destroy_func, + gint after); +void gtk_signal_disconnect (GtkObject *object, + gint anid); +void gtk_signal_disconnect_by_data (GtkObject *object, + gpointer data); +void gtk_signal_handler_block (GtkObject *object, + gint anid); +void gtk_signal_handler_block_by_data (GtkObject *object, + gpointer data); +void gtk_signal_handler_unblock (GtkObject *object, + gint anid); +void gtk_signal_handler_unblock_by_data (GtkObject *object, + gpointer data); +void gtk_signal_handlers_destroy (GtkObject *object); +void gtk_signal_default_marshaller (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void gtk_signal_set_funcs (GtkSignalMarshal marshal_func, + GtkSignalDestroy destroy_func); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SIGNAL_H__ */ diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c new file mode 100644 index 000000000..ae8c1a5d9 --- /dev/null +++ b/gtk/gtkstyle.c @@ -0,0 +1,1795 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkgc.h" +#include "gtkstyle.h" + + +#define LIGHTNESS_MULT 1.3 +#define DARKNESS_MULT 0.7 + + +typedef struct _GtkStyleKey GtkStyleKey; + +struct _GtkStyleKey +{ + GdkColor fg[5]; + GdkColor bg[5]; + GdkColor text[5]; + GdkColor base[5]; + + GdkPixmap *bg_pixmap[5]; + + GdkFont *font; + + gint depth; + GdkColormap *colormap; + GtkStyleClass *klass; +}; + + +static void gtk_style_init (GtkStyle *style); +static void gtk_styles_init (void); +static void gtk_style_remove (GtkStyle *style); +static GtkStyle* gtk_style_find (GtkStyle *style, + GdkColormap *cmap, + gint depth); +static GtkStyle* gtk_style_new_from_key (GtkStyleKey *key); +static GtkStyleKey* gtk_style_key_dup (GtkStyleKey *key); +static void gtk_style_destroy (GtkStyle *style); +static void gtk_style_key_destroy (GtkStyleKey *key); +static guint gtk_style_key_hash (GtkStyleKey *key); +static guint gtk_style_value_hash (GtkStyle *style); +static gint gtk_style_key_compare (GtkStyleKey *a, + GtkStyleKey *b); + +static void gtk_default_draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y); +static void gtk_default_draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x); +static void gtk_default_draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +static void gtk_default_draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *points, + gint npoints, + gint fill); +static void gtk_default_draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height); +static void gtk_default_draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +static void gtk_default_draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +static void gtk_default_draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string); + +static void gtk_style_shade (GdkColor *a, GdkColor *b, gdouble k); +static void rgb_to_hls (gdouble *r, gdouble *g, gdouble *b); +static void hls_to_rgb (gdouble *h, gdouble *l, gdouble *s); + + +static GtkStyleClass default_class = +{ + 2, + 2, + gtk_default_draw_hline, + gtk_default_draw_vline, + gtk_default_draw_shadow, + gtk_default_draw_polygon, + gtk_default_draw_arrow, + gtk_default_draw_diamond, + gtk_default_draw_oval, + gtk_default_draw_string, +}; + +static GdkColor gtk_default_normal_fg = { 0, 0, 0, 0 }; +static GdkColor gtk_default_active_fg = { 0, 0, 0, 0 }; +static GdkColor gtk_default_prelight_fg = { 0, 0, 0, 0 }; +static GdkColor gtk_default_selected_fg = { 0, 0xffff, 0xffff, 0xffff }; +static GdkColor gtk_default_insensitive_fg = { 0, 0x7530, 0x7530, 0x7530 }; + +static GdkColor gtk_default_normal_bg = { 0, 0xd6d6, 0xd6d6, 0xd6d6 }; +static GdkColor gtk_default_active_bg = { 0, 0xc350, 0xc350, 0xc350 }; +static GdkColor gtk_default_prelight_bg = { 0, 0xea60, 0xea60, 0xea60 }; +static GdkColor gtk_default_selected_bg = { 0, 0, 0, 0x9c40 }; +static GdkColor gtk_default_insensitive_bg = { 0, 0xd6d6, 0xd6d6, 0xd6d6 }; + +static GdkFont *default_font = NULL; + +static gint initialize = TRUE; +static GCache *style_cache = NULL; +static GSList *unattached_styles = NULL; + +static GMemChunk *key_mem_chunk = NULL; + + +GtkStyle* +gtk_style_new () +{ + GtkStyle *style; + gint i; + + style = g_new (GtkStyle, 1); + + if (!default_font) + default_font = gdk_font_load ("-adobe-helvetica-medium-r-normal--*-120-*-*-*-*-*-*"); + + style->font = default_font; + gdk_font_ref (style->font); + + style->ref_count = 0; + style->attach_count = 0; + style->colormap = NULL; + style->depth = -1; + style->klass = &default_class; + + style->black.red = 0; + style->black.green = 0; + style->black.blue = 0; + + style->white.red = 65535; + style->white.green = 65535; + style->white.blue = 65535; + + style->black_gc = NULL; + style->white_gc = NULL; + + style->fg[GTK_STATE_NORMAL] = gtk_default_normal_fg; + style->fg[GTK_STATE_ACTIVE] = gtk_default_active_fg; + style->fg[GTK_STATE_PRELIGHT] = gtk_default_prelight_fg; + style->fg[GTK_STATE_SELECTED] = gtk_default_selected_fg; + style->fg[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_fg; + + style->bg[GTK_STATE_NORMAL] = gtk_default_normal_bg; + style->bg[GTK_STATE_ACTIVE] = gtk_default_active_bg; + style->bg[GTK_STATE_PRELIGHT] = gtk_default_prelight_bg; + style->bg[GTK_STATE_SELECTED] = gtk_default_selected_bg; + style->bg[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_bg; + + for (i = 0; i < 5; i++) + { + style->text[i] = style->fg[i]; + style->base[i] = style->white; + } + + for (i = 0; i < 5; i++) + style->bg_pixmap[i] = NULL; + + for (i = 0; i < 5; i++) + { + style->fg_gc[i] = NULL; + style->bg_gc[i] = NULL; + style->light_gc[i] = NULL; + style->dark_gc[i] = NULL; + style->mid_gc[i] = NULL; + style->text_gc[i] = NULL; + style->base_gc[i] = NULL; + } + + unattached_styles = g_slist_prepend (unattached_styles, style); + + return style; +} + +GtkStyle* +gtk_style_attach (GtkStyle *style, + GdkWindow *window) +{ + GtkStyle *new_style; + GdkColormap *colormap; + gint depth; + + g_return_val_if_fail (style != NULL, NULL); + g_return_val_if_fail (window != NULL, NULL); + + colormap = gdk_window_get_colormap (window); + gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + + new_style = gtk_style_find (style, colormap, depth); + + if (new_style && (new_style != style)) + { + gtk_style_unref (style); + style = new_style; + gtk_style_ref (style); + } + + if (style->attach_count == 0) + unattached_styles = g_slist_remove (unattached_styles, style); + + style->attach_count += 1; + + return style; +} + +void +gtk_style_detach (GtkStyle *style) +{ + gint i; + + g_return_if_fail (style != NULL); + + style->attach_count -= 1; + if (style->attach_count == 0) + { + unattached_styles = g_slist_prepend (unattached_styles, style); + + gtk_gc_release (style->black_gc); + gtk_gc_release (style->white_gc); + + style->black_gc = NULL; + style->white_gc = NULL; + + for (i = 0; i < 5; i++) + { + gtk_gc_release (style->fg_gc[i]); + gtk_gc_release (style->bg_gc[i]); + gtk_gc_release (style->light_gc[i]); + gtk_gc_release (style->dark_gc[i]); + gtk_gc_release (style->mid_gc[i]); + gtk_gc_release (style->text_gc[i]); + gtk_gc_release (style->base_gc[i]); + + style->fg_gc[i] = NULL; + style->bg_gc[i] = NULL; + style->light_gc[i] = NULL; + style->dark_gc[i] = NULL; + style->mid_gc[i] = NULL; + style->text_gc[i] = NULL; + style->base_gc[i] = NULL; + } + + style->depth = -1; + style->colormap = NULL; + } + + gtk_style_remove (style); +} + +GtkStyle* +gtk_style_ref (GtkStyle *style) +{ + g_return_val_if_fail (style != NULL, NULL); + + style->ref_count += 1; + return style; +} + +void +gtk_style_unref (GtkStyle *style) +{ + g_return_if_fail (style != NULL); + + style->ref_count -= 1; + if (style->ref_count == 0) + gtk_style_destroy (style); +} + +void +gtk_style_set_background (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type) +{ + GdkPixmap *pixmap; + gint parent_relative; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + if (style->bg_pixmap[state_type]) + { + if (style->bg_pixmap[state_type] == (GdkPixmap*) GDK_PARENT_RELATIVE) + { + pixmap = NULL; + parent_relative = TRUE; + } + else + { + pixmap = style->bg_pixmap[state_type]; + parent_relative = FALSE; + } + + gdk_window_set_back_pixmap (window, pixmap, parent_relative); + } + else + gdk_window_set_background (window, &style->bg[state_type]); +} + + +void +gtk_draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_hline != NULL); + + (*style->klass->draw_hline) (style, window, state_type, x1, x2, y); +} + + +void +gtk_draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_vline != NULL); + + (*style->klass->draw_vline) (style, window, state_type, y1, y2, x); +} + + +void +gtk_draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_shadow != NULL); + + (*style->klass->draw_shadow) (style, window, state_type, shadow_type, x, y, width, height); +} + +void +gtk_draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *points, + gint npoints, + gint fill) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_shadow != NULL); + + (*style->klass->draw_polygon) (style, window, state_type, shadow_type, points, npoints, fill); +} + +void +gtk_draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_arrow != NULL); + + (*style->klass->draw_arrow) (style, window, state_type, shadow_type, arrow_type, fill, x, y, width, height); +} + + +void +gtk_draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_diamond != NULL); + + (*style->klass->draw_diamond) (style, window, state_type, shadow_type, x, y, width, height); +} + + +void +gtk_draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_oval != NULL); + + (*style->klass->draw_oval) (style, window, state_type, shadow_type, x, y, width, height); +} + +void +gtk_draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (style->klass != NULL); + g_return_if_fail (style->klass->draw_oval != NULL); + + (*style->klass->draw_string) (style, window, state_type, x, y, string); +} + + +static void +gtk_style_init (GtkStyle *style) +{ + GdkGCValues gc_values; + GdkGCValuesMask gc_values_mask; + GdkColormap *colormap; + gint i; + + g_return_if_fail (style != NULL); + + if (style->attach_count == 0) + { + for (i = 0; i < 5; i++) + { + gtk_style_shade (&style->bg[i], &style->light[i], LIGHTNESS_MULT); + gtk_style_shade (&style->bg[i], &style->dark[i], DARKNESS_MULT); + + style->mid[i].red = (style->light[i].red + style->dark[i].red) / 2; + style->mid[i].green = (style->light[i].green + style->dark[i].green) / 2; + style->mid[i].blue = (style->light[i].blue + style->dark[i].blue) / 2; + } + + colormap = style->colormap; + + gdk_color_black (colormap, &style->black); + gdk_color_white (colormap, &style->white); + + gc_values_mask = GDK_GC_FOREGROUND | GDK_GC_FONT; + if (style->font->type == GDK_FONT_FONT) + { + gc_values.font = style->font; + } + else if (style->font->type == GDK_FONT_FONTSET) + { + gc_values.font = default_font; + } + + gc_values.foreground = style->black; + style->black_gc = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->white; + style->white_gc = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + for (i = 0; i < 5; i++) + { + if (!gdk_color_alloc (colormap, &style->fg[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->fg[i].red, style->fg[i].green, style->fg[i].blue); + if (!gdk_color_alloc (colormap, &style->bg[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->bg[i].red, style->bg[i].green, style->bg[i].blue); + if (!gdk_color_alloc (colormap, &style->light[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->light[i].red, style->light[i].green, style->light[i].blue); + if (!gdk_color_alloc (colormap, &style->dark[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->dark[i].red, style->dark[i].green, style->dark[i].blue); + if (!gdk_color_alloc (colormap, &style->mid[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->mid[i].red, style->mid[i].green, style->mid[i].blue); + if (!gdk_color_alloc (colormap, &style->text[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->text[i].red, style->text[i].green, style->text[i].blue); + if (!gdk_color_alloc (colormap, &style->base[i])) + g_warning ("unable to allocate color: ( %d %d %d )", + style->base[i].red, style->base[i].green, style->base[i].blue); + + gc_values.foreground = style->fg[i]; + style->fg_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->bg[i]; + style->bg_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->light[i]; + style->light_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->dark[i]; + style->dark_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->mid[i]; + style->mid_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->text[i]; + style->text_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + + gc_values.foreground = style->base[i]; + style->base_gc[i] = gtk_gc_get (style->depth, style->colormap, &gc_values, gc_values_mask); + } + } +} + +static void +gtk_styles_init () +{ + if (initialize) + { + initialize = FALSE; + + style_cache = g_cache_new ((GCacheNewFunc) gtk_style_new_from_key, + (GCacheDestroyFunc) gtk_style_destroy, + (GCacheDupFunc) gtk_style_key_dup, + (GCacheDestroyFunc) gtk_style_key_destroy, + (GHashFunc) gtk_style_key_hash, + (GHashFunc) gtk_style_value_hash, + (GCompareFunc) gtk_style_key_compare); + } +} + +static void +gtk_style_remove (GtkStyle *style) +{ + if (initialize) + gtk_styles_init (); + + g_cache_remove (style_cache, style); +} + +static GtkStyle* +gtk_style_find (GtkStyle *style, + GdkColormap *cmap, + gint depth) +{ + GtkStyleKey key; + gint i; + + if (initialize) + gtk_styles_init (); + + for (i = 0; i < 5; i++) + { + key.fg[i] = style->fg[i]; + key.bg[i] = style->bg[i]; + key.text[i] = style->text[i]; + key.base[i] = style->base[i]; + key.bg_pixmap[i] = style->bg_pixmap[i]; + } + + key.font = style->font; + key.klass = style->klass; + key.depth = depth; + key.colormap = cmap; + + style = g_cache_insert (style_cache, &key); + + return style; +} + +static GtkStyle* +gtk_style_new_from_key (GtkStyleKey *key) +{ + GtkStyle *style; + GSList *list; + gint i; + + style = NULL; + list = unattached_styles; + + while (list) + { + style = list->data; + list = list->next; + + if ((style->depth != -1) && (style->depth != key->depth)) + { + style = NULL; + continue; + } + if (style->colormap && (style->colormap != key->colormap)) + { + style = NULL; + continue; + } + if (style->klass != key->klass) + { + style = NULL; + continue; + } + if (!gdk_font_equal (style->font, key->font)) + { + style = NULL; + continue; + } + + for (i = 0; style && (i < 5); i++) + { + if (style->bg_pixmap[i] != key->bg_pixmap[i]) + { + style = NULL; + continue; + } + + if ((style->fg[i].red != key->fg[i].red) || + (style->fg[i].green != key->fg[i].green) || + (style->fg[i].blue != key->fg[i].blue)) + { + style = NULL; + continue; + } + + if ((style->bg[i].red != key->bg[i].red) || + (style->bg[i].green != key->bg[i].green) || + (style->bg[i].blue != key->bg[i].blue)) + { + style = NULL; + continue; + } + + if ((style->text[i].red != key->text[i].red) || + (style->text[i].green != key->text[i].green) || + (style->text[i].blue != key->text[i].blue)) + { + style = NULL; + continue; + } + + if ((style->base[i].red != key->base[i].red) || + (style->base[i].green != key->base[i].green) || + (style->base[i].blue != key->base[i].blue)) + { + style = NULL; + continue; + } + } + + if (style) + break; + } + + if (!style) + { + style = g_new (GtkStyle, 1); + + style->ref_count = 0; + style->attach_count = 0; + + style->font = key->font; + gdk_font_ref (style->font); + + style->depth = key->depth; + style->colormap = key->colormap; + style->klass = key->klass; + + style->black.red = 0; + style->black.green = 0; + style->black.blue = 0; + + style->white.red = 65535; + style->white.green = 65535; + style->white.blue = 65535; + + style->black_gc = NULL; + style->white_gc = NULL; + + for (i = 0; i < 5; i++) + { + style->fg[i] = key->fg[i]; + style->bg[i] = key->bg[i]; + style->text[i] = key->text[i]; + style->base[i] = key->base[i]; + } + + for (i = 0; i < 5; i++) + style->bg_pixmap[i] = key->bg_pixmap[i]; + + for (i = 0; i < 5; i++) + { + style->fg_gc[i] = NULL; + style->bg_gc[i] = NULL; + style->light_gc[i] = NULL; + style->dark_gc[i] = NULL; + style->mid_gc[i] = NULL; + style->text_gc[i] = NULL; + style->base_gc[i] = NULL; + } + } + + if (style->depth == -1) + style->depth = key->depth; + if (!style->colormap) + style->colormap = key->colormap; + + gtk_style_init (style); + + return style; +} + +static GtkStyleKey* +gtk_style_key_dup (GtkStyleKey *key) +{ + GtkStyleKey *new_key; + + if (!key_mem_chunk) + key_mem_chunk = g_mem_chunk_new ("key mem chunk", sizeof (GtkStyleKey), + 1024, G_ALLOC_AND_FREE); + + new_key = g_chunk_new (GtkStyleKey, key_mem_chunk); + + *new_key = *key; + + return new_key; +} + +static void +gtk_style_destroy (GtkStyle *style) +{ + gint i; + + if (style->ref_count != 0) + return; + + if (style->attach_count > 0) + { + gtk_gc_release (style->black_gc); + gtk_gc_release (style->white_gc); + + for (i = 0; i < 5; i++) + { + gtk_gc_release (style->fg_gc[i]); + gtk_gc_release (style->bg_gc[i]); + gtk_gc_release (style->light_gc[i]); + gtk_gc_release (style->dark_gc[i]); + gtk_gc_release (style->mid_gc[i]); + gtk_gc_release (style->text_gc[i]); + gtk_gc_release (style->base_gc[i]); + } + } + + unattached_styles = g_slist_remove (unattached_styles, style); + + if (style->font->type == GDK_FONT_FONT) + gdk_font_free (style->font); + else if (style->font->type == GDK_FONT_FONTSET) + gdk_fontset_free (style->font); + else + g_error("undefined font type\n"); + + g_free (style); +} + +static void +gtk_style_key_destroy (GtkStyleKey *key) +{ + g_mem_chunk_free (key_mem_chunk, key); +} + +static guint +gtk_style_key_hash (GtkStyleKey *key) +{ + guint hash_val; + gint i; + + hash_val = 0; + + for (i = 0; i < 5; i++) + { + hash_val += key->fg[i].red + key->fg[i].green + key->fg[i].blue; + hash_val += key->bg[i].red + key->bg[i].green + key->bg[i].blue; + hash_val += key->text[i].red + key->text[i].green + key->text[i].blue; + hash_val += key->base[i].red + key->base[i].green + key->base[i].blue; + } + + hash_val += (guint) gdk_font_id (key->font); + hash_val += (guint) key->depth; + hash_val += (gulong) key->colormap; + hash_val += (gulong) key->klass; + + return hash_val; +} + +static guint +gtk_style_value_hash (GtkStyle *style) +{ + guint hash_val; + gint i; + + hash_val = 0; + + for (i = 0; i < 5; i++) + { + hash_val += style->fg[i].red + style->fg[i].green + style->fg[i].blue; + hash_val += style->bg[i].red + style->bg[i].green + style->bg[i].blue; + hash_val += style->text[i].red + style->text[i].green + style->text[i].blue; + hash_val += style->base[i].red + style->base[i].green + style->base[i].blue; + } + + hash_val += (guint) gdk_font_id (style->font); + hash_val += (gulong) style->klass; + + return hash_val; +} + +static gint +gtk_style_key_compare (GtkStyleKey *a, + GtkStyleKey *b) +{ + gint i; + + if (a->depth != b->depth) + return FALSE; + if (a->colormap != b->colormap) + return FALSE; + if (a->klass != b->klass) + return FALSE; + if (!gdk_font_equal (a->font, b->font)) + return FALSE; + + for (i = 0; i < 5; i++) + { + if (a->bg_pixmap[i] != b->bg_pixmap[i]) + return FALSE; + + if ((a->fg[i].red != b->fg[i].red) || + (a->fg[i].green != b->fg[i].green) || + (a->fg[i].blue != b->fg[i].blue)) + return FALSE; + if ((a->bg[i].red != b->bg[i].red) || + (a->bg[i].green != b->bg[i].green) || + (a->bg[i].blue != b->bg[i].blue)) + return FALSE; + if ((a->text[i].red != b->text[i].red) || + (a->text[i].green != b->text[i].green) || + (a->text[i].blue != b->text[i].blue)) + return FALSE; + if ((a->base[i].red != b->base[i].red) || + (a->base[i].green != b->base[i].green) || + (a->base[i].blue != b->base[i].blue)) + return FALSE; + } + + return TRUE; +} + + +static void +gtk_default_draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y) +{ + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + thickness_light = style->klass->ythickness / 2; + thickness_dark = style->klass->ythickness - thickness_light; + + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, style->light_gc[state_type], x2 - i - 1, y + i, x2, y + i); + gdk_draw_line (window, style->dark_gc[state_type], x1, y + i, x2 - i - 1, y + i); + } + + y += thickness_dark; + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, style->dark_gc[state_type], x1, y + i, x1 + thickness_light - i - 1, y + i); + gdk_draw_line (window, style->light_gc[state_type], x1 + thickness_light - i - 1, y + i, x2, y + i); + } +} + + +static void +gtk_default_draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x) +{ + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + thickness_light = style->klass->xthickness / 2; + thickness_dark = style->klass->xthickness - thickness_light; + + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, style->light_gc[state_type], x + i, y2 - i - 1, x + i, y2); + gdk_draw_line (window, style->dark_gc[state_type], x + i, y1, x + i, y2 - i - 1); + } + + x += thickness_dark; + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, style->dark_gc[state_type], x + i, y1, x + i, y1 + thickness_light - i); + gdk_draw_line (window, style->light_gc[state_type], x + i, y1 + thickness_light - i, x + i, y2); + } +} + + +static void +gtk_default_draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + GdkGC *gc1; + GdkGC *gc2; + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + switch (shadow_type) + { + case GTK_SHADOW_NONE: + gc1 = NULL; + gc2 = NULL; + break; + case GTK_SHADOW_IN: + case GTK_SHADOW_ETCHED_IN: + gc1 = style->light_gc[state_type]; + gc2 = style->dark_gc[state_type]; + break; + case GTK_SHADOW_OUT: + case GTK_SHADOW_ETCHED_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + break; + } + + switch (shadow_type) + { + case GTK_SHADOW_NONE: + break; + + case GTK_SHADOW_IN: + gdk_draw_line (window, gc1, + x, y + height - 1, x + width - 1, y + height - 1); + gdk_draw_line (window, gc1, + x + width - 1, y, x + width - 1, y + height - 1); + + gdk_draw_line (window, style->bg_gc[state_type], + x + 1, y + height - 2, x + width - 2, y + height - 2); + gdk_draw_line (window, style->bg_gc[state_type], + x + width - 2, y + 1, x + width - 2, y + height - 2); + + gdk_draw_line (window, style->black_gc, + x + 1, y + 1, x + width - 2, y + 1); + gdk_draw_line (window, style->black_gc, + x + 1, y + 1, x + 1, y + height - 2); + + gdk_draw_line (window, gc2, + x, y, x + width - 1, y); + gdk_draw_line (window, gc2, + x, y, x, y + height - 1); + break; + + case GTK_SHADOW_OUT: + gdk_draw_line (window, gc1, + x + 1, y + height - 2, x + width - 2, y + height - 2); + gdk_draw_line (window, gc1, + x + width - 2, y + 1, x + width - 2, y + height - 2); + + gdk_draw_line (window, gc2, + x, y, x + width - 1, y); + gdk_draw_line (window, gc2, + x, y, x, y + height - 1); + + gdk_draw_line (window, style->bg_gc[state_type], + x + 1, y + 1, x + width - 2, y + 1); + gdk_draw_line (window, style->bg_gc[state_type], + x + 1, y + 1, x + 1, y + height - 2); + + gdk_draw_line (window, style->black_gc, + x, y + height - 1, x + width - 1, y + height - 1); + gdk_draw_line (window, style->black_gc, + x + width - 1, y, x + width - 1, y + height - 1); + break; + + case GTK_SHADOW_ETCHED_IN: + case GTK_SHADOW_ETCHED_OUT: + thickness_light = 1; + thickness_dark = 1; + + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, gc1, + x + i, + y + height - i - 1, + x + width - i - 1, + y + height - i - 1); + gdk_draw_line (window, gc1, + x + width - i - 1, + y + i, + x + width - i - 1, + y + height - i - 1); + + gdk_draw_line (window, gc2, + x + i, + y + i, + x + width - i - 2, + y + i); + gdk_draw_line (window, gc2, + x + i, + y + i, + x + i, + y + height - i - 2); + } + + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, gc1, + x + thickness_dark + i, + y + thickness_dark + i, + x + width - thickness_dark - i - 1, + y + thickness_dark + i); + gdk_draw_line (window, gc1, + x + thickness_dark + i, + y + thickness_dark + i, + x + thickness_dark + i, + y + height - thickness_dark - i - 1); + + gdk_draw_line (window, gc2, + x + thickness_dark + i, + y + height - thickness_light - i - 1, + x + width - thickness_light - 1, + y + height - thickness_light - i - 1); + gdk_draw_line (window, gc2, + x + width - thickness_light - i - 1, + y + thickness_dark + i, + x + width - thickness_light - i - 1, + y + height - thickness_light - 1); + } + break; + } +} + + +static void +gtk_default_draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *points, + gint npoints, + gint fill) +{ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /* M_PI */ +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 +#endif /* M_PI_4 */ + + static const gdouble pi_over_4 = M_PI_4; + static const gdouble pi_3_over_4 = M_PI_4 * 3; + + GdkGC *gc1; + GdkGC *gc2; + GdkGC *gc3; + GdkGC *gc4; + gdouble angle; + gint xadjust; + gint yadjust; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + g_return_if_fail (points != NULL); + + switch (shadow_type) + { + case GTK_SHADOW_IN: + gc1 = style->bg_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->light_gc[state_type]; + gc4 = style->black_gc; + break; + case GTK_SHADOW_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->black_gc; + gc4 = style->bg_gc[state_type]; + break; + default: + return; + } + + if (fill) + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, npoints); + + npoints -= 1; + for (i = 0; i < npoints; i++) + { + if ((points[i].x == points[i+1].x) && + (points[i].y == points[i+1].y)) + { + angle = 0; + } + else + { + angle = atan2 (points[i+1].y - points[i].y, + points[i+1].x - points[i].x); + } + + if ((angle > -pi_3_over_4) && (angle < pi_over_4)) + { + while (angle < 0) + angle += M_PI; + while (angle > M_PI) + angle -= M_PI; + + if ((angle > pi_3_over_4) || (angle < pi_over_4)) + { + xadjust = 0; + yadjust = 1; + } + else + { + xadjust = 1; + yadjust = 0; + } + + gdk_draw_line (window, gc1, + points[i].x-xadjust, points[i].y-yadjust, + points[i+1].x-xadjust, points[i+1].y-yadjust); + gdk_draw_line (window, gc3, + points[i].x, points[i].y, + points[i+1].x, points[i+1].y); + } + } + + for (i = 0; i < npoints; i++) + { + if ((points[i].x == points[i+1].x) && + (points[i].y == points[i+1].y)) + { + angle = 0; + } + else + { + angle = atan2 (points[i+1].y - points[i].y, + points[i+1].x - points[i].x); + } + + if ((angle <= -pi_3_over_4) || (angle >= pi_over_4)) + { + while (angle < 0) + angle += M_PI; + while (angle > M_PI) + angle -= M_PI; + + if ((angle > pi_3_over_4) || (angle < pi_over_4)) + { + xadjust = 0; + yadjust = 1; + } + else + { + xadjust = 1; + yadjust = 0; + } + + gdk_draw_line (window, gc4, + points[i].x+xadjust, points[i].y+yadjust, + points[i+1].x+xadjust, points[i+1].y+yadjust); + gdk_draw_line (window, gc2, + points[i].x, points[i].y, + points[i+1].x, points[i+1].y); + } + } +} + + +static void +gtk_default_draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height) +{ + GdkGC *gc1; + GdkGC *gc2; + GdkGC *gc3; + GdkGC *gc4; + gint half_width; + gint half_height; + GdkPoint points[3]; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + switch (shadow_type) + { + case GTK_SHADOW_IN: + gc1 = style->bg_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->light_gc[state_type]; + gc4 = style->black_gc; + break; + case GTK_SHADOW_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->black_gc; + gc4 = style->bg_gc[state_type]; + break; + default: + return; + } + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + half_width = width / 2; + half_height = height / 2; + + switch (arrow_type) + { + case GTK_ARROW_UP: + if (fill) + { + points[0].x = x + half_width; + points[0].y = y; + points[1].x = x; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y + height - 1; + + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, 3); + } + + gdk_draw_line (window, gc1, + x + 1, y + height - 2, + x + width - 2, y + height - 2); + gdk_draw_line (window, gc3, + x + 0, y + height - 1, + x + width - 1, y + height - 1); + + gdk_draw_line (window, gc1, + x + width - 2, y + height - 1, + x + half_width, y + 1); + gdk_draw_line (window, gc3, + x + width - 1, y + height - 1, + x + half_width, y); + + gdk_draw_line (window, gc4, + x + half_width, y + 1, + x + 1, y + height - 1); + gdk_draw_line (window, gc2, + x + half_width, y, + x, y + height - 1); + break; + case GTK_ARROW_DOWN: + if (fill) + { + points[0].x = x + width - 1; + points[0].y = y; + points[1].x = x; + points[1].y = y; + points[2].x = x + half_width; + points[2].y = y + height - 1; + + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, 3); + } + + gdk_draw_line (window, gc4, + x + width - 2, + y + 1, x + 1, y + 1); + gdk_draw_line (window, gc2, + x + width - 1, y, + x, y); + + gdk_draw_line (window, gc4, + x + 1, y, + x + half_width, y + height - 2); + gdk_draw_line (window, gc2, + x, y, + x + half_width, y + height - 1); + + gdk_draw_line (window, gc1, + x + half_width, y + height - 2, + x + width - 2, y); + gdk_draw_line (window, gc3, + x + half_width, y + height - 1, + x + width - 1, y); + break; + case GTK_ARROW_LEFT: + if (fill) + { + points[0].x = x; + points[0].y = y + half_height; + points[1].x = x + width - 1; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y; + + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, 3); + } + + gdk_draw_line (window, gc1, + x + 1, y + half_height, + x + width - 1, y + height - 1); + gdk_draw_line (window, gc3, + x, y + half_height, + x + width - 1, y + height - 1); + + gdk_draw_line (window, gc1, + x + width - 2, y + height - 1, + x + width - 2, y + 1); + gdk_draw_line (window, gc3, + x + width - 1, y + height - 1, + x + width - 1, y); + + gdk_draw_line (window, gc4, + x + width - 1, y + 1, + x + 1, y + half_width); + gdk_draw_line (window, gc2, + x + width - 1, y, + x, y + half_width); + break; + case GTK_ARROW_RIGHT: + if (fill) + { + points[0].x = x + width - 1; + points[0].y = y + half_height; + points[1].x = x; + points[1].y = y; + points[2].x = x; + points[2].y = y + height - 1; + + gdk_draw_polygon (window, style->bg_gc[state_type], TRUE, points, 3); + } + + gdk_draw_line (window, gc4, + x + width - 1, y + half_height, + x + 1, y + 1); + gdk_draw_line (window, gc2, + x + width - 1, y + half_height, + x, y); + + gdk_draw_line (window, gc4, + x + 1, y + 1, + x + 1, y + height - 2); + gdk_draw_line (window, gc2, + x, y, + x, y + height - 1); + + gdk_draw_line (window, gc1, + x + 1, y + height - 2, + x + width - 1, y + half_height); + gdk_draw_line (window, gc3, + x, y + height - 1, + x + width - 1, y + half_height); + break; + } +} + + +static void +gtk_default_draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + gint half_width; + gint half_height; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + half_width = width / 2; + half_height = height / 2; + + switch (shadow_type) + { + case GTK_SHADOW_IN: + gdk_draw_line (window, style->bg_gc[state_type], + x + 2, y + half_height, + x + half_width, y + height - 2); + gdk_draw_line (window, style->bg_gc[state_type], + x + half_width, y + height - 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x + 1, y + half_height, + x + half_width, y + height - 1); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height - 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x, y + half_height, + x + half_width, y + height); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height, + x + width, y + half_height); + + gdk_draw_line (window, style->black_gc, + x + 2, y + half_height, + x + half_width, y + 2); + gdk_draw_line (window, style->black_gc, + x + half_width, y + 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x + 1, y + half_height, + x + half_width, y + 1); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x, y + half_height, + x + half_width, y); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y, + x + width, y + half_height); + break; + case GTK_SHADOW_OUT: + gdk_draw_line (window, style->dark_gc[state_type], + x + 2, y + half_height, + x + half_width, y + height - 2); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height - 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x + 1, y + half_height, + x + half_width, y + height - 1); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height - 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->black_gc, + x, y + half_height, + x + half_width, y + height); + gdk_draw_line (window, style->black_gc, + x + half_width, y + height, + x + width, y + half_height); + + gdk_draw_line (window, style->bg_gc[state_type], + x + 2, y + half_height, + x + half_width, y + 2); + gdk_draw_line (window, style->bg_gc[state_type], + x + half_width, y + 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x + 1, y + half_height, + x + half_width, y + 1); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x, y + half_height, + x + half_width, y); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y, + x + width, y + half_height); + break; + default: + break; + } +} + + +static void +gtk_default_draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); +} + +static void +gtk_default_draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + if (state_type == GTK_STATE_INSENSITIVE) + gdk_draw_string (window, style->font, style->white_gc, x + 1, y + 1, string); + gdk_draw_string (window, style->font, style->fg_gc[state_type], x, y, string); +} + + +static void +gtk_style_shade (GdkColor *a, + GdkColor *b, + gdouble k) +{ + gdouble red; + gdouble green; + gdouble blue; + + red = (gdouble) a->red / 65535.0; + green = (gdouble) a->green / 65535.0; + blue = (gdouble) a->blue / 65535.0; + + rgb_to_hls (&red, &green, &blue); + + green *= k; + if (green > 1.0) + green = 1.0; + else if (green < 0.0) + green = 0.0; + + blue *= k; + if (blue > 1.0) + blue = 1.0; + else if (blue < 0.0) + blue = 0.0; + + hls_to_rgb (&red, &green, &blue); + + b->red = red * 65535.0; + b->green = green * 65535.0; + b->blue = blue * 65535.0; +} + +static void +rgb_to_hls (gdouble *r, + gdouble *g, + gdouble *b) +{ + gdouble min; + gdouble max; + gdouble red; + gdouble green; + gdouble blue; + gdouble h, l, s; + gdouble delta; + + red = *r; + green = *g; + blue = *b; + + if (red > green) + { + if (red > blue) + max = red; + else + max = blue; + + if (green < blue) + min = green; + else + min = blue; + } + else + { + if (green > blue) + max = green; + else + max = blue; + + if (red < blue) + min = red; + else + min = blue; + } + + l = (max + min) / 2; + s = 0; + h = 0; + + if (max != min) + { + if (l <= 0.5) + s = (max - min) / (max + min); + else + s = (max - min) / (2 - max - min); + + delta = max -min; + if (red == max) + h = (green - blue) / delta; + else if (green == max) + h = 2 + (blue - red) / delta; + else if (blue == max) + h = 4 + (red - green) / delta; + + h *= 60; + if (h < 0.0) + h += 360; + } + + *r = h; + *g = l; + *b = s; +} + +static void +hls_to_rgb (gdouble *h, + gdouble *l, + gdouble *s) +{ + gdouble hue; + gdouble lightness; + gdouble saturation; + gdouble m1, m2; + gdouble r, g, b; + + lightness = *l; + saturation = *s; + + if (lightness <= 0.5) + m2 = lightness * (1 + saturation); + else + m2 = lightness + saturation - lightness * saturation; + m1 = 2 * lightness - m2; + + if (saturation == 0) + { + *h = lightness; + *l = lightness; + *s = lightness; + } + else + { + hue = *h + 120; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + r = m1 + (m2 - m1) * hue / 60; + else if (hue < 180) + r = m2; + else if (hue < 240) + r = m1 + (m2 - m1) * (240 - hue) / 60; + else + r = m1; + + hue = *h; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + g = m1 + (m2 - m1) * hue / 60; + else if (hue < 180) + g = m2; + else if (hue < 240) + g = m1 + (m2 - m1) * (240 - hue) / 60; + else + g = m1; + + hue = *h - 120; + while (hue > 360) + hue -= 360; + while (hue < 0) + hue += 360; + + if (hue < 60) + b = m1 + (m2 - m1) * hue / 60; + else if (hue < 180) + b = m2; + else if (hue < 240) + b = m1 + (m2 - m1) * (240 - hue) / 60; + else + b = m1; + + *h = r; + *l = g; + *s = b; + } +} diff --git a/gtk/gtkstyle.h b/gtk/gtkstyle.h new file mode 100644 index 000000000..c0ec33736 --- /dev/null +++ b/gtk/gtkstyle.h @@ -0,0 +1,217 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_STYLE_H__ +#define __GTK_STYLE_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct _GtkStyle GtkStyle; +typedef struct _GtkStyleClass GtkStyleClass; + +/* This is used for having dynamic style changing stuff */ +/* fg, bg, light, dark, mid, text, base */ +#define GTK_STYLE_NUM_STYLECOLORS() 7*5 + +struct _GtkStyle +{ + GdkColor fg[5]; + GdkColor bg[5]; + GdkColor light[5]; + GdkColor dark[5]; + GdkColor mid[5]; + GdkColor text[5]; + GdkColor base[5]; + + GdkColor black; + GdkColor white; + GdkFont *font; + + GdkGC *fg_gc[5]; + GdkGC *bg_gc[5]; + GdkGC *light_gc[5]; + GdkGC *dark_gc[5]; + GdkGC *mid_gc[5]; + GdkGC *text_gc[5]; + GdkGC *base_gc[5]; + GdkGC *black_gc; + GdkGC *white_gc; + + GdkPixmap *bg_pixmap[5]; + + gint ref_count; + gint attach_count; + + gint depth; + GdkColormap *colormap; + + GtkStyleClass *klass; +}; + +struct _GtkStyleClass +{ + gint xthickness; + gint ythickness; + + void (*draw_hline) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y); + void (*draw_vline) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x); + void (*draw_shadow) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); + void (*draw_polygon) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *point, + gint npoints, + gint fill); + void (*draw_arrow) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height); + void (*draw_diamond) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); + void (*draw_oval) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); + void (*draw_string) (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string); +}; + + +GtkStyle* gtk_style_new (void); +GtkStyle* gtk_style_attach (GtkStyle *style, + GdkWindow *window); +void gtk_style_detach (GtkStyle *style); +GtkStyle *gtk_style_ref (GtkStyle *style); +void gtk_style_unref (GtkStyle *style); +void gtk_style_set_background (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type); + + +void gtk_draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x1, + gint x2, + gint y); +void gtk_draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint y1, + gint y2, + gint x); +void gtk_draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +void gtk_draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkPoint *points, + gint npoints, + gint fill); +void gtk_draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GtkArrowType arrow_type, + gint fill, + gint x, + gint y, + gint width, + gint height); +void gtk_draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +void gtk_draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + gint x, + gint y, + gint width, + gint height); +void gtk_draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + gint x, + gint y, + const gchar *string); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_STYLE_H__ */ diff --git a/gtk/gtktable.c b/gtk/gtktable.c new file mode 100644 index 000000000..7711524de --- /dev/null +++ b/gtk/gtktable.c @@ -0,0 +1,1178 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtktable.h" + + +static void gtk_table_class_init (GtkTableClass *klass); +static void gtk_table_init (GtkTable *table); +static void gtk_table_destroy (GtkObject *object); +static void gtk_table_map (GtkWidget *widget); +static void gtk_table_unmap (GtkWidget *widget); +static void gtk_table_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_table_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_table_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_table_add (GtkContainer *container, + GtkWidget *widget); +static void gtk_table_remove (GtkContainer *container, + GtkWidget *widget); +static void gtk_table_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); + +static void gtk_table_size_request_init (GtkTable *table); +static void gtk_table_size_request_pass1 (GtkTable *table); +static void gtk_table_size_request_pass2 (GtkTable *table); +static void gtk_table_size_request_pass3 (GtkTable *table); + +static void gtk_table_size_allocate_init (GtkTable *table); +static void gtk_table_size_allocate_pass1 (GtkTable *table); +static void gtk_table_size_allocate_pass2 (GtkTable *table); + + +static GtkContainerClass *parent_class = NULL; + + +guint +gtk_table_get_type () +{ + static guint table_type = 0; + + if (!table_type) + { + GtkTypeInfo table_info = + { + "GtkTable", + sizeof (GtkTable), + sizeof (GtkTableClass), + (GtkClassInitFunc) gtk_table_class_init, + (GtkObjectInitFunc) gtk_table_init, + (GtkArgFunc) NULL, + }; + + table_type = gtk_type_unique (gtk_container_get_type (), &table_info); + } + + return table_type; +} + +static void +gtk_table_class_init (GtkTableClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_table_destroy; + + widget_class->map = gtk_table_map; + widget_class->unmap = gtk_table_unmap; + widget_class->draw = gtk_table_draw; + widget_class->expose_event = gtk_table_expose; + widget_class->size_request = gtk_table_size_request; + widget_class->size_allocate = gtk_table_size_allocate; + + container_class->add = gtk_table_add; + container_class->remove = gtk_table_remove; + container_class->foreach = gtk_table_foreach; +} + +static void +gtk_table_init (GtkTable *table) +{ + GTK_WIDGET_SET_FLAGS (table, GTK_NO_WINDOW | GTK_BASIC); + + table->children = NULL; + table->rows = NULL; + table->cols = NULL; + table->nrows = 0; + table->ncols = 0; + table->homogeneous = FALSE; +} + +GtkWidget* +gtk_table_new (gint rows, + gint columns, + gint homogeneous) +{ + GtkTable *table; + gint row, col; + + table = gtk_type_new (gtk_table_get_type ()); + + table->nrows = rows; + table->ncols = columns; + table->homogeneous = (homogeneous ? TRUE : FALSE); + + table->rows = g_new (GtkTableRowCol, table->nrows); + table->cols = g_new (GtkTableRowCol, table->ncols); + + for (row = 0; row < table->nrows; row++) + { + table->rows[row].requisition = 0; + table->rows[row].allocation = 0; + table->rows[row].spacing = 0; + table->rows[row].need_expand = 0; + table->rows[row].need_shrink = 0; + table->rows[row].expand = 0; + table->rows[row].shrink = 0; + } + + for (col = 0; col < table->ncols; col++) + { + table->cols[col].requisition = 0; + table->cols[col].allocation = 0; + table->cols[col].spacing = 0; + table->cols[col].need_expand = 0; + table->cols[col].need_shrink = 0; + table->cols[col].expand = 0; + table->cols[col].shrink = 0; + } + + return GTK_WIDGET (table); +} + +void +gtk_table_attach (GtkTable *table, + GtkWidget *child, + gint left_attach, + gint right_attach, + gint top_attach, + gint bottom_attach, + gint xoptions, + gint yoptions, + gint xpadding, + gint ypadding) +{ + GtkTableChild *table_child; + + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + g_return_if_fail (child != NULL); + + g_return_if_fail ((left_attach >= 0) && (left_attach < table->ncols)); + g_return_if_fail ((left_attach < right_attach) && (right_attach <= table->ncols)); + g_return_if_fail ((top_attach >= 0) && (top_attach < table->nrows)); + g_return_if_fail ((top_attach < bottom_attach) && (bottom_attach <= table->nrows)); + + table_child = g_new (GtkTableChild, 1); + table_child->widget = child; + table_child->left_attach = left_attach; + table_child->right_attach = right_attach; + table_child->top_attach = top_attach; + table_child->bottom_attach = bottom_attach; + table_child->xexpand = (xoptions & GTK_EXPAND) != 0; + table_child->xshrink = (xoptions & GTK_SHRINK) != 0; + table_child->xfill = (xoptions & GTK_FILL) != 0; + table_child->xpadding = xpadding; + table_child->yexpand = (yoptions & GTK_EXPAND) != 0; + table_child->yshrink = (yoptions & GTK_SHRINK) != 0; + table_child->yfill = (yoptions & GTK_FILL) != 0; + table_child->ypadding = ypadding; + + table->children = g_list_prepend (table->children, table_child); + + gtk_widget_set_parent (child, GTK_WIDGET (table)); + + if (GTK_WIDGET_VISIBLE (GTK_WIDGET (table))) + { + if (GTK_WIDGET_REALIZED (GTK_WIDGET (table)) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (GTK_WIDGET (table)) && + !GTK_WIDGET_MAPPED (child)) + gtk_widget_map (child); + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (child); +} + +void +gtk_table_attach_defaults (GtkTable *table, + GtkWidget *widget, + gint left_attach, + gint right_attach, + gint top_attach, + gint bottom_attach) +{ + gtk_table_attach (table, widget, + left_attach, right_attach, + top_attach, bottom_attach, + GTK_EXPAND | GTK_FILL, + GTK_EXPAND | GTK_FILL, + 0, 0); +} + +void +gtk_table_set_row_spacing (GtkTable *table, + gint row, + gint spacing) +{ + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + g_return_if_fail ((row >= 0) && (row < (table->nrows - 1))); + + if (table->rows[row].spacing != spacing) + { + table->rows[row].spacing = spacing; + + if (GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (GTK_WIDGET (table)); + } +} + +void +gtk_table_set_col_spacing (GtkTable *table, + gint column, + gint spacing) +{ + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + g_return_if_fail ((column >= 0) && (column < (table->ncols - 1))); + + if (table->cols[column].spacing != spacing) + { + table->cols[column].spacing = spacing; + + if (GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (GTK_WIDGET (table)); + } +} + +void +gtk_table_set_row_spacings (GtkTable *table, + gint spacing) +{ + gint row; + + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + + for (row = 0; row < table->nrows - 1; row++) + table->rows[row].spacing = spacing; + + if (GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (GTK_WIDGET (table)); +} + +void +gtk_table_set_col_spacings (GtkTable *table, + gint spacing) +{ + gint col; + + g_return_if_fail (table != NULL); + g_return_if_fail (GTK_IS_TABLE (table)); + + for (col = 0; col < table->ncols - 1; col++) + table->cols[col].spacing = spacing; + + if (GTK_WIDGET_VISIBLE (table)) + gtk_widget_queue_resize (GTK_WIDGET (table)); +} + + +static void +gtk_table_destroy (GtkObject *object) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_TABLE (object)); + + table = GTK_TABLE (object); + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + child->widget->parent = NULL; + gtk_object_unref (GTK_OBJECT (child->widget)); + gtk_widget_destroy (child->widget); + g_free (child); + } + + g_list_free (table->children); + g_free (table->rows); + g_free (table->cols); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_table_map (GtkWidget *widget) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + + table = GTK_TABLE (widget); + GTK_WIDGET_SET_FLAGS (table, GTK_MAPPED); + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + !GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); + } +} + +static void +gtk_table_unmap (GtkWidget *widget) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + + table = GTK_TABLE (widget); + GTK_WIDGET_UNSET_FLAGS (table, GTK_MAPPED); + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget) && + GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_unmap (child->widget); + } +} + +static void +gtk_table_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + table = GTK_TABLE (widget); + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); + } + } +} + +static gint +gtk_table_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TABLE (widget), FALSE); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + table = GTK_TABLE (widget); + + child_event = *event; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_NO_WINDOW (child->widget) && + gtk_widget_intersect (child->widget, &event->area, &child_event.area)) + gtk_widget_event (child->widget, (GdkEvent*) &child_event); + } + } + + return FALSE; +} + +static void +gtk_table_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkTable *table; + gint row, col; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + g_return_if_fail (requisition != NULL); + + table = GTK_TABLE (widget); + + requisition->width = 0; + requisition->height = 0; + + gtk_table_size_request_init (table); + gtk_table_size_request_pass1 (table); + gtk_table_size_request_pass2 (table); + gtk_table_size_request_pass3 (table); + gtk_table_size_request_pass2 (table); + + for (col = 0; col < table->ncols; col++) + requisition->width += table->cols[col].requisition; + for (col = 0; col < table->ncols - 1; col++) + requisition->width += table->cols[col].spacing; + + for (row = 0; row < table->nrows; row++) + requisition->height += table->rows[row].requisition; + for (row = 0; row < table->nrows - 1; row++) + requisition->height += table->rows[row].spacing; + + requisition->width += GTK_CONTAINER (table)->border_width * 2; + requisition->height += GTK_CONTAINER (table)->border_width * 2; +} + +static void +gtk_table_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkTable *table; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TABLE (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + table = GTK_TABLE (widget); + + gtk_table_size_allocate_init (table); + gtk_table_size_allocate_pass1 (table); + gtk_table_size_allocate_pass2 (table); +} + +static void +gtk_table_add (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_TABLE (container)); + g_return_if_fail (widget != NULL); + + gtk_table_attach_defaults (GTK_TABLE (container), widget, 0, 1, 0, 1); +} + +static void +gtk_table_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_TABLE (container)); + g_return_if_fail (widget != NULL); + + table = GTK_TABLE (container); + children = table->children; + + while (children) + { + child = children->data; + children = children->next; + + if (child->widget == widget) + { + gtk_widget_unparent (widget); + + table->children = g_list_remove (table->children, child); + g_free (child); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + break; + } + } +} + +static void +gtk_table_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkTable *table; + GtkTableChild *child; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_TABLE (container)); + g_return_if_fail (callback != NULL); + + table = GTK_TABLE (container); + children = table->children; + + while (children) + { + child = children->data; + children = children->next; + + (* callback) (child->widget, callback_data); + } +} + +static void +gtk_table_size_request_init (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint row, col; + + for (row = 0; row < table->nrows; row++) + table->rows[row].requisition = 0; + for (col = 0; col < table->ncols; col++) + table->cols[col].requisition = 0; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + gtk_widget_size_request (child->widget, &child->widget->requisition); + } +} + +static void +gtk_table_size_request_pass1 (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint width; + gint height; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + /* Child spans a single column. + */ + if (child->left_attach == (child->right_attach - 1)) + { + width = child->widget->requisition.width + child->xpadding * 2; + table->cols[child->left_attach].requisition = MAX (table->cols[child->left_attach].requisition, width); + } + + /* Child spans a single row. + */ + if (child->top_attach == (child->bottom_attach - 1)) + { + height = child->widget->requisition.height + child->ypadding * 2; + table->rows[child->top_attach].requisition = MAX (table->rows[child->top_attach].requisition, height); + } + } + } +} + +static void +gtk_table_size_request_pass2 (GtkTable *table) +{ + gint max_width; + gint max_height; + gint row, col; + + if (table->homogeneous) + { + max_width = 0; + max_height = 0; + + for (col = 0; col < table->ncols; col++) + max_width = MAX (max_width, table->cols[col].requisition); + for (row = 0; row < table->nrows; row++) + max_height = MAX (max_height, table->rows[row].requisition); + + for (col = 0; col < table->ncols; col++) + table->cols[col].requisition = max_width; + for (row = 0; row < table->nrows; row++) + table->rows[row].requisition = max_height; + } +} + +static void +gtk_table_size_request_pass3 (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint width, height; + gint row, col; + gint extra; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + /* Child spans multiple columns. + */ + if (child->left_attach != (child->right_attach - 1)) + { + /* Check and see if there is already enough space + * for the child. + */ + width = 0; + for (col = child->left_attach; col < child->right_attach; col++) + { + width += table->cols[col].requisition; + if ((col + 1) < child->right_attach) + width += table->cols[col].spacing; + } + + /* If we need to request more space for this child to fill + * its requisition, then divide up the needed space evenly + * amongst the columns it spans. + */ + if (width < child->widget->requisition.width) + { + width = child->widget->requisition.width - width; + extra = width / (child->right_attach - child->left_attach); + + for (col = child->left_attach; col < child->right_attach; col++) + { + if ((col + 1) < child->right_attach) + table->cols[col].requisition += extra; + else + table->cols[col].requisition += width; + width -= extra; + } + } + } + + /* Child spans multiple rows. + */ + if (child->top_attach != (child->bottom_attach - 1)) + { + /* Check and see if there is already enough space + * for the child. + */ + height = 0; + for (row = child->top_attach; row < child->bottom_attach; row++) + { + height += table->rows[row].requisition; + if ((row + 1) < child->bottom_attach) + height += table->rows[row].spacing; + } + + /* If we need to request more space for this child to fill + * its requisition, then divide up the needed space evenly + * amongst the columns it spans. + */ + if (height < child->widget->requisition.height) + { + height = child->widget->requisition.height - height; + extra = height / (child->bottom_attach - child->top_attach); + + for (row = child->top_attach; row < child->bottom_attach; row++) + { + if ((row + 1) < child->bottom_attach) + table->rows[row].requisition += extra; + else + table->rows[row].requisition += height; + height -= extra; + } + } + } + } + } +} + +static void +gtk_table_size_allocate_init (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint row, col; + gint has_expand; + gint has_shrink; + + /* Initialize the rows and cols. + * By default, rows and cols do not expand and do shrink. + * Those values are modified by the children that occupy + * the rows and cols. + */ + for (col = 0; col < table->ncols; col++) + { + table->cols[col].allocation = table->cols[col].requisition; + table->cols[col].need_expand = FALSE; + table->cols[col].need_shrink = TRUE; + table->cols[col].expand = FALSE; + table->cols[col].shrink = TRUE; + } + for (row = 0; row < table->nrows; row++) + { + table->rows[row].allocation = table->rows[row].requisition; + table->rows[row].need_expand = FALSE; + table->rows[row].need_shrink = TRUE; + table->rows[row].expand = FALSE; + table->rows[row].shrink = TRUE; + } + + /* Loop over all the children and adjust the row and col values + * based on whether the children want to be allowed to expand + * or shrink. This loop handles children that occupy a single + * row or column. + */ + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + if (child->left_attach == (child->right_attach - 1)) + { + if (child->xexpand) + table->cols[child->left_attach].expand = TRUE; + + if (!child->xshrink) + table->cols[child->left_attach].shrink = FALSE; + } + + if (child->top_attach == (child->bottom_attach - 1)) + { + if (child->yexpand) + table->rows[child->top_attach].expand = TRUE; + + if (!child->yshrink) + table->rows[child->top_attach].shrink = FALSE; + } + } + } + + /* Loop over all the children again and this time handle children + * which span multiple rows or columns. + */ + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + if (child->left_attach != (child->right_attach - 1)) + { + if (child->xexpand) + { + has_expand = FALSE; + for (col = child->left_attach; col < child->right_attach; col++) + if (table->cols[col].expand) + { + has_expand = TRUE; + break; + } + + if (!has_expand) + for (col = child->left_attach; col < child->right_attach; col++) + table->cols[col].need_expand = TRUE; + } + + if (!child->xshrink) + { + has_shrink = TRUE; + for (col = child->left_attach; col < child->right_attach; col++) + if (!table->cols[col].shrink) + { + has_shrink = FALSE; + break; + } + + if (has_shrink) + for (col = child->left_attach; col < child->right_attach; col++) + table->cols[col].need_shrink = FALSE; + } + } + + if (child->top_attach != (child->bottom_attach - 1)) + { + if (child->yexpand) + { + has_expand = FALSE; + for (row = child->top_attach; row < child->bottom_attach; row++) + if (table->rows[row].expand) + { + has_expand = TRUE; + break; + } + + if (!has_expand) + for (row = child->top_attach; row < child->bottom_attach; row++) + table->rows[row].need_expand = TRUE; + } + + if (!child->yshrink) + { + has_shrink = TRUE; + for (row = child->top_attach; row < child->bottom_attach; row++) + if (!table->rows[row].shrink) + { + has_shrink = FALSE; + break; + } + + if (has_shrink) + for (row = child->top_attach; row < child->bottom_attach; row++) + table->rows[row].need_shrink = FALSE; + } + } + } + } + + /* Loop over the columns and set the expand and shrink values + * if the column can be expanded or shrunk. + */ + for (col = 0; col < table->ncols; col++) + { + if (table->cols[col].need_expand) + table->cols[col].expand = TRUE; + if (!table->cols[col].need_shrink) + table->cols[col].shrink = FALSE; + } + + /* Loop over the rows and set the expand and shrink values + * if the row can be expanded or shrunk. + */ + for (row = 0; row < table->nrows; row++) + { + if (table->rows[row].need_expand) + table->rows[row].expand = TRUE; + if (!table->rows[row].need_shrink) + table->rows[row].shrink = FALSE; + } +} + +static void +gtk_table_size_allocate_pass1 (GtkTable *table) +{ + gint real_width; + gint real_height; + gint width, height; + gint row, col; + gint nexpand; + gint nshrink; + gint extra; + + /* If we were allocated more space than we requested + * then we have to expand any expandable rows and columns + * to fill in the extra space. + */ + + real_width = GTK_WIDGET (table)->allocation.width - GTK_CONTAINER (table)->border_width * 2; + real_height = GTK_WIDGET (table)->allocation.height - GTK_CONTAINER (table)->border_width * 2; + + if (table->homogeneous) + { + nexpand = 0; + for (col = 0; col < table->ncols; col++) + if (table->cols[col].expand) + { + nexpand += 1; + break; + } + + if (nexpand > 0) + { + width = real_width; + + for (col = 0; col < table->ncols - 1; col++) + width -= table->cols[col].spacing; + + extra = width / table->ncols; + + for (col = 0; col < table->ncols; col++) + { + if ((col + 1) == table->ncols) + table->cols[col].allocation = width; + else + table->cols[col].allocation = extra; + + width -= extra; + } + } + } + else + { + width = 0; + nexpand = 0; + nshrink = 0; + + for (col = 0; col < table->ncols; col++) + { + width += table->cols[col].requisition; + if (table->cols[col].expand) + nexpand += 1; + if (table->cols[col].shrink) + nshrink += 1; + } + for (col = 0; col < table->ncols - 1; col++) + width += table->cols[col].spacing; + + /* Check to see if we were allocated more width than we requested. + */ + if ((width < real_width) && (nexpand >= 1)) + { + width = real_width - width; + extra = width / nexpand; + + for (col = 0; col < table->ncols; col++) + if (table->cols[col].expand) + { + if (nexpand == 1) + table->cols[col].allocation += width; + else + table->cols[col].allocation += extra; + + width -= extra; + nexpand -= 1; + } + } + + /* Check to see if we were allocated less width than we requested. + */ + if ((width > real_width) && (nshrink >= 1)) + { + width = width - real_width; + extra = width / nshrink; + + for (col = 0; col < table->ncols; col++) + if (table->cols[col].shrink) + { + if (nshrink == 1) + table->cols[col].allocation -= width; + else + table->cols[col].allocation -= extra; + + width -= extra; + nshrink -= 1; + } + } + } + + if (table->homogeneous) + { + nexpand = 0; + for (row = 0; row < table->nrows; row++) + if (table->rows[row].expand) + { + nexpand += 1; + break; + } + + if (nexpand > 0) + { + height = real_height; + + for (row = 0; row < table->nrows - 1; row++) + height -= table->rows[row].spacing; + + extra = height / table->nrows; + + for (row = 0; row < table->nrows; row++) + { + if ((row + 1) == table->nrows) + table->rows[row].allocation = height; + else + table->rows[row].allocation = extra; + + height -= extra; + } + } + } + else + { + height = 0; + nexpand = 0; + nshrink = 0; + + for (row = 0; row < table->nrows; row++) + { + height += table->rows[row].requisition; + if (table->rows[row].expand) + nexpand += 1; + if (table->rows[row].shrink) + nshrink += 1; + } + for (row = 0; row < table->nrows - 1; row++) + height += table->rows[row].spacing; + + /* Check to see if we were allocated more height than we requested. + */ + if ((height < real_height) && (nexpand >= 1)) + { + height = real_height - height; + extra = height / nexpand; + + for (row = 0; row < table->nrows; row++) + if (table->rows[row].expand) + { + if (nexpand == 1) + table->rows[row].allocation += height; + else + table->rows[row].allocation += extra; + + height -= extra; + nexpand -= 1; + } + } + + /* Check to see if we were allocated less height than we requested. + */ + if ((height > real_height) && (nshrink >= 1)) + { + height = height - real_height; + extra = height / nshrink; + + for (row = 0; row < table->nrows; row++) + if (table->rows[row].shrink) + { + if (nshrink == 1) + table->rows[row].allocation -= height; + else + table->rows[row].allocation -= extra; + + height -= extra; + nshrink -= 1; + } + } + } +} + +static void +gtk_table_size_allocate_pass2 (GtkTable *table) +{ + GtkTableChild *child; + GList *children; + gint max_width; + gint max_height; + gint x, y; + gint row, col; + GtkAllocation allocation; + + children = table->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + x = GTK_WIDGET (table)->allocation.x + GTK_CONTAINER (table)->border_width; + y = GTK_WIDGET (table)->allocation.y + GTK_CONTAINER (table)->border_width; + max_width = 0; + max_height = 0; + + for (col = 0; col < child->left_attach; col++) + { + x += table->cols[col].allocation; + x += table->cols[col].spacing; + } + + for (col = child->left_attach; col < child->right_attach; col++) + { + max_width += table->cols[col].allocation; + if ((col + 1) < child->right_attach) + max_width += table->cols[col].spacing; + } + + for (row = 0; row < child->top_attach; row++) + { + y += table->rows[row].allocation; + y += table->rows[row].spacing; + } + + for (row = child->top_attach; row < child->bottom_attach; row++) + { + max_height += table->rows[row].allocation; + if ((row + 1) < child->bottom_attach) + max_height += table->rows[row].spacing; + } + + if (child->xfill) + { + allocation.width = max_width - child->xpadding * 2; + allocation.x = x + (max_width - allocation.width) / 2; + } + else + { + allocation.width = child->widget->requisition.width; + allocation.x = x + (max_width - allocation.width) / 2; + } + + if (child->yfill) + { + allocation.height = max_height - child->ypadding * 2; + allocation.y = y + (max_height - allocation.height) / 2; + } + else + { + allocation.height = child->widget->requisition.height; + allocation.y = y + (max_height - allocation.height) / 2; + } + + gtk_widget_size_allocate (child->widget, &allocation); + } + } +} diff --git a/gtk/gtktable.h b/gtk/gtktable.h new file mode 100644 index 000000000..f144e78d2 --- /dev/null +++ b/gtk/gtktable.h @@ -0,0 +1,126 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_TABLE_H__ +#define __GTK_TABLE_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TABLE(obj) GTK_CHECK_CAST (obj, gtk_table_get_type (), GtkTable) +#define GTK_TABLE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_table_get_type (), GtkTableClass) +#define GTK_IS_TABLE(obj) GTK_CHECK_TYPE (obj, gtk_table_get_type ()) + + +typedef struct _GtkTable GtkTable; +typedef struct _GtkTableClass GtkTableClass; +typedef struct _GtkTableChild GtkTableChild; +typedef struct _GtkTableRowCol GtkTableRowCol; + +struct _GtkTable +{ + GtkContainer container; + + GList *children; + GtkTableRowCol *rows; + GtkTableRowCol *cols; + guint16 nrows; + guint16 ncols; + + guint homogeneous : 1; +}; + +struct _GtkTableClass +{ + GtkContainerClass parent_class; +}; + +struct _GtkTableChild +{ + GtkWidget *widget; + guint16 left_attach; + guint16 right_attach; + guint16 top_attach; + guint16 bottom_attach; + guint16 xpadding; + guint16 ypadding; + guint xexpand : 1; + guint yexpand : 1; + guint xshrink : 1; + guint yshrink : 1; + guint xfill : 1; + guint yfill : 1; +}; + +struct _GtkTableRowCol +{ + guint16 requisition; + guint16 allocation; + guint16 spacing; + guint need_expand : 1; + guint need_shrink : 1; + guint expand : 1; + guint shrink : 1; +}; + + +guint gtk_table_get_type (void); +GtkWidget* gtk_table_new (gint rows, + gint columns, + gint homogeneous); + +void gtk_table_attach (GtkTable *table, + GtkWidget *child, + gint left_attach, + gint right_attach, + gint top_attach, + gint bottom_attach, + gint xoptions, + gint yoptions, + gint xpadding, + gint ypadding); +void gtk_table_attach_defaults (GtkTable *table, + GtkWidget *widget, + gint left_attach, + gint right_attach, + gint top_attach, + gint bottom_attach); +void gtk_table_set_row_spacing (GtkTable *table, + gint row, + gint spacing); +void gtk_table_set_col_spacing (GtkTable *table, + gint column, + gint spacing); +void gtk_table_set_row_spacings (GtkTable *table, + gint spacing); +void gtk_table_set_col_spacings (GtkTable *table, + gint spacing); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TABLE_H__ */ diff --git a/gtk/gtktext.c b/gtk/gtktext.c new file mode 100644 index 000000000..ae3dd4b5c --- /dev/null +++ b/gtk/gtktext.c @@ -0,0 +1,3522 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk/gdkkeysyms.h" +#include "gtkmain.h" +#include "gtksignal.h" +#include "gtktext.h" +#include "line-wrap.xbm" +#include "line-arrow.xbm" + + +#define INITIAL_BUFFER_SIZE 1024 +#define INITIAL_LINE_CACHE_SIZE 256 +#define MIN_GAP_SIZE 256 +#define LINE_DELIM '\n' +#define MIN_TEXT_WIDTH_LINES 20 +#define MIN_TEXT_HEIGHT_LINES 10 +#define TEXT_BORDER_ROOM 3 +#define LINE_WRAP_ROOM 8 /* The bitmaps are 6 wide. */ +#define DEFAULT_TAB_STOP_WIDTH 4 +#define SCROLL_PIXELS 5 +#define KEY_SCROLL_PIXELS 10 + +#define SET_PROPERTY_MARK(m, p, o) do { \ + (m)->property = (p); \ + (m)->offset = (o); \ + } while (0) +#define MARK_CURRENT_PROPERTY(mark) ((TextProperty*)(mark)->property->data) +#define MARK_NEXT_PROPERTY(mark) ((TextProperty*)(mark)->property->next->data) +#define MARK_PREV_PROPERTY(mark) ((TextProperty*)((mark)->property->prev ? \ + (mark)->property->prev->data \ + : NULL)) +#define MARK_PREV_LIST_PTR(mark) ((mark)->property->prev) +#define MARK_LIST_PTR(mark) ((mark)->property) +#define MARK_NEXT_LIST_PTR(mark) ((mark)->property->next) +#define MARK_OFFSET(mark) ((mark)->offset) +#define MARK_PROPERTY_LENGTH(mark) (MARK_CURRENT_PROPERTY(mark)->length) +#define MARK_CURRENT_FONT(mark) (((TextProperty*)(mark)->property->data)->font->gdk_font) +#define MARK_CURRENT_FORE(mark) (((TextProperty*)(mark)->property->data)->fore_color) +#define MARK_CURRENT_BACK(mark) (((TextProperty*)(mark)->property->data)->back_color) +#define MARK_CURRENT_TEXT_FONT(m) (((TextProperty*)(m)->property->data)->font) +#define TEXT_INDEX(t, index) ((index) < (t)->gap_position ? (t)->text[index] : \ + (t)->text[(index) + (t)->gap_size]) +#define TEXT_LENGTH(t) ((t)->text_end - (t)->gap_size) +#define FONT_HEIGHT(f) ((f)->ascent + (f)->descent) +#define LINE_HEIGHT(l) ((l).font_ascent + (l).font_descent) +#define LINE_CONTAINS(l, i) ((l).start.index <= (i) && (l).end.index >= (i)) +#define LINE_STARTS_AT(l, i) ((l).start.index == (i)) +#define LINE_START_PIXEL(l) ((l).tab_cont.pixel_offset) +#define LAST_INDEX(t, m) ((m).index == TEXT_LENGTH(t)) +#define CACHE_DATA(c) (*(LineParams*)(c)->data) + + +typedef struct _TextFont TextFont; +typedef struct _TextProperty TextProperty; +typedef struct _TabStopMark TabStopMark; +typedef struct _PrevTabCont PrevTabCont; +typedef struct _FetchLinesData FetchLinesData; +typedef struct _LineParams LineParams; +typedef struct _SetVerticalScrollData SetVerticalScrollData; + +typedef gint (*LineIteratorFunction) (GtkText* text, LineParams* lp, void* data); + +typedef enum +{ + FetchLinesPixels, + FetchLinesCount +} FLType; + +struct _SetVerticalScrollData { + gint pixel_height; + gint last_didnt_wrap; + gint last_line_start; + GtkPropertyMark mark; +}; + +struct _TextFont +{ + /* The actual font. */ + GdkFont *gdk_font; + + gint16 char_widths[256]; +}; + +struct _TextProperty +{ + /* Font. */ + TextFont* font; + + /* Background Color. */ + GdkColor* back_color; + + /* Foreground Color. */ + GdkColor* fore_color; + + /* Length of this property. */ + guint length; +}; + +struct _TabStopMark +{ + GList* tab_stops; /* Index into list containing the next tab position. If + * NULL, using default widths. */ + gint to_next_tab; +}; + +struct _PrevTabCont +{ + guint pixel_offset; + TabStopMark tab_start; +}; + +struct _FetchLinesData +{ + GList* new_lines; + FLType fl_type; + gint data; + gint data_max; +}; + +struct _LineParams +{ + guint font_ascent; + guint font_descent; + guint pixel_width; + guint displayable_chars; + guint wraps : 1; + + PrevTabCont tab_cont; + PrevTabCont tab_cont_next; + + GtkPropertyMark start; + GtkPropertyMark end; +}; + + +static void gtk_text_class_init (GtkTextClass *klass); +static void gtk_text_init (GtkText *text); +static void gtk_text_destroy (GtkObject *object); +static void gtk_text_realize (GtkWidget *widget); +static void gtk_text_unrealize (GtkWidget *widget); +static void gtk_text_draw_focus (GtkWidget *widget); +static void gtk_text_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_text_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_text_adjustment (GtkAdjustment *adjustment, + GtkText *text); +static void gtk_text_disconnect (GtkAdjustment *adjustment, + GtkText *text); + +/* Event handlers */ +static void gtk_text_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_text_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_text_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_text_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_text_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_text_key_press (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_text_focus_in (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_text_focus_out (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_text_selection_clear (GtkWidget *widget, + GdkEventSelection *event); +static gint gtk_text_selection_request (GtkWidget *widget, + GdkEventSelection *event); +static gint gtk_text_selection_notify (GtkWidget *widget, + GdkEventSelection *event); + +static void move_gap_to_point (GtkText* text); +static void make_forward_space (GtkText* text, guint len); +static void insert_text_property (GtkText* text, GdkFont* font, + GdkColor *fore, GdkColor* back, guint len); +static void delete_text_property (GtkText* text, guint len); +static void init_properties (GtkText *text); +static guint pixel_height_of (GtkText* text, GList* cache_line); + +/* Property Movement and Size Computations */ +static void advance_mark (GtkPropertyMark* mark); +static void decrement_mark (GtkPropertyMark* mark); +static void advance_mark_n (GtkPropertyMark* mark, gint n); +static void decrement_mark_n (GtkPropertyMark* mark, gint n); +static void move_mark_n (GtkPropertyMark* mark, gint n); +static GtkPropertyMark find_mark (GtkText* text, guint mark_position); +static GtkPropertyMark find_mark_near (GtkText* text, guint mark_position, const GtkPropertyMark* near); +static void find_line_containing_point (GtkText* text, guint point); +static TextProperty* new_text_property (GdkFont* font, GdkColor* fore, GdkColor* back, guint length); + +/* Display */ +static gint total_line_height (GtkText* text, + GList* line, + gint line_count); +static LineParams find_line_params (GtkText* text, + const GtkPropertyMark *mark, + const PrevTabCont *tab_cont, + PrevTabCont *next_cont); +static void recompute_geometry (GtkText* text); +static void insert_char_line_expose (GtkText* text, gchar key, guint old_pixels); +static void delete_char_line_expose (GtkText* text, gchar key, guint old_pixels); +static void clear_area (GtkText *text, GdkRectangle *area); +static void draw_line (GtkText* text, + gint pixel_height, + LineParams* lp); +static void draw_line_wrap (GtkText* text, + guint height); +static void draw_cursor (GtkText* text, gint absolute); +static void undraw_cursor (GtkText* text, gint absolute); +static gint drawn_cursor_min (GtkText* text); +static gint drawn_cursor_max (GtkText* text); +static void expose_text (GtkText* text, GdkRectangle *area, gboolean cursor); + +/* Search and Placement. */ +static void find_cursor (GtkText* text); +static void find_cursor_at_line (GtkText* text, + const LineParams* start_line, + gint pixel_height); +static void mouse_click_1 (GtkText* text, GdkEventButton *event); + +/* Scrolling. */ +static void adjust_adj (GtkText* text, GtkAdjustment* adj); +static void scroll_up (GtkText* text, gint diff); +static void scroll_down (GtkText* text, gint diff); +static void scroll_int (GtkText* text, gint diff); + +/* Cache Management. */ +static GList* remove_cache_line (GtkText* text, GList* list); + +/* Key Motion. */ +static void move_cursor_buffer_ver (GtkText *text, int dir); +static void move_cursor_page_ver (GtkText *text, int dir); +static void move_cursor_ver (GtkText *text, int count); +static void move_cursor_hor (GtkText *text, int count); + +/*#define DEBUG_GTK_TEXT*/ + +#if defined(DEBUG_GTK_TEXT) && defined(__GNUC__) +/* Debugging utilities. */ +static void gtk_text_assert_mark (GtkText *text, + GtkPropertyMark *mark, + GtkPropertyMark *before, + GtkPropertyMark *after, + const gchar *msg, + const gchar *where, + gint line); + +static void gtk_text_assert (GtkText *text, + const gchar *msg, + gint line); +static void gtk_text_show_cache_line (GtkText *text, GList *cache, + const char* what, const char* func, gint line); +static void gtk_text_show_cache (GtkText *text, const char* func, gint line); +static void gtk_text_show_adj (GtkText *text, + GtkAdjustment *adj, + const char* what, + const char* func, + gint line); +static void gtk_text_show_props (GtkText* test, + const char* func, + int line); + +#define TDEBUG(args) g_print args +#define TEXT_ASSERT(text) gtk_text_assert (text,__PRETTY_FUNCTION__,__LINE__) +#define TEXT_ASSERT_MARK(text,mark,msg) gtk_text_assert_mark (text,mark, \ + __PRETTY_FUNCTION__,msg,__LINE__) +#define TEXT_SHOW(text) gtk_text_show_cache (text, __PRETTY_FUNCTION__,__LINE__) +#define TEXT_SHOW_LINE(text,line,msg) gtk_text_show_cache_line (text,line,msg,\ + __PRETTY_FUNCTION__,__LINE__) +#define TEXT_SHOW_ADJ(text,adj,msg) gtk_text_show_adj (text,adj,msg, \ + __PRETTY_FUNCTION__,__LINE__) +#else +#define TDEBUG(args) +#define TEXT_ASSERT(text) +#define TEXT_ASSERT_MARK(text,mark,msg) +#define TEXT_SHOW(text) +#define TEXT_SHOW_LINE(text,line,msg) +#define TEXT_SHOW_ADJ(text,adj,msg) +#endif + +/* Memory Management. */ +static GMemChunk *params_mem_chunk = NULL; +static GMemChunk *text_property_chunk = NULL; + +static GtkWidgetClass *parent_class = NULL; + + +/**********************************************************************/ +/* Widget Crap */ +/**********************************************************************/ + +guint +gtk_text_get_type () +{ + static guint text_type = 0; + + if (!text_type) + { + GtkTypeInfo text_info = + { + "GtkText", + sizeof (GtkText), + sizeof (GtkTextClass), + (GtkClassInitFunc) gtk_text_class_init, + (GtkObjectInitFunc) gtk_text_init, + (GtkArgFunc) NULL, + }; + + text_type = gtk_type_unique (gtk_widget_get_type (), &text_info); + } + + return text_type; +} + +static void +gtk_text_class_init (GtkTextClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = gtk_text_destroy; + + widget_class->realize = gtk_text_realize; + widget_class->unrealize = gtk_text_unrealize; + widget_class->draw_focus = gtk_text_draw_focus; + widget_class->size_request = gtk_text_size_request; + widget_class->size_allocate = gtk_text_size_allocate; + widget_class->draw = gtk_text_draw; + widget_class->expose_event = gtk_text_expose; + widget_class->button_press_event = gtk_text_button_press; + widget_class->button_release_event = gtk_text_button_release; + widget_class->motion_notify_event = gtk_text_motion_notify; + widget_class->key_press_event = gtk_text_key_press; + widget_class->focus_in_event = gtk_text_focus_in; + widget_class->focus_out_event = gtk_text_focus_out; + widget_class->selection_clear_event = gtk_text_selection_clear; + widget_class->selection_request_event = gtk_text_selection_request; + widget_class->selection_notify_event = gtk_text_selection_notify; +} + +static void +gtk_text_init (GtkText *text) +{ + GTK_WIDGET_SET_FLAGS (text, GTK_CAN_FOCUS); + + text->text = g_new (guchar, INITIAL_BUFFER_SIZE); + text->text_len = INITIAL_BUFFER_SIZE; + + if (!params_mem_chunk) + params_mem_chunk = g_mem_chunk_new ("LineParams", + sizeof (LineParams), + 256 * sizeof (LineParams), + G_ALLOC_AND_FREE); + + text->default_tab_width = 4; + text->tab_stops = NULL; + + text->tab_stops = g_list_prepend (text->tab_stops, (void*)8); + text->tab_stops = g_list_prepend (text->tab_stops, (void*)8); + + text->line_wrap = TRUE; + text->is_editable = TRUE; +} + +GtkWidget* +gtk_text_new (GtkAdjustment *hadj, + GtkAdjustment *vadj) +{ + GtkText *text; + + text = gtk_type_new (gtk_text_get_type ()); + + gtk_text_set_adjustments (text, hadj, vadj); + + return GTK_WIDGET (text); +} + +void +gtk_text_set_editable (GtkText *text, + gint editable) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + text->is_editable = (editable != FALSE); + text->is_editable = FALSE; /* UNTIL JOSH FIXES IT */ +} + +void +gtk_text_set_adjustments (GtkText *text, + GtkAdjustment *hadj, + GtkAdjustment *vadj) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + if (text->hadj && (text->hadj != hadj)) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (text->hadj), text); + gtk_object_unref (GTK_OBJECT (text->hadj)); + } + + if (text->vadj && (text->vadj != vadj)) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (text->vadj), text); + gtk_object_unref (GTK_OBJECT (text->vadj)); + } + + if (!hadj) + hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); + + if (!vadj) + vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); + + if (text->hadj != hadj) + { + text->hadj = hadj; + gtk_object_ref (GTK_OBJECT (text->hadj)); + + gtk_signal_connect (GTK_OBJECT (text->hadj), "changed", + (GtkSignalFunc) gtk_text_adjustment, + text); + gtk_signal_connect (GTK_OBJECT (text->hadj), "value_changed", + (GtkSignalFunc) gtk_text_adjustment, + text); + gtk_signal_connect (GTK_OBJECT (text->hadj), "disconnect", + (GtkSignalFunc) gtk_text_disconnect, + text); + } + + if (text->vadj != vadj) + { + text->vadj = vadj; + gtk_object_ref (GTK_OBJECT (text->vadj)); + + gtk_signal_connect (GTK_OBJECT (text->vadj), "changed", + (GtkSignalFunc) gtk_text_adjustment, + text); + gtk_signal_connect (GTK_OBJECT (text->vadj), "value_changed", + (GtkSignalFunc) gtk_text_adjustment, + text); + gtk_signal_connect (GTK_OBJECT (text->vadj), "disconnect", + (GtkSignalFunc) gtk_text_disconnect, + text); + } +} + +void +gtk_text_set_point (GtkText *text, + guint index) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + g_return_if_fail (index >= 0 && index <= TEXT_LENGTH (text)) + + text->point = find_mark (text, index); +} + +guint +gtk_text_get_point (GtkText *text) +{ + g_return_val_if_fail (text != NULL, 0); + g_return_val_if_fail (GTK_IS_TEXT (text), 0); + + return text->point.index; +} + +guint +gtk_text_get_length (GtkText *text) +{ + g_return_val_if_fail (text != NULL, 0); + g_return_val_if_fail (GTK_IS_TEXT (text), 0); + + return TEXT_LENGTH (text); +} + +void +gtk_text_freeze (GtkText *text) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + text->freeze = TRUE; +} + +void +gtk_text_thaw (GtkText *text) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + text->freeze = FALSE; + + if (GTK_WIDGET_DRAWABLE (text)) + { + recompute_geometry (text); + gtk_widget_queue_draw (GTK_WIDGET (text)); + } +} + +void +gtk_text_insert (GtkText *text, + GdkFont *font, + GdkColor *fore, + GdkColor *back, + const char *chars, + gint length) +{ + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + g_assert (GTK_WIDGET_REALIZED (text)); + + /* back may be NULL, fore may not. */ + if (fore == NULL) + fore = &text->widget.style->fg[GTK_STATE_NORMAL]; + + /* This must be because we need to have the style set up. */ + g_assert (GTK_WIDGET_REALIZED(text)); + + if (length < 0) + length = strlen (chars); + + if (length == 0) + return; + + move_gap_to_point (text); + + if (font == NULL) + font = GTK_WIDGET (text)->style->font; + + make_forward_space (text, length); + + memcpy (text->text + text->gap_position, chars, length); + + insert_text_property (text, font, fore, back, length); + + text->gap_size -= length; + text->gap_position += length; + + advance_mark_n (&text->point, length); +} + +gint +gtk_text_backward_delete (GtkText *text, + guint nchars) +{ + g_return_val_if_fail (text != NULL, 0); + g_return_val_if_fail (GTK_IS_TEXT (text), 0); + + if (nchars > text->point.index || nchars <= 0) + return FALSE; + + gtk_text_set_point (text, text->point.index - nchars); + + return gtk_text_foreward_delete (text, nchars); +} + +gint +gtk_text_foreward_delete (GtkText *text, + guint nchars) +{ + g_return_val_if_fail (text != NULL, 0); + g_return_val_if_fail (GTK_IS_TEXT (text), 0); + + if (text->point.index + nchars > TEXT_LENGTH (text) || nchars <= 0) + return FALSE; + + move_gap_to_point (text); + + text->gap_size += nchars; + + delete_text_property (text, nchars); + + return TRUE; +} + +static void +gtk_text_destroy (GtkObject *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_TEXT (object)); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_text_realize (GtkWidget *widget) +{ + GtkText *text; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + + text = (GtkText*) widget; + GTK_WIDGET_SET_FLAGS (text, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_KEY_PRESS_MASK); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, text); + + attributes.x = (widget->style->klass->xthickness + TEXT_BORDER_ROOM); + attributes.y = (widget->style->klass->ythickness + TEXT_BORDER_ROOM); + attributes.width = widget->allocation.width - attributes.x * 2; + attributes.height = widget->allocation.height - attributes.y * 2; + + text->text_area = gdk_window_new (widget->window, &attributes, attributes_mask); + gdk_window_set_user_data (text->text_area, text); + + widget->style = gtk_style_attach (widget->style, widget->window); + + /* Can't call gtk_style_set_background here because its handled specially */ + if (!text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + gdk_window_set_background (text->widget.window, &text->widget.style->bg[GTK_STATE_NORMAL]); + + if (!text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + gdk_window_set_background (text->text_area, &text->widget.style->bg[GTK_STATE_NORMAL]); + + text->line_wrap_bitmap = gdk_bitmap_create_from_data (text->text_area, + (gchar*) line_wrap_bits, + line_wrap_width, + line_wrap_height); + + text->line_arrow_bitmap = gdk_bitmap_create_from_data (text->text_area, + (gchar*) line_arrow_bits, + line_arrow_width, + line_arrow_height); + + text->gc = gdk_gc_new (text->text_area); + gdk_gc_set_exposures (text->gc, TRUE); + gdk_gc_set_foreground (text->gc, &widget->style->fg[GTK_STATE_NORMAL]); + + init_properties (text); + + gdk_window_show (text->text_area); +} + +static void +gtk_text_unrealize (GtkWidget *widget) +{ + GtkText *text; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + + text = GTK_TEXT (widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + gdk_window_destroy (widget->window); + gdk_window_destroy (text->text_area); + gdk_gc_destroy (text->gc); + + widget->window = NULL; + text->text_area = NULL; + text->gc = NULL; +} + +static void +clear_focus_area (GtkText *text, gint area_x, gint area_y, gint area_width, gint area_height) +{ + gint ythick = TEXT_BORDER_ROOM + text->widget.style->klass->ythickness; + gint xthick = TEXT_BORDER_ROOM + text->widget.style->klass->xthickness; + + gint width, height; + gint xorig, yorig; + gint x, y; + + gdk_window_get_size (text->widget.style->bg_pixmap[GTK_STATE_NORMAL], &width, &height); + + yorig = - text->first_onscreen_ver_pixel + ythick; + xorig = - text->first_onscreen_hor_pixel + xthick; + + while (yorig > 0) + yorig -= height; + + while (xorig > 0) + xorig -= width; + + for (y = area_y; y < area_y + area_height; ) + { + gint yoff = (y - yorig) % height; + gint yw = MIN(height - yoff, (area_y + area_height) - y); + + for (x = area_x; x < area_x + area_width; ) + { + gint xoff = (x - xorig) % width; + gint xw = MIN(width - xoff, (area_x + area_width) - x); + + gdk_draw_pixmap (text->widget.window, + text->gc, + text->widget.style->bg_pixmap[GTK_STATE_NORMAL], + xoff, + yoff, + x, + y, + xw, + yw); + + x += width - xoff; + } + y += height - yoff; + } +} + +static void +gtk_text_draw_focus (GtkWidget *widget) +{ + GtkText *text; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + + text = GTK_TEXT (widget); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + TDEBUG (("in gtk_text_draw_focus\n")); + + x = 0; + y = 0; + width = widget->allocation.width; + height = widget->allocation.height; + + if (widget->style->bg_pixmap[GTK_STATE_NORMAL]) + { + gint ythick = TEXT_BORDER_ROOM + widget->style->klass->ythickness; + gint xthick = TEXT_BORDER_ROOM + widget->style->klass->xthickness; + + /* top rect */ + clear_focus_area (text, 0, 0, width, ythick); + /* right rect */ + clear_focus_area (text, 0, ythick, xthick, height - 2 * ythick); + /* left rect */ + clear_focus_area (text, width - xthick, ythick, xthick, height - 2 * ythick); + /* bottom rect */ + clear_focus_area (text, 0, height - ythick, width, ythick); + } + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + + gdk_draw_rectangle (widget->window, + widget->style->fg_gc[GTK_STATE_NORMAL], + FALSE, 0, 0, + widget->allocation.width - 1, + widget->allocation.height - 1); + } + else + { + gdk_draw_rectangle (widget->window, + widget->style->white_gc, FALSE, + x + 2, + y + 2, + width - 1 - 2, + height - 1 - 2); + } + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_IN, + x, y, width, height); + } + else + { + TDEBUG (("in gtk_text_draw_focus (undrawable !!!)\n")); + } +} + +static void +gtk_text_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + gint xthickness; + gint ythickness; + gint char_height; + gint char_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + g_return_if_fail (requisition != NULL); + + xthickness = widget->style->klass->xthickness + TEXT_BORDER_ROOM; + ythickness = widget->style->klass->ythickness + TEXT_BORDER_ROOM; + + char_height = MIN_TEXT_HEIGHT_LINES * (widget->style->font->ascent + + widget->style->font->descent); + + char_width = MIN_TEXT_WIDTH_LINES * (gdk_text_width (widget->style->font, + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + 26) + / 26); + + requisition->width = char_width + xthickness * 2; + requisition->height = char_height + ythickness * 2; +} + +static void +gtk_text_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkText *text; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + g_return_if_fail (allocation != NULL); + + text = GTK_TEXT (widget); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gdk_window_move_resize (text->text_area, + widget->style->klass->xthickness + TEXT_BORDER_ROOM, + widget->style->klass->ythickness + TEXT_BORDER_ROOM, + widget->allocation.width - (widget->style->klass->xthickness + + TEXT_BORDER_ROOM) * 2, + widget->allocation.height - (widget->style->klass->ythickness + + TEXT_BORDER_ROOM) * 2); + + recompute_geometry (text); + } +} + +static void +gtk_text_draw (GtkWidget *widget, + GdkRectangle *area) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TEXT (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + expose_text (GTK_TEXT (widget), area, TRUE); + gtk_widget_draw_focus (widget); + } +} + +static gint +gtk_text_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->window == GTK_TEXT (widget)->text_area) + { + TDEBUG (("in gtk_text_expose (expose)\n")); + expose_text (GTK_TEXT (widget), &event->area, TRUE); + } + else if (event->count == 0) + { + TDEBUG (("in gtk_text_expose (focus)\n")); + gtk_widget_draw_focus (widget); + } + + return FALSE; +} + +static gint +gtk_text_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkText *text; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + text = GTK_TEXT(widget); + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + if (event->type == GDK_BUTTON_PRESS && event->button != 2) + gtk_grab_add (widget); + + if (event->button == 1) + { + switch (event->type) + { + case GDK_BUTTON_PRESS: + undraw_cursor (GTK_TEXT (widget), FALSE); + mouse_click_1 (GTK_TEXT (widget), event); + draw_cursor (GTK_TEXT (widget), FALSE); + /* start selection */ + break; + + case GDK_2BUTTON_PRESS: + /* select word */ + break; + + case GDK_3BUTTON_PRESS: + /* select line */ + break; + + default: + break; + } + } + else if (event->type == GDK_BUTTON_PRESS) + { + if (event->button == 2) + { + /* insert selection. */ + } + else + { + /* start selection */ + } + } + + return FALSE; +} + +static gint +gtk_text_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + GtkText *text; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (event->button != 2) + { + gtk_grab_remove (widget); + + text = GTK_TEXT (widget); + + /* stop selecting. */ + } + + return FALSE; +} + +static gint +gtk_text_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkText *text; + gint x; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + text = GTK_TEXT (widget); + + x = event->x; + if (event->is_hint || (text->text_area != event->window)) + gdk_window_get_pointer (text->text_area, &x, NULL, NULL); + + /* update selection */ + + return FALSE; +} + +static void +gtk_text_insert_1_at_point (GtkText* text, char key) +{ + gtk_text_insert (text, + MARK_CURRENT_FONT (&text->point), + MARK_CURRENT_FORE (&text->point), + MARK_CURRENT_BACK (&text->point), + &key, 1); +} + +static gint +gtk_text_key_press (GtkWidget *widget, + GdkEventKey *event) +{ + GtkText *text; + gchar key; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return_val = FALSE; + + text = GTK_TEXT (widget); + + if (!return_val) + { + key = event->keyval; + return_val = TRUE; + + if (text->is_editable == FALSE) + { + switch (event->keyval) + { + case GDK_Home: scroll_int (text, -text->vadj->value); break; + case GDK_End: scroll_int (text, +text->vadj->upper); break; + case GDK_Page_Up: scroll_int (text, -text->vadj->page_increment); break; + case GDK_Page_Down: scroll_int (text, +text->vadj->page_increment); break; + case GDK_Up: scroll_int (text, -KEY_SCROLL_PIXELS); break; + case GDK_Down: scroll_int (text, +KEY_SCROLL_PIXELS); break; + default: break; + } + } + else + { + text->point = find_mark (text, text->cursor_mark.index); + + switch (event->keyval) + { + case GDK_Home: move_cursor_buffer_ver (text, -1); break; + case GDK_End: move_cursor_buffer_ver (text, +1); break; + case GDK_Page_Up: move_cursor_page_ver (text, -1); break; + case GDK_Page_Down: move_cursor_page_ver (text, +1); break; + case GDK_Up: move_cursor_ver (text, -1); break; + case GDK_Down: move_cursor_ver (text, +1); break; + case GDK_Left: move_cursor_hor (text, -1); break; + case GDK_Right: move_cursor_hor (text, +1); break; + + case GDK_BackSpace: + if (!text->has_cursor || text->cursor_mark.index == 0) + break; + + gtk_text_backward_delete (text, 1); + break; + case GDK_Delete: + if (!text->has_cursor || LAST_INDEX (text, text->cursor_mark)) + break; + + gtk_text_foreward_delete (text, 1); + break; + case GDK_Tab: + if (!text->has_cursor) + break; + + gtk_text_insert_1_at_point (text, '\t'); + break; + case GDK_Return: + if (!text->has_cursor) + break; + + gtk_text_insert_1_at_point (text, '\n'); + break; + default: + if (!text->has_cursor) + break; + + if ((event->keyval >= 0x20) && (event->keyval <= 0x7e)) + { + return_val = TRUE; + + if (event->state & GDK_CONTROL_MASK) + { + if ((key >= 'A') && (key <= 'Z')) + key -= 'A' - 'a'; + + if ((key >= 'a') && (key <= 'z') && text->control_keys[(int) (key - 'a')]) + (* text->control_keys[(int) (key - 'a')]) (text); + } + else if (event->state & GDK_MOD1_MASK) + { + g_message ("alt key"); + + if ((key >= 'A') && (key <= 'Z')) + key -= 'A' - 'a'; + + if ((key >= 'a') && (key <= 'z') && text->alt_keys[(int) (key - 'a')]) + (* text->alt_keys[(int) (key - 'a')]) (text); + } + else + { + gtk_text_insert_1_at_point (text, key); + } + } + else + { + return_val = FALSE; + } + break; + } + } + } + + return return_val; +} + +static gint +gtk_text_focus_in (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + TDEBUG (("in gtk_text_focus_in\n")); + + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + draw_cursor (GTK_TEXT(widget), TRUE); + + return FALSE; +} + +static gint +gtk_text_focus_out (GtkWidget *widget, + GdkEventFocus *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_TEXT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + TDEBUG (("in gtk_text_focus_out\n")); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); + gtk_widget_draw_focus (widget); + + undraw_cursor (GTK_TEXT(widget), TRUE); + + return FALSE; +} + +static void +gtk_text_adjustment (GtkAdjustment *adjustment, + GtkText *text) +{ + g_return_if_fail (adjustment != NULL); + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + if (adjustment == text->hadj) + { + g_warning ("horizontal scrolling not implemented"); + } + else + { + gint diff = ((gint)adjustment->value) - text->last_ver_value; + + if (diff != 0) + { + undraw_cursor (text, FALSE); + + if (diff > 0) + scroll_down (text, diff); + else /* if (diff < 0) */ + scroll_up (text, diff); + + draw_cursor (text, FALSE); + + text->last_ver_value = adjustment->value; + } + } +} + +static void +gtk_text_disconnect (GtkAdjustment *adjustment, + GtkText *text) +{ + g_return_if_fail (adjustment != NULL); + g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); + g_return_if_fail (text != NULL); + g_return_if_fail (GTK_IS_TEXT (text)); + + if (adjustment == text->hadj) + text->hadj = NULL; + if (adjustment == text->vadj) + text->vadj = NULL; +} + + +static GtkPropertyMark +find_this_line_start_mark (GtkText* text, guint point_position, const GtkPropertyMark* near) +{ + GtkPropertyMark mark; + + mark = find_mark_near (text, point_position, near); + + while (mark.index > 0 && + TEXT_INDEX (text, mark.index - 1) != LINE_DELIM) + decrement_mark (&mark); + + return mark; +} + +static void +init_tab_cont (GtkText* text, PrevTabCont* tab_cont) +{ + tab_cont->pixel_offset = 0; + tab_cont->tab_start.tab_stops = text->tab_stops; + tab_cont->tab_start.to_next_tab = (gulong) text->tab_stops->data; + + if (!tab_cont->tab_start.to_next_tab) + tab_cont->tab_start.to_next_tab = text->default_tab_width; +} + +static void +line_params_iterate (GtkText* text, + const GtkPropertyMark* mark0, + const PrevTabCont* tab_mark0, + gint8 alloc, + void* data, + LineIteratorFunction iter) + /* mark0 MUST be a real line start. if ALLOC, allocate line params + * from a mem chunk. DATA is passed to ITER_CALL, which is called + * for each line following MARK, iteration continues unless ITER_CALL + * returns TRUE. */ +{ + GtkPropertyMark mark = *mark0; + PrevTabCont tab_conts[2]; + LineParams *lp, lpbuf; + gint tab_cont_index = 0; + + if (tab_mark0) + tab_conts[0] = *tab_mark0; + else + init_tab_cont (text, tab_conts); + + for (;;) + { + if (alloc) + lp = g_chunk_new (LineParams, params_mem_chunk); + else + lp = &lpbuf; + + *lp = find_line_params (text, &mark, tab_conts + tab_cont_index, + tab_conts + (tab_cont_index + 1) % 2); + + if ((*iter) (text, lp, data)) + return; + + if (LAST_INDEX (text, lp->end)) + break; + + mark = lp->end; + advance_mark (&mark); + tab_cont_index = (tab_cont_index + 1) % 2; + } +} + +static gint +fetch_lines_iterator (GtkText* text, LineParams* lp, void* data) +{ + FetchLinesData *fldata = (FetchLinesData*) data; + + fldata->new_lines = g_list_prepend (fldata->new_lines, lp); + + switch (fldata->fl_type) + { + case FetchLinesCount: + if (!text->line_wrap || !lp->wraps) + fldata->data += 1; + + if (fldata->data >= fldata->data_max) + return TRUE; + + break; + case FetchLinesPixels: + + fldata->data += LINE_HEIGHT(*lp); + + if (fldata->data >= fldata->data_max) + return TRUE; + + break; + } + + return FALSE; +} + +static GList* +fetch_lines (GtkText* text, + const GtkPropertyMark* mark0, + const PrevTabCont* tab_cont0, + FLType fl_type, + gint data) +{ + FetchLinesData fl_data; + + fl_data.new_lines = NULL; + fl_data.data = 0; + fl_data.data_max = data; + fl_data.fl_type = fl_type; + + line_params_iterate (text, mark0, tab_cont0, TRUE, &fl_data, fetch_lines_iterator); + + return g_list_reverse (fl_data.new_lines); +} + +static void +fetch_lines_backward (GtkText* text) +{ + GList* new_lines = NULL, *new_line_start; + + GtkPropertyMark mark = find_this_line_start_mark (text, + CACHE_DATA(text->line_start_cache).start.index - 1, + &CACHE_DATA(text->line_start_cache).start); + + new_line_start = new_lines = fetch_lines (text, &mark, NULL, FetchLinesCount, 1); + + while (new_line_start->next) + new_line_start = new_line_start->next; + + new_line_start->next = text->line_start_cache; + text->line_start_cache->prev = new_line_start; +} + +static void +fetch_lines_forward (GtkText* text, gint line_count) +{ + GtkPropertyMark mark; + GList* line = text->line_start_cache; + + while(line->next) + line = line->next; + + mark = CACHE_DATA(line).end; + + if (LAST_INDEX (text, mark)) + return; + + advance_mark(&mark); + + line->next = fetch_lines (text, &mark, &CACHE_DATA(line).tab_cont_next, FetchLinesCount, line_count); + + if (line->next) + line->next->prev = line; +} + +static gint +total_line_height (GtkText* text, GList* line, gint line_count) +{ + gint height = 0; + + for (; line && line_count > 0; line = line->next) + { + height += LINE_HEIGHT(CACHE_DATA(line)); + + if (!text->line_wrap || !CACHE_DATA(line).wraps) + line_count -= 1; + + if (!line->next) + fetch_lines_forward (text, line_count); + } + + return height; +} + +static void +swap_lines (GtkText* text, GList* old, GList* new, gint old_line_count) +{ + if (old == text->line_start_cache) + { + GList* last; + + for (; old_line_count > 0; old_line_count -= 1) + { + while (text->line_start_cache && + text->line_wrap && + CACHE_DATA(text->line_start_cache).wraps) + remove_cache_line(text, text->line_start_cache); + + remove_cache_line(text, text->line_start_cache); + } + + last = g_list_last (new); + + last->next = text->line_start_cache; + + if (text->line_start_cache) + text->line_start_cache->prev = last; + + text->line_start_cache = new; + } + else + { + GList *last; + + g_assert (old->prev); + + last = old->prev; + + for (; old_line_count > 0; old_line_count -= 1) + { + while (old && text->line_wrap && CACHE_DATA(old).wraps) + old = remove_cache_line (text, old); + + old = remove_cache_line (text, old); + } + + last->next = new; + new->prev = last; + + last = g_list_last (new); + + last->next = old; + + if (old) + old->prev = last; + } +} + +static void +correct_cache_delete (GtkText* text, gint lines) +{ + GList* cache = text->current_line; + gint i; + + for (i = 0; cache && i < lines; i += 1, cache = cache->next) + /* nothing */; + + for (; cache; cache = cache->next) + { + GtkPropertyMark *start = &CACHE_DATA(cache).start; + GtkPropertyMark *end = &CACHE_DATA(cache).end; + + start->index -= 1; + end->index -= 1; + + if (start->property == text->point.property) + start->offset = start->index - (text->point.index - text->point.offset); + + if (end->property == text->point.property) + end->offset = end->index - (text->point.index - text->point.offset); + + /*TEXT_ASSERT_MARK(text, start, "start");*/ + /*TEXT_ASSERT_MARK(text, end, "end");*/ + } +} + +static void +delete_char_line_expose (GtkText* text, gchar key, guint old_pixels) +{ + gint pixel_height; + guint new_pixels = 0; + gint old_line_count = 1 + (key == LINE_DELIM); + GdkRectangle rect; + GList* new_line = NULL; + gint width, height; + + text->cursor_virtual_x = 0; + + undraw_cursor (text, FALSE); + + correct_cache_delete (text, old_line_count); + + pixel_height = pixel_height_of(text, text->current_line) - + LINE_HEIGHT(CACHE_DATA(text->current_line)); + + if (CACHE_DATA(text->current_line).start.index == text->point.index) + CACHE_DATA(text->current_line).start = text->point; + + new_line = fetch_lines (text, + &CACHE_DATA(text->current_line).start, + &CACHE_DATA(text->current_line).tab_cont, + FetchLinesCount, + 1); + + swap_lines (text, text->current_line, new_line, old_line_count); + + text->current_line = new_line; + + new_pixels = total_line_height (text, new_line, 1); + + gdk_window_get_size (text->text_area, &width, &height); + + if (old_pixels != new_pixels) + { + gdk_draw_pixmap (text->text_area, + text->gc, + text->text_area, + 0, + pixel_height + old_pixels, + 0, + pixel_height + new_pixels, + width, + height); + + text->vadj->upper += new_pixels; + text->vadj->upper -= old_pixels; + adjust_adj (text, text->vadj); + } + + rect.x = 0; + rect.y = pixel_height; + rect.width = width; + rect.height = new_pixels; + + expose_text (text, &rect, FALSE); + gtk_text_draw_focus ( (GtkWidget *) text); + + text->cursor_mark = text->point; + + find_cursor (text); + + draw_cursor (text, FALSE); + + TEXT_ASSERT (text); + TEXT_SHOW(text); +} + +static void +correct_cache_insert (GtkText* text) +{ + GList* cache = text->current_line; + + for (; cache; cache = cache->next) + { + GtkPropertyMark *start = &CACHE_DATA(cache).start; + GtkPropertyMark *end = &CACHE_DATA(cache).end; + + if (start->index >= text->point.index) + { + if (start->property == text->point.property) + move_mark_n(start, 1); + else + start->index += 1; + } + + if (end->index >= text->point.index) + { + if (end->property == text->point.property) + move_mark_n(end, 1); + else + end->index += 1; + } + + /*TEXT_ASSERT_MARK(text, start, "start");*/ + /*TEXT_ASSERT_MARK(text, end, "end");*/ + } +} + + +static void +insert_char_line_expose (GtkText* text, gchar key, guint old_pixels) +{ + gint pixel_height; + guint new_pixels = 0; + guint new_line_count = 1 + (key == LINE_DELIM); + GdkRectangle rect; + GList* new_line = NULL; + gint width, height; + + text->cursor_virtual_x = 0; + + undraw_cursor (text, FALSE); + + correct_cache_insert (text); + + TEXT_SHOW_ADJ (text, text->vadj, "vadj"); + + pixel_height = pixel_height_of(text, text->current_line) - + LINE_HEIGHT(CACHE_DATA(text->current_line)); + + new_line = fetch_lines (text, + &CACHE_DATA(text->current_line).start, + &CACHE_DATA(text->current_line).tab_cont, + FetchLinesCount, + new_line_count); + + swap_lines (text, text->current_line, new_line, 1); + + text->current_line = new_line; + + new_pixels = total_line_height (text, new_line, new_line_count); + + gdk_window_get_size (text->text_area, &width, &height); + + if (old_pixels != new_pixels) + { + gdk_draw_pixmap (text->text_area, + text->gc, + text->text_area, + 0, + pixel_height + old_pixels, + 0, + pixel_height + new_pixels, + width, + height + (old_pixels - new_pixels) - pixel_height); + + text->vadj->upper += new_pixels; + text->vadj->upper -= old_pixels; + adjust_adj (text, text->vadj); + } + + rect.x = 0; + rect.y = pixel_height; + rect.width = width; + rect.height = new_pixels; + + expose_text (text, &rect, FALSE); + gtk_text_draw_focus ( (GtkWidget *) text); + + text->cursor_mark = text->point; + + find_cursor (text); + + draw_cursor (text, FALSE); + + TEXT_SHOW_ADJ (text, text->vadj, "vadj"); + TEXT_ASSERT (text); + TEXT_SHOW(text); +} + +static guint +font_hash (gpointer font) +{ + return gdk_font_id ((GdkFont*) font); +} + +static TextFont* +get_text_font (GdkFont* gfont) +{ + static GHashTable *font_cache_table = NULL; + TextFont* tf; + gpointer lu; + gint i; + + if (!font_cache_table) + font_cache_table = g_hash_table_new (font_hash, (GCompareFunc) gdk_font_equal); + + lu = g_hash_table_lookup (font_cache_table, gfont); + + if (lu) + return (TextFont*)lu; + + tf = g_new (TextFont, 1); + + tf->gdk_font = gfont; + + for(i = 0; i < 256; i += 1) + tf->char_widths[i] = gdk_char_width (gfont, (char)i); + + g_hash_table_insert (font_cache_table, gfont, tf); + + return tf; +} + +static gint +text_properties_equal (TextProperty* prop, GdkFont* font, GdkColor *fore, GdkColor *back) +{ + return prop->font == get_text_font(font) && + (fore == prop->fore_color || gdk_color_equal(prop->fore_color, fore)) && + (back == prop->back_color || (back && prop->back_color && gdk_color_equal(prop->back_color, back))); +} + +static TextProperty* +new_text_property (GdkFont* font, GdkColor* fore, GdkColor* back, guint length) +{ + TextProperty *prop; + + if (text_property_chunk == NULL) + { + text_property_chunk = g_mem_chunk_new ("text property mem chunk", + sizeof(TextProperty), + 1024*sizeof(TextProperty), + G_ALLOC_ONLY); + } + + prop = g_chunk_new(TextProperty, text_property_chunk); + + prop->font = get_text_font (font); + prop->fore_color = fore; + prop->back_color = back; + prop->length = length; + + return prop; +} + +/* Flop the memory between the point and the gap around like a + * dead fish. */ +static void +move_gap_to_point (GtkText* text) +{ + if (text->gap_position < text->point.index) + { + gint diff = text->point.index - text->gap_position; + + memmove (text->text + text->gap_position, + text->text + text->gap_position + text->gap_size, + diff); + + text->gap_position = text->point.index; + } + else if (text->gap_position > text->point.index) + { + gint diff = text->gap_position - text->point.index; + + memmove (text->text + text->point.index + text->gap_size, + text->text + text->point.index, + diff); + + text->gap_position = text->point.index; + } +} + +/* Increase the gap size. */ +static void +make_forward_space (GtkText* text, guint len) +{ + if (text->gap_size < len) + { + guint sum = MAX(2*len, MIN_GAP_SIZE) + text->text_end; + + if (sum >= text->text_len) + { + guint i = 1; + + while (i <= sum) i <<= 1; + + text->text = (guchar*)g_realloc(text->text, i); + } + + memmove (text->text + text->gap_position + text->gap_size + 2*len, + text->text + text->gap_position + text->gap_size, + text->text_end - (text->gap_position + text->gap_size)); + + text->text_end += len*2; + text->gap_size += len*2; + } +} + +/* Inserts into the text property list a list element that guarantees + * that for len characters following the point, text has the correct + * property. does not move point. adjusts text_properties_point and + * text_properties_point_offset relative to the current value of + * point. */ +static void +insert_text_property (GtkText* text, GdkFont* font, + GdkColor *fore, GdkColor* back, guint len) +{ + GtkPropertyMark *mark = &text->point; + TextProperty* forward_prop = MARK_CURRENT_PROPERTY(mark); + TextProperty* backward_prop = MARK_PREV_PROPERTY(mark); + + if (MARK_OFFSET(mark) == 0) + { + /* Point is on the boundary of two properties. + * If it is the same as either, grow, else insert + * a new one. */ + + if (text_properties_equal(forward_prop, font, fore, back)) + { + /* Grow the property in front of us. */ + + MARK_PROPERTY_LENGTH(mark) += len; + } + else if (backward_prop && + text_properties_equal(backward_prop, font, fore, back)) + { + /* Grow property behind us, point property and offset + * change. */ + + SET_PROPERTY_MARK (&text->point, + MARK_PREV_LIST_PTR (mark), + backward_prop->length); + + backward_prop->length += len; + } + else + { + /* Splice a new property into the list. */ + + GList* new_prop = g_list_alloc(); + + new_prop->next = MARK_LIST_PTR(mark); + new_prop->prev = MARK_PREV_LIST_PTR(mark); + new_prop->next->prev = new_prop; + + if (new_prop->prev) + new_prop->prev->next = new_prop; + + new_prop->data = new_text_property (font, fore, back, len); + + SET_PROPERTY_MARK (mark, new_prop, 0); + } + } + else + { + /* In the middle of forward_prop, if properties are equal, + * just add to its length, else split it into two and splice + * in a new one. */ + if (text_properties_equal (forward_prop, font, fore, back)) + { + forward_prop->length += len; + } + else + { + GList* new_prop = g_list_alloc(); + GList* new_prop_forward = g_list_alloc(); + gint old_length = forward_prop->length; + GList* next = MARK_NEXT_LIST_PTR(mark); + + /* Set the new lengths according to where they are split. Construct + * two new properties. */ + forward_prop->length = MARK_OFFSET(mark); + + new_prop_forward->data = new_text_property(forward_prop->font->gdk_font, + fore, + back, + old_length - forward_prop->length); + + new_prop->data = new_text_property(font, fore, back, len); + + /* Now splice things in. */ + MARK_NEXT_LIST_PTR(mark) = new_prop; + new_prop->prev = MARK_LIST_PTR(mark); + + new_prop->next = new_prop_forward; + new_prop_forward->prev = new_prop; + + new_prop_forward->next = next; + + if (next) + next->prev = new_prop_forward; + + SET_PROPERTY_MARK (mark, new_prop, 0); + } + } + + while (text->text_properties_end->next) + text->text_properties_end = text->text_properties_end->next; + + while (text->text_properties->prev) + text->text_properties = text->text_properties->prev; +} + +static void +delete_text_property (GtkText* text, guint nchars) +{ + /* Delete nchars forward from point. */ + TextProperty *prop; + GList *tmp; + gint is_first; + + for(; nchars; nchars -= 1) + { + prop = MARK_CURRENT_PROPERTY(&text->point); + + prop->length -= 1; + + if (prop->length == 0) + { + tmp = MARK_LIST_PTR (&text->point); + + is_first = tmp == text->text_properties; + + MARK_LIST_PTR (&text->point) = g_list_remove_link (tmp, tmp); + text->point.offset = 0; + + g_mem_chunk_free (text_property_chunk, prop); + + prop = MARK_CURRENT_PROPERTY (&text->point); + + if (is_first) + text->text_properties = MARK_LIST_PTR (&text->point); + + g_assert (prop->length != 0); + } + else if (prop->length == text->point.offset) + { + MARK_LIST_PTR (&text->point) = MARK_NEXT_LIST_PTR (&text->point); + text->point.offset = 0; + } + } +} + +static void +init_properties (GtkText *text) +{ + if (!text->text_properties) + { + text->text_properties = g_list_alloc(); + text->text_properties->next = NULL; + text->text_properties->prev = NULL; + text->text_properties->data = new_text_property (text->widget.style->font, + &text->widget.style->fg[GTK_STATE_NORMAL], + &text->widget.style->bg[GTK_STATE_NORMAL], + 1); + text->text_properties_end = text->text_properties; + + SET_PROPERTY_MARK (&text->point, text->text_properties, 0); + + text->point.index = 0; + } +} + + +/**********************************************************************/ +/* Property Movement */ +/**********************************************************************/ + +static void +move_mark_n (GtkPropertyMark* mark, gint n) +{ + if (n > 0) + advance_mark_n(mark, n); + else if (n < 0) + decrement_mark_n(mark, -n); +} + +static void +advance_mark_n (GtkPropertyMark* mark, gint n) +{ + gint i; + + g_assert (n > 0); + + for (i = 0; i < n; i += 1) + advance_mark (mark); +} + +static void +advance_mark (GtkPropertyMark* mark) +{ + TextProperty* prop = MARK_CURRENT_PROPERTY (mark); + + mark->index += 1; + + if (prop->length > mark->offset + 1) + mark->offset += 1; + else + { + mark->property = MARK_NEXT_LIST_PTR (mark); + mark->offset = 0; + } +} + +static void +decrement_mark (GtkPropertyMark* mark) +{ + mark->index -= 1; + + if (mark->offset > 0) + mark->offset -= 1; + else + { + mark->property = MARK_PREV_LIST_PTR (mark); + mark->offset = MARK_CURRENT_PROPERTY (mark)->length - 1; + } +} + +static void +decrement_mark_n (GtkPropertyMark* mark, gint n) +{ + gint i; + + g_assert (n > 0); + + for (i = 0; i < n; i += 1) + decrement_mark (mark); +} + +static GtkPropertyMark +find_mark (GtkText* text, guint mark_position) +{ + return find_mark_near (text, mark_position, &text->point); +} + +/* This can be optimized in two ways. + * First, advances can be made in units of the current TextProperty + * length, when possible. This will reduce computation and function + * call overhead. + * + * You can also start from the end, what a drag. + */ +static GtkPropertyMark +find_mark_near (GtkText* text, guint mark_position, const GtkPropertyMark* near) +{ + gint diffa; + gint diffb; + + GtkPropertyMark mark; + + if (!near) + diffa = mark_position + 1; + else + diffa = mark_position - near->index; + + diffb = mark_position; + + if (diffa < 0) + diffa = -diffa; + + if (diffa <= diffb) + { + mark = *near; + } + else + { + mark.index = 0; + mark.property = text->text_properties; + mark.offset = 0; + } + + if (mark.index > mark_position) + { + while (mark.index > mark_position) + decrement_mark (&mark); + } + else + { + while (mark_position > mark.index) + advance_mark (&mark); + } + + return mark; +} + +static void +find_line_containing_point (GtkText* text, guint point) +{ + GList* cache; + gint height; + + text->current_line = NULL; + + if (!text->line_start_cache->next) + { + /* @@@ Its visible, right? */ + text->current_line = text->line_start_cache; + return; + } + + while ( ( (text->first_cut_pixels != 0) && + (CACHE_DATA(text->line_start_cache->next).start.index > point) ) || + ( (text->first_cut_pixels == 0) && + (CACHE_DATA(text->line_start_cache).start.index > point) ) ) + { + scroll_int (text, - SCROLL_PIXELS); + g_assert (text->line_start_cache->next); + } + + TEXT_SHOW (text); + gdk_window_get_size (text->text_area, NULL, &height); + + for (cache = text->line_start_cache; cache; cache = cache->next) + { + guint lph; + + if (CACHE_DATA(cache).end.index >= point || + LAST_INDEX(text, CACHE_DATA(cache).end)) + { + text->current_line = cache; /* LOOK HERE, this proc has an + * important side effect. */ + return; + } + + TEXT_SHOW_LINE (text, cache, "cache"); + + lph = pixel_height_of (text, cache->next); + + while (lph > height || lph == 0) + { + TEXT_SHOW_LINE (text, cache, "cache"); + TEXT_SHOW_LINE (text, cache->next, "cache->next"); + scroll_int (text, LINE_HEIGHT(CACHE_DATA(cache->next))); + lph = pixel_height_of (text, cache->next); + } + } + + g_assert (FALSE); /* Must set text->current_line here */ +} + +static guint +pixel_height_of (GtkText* text, GList* cache_line) +{ + gint pixels = - text->first_cut_pixels; + GList *cache = text->line_start_cache; + + while (TRUE) { + pixels += LINE_HEIGHT (CACHE_DATA(cache)); + + if (cache->data == cache_line->data) + break; + + cache = cache->next; + } + + return pixels; +} + +/**********************************************************************/ +/* Search and Placement */ +/**********************************************************************/ + +static gint +find_char_width (GtkText* text, const GtkPropertyMark *mark, const TabStopMark *tab_mark) +{ + gchar ch = TEXT_INDEX (text, mark->index); + gint16* char_widths = MARK_CURRENT_TEXT_FONT (mark)->char_widths; + + if (ch == '\t') + { + return tab_mark->to_next_tab * char_widths[' ']; + } + else + { + return char_widths[ch & 0xff]; + } +} + +static void +advance_tab_mark (GtkText* text, TabStopMark* tab_mark, gchar ch) +{ + if (tab_mark->to_next_tab == 1 || ch == '\t') + { + if (tab_mark->tab_stops->next) + { + tab_mark->tab_stops = tab_mark->tab_stops->next; + tab_mark->to_next_tab = (gulong) tab_mark->tab_stops->data; + } + else + { + tab_mark->to_next_tab = text->default_tab_width; + } + } + else + { + tab_mark->to_next_tab -= 1; + } +} + +static void +advance_tab_mark_n (GtkText* text, TabStopMark* tab_mark, gint n) + /* No tabs! */ +{ + while (n--) + advance_tab_mark (text, tab_mark, 0); +} + +static void +find_cursor_at_line (GtkText* text, const LineParams* start_line, gint pixel_height) +{ + gchar ch; + + GtkPropertyMark mark = start_line->start; + TabStopMark tab_mark = start_line->tab_cont.tab_start; + gint pixel_width = LINE_START_PIXEL (*start_line); + + while (mark.index < text->cursor_mark.index) + { + pixel_width += find_char_width (text, &mark, &tab_mark); + + advance_tab_mark (text, &tab_mark, TEXT_INDEX(text, mark.index)); + advance_mark (&mark); + } + + text->cursor_pos_x = pixel_width; + text->cursor_pos_y = pixel_height; + text->cursor_char_offset = start_line->font_descent; + text->cursor_mark = mark; + + ch = TEXT_INDEX (text, mark.index); + + if (!isspace(ch)) + text->cursor_char = ch; + else + text->cursor_char = 0; +} + +static void +find_cursor (GtkText* text) +{ + if (!text->has_cursor) + return; + + find_line_containing_point (text, text->cursor_mark.index); + + g_assert (text->cursor_mark.index >= text->first_line_start_index); + + if (text->current_line) + find_cursor_at_line (text, + &CACHE_DATA(text->current_line), + pixel_height_of(text, text->current_line)); +} + +static void +mouse_click_1_at_line (GtkText *text, const LineParams* lp, + guint line_pixel_height, + gint button_x) +{ + GtkPropertyMark mark = lp->start; + TabStopMark tab_mark = lp->tab_cont.tab_start; + + guint char_width = find_char_width(text, &mark, &tab_mark); + guint pixel_width = LINE_START_PIXEL (*lp) + (char_width+1)/2; + + text->cursor_pos_y = line_pixel_height; + + for (;;) + { + gchar ch = TEXT_INDEX (text, mark.index); + + if (button_x < pixel_width || mark.index == lp->end.index) + { + text->cursor_pos_x = pixel_width - (char_width+1)/2; + text->cursor_mark = mark; + text->cursor_char_offset = lp->font_descent; + + if (!isspace(ch)) + text->cursor_char = ch; + else + text->cursor_char = 0; + + break; + } + + advance_tab_mark (text, &tab_mark, ch); + advance_mark (&mark); + + pixel_width += char_width/2; + + char_width = find_char_width (text, &mark, &tab_mark); + + pixel_width += (char_width+1)/2; + } +} + +static void +mouse_click_1 (GtkText* text, GdkEventButton *event) +{ + if (text->is_editable) + { + gint pixel_height; + GList* cache = text->line_start_cache; + + g_assert (cache); + + pixel_height = - text->first_cut_pixels; + + text->has_cursor = 1; + + for (; cache; cache = cache->next) + { + pixel_height += LINE_HEIGHT(CACHE_DATA(cache)); + + if (event->y < pixel_height || !cache->next) + { + mouse_click_1_at_line (text, &CACHE_DATA(cache), pixel_height, event->x); + + find_cursor (text); + + return; + } + } + } +} + +/**********************************************************************/ +/* Cache Manager */ +/**********************************************************************/ + +static void +free_cache (GtkText* text) +{ + GList* cache = text->line_start_cache; + + for (; cache; cache = cache->next) + g_mem_chunk_free (params_mem_chunk, cache->data); + + g_list_free (text->line_start_cache); + + text->line_start_cache = NULL; +} + +static GList* +remove_cache_line (GtkText* text, GList* member) +{ + if (member == text->line_start_cache) + { + if (text->line_start_cache) + text->line_start_cache = text->line_start_cache->next; + return text->line_start_cache; + } + else + { + GList *list = member->prev; + + list->next = list->next->next; + if (list->next) + list->next->prev = list; + + member->next = NULL; + g_mem_chunk_free (params_mem_chunk, member->data); + g_list_free (member); + + return list->next; + } +} + +/**********************************************************************/ +/* Key Motion */ +/**********************************************************************/ + +static void +move_cursor_buffer_ver (GtkText *text, int dir) +{ + if (dir > 0) + scroll_int (text, text->vadj->upper); + else + scroll_int (text, - text->vadj->value); +} + +static void +move_cursor_page_ver (GtkText *text, int dir) +{ + scroll_int (text, dir * text->vadj->page_increment); +} + +static void +move_cursor_ver (GtkText *text, int count) +{ + gint i; + GtkPropertyMark mark; + gint offset; + + if (!text->has_cursor) + { + scroll_int (text, count * KEY_SCROLL_PIXELS); + return; + } + + mark = find_this_line_start_mark (text, text->cursor_mark.index, &text->cursor_mark); + offset = text->cursor_mark.index - mark.index; + + if (offset > text->cursor_virtual_x) + text->cursor_virtual_x = offset; + + if (count < 0) + { + if (mark.index == 0) + return; + + decrement_mark (&mark); + mark = find_this_line_start_mark (text, mark.index, &mark); + } + else + { + mark = text->cursor_mark; + + while (!LAST_INDEX(text, mark) && TEXT_INDEX(text, mark.index) != LINE_DELIM) + advance_mark (&mark); + + if (LAST_INDEX(text, mark)) + return; + + advance_mark (&mark); + } + + for (i=0; i < text->cursor_virtual_x; i += 1, advance_mark(&mark)) + if (LAST_INDEX(text, mark) || TEXT_INDEX(text, mark.index) == LINE_DELIM) + break; + + undraw_cursor (text, FALSE); + + text->cursor_mark = mark; + + find_cursor (text); + + draw_cursor (text, FALSE); +} + +static void +move_cursor_hor (GtkText *text, int count) +{ + /* count should be +-1. */ + if (!text->has_cursor) + return; + + if ( (count > 0 && text->cursor_mark.index + count > TEXT_LENGTH(text)) || + (count < 0 && text->cursor_mark.index < (- count)) || + (count == 0) ) + return; + + text->cursor_virtual_x = 0; + + undraw_cursor (text, FALSE); + + move_mark_n (&text->cursor_mark, count); + + find_cursor (text); + + draw_cursor (text, FALSE); +} + +/**********************************************************************/ +/* Scrolling */ +/**********************************************************************/ + +static void +adjust_adj (GtkText* text, GtkAdjustment* adj) +{ + gint height; + + gdk_window_get_size (text->text_area, NULL, &height); + + adj->step_increment = MIN (adj->upper, (float) SCROLL_PIXELS); + adj->page_increment = MIN (adj->upper, height - (float) KEY_SCROLL_PIXELS); + adj->page_size = MIN (adj->upper, height); + adj->value = MIN (adj->value, adj->upper - adj->page_size); + adj->value = MAX (adj->value, 0.0); + + gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed"); +} + +static gint +set_vertical_scroll_iterator (GtkText* text, LineParams* lp, void* data) +{ + gint *pixel_count = (gint*) data; + + if (text->first_line_start_index == lp->start.index) + text->vadj->value = (float) *pixel_count; + + *pixel_count += LINE_HEIGHT (*lp); + + return FALSE; +} + +static gint +set_vertical_scroll_find_iterator (GtkText* text, LineParams* lp, void* data) +{ + SetVerticalScrollData *svdata = (SetVerticalScrollData *) data; + gint return_val; + + if (svdata->last_didnt_wrap) + svdata->last_line_start = lp->start.index; + + if (svdata->pixel_height <= (gint) text->vadj->value && + svdata->pixel_height + LINE_HEIGHT(*lp) > (gint) text->vadj->value) + { + svdata->mark = lp->start; + + text->first_cut_pixels = (gint)text->vadj->value - svdata->pixel_height; + text->first_onscreen_ver_pixel = svdata->pixel_height; + text->first_line_start_index = svdata->last_line_start; + + return_val = TRUE; + } + else + { + svdata->pixel_height += LINE_HEIGHT (*lp); + + return_val = FALSE; + } + + if (!lp->wraps) + svdata->last_didnt_wrap = TRUE; + else + svdata->last_didnt_wrap = FALSE; + + return return_val; +} + +static GtkPropertyMark +set_vertical_scroll (GtkText* text) +{ + GtkPropertyMark mark = find_mark (text, 0); + SetVerticalScrollData data; + gint height; + gint pixel_count = 0; + gint orig_value; + + line_params_iterate (text, &mark, NULL, FALSE, &pixel_count, set_vertical_scroll_iterator); + + text->vadj->upper = (float) pixel_count; + orig_value = (gint) text->vadj->value; + + gdk_window_get_size (text->text_area, NULL, &height); + + text->vadj->step_increment = MIN (text->vadj->upper, (float) SCROLL_PIXELS); + text->vadj->page_increment = MIN (text->vadj->upper, height - (float) KEY_SCROLL_PIXELS); + text->vadj->page_size = MIN (text->vadj->upper, height); + text->vadj->value = MIN (text->vadj->value, text->vadj->upper - text->vadj->page_size); + text->vadj->value = MAX (text->vadj->value, 0.0); + + text->last_ver_value = (gint)text->vadj->value; + text->first_cut_pixels = 0; + + gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "changed"); + + if (text->vadj->value != orig_value) + { + /* We got clipped, and don't really know which line to put first. */ + data.pixel_height = 0; + data.last_didnt_wrap = TRUE; + + line_params_iterate (text, &mark, NULL, + FALSE, &data, + set_vertical_scroll_find_iterator); + + return data.mark; + } + else + { + return find_mark (text, text->first_line_start_index); + } +} + +static void +scroll_int (GtkText* text, gint diff) +{ + gfloat upper; + + text->vadj->value += diff; + + upper = text->vadj->upper - text->vadj->page_size; + text->vadj->value = MIN (text->vadj->value, upper); + text->vadj->value = MAX (text->vadj->value, 0.0); + + gtk_signal_emit_by_name (GTK_OBJECT (text->vadj), "value_changed"); +} + +static gint last_visible_line_height (GtkText* text) +{ + GList *cache = text->line_start_cache; + gint height; + + gdk_window_get_size (text->text_area, NULL, &height); + + for (; cache->next; cache = cache->next) + if (pixel_height_of(text, cache->next) > height) + break; + + if (cache) + return pixel_height_of(text, cache) - 1; + else + return 0; +} + +static gint first_visible_line_height (GtkText* text) +{ + if (text->first_cut_pixels) + return pixel_height_of(text, text->line_start_cache) + 1; + else + return 1; +} + +static void +scroll_down (GtkText* text, gint diff0) +{ + GdkRectangle rect; + gint real_diff = 0; + gint width, height; + + text->first_onscreen_ver_pixel += diff0; + + while (diff0-- > 0) + { + g_assert (text->line_start_cache && + text->line_start_cache->next); + + if (text->first_cut_pixels < LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1) + { + text->first_cut_pixels += 1; + } + else + { + text->first_cut_pixels = 0; + + text->line_start_cache = text->line_start_cache->next; + + text->first_line_start_index = + CACHE_DATA(text->line_start_cache).start.index; + + if (!text->line_start_cache->next) + fetch_lines_forward (text, 1); + } + + real_diff += 1; + } + + gdk_window_get_size (text->text_area, &width, &height); + if (height > real_diff) + gdk_draw_pixmap (text->text_area, + text->gc, + text->text_area, + 0, + real_diff, + 0, + 0, + width, + height - real_diff); + + rect.x = 0; + rect.y = MAX (0, height - real_diff); + rect.width = width; + rect.height = MIN (height, real_diff); + + expose_text (text, &rect, FALSE); + gtk_text_draw_focus ( (GtkWidget *) text); + + if (text->current_line) + { + gint cursor_min; + + text->cursor_pos_y -= real_diff; + cursor_min = drawn_cursor_min(text); + + if (cursor_min < 0) + { + GdkEventButton button; + + button.x = text->cursor_pos_x; + button.y = first_visible_line_height (text); + + mouse_click_1 (text, &button); + } + } +} + +static void +scroll_up (GtkText* text, gint diff0) +{ + gint real_diff = 0; + GdkRectangle rect; + gint width, height; + + text->first_onscreen_ver_pixel += diff0; + + while (diff0++ < 0) + { + g_assert (text->line_start_cache); + + if (text->first_cut_pixels > 0) + { + text->first_cut_pixels -= 1; + } + else + { + if (!text->line_start_cache->prev) + fetch_lines_backward (text); + + text->line_start_cache = text->line_start_cache->prev; + + text->first_line_start_index = + CACHE_DATA(text->line_start_cache).start.index; + + text->first_cut_pixels = LINE_HEIGHT(CACHE_DATA(text->line_start_cache)) - 1; + } + + real_diff += 1; + } + + gdk_window_get_size (text->text_area, &width, &height); + if (height > real_diff) + gdk_draw_pixmap (text->text_area, + text->gc, + text->text_area, + 0, + 0, + 0, + real_diff, + width, + height - real_diff); + + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = MIN (height, real_diff); + + expose_text (text, &rect, FALSE); + gtk_text_draw_focus ( (GtkWidget *) text); + + if (text->current_line) + { + gint cursor_max; + gint height; + + text->cursor_pos_y += real_diff; + cursor_max = drawn_cursor_max(text); + gdk_window_get_size (text->text_area, NULL, &height); + + if (cursor_max >= height) + { + GdkEventButton button; + + button.x = text->cursor_pos_x; + button.y = last_visible_line_height(text); + + mouse_click_1 (text, &button); + } + } +} + +/**********************************************************************/ +/* Display Code */ +/**********************************************************************/ + +/* Assumes mark starts a line. Calculates the height, width, and + * displayable character count of a single DISPLAYABLE line. That + * means that in line-wrap mode, this does may not compute the + * properties of an entire line. */ +static LineParams +find_line_params (GtkText* text, + const GtkPropertyMark* mark, + const PrevTabCont *tab_cont, + PrevTabCont *next_cont) +{ + LineParams lp; + TabStopMark tab_mark = tab_cont->tab_start; + guint max_display_pixels; + gchar ch; + gint ch_width; + GdkFont *font; + + gdk_window_get_size (text->text_area, (gint*) &max_display_pixels, NULL); + max_display_pixels -= LINE_WRAP_ROOM; + + lp.wraps = 0; + lp.tab_cont = *tab_cont; + lp.start = *mark; + lp.end = *mark; + lp.pixel_width = tab_cont->pixel_offset; + lp.displayable_chars = 0; + lp.font_ascent = 0; + lp.font_descent = 0; + + init_tab_cont (text, next_cont); + + while (!LAST_INDEX(text, lp.end)) + { + g_assert (lp.end.property); + + ch = TEXT_INDEX (text, lp.end.index); + font = MARK_CURRENT_FONT (&lp.end); + + if (ch == LINE_DELIM) + { + /* Newline doesn't count in computation of line height, even + * if its in a bigger font than the rest of the line. Unless, + * of course, there are no other characters. */ + + if (!lp.font_ascent && !lp.font_descent) + { + lp.font_ascent = font->ascent; + lp.font_descent = font->descent; + } + + lp.tab_cont_next = *next_cont; + + return lp; + } + + ch_width = find_char_width (text, &lp.end, &tab_mark); + + if (ch_width + lp.pixel_width > max_display_pixels) + { + lp.wraps = 1; + + if (text->line_wrap) + { + next_cont->tab_start = tab_mark; + next_cont->pixel_offset = 0; + + if (ch == '\t') + { + /* Here's the tough case, a tab is wrapping. */ + gint pixels_avail = max_display_pixels - lp.pixel_width; + gint space_width = MARK_CURRENT_TEXT_FONT(&lp.end)->char_widths[' ']; + gint spaces_avail = pixels_avail / space_width; + + if (spaces_avail == 0) + { + decrement_mark (&lp.end); + } + else + { + advance_tab_mark (text, &next_cont->tab_start, '\t'); + next_cont->pixel_offset = space_width * (tab_mark.to_next_tab - + spaces_avail); + lp.displayable_chars += 1; + } + } + else + { + /* Don't include this character, it will wrap. */ + decrement_mark (&lp.end); + } + + lp.tab_cont_next = *next_cont; + + return lp; + } + } + else + { + lp.displayable_chars += 1; + } + + lp.font_ascent = MAX (font->ascent, lp.font_ascent); + lp.font_descent = MAX (font->descent, lp.font_descent); + lp.pixel_width += ch_width; + + advance_mark(&lp.end); + advance_tab_mark (text, &tab_mark, ch); + } + + if (LAST_INDEX(text, lp.start)) + { + /* Special case, empty last line. */ + font = MARK_CURRENT_FONT (&lp.end); + + lp.font_ascent = font->ascent; + lp.font_descent = font->descent; + } + + lp.tab_cont_next = *next_cont; + + return lp; +} + +static void +expand_scratch_buffer (GtkText* text, guint len) +{ + if (len >= text->scratch_buffer_len) + { + guint i = 1; + + while (i <= len && i < MIN_GAP_SIZE) i <<= 1; + + if (text->scratch_buffer) + text->scratch_buffer = g_new (guchar, i); + else + text->scratch_buffer = g_realloc (text->scratch_buffer, i); + + text->scratch_buffer_len = i; + } +} + +static void +draw_line (GtkText* text, + gint pixel_start_height, + LineParams* lp) +{ + GdkGCValues gc_values; + gint i; + gint len = 0; + guint running_offset = lp->tab_cont.pixel_offset; + guchar* buffer; + + GtkPropertyMark mark = lp->start; + TabStopMark tab_mark = lp->tab_cont.tab_start; + gint pixel_height = pixel_start_height + lp->font_ascent; + guint chars = lp->displayable_chars; + + /* First provide a contiguous segment of memory. This makes reading + * the code below *much* easier, and only incurs the cost of copying + * when the line being displayed spans the gap. */ + if (mark.index <= text->gap_position && + mark.index + chars > text->gap_position) + { + expand_scratch_buffer (text, chars); + + for (i = 0; i < chars; i += 1) + text->scratch_buffer[i] = TEXT_INDEX(text, mark.index + i); + + buffer = text->scratch_buffer; + } + else + { + if (mark.index >= text->gap_position) + buffer = text->text + mark.index + text->gap_size; + else + buffer = text->text + mark.index; + } + + if (running_offset > 0 && MARK_CURRENT_BACK (&mark)) + { + gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&mark)); + + gdk_draw_rectangle (text->text_area, + text->gc, + TRUE, + 0, + pixel_start_height, + running_offset, + LINE_HEIGHT (*lp)); + } + + for (; chars > 0; chars -= len, buffer += len, len = 0) + { + if (buffer[0] != '\t') + { + guchar* next_tab = memchr (buffer, '\t', chars); + gint pixel_width; + GdkFont *font; + + len = MIN (MARK_CURRENT_PROPERTY (&mark)->length - mark.offset, chars); + + if (next_tab) + len = MIN (len, next_tab - buffer); + + font = MARK_CURRENT_PROPERTY (&mark)->font->gdk_font; + if (font->type == GDK_FONT_FONT) + { + gdk_gc_set_font (text->gc, font); + gdk_gc_get_values (text->gc, &gc_values); + pixel_width = gdk_text_width (gc_values.font, + (gchar*) buffer, len); + } + else + pixel_width = gdk_text_width (font, (gchar*) buffer, len); + + if (MARK_CURRENT_BACK (&mark)) + { + gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&mark)); + + gdk_draw_rectangle (text->text_area, + text->gc, + TRUE, + running_offset, + pixel_start_height, + pixel_width, + LINE_HEIGHT(*lp)); + } + + gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (&mark)); + + gdk_draw_text (text->text_area, MARK_CURRENT_FONT (&mark), + text->gc, + running_offset, + pixel_height, + (gchar*) buffer, + len); + + running_offset += pixel_width; + + advance_tab_mark_n (text, &tab_mark, len); + } + else + { + len = 1; + + if (MARK_CURRENT_BACK (&mark)) + { + gint pixels_remaining; + gint space_width; + gint spaces_avail; + + gdk_window_get_size (text->text_area, &pixels_remaining, NULL); + pixels_remaining -= (LINE_WRAP_ROOM + running_offset); + + space_width = MARK_CURRENT_TEXT_FONT(&mark)->char_widths[' ']; + + spaces_avail = pixels_remaining / space_width; + spaces_avail = MIN (spaces_avail, tab_mark.to_next_tab); + + gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&mark)); + + gdk_draw_rectangle (text->text_area, + text->gc, + TRUE, + running_offset, + pixel_start_height, + spaces_avail * space_width, + LINE_HEIGHT (*lp)); + } + + running_offset += tab_mark.to_next_tab * + MARK_CURRENT_TEXT_FONT(&mark)->char_widths[' ']; + + advance_tab_mark (text, &tab_mark, '\t'); + } + + advance_mark_n (&mark, len); + } +} + +static void +draw_line_wrap (GtkText* text, guint height /* baseline height */) +{ + gint width; + GdkPixmap *bitmap; + gint bitmap_width; + gint bitmap_height; + + if (text->line_wrap) + { + bitmap = text->line_wrap_bitmap; + bitmap_width = line_wrap_width; + bitmap_height = line_wrap_height; + } + else + { + bitmap = text->line_arrow_bitmap; + bitmap_width = line_arrow_width; + bitmap_height = line_arrow_height; + } + + gdk_window_get_size (text->text_area, &width, NULL); + width -= LINE_WRAP_ROOM; + + gdk_gc_set_stipple (text->gc, + bitmap); + + gdk_gc_set_fill (text->gc, GDK_STIPPLED); + + gdk_gc_set_foreground (text->gc, &text->widget.style->fg[GTK_STATE_NORMAL]); + + gdk_gc_set_ts_origin (text->gc, + width + 1, + height - bitmap_height - 1); + + gdk_draw_rectangle (text->text_area, + text->gc, + TRUE, + width + 1, + height - bitmap_height - 1 /* one pixel above the baseline. */, + bitmap_width, + bitmap_height); + + gdk_gc_set_ts_origin (text->gc, 0, 0); + + gdk_gc_set_fill (text->gc, GDK_SOLID); +} + +static void +undraw_cursor (GtkText* text, gint absolute) +{ + TDEBUG (("in undraw_cursor\n")); + + if (absolute) + text->cursor_drawn_level = 0; + + if (text->has_cursor && (text->cursor_drawn_level ++ == 0)) + { + GdkFont* font; + + g_assert(text->cursor_mark.property); + + font = MARK_CURRENT_FONT(&text->cursor_mark); + + if (text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + { + GdkRectangle rect; + + rect.x = text->cursor_pos_x; + rect.y = text->cursor_pos_y - text->cursor_char_offset - font->ascent; + rect.width = 1; + rect.height = font->ascent + 1; /* @@@ I add one here because draw_line is inclusive, right? */ + + clear_area (text, &rect); + } + else + { + if (MARK_CURRENT_BACK (&text->cursor_mark)) + gdk_gc_set_foreground (text->gc, MARK_CURRENT_BACK (&text->cursor_mark)); + else + gdk_gc_set_foreground (text->gc, &text->widget.style->bg[GTK_STATE_NORMAL]); + + gdk_draw_line (text->text_area, text->gc, text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset, text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset - font->ascent); + } + + if (text->cursor_char) + { + if (font->type == GDK_FONT_FONT) + gdk_gc_set_font (text->gc, font); + + gdk_gc_set_foreground (text->gc, MARK_CURRENT_FORE (&text->cursor_mark)); + + gdk_draw_text (text->text_area, font, + text->gc, + text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset, + &text->cursor_char, + 1); + } + } +} + +static gint +drawn_cursor_min (GtkText* text) +{ + if (text->has_cursor) + { + GdkFont* font; + + g_assert(text->cursor_mark.property); + + font = MARK_CURRENT_FONT(&text->cursor_mark); + + return text->cursor_pos_y - text->cursor_char_offset - font->ascent; + } + else + return 0; +} + +static gint +drawn_cursor_max (GtkText* text) +{ + if (text->has_cursor) + { + GdkFont* font; + + g_assert(text->cursor_mark.property); + + font = MARK_CURRENT_FONT(&text->cursor_mark); + + return text->cursor_pos_y - text->cursor_char_offset; + } + else + return 0; +} + +static void +draw_cursor (GtkText* text, gint absolute) +{ + TDEBUG (("in draw_cursor\n")); + + if (absolute) + text->cursor_drawn_level = 1; + + if (text->has_cursor && (--text->cursor_drawn_level == 0)) + { + GdkFont* font; + + g_assert (text->cursor_mark.property); + + font = MARK_CURRENT_FONT (&text->cursor_mark); + + gdk_gc_set_foreground (text->gc, &text->widget.style->fg[GTK_STATE_NORMAL]); + + gdk_draw_line (text->text_area, text->gc, text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset, + text->cursor_pos_x, + text->cursor_pos_y - text->cursor_char_offset - font->ascent); + } +} + +static void +clear_area (GtkText *text, GdkRectangle *area) +{ + if (text->widget.style->bg_pixmap[GTK_STATE_NORMAL]) + { + gint width, height; + gint x = area->x, y = area->y; + gint xorig, yorig; + + gdk_window_get_size (text->widget.style->bg_pixmap[GTK_STATE_NORMAL], &width, &height); + + yorig = - text->first_onscreen_ver_pixel; + xorig = - text->first_onscreen_hor_pixel; + + for (y = area->y; y < area->y + area->height; ) + { + gint yoff = (y - yorig) % height; + gint yw = MIN(height - yoff, (area->y + area->height) - y); + + for (x = area->x; x < area->x + area->width; ) + { + gint xoff = (x - xorig) % width; + gint xw = MIN(width - xoff, (area->x + area->width) - x); + + gdk_draw_pixmap (text->text_area, + text->gc, + text->widget.style->bg_pixmap[GTK_STATE_NORMAL], + xoff, + yoff, + x, + y, + xw, + yw); + + x += width - xoff; + } + y += height - yoff; + } + } + else + gdk_window_clear_area (text->text_area, area->x, area->y, area->width, area->height); +} + +static void +expose_text (GtkText* text, GdkRectangle *area, gboolean cursor) +{ + GList *cache = text->line_start_cache; + gint pixels = - text->first_cut_pixels; + gint min_y = area->y; + gint max_y = area->y + area->height; + gint height; + + gdk_window_get_size (text->text_area, NULL, &height); + max_y = MIN (max_y, height); + + TDEBUG (("in expose x=%d y=%d w=%d h=%d\n", area->x, area->y, area->width, area->height)); + + clear_area (text, area); + + for (; pixels < height; cache = cache->next) + { + if (pixels < max_y && (pixels + LINE_HEIGHT(CACHE_DATA(cache))) >= min_y) + { + draw_line (text, pixels, &CACHE_DATA(cache)); + + if (CACHE_DATA(cache).wraps) + draw_line_wrap (text, pixels + CACHE_DATA(cache).font_ascent); + } + + if (cursor && text->has_cursor && GTK_WIDGET_HAS_FOCUS (&text->widget)) + { + if (CACHE_DATA(cache).start.index <= text->cursor_mark.index && + CACHE_DATA(cache).end.index >= text->cursor_mark.index) + draw_cursor (text, TRUE); + } + + pixels += LINE_HEIGHT(CACHE_DATA(cache)); + + if (!cache->next) + { + fetch_lines_forward (text, 1); + + if (!cache->next) + break; + } + } +} + +static void +recompute_geometry (GtkText* text) +{ + GtkPropertyMark start_mark; + gint height; + gint width; + + free_cache (text); + + start_mark = set_vertical_scroll (text); + + gdk_window_get_size (text->text_area, &width, &height); + + text->line_start_cache = fetch_lines (text, + &start_mark, + NULL, + FetchLinesPixels, + height + text->first_cut_pixels); + + find_cursor (text); +} + +/**********************************************************************/ +/* Selection */ +/**********************************************************************/ + +static gint +gtk_text_selection_clear (GtkWidget *widget, + GdkEventSelection *event) +{ +#if 0 + GtkEntry *entry; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + if (entry->have_selection) + { + entry->have_selection = FALSE; + gtk_entry_queue_draw (entry); + } +#endif + return FALSE; +} + +static gint +gtk_text_selection_request (GtkWidget *widget, + GdkEventSelection *event) +{ +#if 0 + + GtkEntry *entry; + gint selection_start_pos; + gint selection_end_pos; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + if (entry->selection_start_pos != entry->selection_end_pos) + { + selection_start_pos = MIN (entry->selection_start_pos, entry->selection_end_pos); + selection_end_pos = MAX (entry->selection_start_pos, entry->selection_end_pos); + + gdk_selection_set (event->requestor, event->selection, + event->property, event->time, + (guchar*) &entry->text[selection_start_pos], + selection_end_pos - selection_start_pos); + } +#endif + return FALSE; +} + +static gint +gtk_text_selection_notify (GtkWidget *widget, + GdkEventSelection *event) +{ +#if 0 + GtkEntry *entry; + gchar *data; + gint tmp_pos; + gint reselect; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + entry = GTK_ENTRY (widget); + + gdk_selection_get (widget->window, (guchar**) &data); + + reselect = FALSE; + if (entry->selection_start_pos != entry->selection_end_pos) + { + reselect = TRUE; + gtk_delete_selection (entry); + } + + tmp_pos = entry->current_pos; + gtk_entry_insert_text (entry, data, strlen (data), &tmp_pos); + + if (reselect) + { + reselect = entry->have_selection; + gtk_select_region (entry, entry->current_pos, tmp_pos); + entry->have_selection = reselect; + } + + entry->current_pos = tmp_pos; + + gtk_entry_queue_draw (entry); +#endif + return FALSE; +} + +/**********************************************************************/ +/* Debug */ +/**********************************************************************/ + +#ifdef DEBUG_GTK_TEXT +static void +gtk_text_show_cache_line (GtkText *text, GList *cache, + const char* what, const char* func, gint line) +{ + LineParams *lp = &CACHE_DATA(cache); + gint i; + + g_print ("%s:%d: cache line %s s=%d,e=%d,lh=%d (", + func, + line, + what, + lp->start.index, + lp->end.index, + LINE_HEIGHT(*lp)); + + for (i = lp->start.index; i < (lp->end.index + lp->wraps); i += 1) + g_print ("%c", TEXT_INDEX (text, i)); + + g_print (")\n"); +} + +static void +gtk_text_show_cache (GtkText *text, const char* func, gint line) +{ + GList *l = text->line_start_cache; + + g_print ("*** line cache ***\n"); + for (; l; l = l->next) + gtk_text_show_cache_line (text, l, "all", func, line); +} + +static void +gtk_text_assert_mark (GtkText *text, + GtkPropertyMark *mark, + GtkPropertyMark *before, + GtkPropertyMark *after, + const gchar *msg, + const gchar *where, + gint line) +{ + GtkPropertyMark correct_mark = find_mark (text, mark->index); + + if (mark->offset != correct_mark.offset || + mark->property != correct_mark.property) + g_warning ("incorrect %s text property marker in %s:%d, index %d -- bad!", where, msg, line, mark->index); +} + +static void +gtk_text_assert (GtkText *text, + const gchar *msg, + gint line) +{ + GList* cache = text->line_start_cache; + GtkPropertyMark* before_mark = NULL; + GtkPropertyMark* after_mark = NULL; + + gtk_text_show_props (text, msg, line); + + for (; cache->prev; cache = cache->prev) + /* nothing */; + + g_print ("*** line markers ***\n"); + + for (; cache; cache = cache->next) + { + after_mark = &CACHE_DATA(cache).end; + gtk_text_assert_mark (text, &CACHE_DATA(cache).start, before_mark, after_mark, msg, "start", line); + before_mark = &CACHE_DATA(cache).start; + + if (cache->next) + after_mark = &CACHE_DATA(cache->next).start; + else + after_mark = NULL; + + gtk_text_assert_mark (text, &CACHE_DATA(cache).end, before_mark, after_mark, msg, "end", line); + before_mark = &CACHE_DATA(cache).end; + } +} + +static void +gtk_text_show_adj (GtkText *text, + GtkAdjustment *adj, + const char* what, + const char* func, + gint line) +{ + g_print ("*** adjustment ***\n"); + + g_print ("%s:%d: %s adjustment l=%.1f u=%.1f v=%.1f si=%.1f pi=%.1f ps=%.1f\n", + func, + line, + what, + adj->lower, + adj->upper, + adj->value, + adj->step_increment, + adj->page_increment, + adj->page_size); +} + +static void +gtk_text_show_props (GtkText *text, + const char* msg, + int line) +{ + GList* props = text->text_properties; + int proplen = 0; + + g_print ("%s:%d: ", msg, line); + + for (; props; props = props->next) + { + TextProperty *p = (TextProperty*)props->data; + + proplen += p->length; + + g_print ("[%d,%p,%p,%p,%p] ", p->length, p, p->font, p->fore_color, p->back_color); + } + + g_print ("\n"); + + if (proplen - 1 != TEXT_LENGTH(text)) + g_warning ("incorrect property list length in %s:%d -- bad!", msg, line); +} +#endif diff --git a/gtk/gtktext.h b/gtk/gtktext.h new file mode 100644 index 000000000..012d679a3 --- /dev/null +++ b/gtk/gtktext.h @@ -0,0 +1,204 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_TEXT_H__ +#define __GTK_TEXT_H__ + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TEXT(obj) GTK_CHECK_CAST (obj, gtk_text_get_type (), GtkText) +#define GTK_TEXT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_text_get_type (), GtkTextClass) +#define GTK_IS_TEXT(obj) GTK_CHECK_TYPE (obj, gtk_text_get_type ()) + + +typedef struct _GtkPropertyMark GtkPropertyMark; +typedef struct _GtkText GtkText; +typedef struct _GtkTextClass GtkTextClass; + +typedef void (*GtkTextFunction) (GtkText *text); + +struct _GtkPropertyMark +{ + /* Position in list. */ + GList* property; + + /* Offset into that property. */ + guint offset; + + /* Current index. */ + guint index; +}; + +struct _GtkText +{ + GtkWidget widget; + + GdkWindow *text_area; + + GtkAdjustment *hadj; + GtkAdjustment *vadj; + + GdkGC *gc; + + GdkPixmap* line_wrap_bitmap; + GdkPixmap* line_arrow_bitmap; + + /* GAPPED TEXT SEGMENT */ + + /* The text, a single segment of text a'la emacs, with a gap + * where insertion occurs. */ + guchar* text; + /* The allocated length of the text segment. */ + guint text_len; + /* The gap position, index into address where a char + * should be inserted. */ + guint gap_position; + /* The gap size, s.t. *(text + gap_position + gap_size) is + * the first valid character following the gap. */ + guint gap_size; + /* The last character position, index into address where a + * character should be appeneded. Thus, text_end - gap_size + * is the length of the actual data. */ + guint text_end; + /* LINE START CACHE */ + + /* A cache of line-start information. Data is a LineParam*. */ + GList *line_start_cache; + /* Index to the start of the first visible line. */ + guint first_line_start_index; + /* The number of pixels cut off of the top line. */ + guint first_cut_pixels; + /* First visible horizontal pixel. */ + guint first_onscreen_hor_pixel; + /* First visible vertical pixel. */ + guint first_onscreen_ver_pixel; + + /* FLAGS */ + + /* True iff the cursor has been placed yet. */ + guint has_cursor : 1; + /* True iff this buffer is editable. (Allowing a cursor to be placed). */ + guint is_editable : 1; + /* True iff this buffer is wrapping lines, otherwise it is using a + * horizontal scrollbar. */ + guint line_wrap : 1; + /* Frozen, don't do updates. @@@ fixme */ + guint freeze : 1; + /* Whether a selection. */ + guint has_selection : 1; + /* Whether the selection is in the clipboard. */ + guint own_selection : 1; + /* Whether it has been realized yet. */ + + /* TEXT PROPERTIES */ + + /* A doubly-linked-list containing TextProperty objects. */ + GList *text_properties; + /* The end of this list. */ + GList *text_properties_end; + /* The first node before or on the point along with its offset to + * the point and the buffer's current point. This is the only + * PropertyMark whose index is guaranteed to remain correct + * following a buffer insertion or deletion. */ + GtkPropertyMark point; + + /* SCRATCH AREA */ + + guchar* scratch_buffer; + guint scratch_buffer_len; + + /* SCROLLING */ + + gint last_ver_value; + + /* CURSOR */ + + gint cursor_pos_x; /* Position of cursor. */ + gint cursor_pos_y; /* Baseline of line cursor is drawn on. */ + GtkPropertyMark cursor_mark; /* Where it is in the buffer. */ + gchar cursor_char; /* Character to redraw. */ + gchar cursor_char_offset; /* Distance from baseline of the font. */ + gint cursor_virtual_x; /* Where it would be if it could be. */ + gint cursor_drawn_level; /* How many people have undrawn. */ + + /* Current Line */ + + GList *current_line; + + /* Tab Stops */ + + GList *tab_stops; + gint default_tab_width; + + /* Key bindings */ + + GtkTextFunction control_keys[26]; + GtkTextFunction alt_keys[26]; + + /* Selection nonsense. */ + + guint selection_start; + guint selection_stop; +}; + +struct _GtkTextClass +{ + GtkWidgetClass parent_class; +}; + + +guint gtk_text_get_type (void); +GtkWidget* gtk_text_new (GtkAdjustment *hadj, + GtkAdjustment *vadj); +void gtk_text_set_editable (GtkText *text, + gint editable); +void gtk_text_set_adjustments (GtkText *text, + GtkAdjustment *hadj, + GtkAdjustment *vadj); +void gtk_text_set_point (GtkText *text, + guint index); +guint gtk_text_get_point (GtkText *text); +guint gtk_text_get_length (GtkText *text); +void gtk_text_freeze (GtkText *text); +void gtk_text_thaw (GtkText *text); +void gtk_text_insert (GtkText *text, + GdkFont *font, + GdkColor *fore, + GdkColor *back, + const char *chars, + gint length); +gint gtk_text_backward_delete (GtkText *text, + guint nchars); +gint gtk_text_foreward_delete (GtkText *text, + guint nchars); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TEXT_H__ */ diff --git a/gtk/gtktogglebutton.c b/gtk/gtktogglebutton.c new file mode 100644 index 000000000..eabcb1b26 --- /dev/null +++ b/gtk/gtktogglebutton.c @@ -0,0 +1,372 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtksignal.h" +#include "gtktogglebutton.h" + + +#define DEFAULT_LEFT_POS 4 +#define DEFAULT_TOP_POS 4 +#define DEFAULT_SPACING 7 + +enum { + TOGGLED, + LAST_SIGNAL +}; + + +static void gtk_toggle_button_class_init (GtkToggleButtonClass *klass); +static void gtk_toggle_button_init (GtkToggleButton *toggle_button); +static void gtk_toggle_button_draw_focus (GtkWidget *widget); +static void gtk_toggle_button_pressed (GtkButton *button); +static void gtk_toggle_button_released (GtkButton *button); +static void gtk_toggle_button_clicked (GtkButton *button); +static void gtk_toggle_button_enter (GtkButton *button); +static void gtk_toggle_button_leave (GtkButton *button); + + +static gint toggle_button_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_toggle_button_get_type () +{ + static guint toggle_button_type = 0; + + if (!toggle_button_type) + { + GtkTypeInfo toggle_button_info = + { + "GtkToggleButton", + sizeof (GtkToggleButton), + sizeof (GtkToggleButtonClass), + (GtkClassInitFunc) gtk_toggle_button_class_init, + (GtkObjectInitFunc) gtk_toggle_button_init, + (GtkArgFunc) NULL, + }; + + toggle_button_type = gtk_type_unique (gtk_button_get_type (), &toggle_button_info); + } + + return toggle_button_type; +} + +static void +gtk_toggle_button_class_init (GtkToggleButtonClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + GtkButtonClass *button_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + button_class = (GtkButtonClass*) class; + + toggle_button_signals[TOGGLED] = + gtk_signal_new ("toggled", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkToggleButtonClass, toggled), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, toggle_button_signals, LAST_SIGNAL); + + widget_class->draw_focus = gtk_toggle_button_draw_focus; + widget_class->draw_default = NULL; + + button_class->pressed = gtk_toggle_button_pressed; + button_class->released = gtk_toggle_button_released; + button_class->clicked = gtk_toggle_button_clicked; + button_class->enter = gtk_toggle_button_enter; + button_class->leave = gtk_toggle_button_leave; + + class->toggled = NULL; +} + +static void +gtk_toggle_button_init (GtkToggleButton *toggle_button) +{ + toggle_button->active = FALSE; + toggle_button->draw_indicator = FALSE; +} + + +GtkWidget* +gtk_toggle_button_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_toggle_button_get_type ())); +} + +GtkWidget* +gtk_toggle_button_new_with_label (const gchar *label) +{ + GtkWidget *toggle_button; + GtkWidget *label_widget; + + toggle_button = gtk_toggle_button_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5); + + gtk_container_add (GTK_CONTAINER (toggle_button), label_widget); + gtk_widget_show (label_widget); + + return toggle_button; +} + +void +gtk_toggle_button_set_mode (GtkToggleButton *toggle_button, + gint draw_indicator) +{ + g_return_if_fail (toggle_button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); + + draw_indicator = draw_indicator ? TRUE : FALSE; + + if (toggle_button->draw_indicator != draw_indicator) + { + toggle_button->draw_indicator = draw_indicator; + + if (GTK_WIDGET_VISIBLE (toggle_button)) + gtk_widget_queue_resize (GTK_WIDGET (toggle_button)); + } +} + +void +gtk_toggle_button_set_state (GtkToggleButton *toggle_button, + gint state) +{ + g_return_if_fail (toggle_button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); + + if (toggle_button->active != state) + gtk_button_clicked (GTK_BUTTON (toggle_button)); +} + +void +gtk_toggle_button_toggled (GtkToggleButton *toggle_button) +{ + gtk_signal_emit (GTK_OBJECT (toggle_button), toggle_button_signals[TOGGLED]); +} + + +static void +gtk_toggle_button_draw_focus (GtkWidget *widget) +{ + GtkButton *button; + GtkToggleButton *toggle_button; + GtkShadowType shadow_type; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + button = GTK_BUTTON (widget); + toggle_button = GTK_TOGGLE_BUTTON (widget); + + x = 0; + y = 0; + width = widget->allocation.width; + height = widget->allocation.height; + + if (GTK_WIDGET_CAN_DEFAULT (widget)) + { + x += widget->style->klass->xthickness; + y += widget->style->klass->ythickness; + width -= 2 * x + DEFAULT_SPACING; + height -= 2 * y + DEFAULT_SPACING; + x += DEFAULT_LEFT_POS; + y += DEFAULT_TOP_POS; + } + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x += 1; + y += 1; + width -= 2; + height -= 2; + } + else + { + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE, + x + 1, y + 1, width - 4, height - 4); + else + gdk_draw_rectangle (widget->window, + widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE, + x + 2, y + 2, width - 5, height - 5); + } + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) + shadow_type = GTK_SHADOW_IN; + else if ((GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) && toggle_button->active) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_shadow (widget->style, widget->window, + GTK_WIDGET_STATE (widget), shadow_type, + x, y, width, height); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + x -= 1; + y -= 1; + width += 2; + height += 2; + + gdk_draw_rectangle (widget->window, + widget->style->black_gc, FALSE, + x, y, width - 1, height - 1); + } + } +} + +static void +gtk_toggle_button_pressed (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + toggle_button = GTK_TOGGLE_BUTTON (button); + + button->button_down = TRUE; + + if (toggle_button->active) + new_state = (button->in_button ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE); + else + new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} + +static void +gtk_toggle_button_released (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + if (button->button_down) + { + toggle_button = GTK_TOGGLE_BUTTON (button); + + button->button_down = FALSE; + + if (button->in_button) + { + gtk_button_clicked (button); + } + else + { + if (toggle_button->active) + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + else + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } + } + } +} + +static void +gtk_toggle_button_clicked (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + toggle_button = GTK_TOGGLE_BUTTON (button); + toggle_button->active = !toggle_button->active; + + gtk_toggle_button_toggled (toggle_button); + + if (toggle_button->active) + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + else + new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); +} + +static void +gtk_toggle_button_enter (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + toggle_button = GTK_TOGGLE_BUTTON (button); + + if (toggle_button->active) + new_state = (button->button_down ? GTK_STATE_NORMAL : GTK_STATE_PRELIGHT); + else + new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} + +static void +gtk_toggle_button_leave (GtkButton *button) +{ + GtkToggleButton *toggle_button; + GtkStateType new_state; + + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); + + toggle_button = GTK_TOGGLE_BUTTON (button); + + new_state = (toggle_button->active ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL); + + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} diff --git a/gtk/gtktogglebutton.h b/gtk/gtktogglebutton.h new file mode 100644 index 000000000..e48d1cf5a --- /dev/null +++ b/gtk/gtktogglebutton.h @@ -0,0 +1,70 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_TOGGLE_BUTTON_H__ +#define __GTK_TOGGLE_BUTTON_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TOGGLE_BUTTON(obj) GTK_CHECK_CAST (obj, gtk_toggle_button_get_type (), GtkToggleButton) +#define GTK_TOGGLE_BUTTON_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_toggle_button_get_type (), GtkToggleButtonClass) +#define GTK_IS_TOGGLE_BUTTON(obj) GTK_CHECK_TYPE (obj, gtk_toggle_button_get_type ()) + + +typedef struct _GtkToggleButton GtkToggleButton; +typedef struct _GtkToggleButtonClass GtkToggleButtonClass; + +struct _GtkToggleButton +{ + GtkButton button; + + guint active : 1; + guint draw_indicator : 1; +}; + +struct _GtkToggleButtonClass +{ + GtkButtonClass parent_class; + + void (* toggled) (GtkToggleButton *toggle_button); +}; + + +guint gtk_toggle_button_get_type (void); +GtkWidget* gtk_toggle_button_new (void); +GtkWidget* gtk_toggle_button_new_with_label (const gchar *label); +void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button, + gint draw_indicator); +void gtk_toggle_button_set_state (GtkToggleButton *toggle_button, + gint state); +void gtk_toggle_button_toggled (GtkToggleButton *toggle_button); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TOGGLE_BUTTON_H__ */ diff --git a/gtk/gtktooltips.c b/gtk/gtktooltips.c new file mode 100644 index 000000000..953d42592 --- /dev/null +++ b/gtk/gtktooltips.c @@ -0,0 +1,632 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include + +#include "gtkmain.h" +#include "gtkwidget.h" +#include "gtkwindow.h" +#include "gtksignal.h" +#include "gtkstyle.h" +#include "gtktooltips.h" + + +#define DEFAULT_DELAY 500 /* Default delay in ms */ + + +static gint gtk_tooltips_event_handler (GtkWidget *widget, + GdkEvent *event); +static void gtk_tooltips_widget_unmap (GtkWidget *widget, + gpointer data); +static void gtk_tooltips_widget_remove (GtkWidget *widget, + gpointer data); +static void gtk_tooltips_set_active_widget (GtkTooltips *tooltips, + GtkWidget *widget); +static gint gtk_tooltips_widget_visible (GtkWidget *widget); +static gint gtk_tooltips_timeout (gpointer data); +static void gtk_tooltips_draw_tips (GtkTooltips *tooltips); + + +GtkTooltips * +gtk_tooltips_new () +{ + GtkTooltips *tooltips; + + tooltips = g_new0 (GtkTooltips, 1); + + if (tooltips != NULL) + { + tooltips->ref_count = 0; + tooltips->pending_destroy = 0; + + tooltips->enabled = TRUE; + tooltips->numwidgets = 0; + tooltips->delay = DEFAULT_DELAY; + tooltips->widget_list = NULL; + tooltips->gc = NULL; + tooltips->foreground = NULL; + tooltips->background = NULL; + tooltips->tip_window = NULL; + } + + return tooltips; +} + +GtkTooltips* +gtk_tooltips_ref (GtkTooltips *tooltips) +{ + g_return_val_if_fail (tooltips != NULL, NULL); + tooltips->ref_count += 1; + return tooltips; +} + +void +gtk_tooltips_unref (GtkTooltips *tooltips) +{ + g_return_if_fail (tooltips != NULL); + tooltips->ref_count -= 1; + if (tooltips->ref_count == 0 && tooltips->pending_destroy) + gtk_tooltips_destroy (tooltips); +} + +void +gtk_tooltips_free_string (gpointer data, gpointer user_data) +{ + if (data) + g_free (data); +} + +static void +gtk_tooltips_destroy_data (GtkTooltips *tooltips, + GtkTooltipsData *tooltipsdata) +{ + g_free (tooltipsdata->tips_text); + g_list_foreach (tooltipsdata->row, gtk_tooltips_free_string, 0); + if (tooltipsdata->row) + g_list_free (tooltipsdata->row); + gtk_signal_disconnect_by_data (GTK_OBJECT (tooltipsdata->widget), + (gpointer) tooltips); + gtk_widget_set_events(tooltipsdata->widget,tooltipsdata->old_event_mask); + g_free (tooltipsdata); +} + +void +gtk_tooltips_destroy (GtkTooltips *tooltips) +{ + GList *current; + GtkTooltipsData *tooltipsdata; + + g_return_if_fail (tooltips != NULL); + + if (tooltips->ref_count > 0) + { + tooltips->pending_destroy = 1; + return; + } + + if (tooltips->timer_active == TRUE) + { + tooltips->timer_active = FALSE; + gtk_timeout_remove (tooltips->timer_tag); + } + + if (tooltips->widget_list != NULL) + { + current = g_list_first (tooltips->widget_list); + while (current != NULL) + { + tooltipsdata = (GtkTooltipsData*) current->data; + gtk_tooltips_destroy_data (tooltips, tooltipsdata); + current = current->next; + } + g_list_free (tooltips->widget_list); + } + + if (tooltips->tip_window != NULL) + gtk_widget_destroy (tooltips->tip_window); + + if (tooltips->gc != NULL) + gdk_gc_destroy (tooltips->gc); + + g_free (tooltips); +} + +static void +gtk_tooltips_layout_text (GtkTooltips *tooltips, GtkTooltipsData *data) +{ + GtkStyle *style = gtk_widget_get_default_style (); + gchar *row_end, *text, *row_text, *break_pos; + gint i, row_width, window_width = 0; + size_t len; + + g_list_foreach (data->row, gtk_tooltips_free_string, 0); + if (data->row) + g_list_free (data->row); + data->row = 0; + data->font = style->font; + data->width = 0; + + text = data->tips_text; + if (!text) + return; + + while (*text) + { + row_end = strchr (text, '\n'); + if (!row_end) + row_end = strchr (text, '\0'); + + len = row_end - text + 1; + row_text = g_new(gchar, len); + memcpy (row_text, text, len - 1); + row_text[len - 1] = '\0'; + + /* now either adjust the window's width or shorten the row until + it fits in the window */ + + while (1) + { + row_width = gdk_string_width (data->font, row_text); + if (!window_width) + { + /* make an initial guess at window's width: */ + + if (row_width > gdk_screen_width () / 4) + window_width = gdk_screen_width () / 4; + else + window_width = row_width; + } + if (row_width <= window_width) + break; + + if (strchr (row_text, ' ')) + { + /* the row is currently too wide, but we have blanks in + the row so we can break it into smaller pieces */ + + gint avg_width = row_width / strlen (row_text); + + i = window_width; + if (avg_width) + i /= avg_width; + if ((size_t) i >= len) + i = len - 1; + + break_pos = strchr (row_text + i, ' '); + if (!break_pos) + { + break_pos = row_text + i; + while (*--break_pos != ' '); + } + *break_pos = '\0'; + } + else + { + /* we can't break this row into any smaller pieces, so + we have no choice but to widen the window: */ + + window_width = row_width; + break; + } + } + if (row_width > data->width) + data->width = row_width; + data->row = g_list_append (data->row, row_text); + text += strlen (row_text); + if (!*text) + break; + + if (text[0] == '\n' && text[1]) + /* end of paragraph and there is more text to come */ + data->row = g_list_append (data->row, 0); + ++text; /* skip blank or newline */ + } + data->width += 8; /* leave some border */ +} + +void +gtk_tooltips_enable (GtkTooltips *tooltips) +{ + g_return_if_fail (tooltips != NULL); + + tooltips->enabled = TRUE; +} + +void +gtk_tooltips_disable (GtkTooltips *tooltips) +{ + g_return_if_fail (tooltips != NULL); + + tooltips->enabled = FALSE; + + if (tooltips->timer_active == TRUE) + { + gtk_timeout_remove (tooltips->timer_tag); + tooltips->timer_active = FALSE; + } + + if (tooltips->active_widget != NULL) + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + tooltips->active_widget = NULL; + } +} + +void +gtk_tooltips_set_delay (GtkTooltips *tooltips, + gint delay) +{ + g_return_if_fail (tooltips != NULL); + + tooltips->delay = delay; +} + +void +gtk_tooltips_set_tips (GtkTooltips *tooltips, + GtkWidget *widget, + const gchar *tips_text) +{ + GtkTooltipsData *tooltipsdata; + + g_return_if_fail (tooltips != NULL); + g_return_if_fail (widget != NULL); + + if (gtk_object_get_data (GTK_OBJECT (widget), "_GtkTooltips") != NULL) + gtk_tooltips_widget_remove (widget, NULL); + + if (gtk_object_get_data (GTK_OBJECT (widget), "_GtkTooltips") != NULL) + gtk_tooltips_widget_remove (widget, NULL); + + tooltipsdata = g_new(GtkTooltipsData, 1); + + if (tooltipsdata != NULL) + { + memset (tooltipsdata, 0, sizeof (*tooltipsdata)); + tooltipsdata->widget = widget; + + tooltipsdata->tips_text = g_strdup (tips_text); + if (!tooltipsdata->tips_text) + { + g_free (tooltipsdata); + return; + } + + gtk_tooltips_layout_text (tooltips, tooltipsdata); + tooltips->widget_list = g_list_append (tooltips->widget_list, + tooltipsdata); + tooltips->numwidgets++; + tooltipsdata->old_event_mask = gtk_widget_get_events (widget); + + gtk_signal_connect_after(GTK_OBJECT (widget), "event", + (GtkSignalFunc) gtk_tooltips_event_handler, + (gpointer) tooltips); + + gtk_object_set_data (GTK_OBJECT (widget), "_GtkTooltips", + (gpointer) tooltips); + + gtk_signal_connect (GTK_OBJECT (widget), "destroy", + (GtkSignalFunc) gtk_tooltips_widget_remove, + (gpointer) tooltips); + + gtk_signal_connect (GTK_OBJECT (widget), "unmap", + (GtkSignalFunc) gtk_tooltips_widget_unmap, + (gpointer) tooltips); + + gtk_signal_connect (GTK_OBJECT (widget), "unrealize", + (GtkSignalFunc) gtk_tooltips_widget_unmap, + (gpointer) tooltips); + } +} + +void +gtk_tooltips_set_colors (GtkTooltips *tooltips, + GdkColor *background, + GdkColor *foreground) +{ + g_return_if_fail (tooltips != NULL); + + if (background != NULL) + tooltips->foreground = foreground; + if (foreground != NULL) + tooltips->background = background; +} + +static void +gtk_tooltips_draw_tips (GtkTooltips * tooltips) +{ + GtkWidget *widget; + GtkStyle *style = gtk_widget_get_default_style (); + gint gap, x, y, w, h, scr_w, scr_h, baseline_skip; + GtkTooltipsData *data; + GList *el; + + if (tooltips->tip_window == NULL) + { + tooltips->tip_window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_policy (GTK_WINDOW (tooltips->tip_window), FALSE, FALSE, TRUE); + } + else + gtk_widget_hide (tooltips->tip_window); + + widget = tooltips->active_widget->widget; + + scr_w = gdk_screen_width (); + scr_h = gdk_screen_height (); + + data = tooltips->active_widget; + if (data->font != style->font) + gtk_tooltips_layout_text (tooltips, data); + + gap = (style->font->ascent + style->font->descent) / 4; + if (gap < 2) + gap = 2; + baseline_skip = style->font->ascent + style->font->descent + gap; + w = data->width; + h = 8 - gap; + for (el = data->row; el; el = el->next) + if (el->data) + h += baseline_skip; + else + h += baseline_skip / 2; + if (h < 8) + h = 8; + + gdk_window_get_pointer (NULL, &x, NULL, NULL); + gdk_window_get_origin (widget->window, NULL, &y); + + x -= ((w >> 1) + 4); + + if ((x + w) > scr_w) + x -= (x + w) - scr_w; + else if (x < 0) + x = 0; + + if ((y + h + widget->allocation.height + 4) > scr_h) + y = y - h - 4; + else + y = y + widget->allocation.height + 4; + + gtk_widget_set_usize (tooltips->tip_window, w + 1, h + 1); + gtk_widget_popup (tooltips->tip_window, x, y); + + if (tooltips->gc == NULL) + tooltips->gc = gdk_gc_new (tooltips->tip_window->window); + + if (tooltips->background != NULL) + { + gdk_gc_set_foreground (tooltips->gc, tooltips->background); + gdk_gc_set_background (tooltips->gc, tooltips->foreground); + } + else + { + gdk_gc_set_foreground (tooltips->gc, &style->bg[GTK_STATE_NORMAL]); + gdk_gc_set_background (tooltips->gc, &style->fg[GTK_STATE_NORMAL]); + } + + gdk_gc_set_font (tooltips->gc, style->font); + gdk_draw_rectangle (tooltips->tip_window->window, tooltips->gc, TRUE, 0, 0, w, h); + + if (tooltips->foreground != NULL) + { + gdk_gc_set_foreground (tooltips->gc, tooltips->foreground); + gdk_gc_set_background (tooltips->gc, tooltips->background); + } + else + { + gdk_gc_set_foreground (tooltips->gc, &style->fg[GTK_STATE_NORMAL]); + gdk_gc_set_background (tooltips->gc, &style->bg[GTK_STATE_NORMAL]); + } + + gdk_draw_rectangle (tooltips->tip_window->window, tooltips->gc, FALSE, 0, 0, w, h); + y = style->font->ascent + 4; + + for (el = data->row; el; el = el->next) + { + if (el->data) + { + gdk_draw_string (tooltips->tip_window->window, style->font, + tooltips->gc, 4, y, el->data); + y += baseline_skip; + } + else + y += baseline_skip / 2; + } +} + +static gint +gtk_tooltips_timeout (gpointer data) +{ + GtkTooltips *tooltips = (GtkTooltips *) data; + + if (tooltips->active_widget != NULL && + GTK_WIDGET_DRAWABLE (tooltips->active_widget->widget)) + gtk_tooltips_draw_tips (tooltips); + + return FALSE; +} + +static gint +gtk_tooltips_widget_visible (GtkWidget *widget) +{ + GtkWidget *current; + + current = widget; + + while (current != NULL) + { + if (!GTK_WIDGET_MAPPED (current) || !GTK_WIDGET_REALIZED (current)) + return FALSE; + current = current->parent; + } + + return TRUE; +} + +static void +gtk_tooltips_set_active_widget (GtkTooltips *tooltips, + GtkWidget *widget) +{ + GtkTooltipsData *tooltipsdata; + GList *current; + + current = g_list_first (tooltips->widget_list); + tooltips->active_widget = NULL; + + while (current != NULL) + { + tooltipsdata = (GtkTooltipsData*) current->data; + + if (widget == tooltipsdata->widget && + gtk_tooltips_widget_visible (tooltipsdata->widget) == TRUE) + { + tooltips->active_widget = tooltipsdata; + return; + } + + current = current->next; + } +} + +static gint +gtk_tooltips_event_handler (GtkWidget *widget, + GdkEvent *event) +{ + GtkTooltips *tooltips; + GtkTooltipsData *old_widget; + gint returnval = FALSE; + + tooltips = (GtkTooltips*) gtk_object_get_data (GTK_OBJECT (widget),"_GtkTooltips"); + + if (tooltips->enabled == FALSE) + return returnval; + + if ((event->type == GDK_LEAVE_NOTIFY || event->type == GDK_ENTER_NOTIFY) && + event->crossing.detail == GDK_NOTIFY_INFERIOR) + return returnval; + + if (event->type == GDK_LEAVE_NOTIFY) + { + if (tooltips->timer_active == TRUE) + { + gtk_timeout_remove (tooltips->timer_tag); + tooltips->timer_active = FALSE; + } + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + tooltips->active_widget = NULL; + } + else if (event->type == GDK_MOTION_NOTIFY || event->type == GDK_ENTER_NOTIFY) + { + old_widget = tooltips->active_widget; +#if 0 + if (widget->window != event->crossing.window) + tooltips->active_widget = NULL; + else +#endif + gtk_tooltips_set_active_widget (tooltips, widget); + + if (old_widget != tooltips->active_widget) + { + if (tooltips->timer_active == TRUE) + { + gtk_timeout_remove (tooltips->timer_tag); + tooltips->timer_active = FALSE; + } + if (tooltips->active_widget != NULL) + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + + tooltips->timer_tag = gtk_timeout_add (tooltips->delay, + gtk_tooltips_timeout, (gpointer) tooltips); + + tooltips->timer_active = TRUE; + } + } + else if (tooltips->active_widget == NULL) + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + } + } + else + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + } + + return returnval; +} + +static void +gtk_tooltips_widget_unmap (GtkWidget *widget, + gpointer data) +{ + GtkTooltips *tooltips; + + tooltips = (GtkTooltips*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkTooltips"); + + if (tooltips->active_widget && + (tooltips->active_widget->widget == widget)) + { + if (tooltips->tip_window != NULL) + gtk_widget_hide (tooltips->tip_window); + tooltips->active_widget = NULL; + } +} + +static void +gtk_tooltips_widget_remove (GtkWidget *widget, + gpointer data) +{ + GtkTooltips *tooltips; + GtkTooltipsData *tooltipsdata; + GList *list; + + tooltips = (GtkTooltips*) gtk_object_get_data (GTK_OBJECT (widget), "_GtkTooltips"); + + gtk_tooltips_widget_unmap (widget, data); + + list = g_list_first (tooltips->widget_list); + while (list) + { + tooltipsdata = (GtkTooltipsData*) list->data; + + if (tooltipsdata->widget == widget) + break; + + list = list->next; + } + + if (list) + { + tooltipsdata = (GtkTooltipsData*) list->data; + + g_free (tooltipsdata->tips_text); + g_list_foreach (tooltipsdata->row, gtk_tooltips_free_string, 0); + g_list_free (tooltipsdata->row); + gtk_signal_disconnect_by_data (GTK_OBJECT (tooltipsdata->widget), (gpointer) tooltips); + gtk_widget_set_events (tooltipsdata->widget,tooltipsdata->old_event_mask); + g_free (tooltipsdata); + + tooltips->widget_list = g_list_remove (tooltips->widget_list, tooltipsdata); + } + + gtk_object_set_data (GTK_OBJECT (widget), "_GtkTooltips", NULL); +} diff --git a/gtk/gtktooltips.h b/gtk/gtktooltips.h new file mode 100644 index 000000000..e3ac59696 --- /dev/null +++ b/gtk/gtktooltips.h @@ -0,0 +1,88 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_TOOLTIPS_H__ +#define __GTK_TOOLTIPS_H__ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +typedef struct +{ + GtkWidget *widget; + gchar *tips_text; + GdkFont *font; + gint width; + GList *row; + gint old_event_mask; +} GtkTooltipsData; + +typedef struct +{ + GtkWidget *tip_window; + GtkTooltipsData *active_widget; + GList *widget_list; + + GdkGC *gc; + GdkColor *foreground; + GdkColor *background; + + gint numwidgets; + gint enabled; + gint inside; + gint delay; + gint timer_tag; + gint timer_active; + + gint ref_count; + gint pending_destroy; +} GtkTooltips; + + +GtkTooltips* gtk_tooltips_new (void); + +void gtk_tooltips_destroy (GtkTooltips *tooltips); +GtkTooltips* gtk_tooltips_ref (GtkTooltips *tooltips); +void gtk_tooltips_unref (GtkTooltips *tooltips); + +void gtk_tooltips_enable (GtkTooltips *tooltips); + +void gtk_tooltips_disable (GtkTooltips *tooltips); + +void gtk_tooltips_set_delay (GtkTooltips *tooltips, + gint delay); + +void gtk_tooltips_set_tips (GtkTooltips *tooltips, + GtkWidget *widget, + const gchar *tips_text); + +void gtk_tooltips_set_colors (GtkTooltips *tooltips, + GdkColor *background, + GdkColor *foreground); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TOOLTIPS_H__ */ diff --git a/gtk/gtktree.c b/gtk/gtktree.c new file mode 100644 index 000000000..f3981ea0a --- /dev/null +++ b/gtk/gtktree.c @@ -0,0 +1,81 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtktree.h" + + +static void gtk_tree_class_init (GtkTreeClass *klass); +static void gtk_tree_init (GtkTree *tree); + + +guint +gtk_tree_get_type () +{ + static guint tree_type = 0; + + if (!tree_type) + { + GtkTypeInfo tree_info = + { + "GtkTree", + sizeof (GtkTree), + sizeof (GtkTreeClass), + (GtkClassInitFunc) gtk_tree_class_init, + (GtkObjectInitFunc) gtk_tree_init, + (GtkArgFunc) NULL, + }; + + tree_type = gtk_type_unique (gtk_container_get_type (), &tree_info); + } + + return tree_type; +} + +static void +gtk_tree_class_init (GtkTreeClass *class) +{ +} + +static void +gtk_tree_init (GtkTree *tree) +{ +} + +GtkWidget* +gtk_tree_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_tree_get_type ())); +} + +void +gtk_tree_append (GtkTree *tree, + GtkWidget *child) +{ +} + +void +gtk_tree_prepend (GtkTree *tree, + GtkWidget *child) +{ +} + +void +gtk_tree_insert (GtkTree *tree, + GtkWidget *child, + gint position) +{ +} diff --git a/gtk/gtktree.h b/gtk/gtktree.h new file mode 100644 index 000000000..1486a82ab --- /dev/null +++ b/gtk/gtktree.h @@ -0,0 +1,68 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_TREE_H__ +#define __GTK_TREE_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TREE(obj) GTK_CHECK_CAST (obj, gtk_tree_get_type (), GtkTree) +#define GTK_TREE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_tree_get_type (), GtkTreeClass) +#define GTK_IS_TREE(obj) GTK_CHECK_TYPE (obj, gtk_tree_get_type ()) + + +typedef struct _GtkTree GtkTree; +typedef struct _GtkTreeClass GtkTreeClass; + +struct _GtkTree +{ + GtkContainer container; + + GList *children; +}; + +struct _GtkTreeClass +{ + GtkContainerClass parent_class; +}; + + +guint gtk_tree_get_type (void); +GtkWidget* gtk_tree_new (void); +void gtk_tree_append (GtkTree *tree, + GtkWidget *child); +void gtk_tree_prepend (GtkTree *tree, + GtkWidget *child); +void gtk_tree_insert (GtkTree *tree, + GtkWidget *child, + gint position); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TREE_H__ */ diff --git a/gtk/gtktreeitem.c b/gtk/gtktreeitem.c new file mode 100644 index 000000000..8f0d9f078 --- /dev/null +++ b/gtk/gtktreeitem.c @@ -0,0 +1,108 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtklabel.h" +#include "gtktreeitem.h" + + +static void gtk_tree_item_class_init (GtkTreeItemClass *klass); +static void gtk_tree_item_init (GtkTreeItem *tree_item); + + +guint +gtk_tree_item_get_type () +{ + static guint tree_item_type = 0; + + if (!tree_item_type) + { + GtkTypeInfo tree_item_info = + { + "GtkTreeItem", + sizeof (GtkTreeItem), + sizeof (GtkTreeItemClass), + (GtkClassInitFunc) gtk_tree_item_class_init, + (GtkObjectInitFunc) gtk_tree_item_init, + (GtkArgFunc) NULL, + }; + + tree_item_type = gtk_type_unique (gtk_item_get_type (), &tree_item_info); + } + + return tree_item_type; +} + +static void +gtk_tree_item_class_init (GtkTreeItemClass *class) +{ +} + +static void +gtk_tree_item_init (GtkTreeItem *tree_item) +{ +} + + +GtkWidget* +gtk_tree_item_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_tree_item_get_type ())); +} + +GtkWidget* +gtk_tree_item_new_with_label (gchar *label) +{ + GtkWidget *tree_item; + GtkWidget *label_widget; + + tree_item = gtk_tree_item_new (); + label_widget = gtk_label_new (label); + gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); + + gtk_container_add (GTK_CONTAINER (tree_item), label_widget); + gtk_widget_show (label_widget); + + return tree_item; +} + +void +gtk_tree_item_set_subtree (GtkTreeItem *tree_item, + GtkWidget *subtree) +{ + g_return_if_fail (tree_item != NULL); + g_return_if_fail (GTK_IS_TREE_ITEM (tree_item)); +} + +void +gtk_tree_item_select (GtkTreeItem *tree_item) +{ +} + +void +gtk_tree_item_deselect (GtkTreeItem *tree_item) +{ +} + +void +gtk_tree_item_expand (GtkTreeItem *tree_item) +{ +} + +void +gtk_tree_item_collapse (GtkTreeItem *tree_item) +{ +} diff --git a/gtk/gtktreeitem.h b/gtk/gtktreeitem.h new file mode 100644 index 000000000..921f681bc --- /dev/null +++ b/gtk/gtktreeitem.h @@ -0,0 +1,72 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_TREE_ITEM_H__ +#define __GTK_TREE_ITEM_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_TREE_ITEM(obj) GTK_CHECK_CAST (obj, gtk_tree_item_get_type (), GtkTreeItem) +#define GTK_TREE_ITEM_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_tree_item_get_type (), GtkTreeItemClass) +#define GTK_IS_TREE_ITEM(obj) GTK_CHECK_TYPE (obj, gtk_tree_item_get_type ()) + + +typedef struct _GtkTreeItem GtkTreeItem; +typedef struct _GtkTreeItemClass GtkTreeItemClass; + +struct _GtkTreeItem +{ + GtkItem item; + + GtkWidget *child; + GtkWidget *subtree; +}; + +struct _GtkTreeItemClass +{ + GtkItemClass parent_class; + + void (* expand) (GtkTreeItem *tree_item); + void (* collapse) (GtkTreeItem *tree_item); +}; + + +guint gtk_tree_item_get_type (void); +GtkWidget* gtk_tree_item_new (void); +GtkWidget* gtk_tree_item_new_with_label (gchar *label); +void gtk_tree_item_set_subtree (GtkTreeItem *tree_item, + GtkWidget *subtree); +void gtk_tree_item_select (GtkTreeItem *tree_item); +void gtk_tree_item_deselect (GtkTreeItem *tree_item); +void gtk_tree_item_expand (GtkTreeItem *tree_item); +void gtk_tree_item_collapse (GtkTreeItem *tree_item); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TREE_ITEM_H__ */ diff --git a/gtk/gtktypebuiltins.c b/gtk/gtktypebuiltins.c new file mode 100644 index 000000000..e43573119 --- /dev/null +++ b/gtk/gtktypebuiltins.c @@ -0,0 +1,53 @@ +/* generated by gentypeinfo from "gtk.defs" */ + + { "GtkWindowType", GTK_TYPE_ENUM }, + { "GtkStateType", GTK_TYPE_ENUM }, + { "GtkDirectionType", GTK_TYPE_ENUM }, + { "GtkShadowType", GTK_TYPE_ENUM }, + { "GtkArrowType", GTK_TYPE_ENUM }, + { "GtkPackType", GTK_TYPE_ENUM }, + { "GtkPolicyType", GTK_TYPE_ENUM }, + { "GtkUpdateType", GTK_TYPE_ENUM }, + { "GtkAttachOptions", GTK_TYPE_FLAGS }, + { "GtkSignalRunType", GTK_TYPE_FLAGS }, + { "GtkWindowPosition", GTK_TYPE_ENUM }, + { "GtkSubmenuDirection", GTK_TYPE_ENUM }, + { "GtkSubmenuPlacement", GTK_TYPE_ENUM }, + { "GtkMenuFactoryType", GTK_TYPE_ENUM }, + { "GtkMetricType", GTK_TYPE_ENUM }, + { "GtkScrollType", GTK_TYPE_ENUM }, + { "GtkTroughType", GTK_TYPE_ENUM }, + { "GtkPositionType", GTK_TYPE_ENUM }, + { "GtkPreviewType", GTK_TYPE_ENUM }, + { "GtkWidgetFlags", GTK_TYPE_FLAGS }, + { "GdkWindowType", GTK_TYPE_ENUM }, + { "GdkWindowClass", GTK_TYPE_ENUM }, + { "GdkImageType", GTK_TYPE_ENUM }, + { "GdkVisualType", GTK_TYPE_ENUM }, + { "GdkWindowAttributesType", GTK_TYPE_FLAGS }, + { "GdkWindowHints", GTK_TYPE_FLAGS }, + { "GdkFunction", GTK_TYPE_ENUM }, + { "GdkFill", GTK_TYPE_ENUM }, + { "GdkLineStyle", GTK_TYPE_ENUM }, + { "GdkCapStyle", GTK_TYPE_ENUM }, + { "GdkJoinStyle", GTK_TYPE_ENUM }, + { "GdkCursorType", GTK_TYPE_ENUM }, + { "GdkEventType", GTK_TYPE_ENUM }, + { "GdkEventMask", GTK_TYPE_FLAGS }, + { "GdkNotifyType", GTK_TYPE_ENUM }, + { "GdkModifierType", GTK_TYPE_FLAGS }, + { "GdkSubwindowMode", GTK_TYPE_ENUM }, + { "GdkInputCondition", GTK_TYPE_FLAGS }, + { "GdkStatus", GTK_TYPE_ENUM }, + { "GdkByteOrder", GTK_TYPE_ENUM }, + { "GdkGCValuesMask", GTK_TYPE_FLAGS }, + { "GdkSelection", GTK_TYPE_ENUM }, + { "GdkPropertyState", GTK_TYPE_ENUM }, + { "GdkPropMode", GTK_TYPE_ENUM }, + { "GtkAcceleratorTable", GTK_TYPE_BOXED }, + { "GtkStyle", GTK_TYPE_BOXED }, + { "GdkColormap", GTK_TYPE_BOXED }, + { "GdkVisual", GTK_TYPE_BOXED }, + { "GdkFont", GTK_TYPE_BOXED }, + { "GdkWindow", GTK_TYPE_BOXED }, + { "GdkEvent", GTK_TYPE_BOXED }, diff --git a/gtk/gtktypebuiltins.h b/gtk/gtktypebuiltins.h new file mode 100644 index 000000000..ba9131f0f --- /dev/null +++ b/gtk/gtktypebuiltins.h @@ -0,0 +1,54 @@ +/* generated by gentypeinfo from "gtk.defs" */ + +#define GTK_TYPE_WINDOW_TYPE (gtk_type_builtins[0]) +#define GTK_TYPE_STATE_TYPE (gtk_type_builtins[1]) +#define GTK_TYPE_DIRECTION_TYPE (gtk_type_builtins[2]) +#define GTK_TYPE_SHADOW_TYPE (gtk_type_builtins[3]) +#define GTK_TYPE_ARROW_TYPE (gtk_type_builtins[4]) +#define GTK_TYPE_PACK_TYPE (gtk_type_builtins[5]) +#define GTK_TYPE_POLICY_TYPE (gtk_type_builtins[6]) +#define GTK_TYPE_UPDATE_TYPE (gtk_type_builtins[7]) +#define GTK_TYPE_ATTACH_OPTIONS (gtk_type_builtins[8]) +#define GTK_TYPE_SIGNAL_RUN_TYPE (gtk_type_builtins[9]) +#define GTK_TYPE_WINDOW_POSITION (gtk_type_builtins[10]) +#define GTK_TYPE_SUBMENU_DIRECTION (gtk_type_builtins[11]) +#define GTK_TYPE_SUBMENU_PLACEMENT (gtk_type_builtins[12]) +#define GTK_TYPE_MENU_FACTORY_TYPE (gtk_type_builtins[13]) +#define GTK_TYPE_METRIC_TYPE (gtk_type_builtins[14]) +#define GTK_TYPE_SCROLL_TYPE (gtk_type_builtins[15]) +#define GTK_TYPE_TROUGH_TYPE (gtk_type_builtins[16]) +#define GTK_TYPE_POSITION_TYPE (gtk_type_builtins[17]) +#define GTK_TYPE_PREVIEW_TYPE (gtk_type_builtins[18]) +#define GTK_TYPE_WIDGET_FLAGS (gtk_type_builtins[19]) +#define GTK_TYPE_GDK_WINDOW_TYPE (gtk_type_builtins[20]) +#define GTK_TYPE_GDK_WINDOW_CLASS (gtk_type_builtins[21]) +#define GTK_TYPE_GDK_IMAGE_TYPE (gtk_type_builtins[22]) +#define GTK_TYPE_GDK_VISUAL_TYPE (gtk_type_builtins[23]) +#define GTK_TYPE_GDK_WINDOW_ATTRIBUTES_TYPE (gtk_type_builtins[24]) +#define GTK_TYPE_GDK_WINDOW_HINTS (gtk_type_builtins[25]) +#define GTK_TYPE_GDK_FUNCTION (gtk_type_builtins[26]) +#define GTK_TYPE_GDK_FILL (gtk_type_builtins[27]) +#define GTK_TYPE_GDK_LINE_STYLE (gtk_type_builtins[28]) +#define GTK_TYPE_GDK_CAP_STYLE (gtk_type_builtins[29]) +#define GTK_TYPE_GDK_JOIN_STYLE (gtk_type_builtins[30]) +#define GTK_TYPE_GDK_CURSOR_TYPE (gtk_type_builtins[31]) +#define GTK_TYPE_GDK_EVENT_TYPE (gtk_type_builtins[32]) +#define GTK_TYPE_GDK_EVENT_MASK (gtk_type_builtins[33]) +#define GTK_TYPE_GDK_NOTIFY_TYPE (gtk_type_builtins[34]) +#define GTK_TYPE_GDK_MODIFIER_TYPE (gtk_type_builtins[35]) +#define GTK_TYPE_GDK_SUBWINDOW_MODE (gtk_type_builtins[36]) +#define GTK_TYPE_GDK_INPUT_CONDITION (gtk_type_builtins[37]) +#define GTK_TYPE_GDK_STATUS (gtk_type_builtins[38]) +#define GTK_TYPE_GDK_BYTE_ORDER (gtk_type_builtins[39]) +#define GTK_TYPE_GDK_GCVALUES_MASK (gtk_type_builtins[40]) +#define GTK_TYPE_GDK_SELECTION (gtk_type_builtins[41]) +#define GTK_TYPE_GDK_PROPERTY_STATE (gtk_type_builtins[42]) +#define GTK_TYPE_GDK_PROP_MODE (gtk_type_builtins[43]) +#define GTK_TYPE_ACCELERATOR_TABLE (gtk_type_builtins[44]) +#define GTK_TYPE_STYLE (gtk_type_builtins[45]) +#define GTK_TYPE_GDK_COLORMAP (gtk_type_builtins[46]) +#define GTK_TYPE_GDK_VISUAL (gtk_type_builtins[47]) +#define GTK_TYPE_GDK_FONT (gtk_type_builtins[48]) +#define GTK_TYPE_GDK_WINDOW (gtk_type_builtins[49]) +#define GTK_TYPE_GDK_EVENT (gtk_type_builtins[50]) +#define GTK_TYPE_NUM_BUILTINS 51 diff --git a/gtk/gtktypeutils.c b/gtk/gtktypeutils.c new file mode 100644 index 000000000..46e035fd9 --- /dev/null +++ b/gtk/gtktypeutils.c @@ -0,0 +1,459 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkobject.h" +#include "gtktypeutils.h" + + +typedef struct _GtkTypeNode GtkTypeNode; + +struct _GtkTypeNode +{ + GtkType type; + gint init_class; + gpointer klass; + GtkTypeInfo type_info; + GtkTypeNode *parent; + GList *children; +}; + + +static void gtk_type_insert (guint parent_type, + GtkType type, + GtkTypeInfo *type_info); +static void gtk_type_class_init (GtkTypeNode *node); +static void gtk_type_object_init (GtkTypeNode *node, + gpointer object); +static guint gtk_type_hash (GtkType *key); +static gint gtk_type_compare (GtkType *a, + GtkType *b); +static guint gtk_type_name_hash (const char *key); +static gint gtk_type_name_compare (const char *a, + const char *b); +static void gtk_type_init_builtin_types (); + + +static int initialize = TRUE; +static GHashTable *type_hash_table = NULL; +static GHashTable *name_hash_table = NULL; + + +void +gtk_type_init () +{ + if (initialize) + { + g_assert (sizeof (GtkType) >= 4); + + initialize = FALSE; + type_hash_table = g_hash_table_new ((GHashFunc) gtk_type_hash, + (GCompareFunc) gtk_type_compare); + name_hash_table = g_hash_table_new ((GHashFunc) gtk_type_name_hash, + (GCompareFunc) gtk_type_name_compare); + gtk_type_init_builtin_types (); + } +} + +GtkType +gtk_type_unique (GtkType parent_type, + GtkTypeInfo *type_info) +{ + static guint next_seqno = 0; + GtkType new_type; + + g_return_val_if_fail (type_info != NULL, 0); + + if (initialize) + gtk_type_init (); + + next_seqno++; + if (parent_type == GTK_TYPE_INVALID) + new_type = next_seqno; + else + new_type = GTK_TYPE_MAKE (GTK_FUNDAMENTAL_TYPE (parent_type), next_seqno); + gtk_type_insert (parent_type, new_type, type_info); + + return new_type; +} + +gchar* +gtk_type_name (GtkType type) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + if (node) + return node->type_info.type_name; + + return NULL; +} + +GtkType +gtk_type_from_name (const gchar *name) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (name_hash_table, (gpointer) name); + + if (node) + return node->type; + + return 0; +} + +GtkType +gtk_type_parent (GtkType type) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + if (node && node->parent) + return node->parent->type; + + return 0; +} + +gpointer +gtk_type_class (GtkType type) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + g_return_val_if_fail (node != NULL, NULL); + + if (node->init_class) + gtk_type_class_init (node); + + return node->klass; +} + +gpointer +gtk_type_new (GtkType type) +{ + GtkTypeNode *node; + gpointer object; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + g_return_val_if_fail (node != NULL, NULL); + + object = g_new0 (guchar, node->type_info.object_size); + ((GtkObject*) object)->klass = gtk_type_class (type); + gtk_type_object_init (node, object); + + return object; +} + +void +gtk_type_describe_heritage (GtkType type) +{ + GtkTypeNode *node; + gint first; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + first = TRUE; + + while (node) + { + if (first) + { + first = FALSE; + g_print ("is a "); + } + + if (node->type_info.type_name) + g_print ("%s\n", node->type_info.type_name); + else + g_print ("\n"); + + node = node->parent; + } +} + +void +gtk_type_describe_tree (GtkType type, + gint show_size) +{ + static gint indent = 0; + GtkTypeNode *node; + GtkTypeNode *child; + GList *children; + gint old_indent; + gint i; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + for (i = 0; i < indent; i++) + g_print (" "); + + if (node->type_info.type_name) + g_print ("%s", node->type_info.type_name); + else + g_print (""); + + if (show_size) + g_print (" ( %d bytes )\n", node->type_info.object_size); + else + g_print ("\n"); + + old_indent = indent; + indent += 4; + + children = node->children; + while (children) + { + child = children->data; + children = children->next; + + gtk_type_describe_tree (child->type, show_size); + } + + indent = old_indent; +} + +gint +gtk_type_is_a (GtkType type, + GtkType is_a_type) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + while (node) + { + if (node->type == is_a_type) + return TRUE; + node = node->parent; + } + + return FALSE; +} + +void +gtk_type_set_arg (GtkObject *object, + GtkType type, + GtkArg *arg) +{ + GtkTypeNode *node; + + if (initialize) + gtk_type_init (); + + node = g_hash_table_lookup (type_hash_table, &type); + + if (node->type_info.arg_func) + (* node->type_info.arg_func) (object, arg); +} + +static void +gtk_type_insert (GtkType parent_type, + GtkType type, + GtkTypeInfo *type_info) +{ + GtkTypeNode *node; + GtkTypeNode *parent; + + parent = g_hash_table_lookup (type_hash_table, &parent_type); + + node = g_new (GtkTypeNode, 1); + node->type = type; + node->init_class = TRUE; + node->klass = NULL; + node->type_info = *type_info; + node->parent = parent; + node->children = NULL; + + if (node->parent) + node->parent->children = g_list_append (node->parent->children, node); + + g_hash_table_insert (type_hash_table, &node->type, node); + g_hash_table_insert (name_hash_table, node->type_info.type_name, node); +} + +static void +gtk_type_class_init (GtkTypeNode *node) +{ + GtkObjectClass *object_class; + + if (node->init_class) + { + node->init_class = FALSE; + node->klass = g_new0 (guchar, node->type_info.class_size); + + if (node->parent) + { + if (node->parent->init_class) + gtk_type_class_init (node->parent); + + memcpy (node->klass, node->parent->klass, node->parent->type_info.class_size); + } + + object_class = node->klass; + object_class->type = node->type; + + if (node->type_info.class_init_func) + (* node->type_info.class_init_func) (node->klass); + } +} + +static void +gtk_type_object_init (GtkTypeNode *node, + gpointer object) +{ + if (node->parent) + gtk_type_object_init (node->parent, object); + + if (node->type_info.object_init_func) + (* node->type_info.object_init_func) (object); +} + +static guint +gtk_type_hash (GtkType *key) +{ + return GTK_TYPE_SEQNO (*key); +} + +static gint +gtk_type_compare (GtkType *a, + GtkType *b) +{ + g_return_val_if_fail(a != NULL && b != NULL, 0); + return (*a == *b); +} + +static guint +gtk_type_name_hash (const char *key) +{ + guint result; + + result = 0; + while (*key) + result += (result << 3) + *key++; + + return result; +} + +static gint +gtk_type_name_compare (const char *a, + const char *b) +{ + return (strcmp (a, b) == 0); +} + +static GtkType +gtk_type_register_builtin (char *name, + GtkType parent) +{ + GtkTypeInfo info; + + info.type_name = name; + info.object_size = info.class_size = 0; + info.class_init_func = NULL; + info.object_init_func = NULL; + info.arg_func = NULL; + + return gtk_type_unique (parent, &info); +} + +extern void gtk_object_init_type (); + +GtkType gtk_type_builtins[GTK_TYPE_NUM_BUILTINS]; + +static void +gtk_type_init_builtin_types () +{ + /* GTK_TYPE_INVALID has typeid 0. The first type id returned by + gtk_type_unique is 1, which is GTK_TYPE_NONE. And so on. */ + + static struct { + GtkType enum_id; + gchar *name; + } fundamental_info[] = { + { GTK_TYPE_NONE, "void" }, + { GTK_TYPE_CHAR, "char" }, + { GTK_TYPE_BOOL, "bool" }, + { GTK_TYPE_INT, "int" }, + { GTK_TYPE_UINT, "uint" }, + { GTK_TYPE_LONG, "long" }, + { GTK_TYPE_ULONG, "ulong" }, + { GTK_TYPE_FLOAT, "float" }, + { GTK_TYPE_STRING, "string" }, + { GTK_TYPE_ENUM, "enum" }, + { GTK_TYPE_FLAGS, "flags" }, + { GTK_TYPE_BOXED, "boxed" }, + { GTK_TYPE_FOREIGN, "foreign" }, + { GTK_TYPE_CALLBACK, "callback" }, + { GTK_TYPE_ARGS, "args" }, + + { GTK_TYPE_POINTER, "pointer" }, + { GTK_TYPE_SIGNAL, "signal" }, + { GTK_TYPE_C_CALLBACK, "c_callback" } + }; + + static struct { + char *name; + GtkType parent; + } builtin_info[] = { +#include "gtktypebuiltins.c" + { NULL } + }; + + int i; + + for (i = 0; i < sizeof (fundamental_info)/sizeof(fundamental_info[0]); i++) + { + GtkType id; + id = gtk_type_register_builtin (fundamental_info[i].name, + GTK_TYPE_INVALID); + g_assert (id == fundamental_info[i].enum_id); + } + + gtk_object_init_type (); + + for (i = 0; builtin_info[i].name; i++) + { + gtk_type_builtins[i] = + gtk_type_register_builtin (builtin_info[i].name, + builtin_info[i].parent); + } +} diff --git a/gtk/gtktypeutils.h b/gtk/gtktypeutils.h new file mode 100644 index 000000000..911885be9 --- /dev/null +++ b/gtk/gtktypeutils.h @@ -0,0 +1,196 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_TYPE_UTILS_H__ +#define __GTK_TYPE_UTILS_H__ + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* Fundamental Types */ + +typedef enum +{ + GTK_TYPE_INVALID, + GTK_TYPE_NONE, + GTK_TYPE_CHAR, + GTK_TYPE_BOOL, + GTK_TYPE_INT, + GTK_TYPE_UINT, + GTK_TYPE_LONG, + GTK_TYPE_ULONG, + GTK_TYPE_FLOAT, + GTK_TYPE_STRING, + GTK_TYPE_ENUM, + GTK_TYPE_FLAGS, + GTK_TYPE_BOXED, + GTK_TYPE_FOREIGN, + GTK_TYPE_CALLBACK, + GTK_TYPE_ARGS, + + GTK_TYPE_POINTER, + + /* it'd be great if the next two could be removed eventually */ + GTK_TYPE_SIGNAL, + GTK_TYPE_C_CALLBACK, + + GTK_TYPE_OBJECT + +} GtkFundamentalType; + +typedef guint GtkType; + +/* Builtin Types */ + +extern GtkType gtk_type_builtins[]; +#include + +/* General Types */ + +#define GTK_TYPE_MAKE(ft, seqno) (((seqno)<<8)|ft) +#define GTK_FUNDAMENTAL_TYPE(t) ((GtkFundamentalType)((t)&0xFF)) +#define GTK_TYPE_SEQNO(t) ((t)>0xFF? (t)>>8:(t)) + +typedef struct _GtkArg GtkArg; +typedef struct _GtkObject GtkObject; /* forward declaration of object type */ +typedef struct _GtkTypeInfo GtkTypeInfo; + +typedef void (*GtkClassInitFunc) (gpointer klass); +typedef void (*GtkObjectInitFunc) (gpointer object); +typedef void (*GtkArgFunc) (GtkObject *object, GtkArg *arg); +typedef gint (*GtkFunction) (gpointer data); +typedef void (*GtkRemoveFunction) (gpointer data); +typedef void (*GtkCallbackMarshal) (GtkObject *object, + gpointer data, + int n_args, + GtkArg *args); +typedef void (*GtkDestroyNotify) (gpointer data); + +struct _GtkArg +{ + GtkType type; + char *name; + + union { + gchar char_data; + gint int_data; + guint uint_data; + gint bool_data; + glong long_data; + gulong ulong_data; + gfloat float_data; + gchar *string_data; + gpointer pointer_data; + GtkObject *object_data; + struct { + GtkCallbackMarshal marshal; + gpointer data; + GtkDestroyNotify notify; + } callback_data; + struct { + gpointer data; + GtkDestroyNotify notify; + } foreign_data; + struct { + gint n_args; + GtkArg *args; + } args_data; + struct { + GtkFunction f; + gpointer d; + } signal_data; + struct { + GtkFunction func; + gpointer func_data; + } c_callback_data; + } d; +}; + +#define GTK_VALUE_CHAR(a) ((a).d.char_data) +#define GTK_VALUE_BOOL(a) ((a).d.bool_data) +#define GTK_VALUE_INT(a) ((a).d.int_data) +#define GTK_VALUE_UINT(a) ((a).d.uint_data) +#define GTK_VALUE_LONG(a) ((a).d.long_data) +#define GTK_VALUE_ULONG(a) ((a).d.ulong_data) +#define GTK_VALUE_FLOAT(a) ((a).d.float_data) +#define GTK_VALUE_STRING(a) ((a).d.string_data) +#define GTK_VALUE_ENUM(a) ((a).d.int_data) +#define GTK_VALUE_FLAGS(a) ((a).d.int_data) +#define GTK_VALUE_BOXED(a) ((a).d.pointer_data) +#define GTK_VALUE_FOREIGN(a) ((a).d.foreign_data) +#define GTK_VALUE_CALLBACK(a) ((a).d.callback_data) +#define GTK_VALUE_ARGS(a) ((a).d.args_data) +#define GTK_VALUE_OBJECT(a) ((a).d.object_data) +#define GTK_VALUE_POINTER(a) ((a).d.pointer_data) +#define GTK_VALUE_SIGNAL(a) ((a).d.signal_data) +#define GTK_VALUE_C_CALLBACK(a) ((a).d.c_callback_data) + +#define GTK_RETLOC_CHAR(a) ((gchar*)(a).d.pointer_data) +#define GTK_RETLOC_BOOL(a) ((gint*)(a).d.pointer_data) +#define GTK_RETLOC_INT(a) ((gint*)(a).d.pointer_data) +#define GTK_RETLOC_UINT(a) ((guint*)(a).d.pointer_data) +#define GTK_RETLOC_LONG(a) ((glong*)(a).d.pointer_data) +#define GTK_RETLOC_ULONG(a) ((gulong*)(a).d.pointer_data) +#define GTK_RETLOC_FLOAT(a) ((gfloat*)(a).d.pointer_data) +#define GTK_RETLOC_STRING(a) ((gchar**)(a).d.pointer_data) +#define GTK_RETLOC_ENUM(a) ((gint*)(a).d.pointer_data) +#define GTK_RETLOC_FLAGS(a) ((gint*)(a).d.pointer_data) +#define GTK_RETLOC_BOXED(a) ((gpointer*)(a).d.pointer_data) +#define GTK_RETLOC_OBJECT(a) ((GtkObject**)(a).d.pointer_data) +#define GTK_RETLOC_POINTER(a) ((gpointer*)(a).d.pointer_data) + +struct _GtkTypeInfo +{ + gchar *type_name; + guint object_size; + guint class_size; + GtkClassInitFunc class_init_func; + GtkObjectInitFunc object_init_func; + GtkArgFunc arg_func; +}; + + +void gtk_type_init (void); +GtkType gtk_type_unique (guint parent_type, + GtkTypeInfo *type_info); +gchar* gtk_type_name (guint type); +GtkType gtk_type_from_name (const gchar *name); +GtkType gtk_type_parent (GtkType type); +gpointer gtk_type_class (GtkType type); +gpointer gtk_type_new (GtkType type); +void gtk_type_describe_heritage (GtkType type); +void gtk_type_describe_tree (GtkType type, + gint show_size); +gint gtk_type_is_a (GtkType type, + GtkType is_a_type); +void gtk_type_set_arg (GtkObject *object, + GtkType type, + GtkArg *arg); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_TYPE_UTILS_H__ */ diff --git a/gtk/gtkvbbox.c b/gtk/gtkvbbox.c new file mode 100644 index 000000000..4fc867fdf --- /dev/null +++ b/gtk/gtkvbbox.c @@ -0,0 +1,272 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkvbbox.h" + + +static void gtk_vbutton_box_class_init (GtkVButtonBoxClass *klass); +static void gtk_vbutton_box_init (GtkVButtonBox *box); +static void gtk_vbutton_box_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_vbutton_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +static gint default_spacing = 10; +static gint default_layout_style = GTK_BUTTONBOX_EDGE; + +guint +gtk_vbutton_box_get_type () +{ + static guint vbutton_box_type = 0; + + if (!vbutton_box_type) + { + GtkTypeInfo vbutton_box_info = + { + "GtkVButtonBox", + sizeof (GtkVButtonBox), + sizeof (GtkVButtonBoxClass), + (GtkClassInitFunc) gtk_vbutton_box_class_init, + (GtkObjectInitFunc) gtk_vbutton_box_init, + (GtkArgFunc) NULL, + }; + + vbutton_box_type = gtk_type_unique (gtk_button_box_get_type (), &vbutton_box_info); + } + + return vbutton_box_type; +} + +static void +gtk_vbutton_box_class_init (GtkVButtonBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_vbutton_box_size_request; + widget_class->size_allocate = gtk_vbutton_box_size_allocate; +} + +static void +gtk_vbutton_box_init (GtkVButtonBox *vbutton_box) +{ + /* button_box_init has done everything allready */ +} + +GtkWidget* +gtk_vbutton_box_new () +{ + GtkVButtonBox *vbutton_box; + + vbutton_box = gtk_type_new (gtk_vbutton_box_get_type ()); + return GTK_WIDGET (vbutton_box); +} + + + +/* set default value for spacing */ + +void gtk_vbutton_box_set_spacing_default (gint spacing) +{ + default_spacing = spacing; +} + + +/* set default value for layout style */ + +void gtk_vbutton_box_set_layout_default (gint layout) +{ + default_layout_style = layout; +} + +/* get default value for spacing */ + +gint gtk_vbutton_box_get_spacing_default (void) +{ + return default_spacing; +} + + + +/* get default value for layout style */ + +gint gtk_vbutton_box_get_layout_default (void) +{ + return default_layout_style; +} + + + + +static void +gtk_vbutton_box_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBox *box; + GtkButtonBox *bbox; + gint nvis_children; + gint child_width; + gint child_height; + gint spacing; + gint layout; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VBUTTON_BOX (widget)); + g_return_if_fail (requisition != NULL); + + box = GTK_BOX (widget); + bbox = GTK_BUTTON_BOX (widget); + + spacing = bbox->spacing != GTK_BUTTONBOX_DEFAULT + ? bbox->spacing : default_spacing; + layout = bbox->layout_style != GTK_BUTTONBOX_DEFAULT + ? bbox->layout_style : default_layout_style; + + gtk_button_box_child_requisition (widget, + &nvis_children, + &child_width, + &child_height); + + if (nvis_children == 0) + { + requisition->width = 0; + requisition->height = 0; + } + else + { + switch (layout) + { + case GTK_BUTTONBOX_SPREAD: + requisition->height = + nvis_children*child_height + ((nvis_children+1)*spacing); + break; + case GTK_BUTTONBOX_EDGE: + case GTK_BUTTONBOX_START: + case GTK_BUTTONBOX_END: + requisition->height = + nvis_children*child_height + ((nvis_children-1)*spacing); + break; + default: + g_assert_not_reached(); + break; + } + + requisition->width = child_width; + } + + requisition->width += GTK_CONTAINER (box)->border_width * 2; + requisition->height += GTK_CONTAINER (box)->border_width * 2; +} + + + +static void +gtk_vbutton_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkButtonBox *box; + GtkVButtonBox *hbox; + GtkBoxChild *child; + GList *children; + GtkAllocation child_allocation; + gint nvis_children; + gint child_width; + gint child_height; + gint x = 0; + gint y = 0; + gint height; + gint childspace; + gint childspacing = 0; + gint layout; + gint spacing; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VBUTTON_BOX (widget)); + g_return_if_fail (allocation != NULL); + + box = GTK_BUTTON_BOX (widget); + hbox = GTK_VBUTTON_BOX (widget); + spacing = box->spacing != GTK_BUTTONBOX_DEFAULT + ? box->spacing : default_spacing; + layout = box->layout_style != GTK_BUTTONBOX_DEFAULT + ? box->layout_style : default_layout_style; + gtk_button_box_child_requisition (widget, + &nvis_children, + &child_width, + &child_height); + widget->allocation = *allocation; + height = allocation->height - GTK_CONTAINER (box)->border_width*2; + switch (layout) + { + case GTK_BUTTONBOX_SPREAD: + childspacing = (height - (nvis_children*child_height)) / (nvis_children+1); + y = allocation->y + GTK_CONTAINER (box)->border_width + childspacing; + break; + case GTK_BUTTONBOX_EDGE: + if (nvis_children >= 2) + { + childspacing = + (height - (nvis_children*child_height)) / (nvis_children-1); + y = allocation->y + GTK_CONTAINER (box)->border_width; + } + else + { + /* one or zero children, just center */ + childspacing = height; + y = allocation->y + (allocation->height - child_height) / 2; + } + break; + case GTK_BUTTONBOX_START: + childspacing = spacing; + y = allocation->y + GTK_CONTAINER (box)->border_width; + break; + case GTK_BUTTONBOX_END: + childspacing = spacing; + y = allocation->x + allocation->height - child_height * nvis_children + - spacing * (nvis_children-1) + - GTK_CONTAINER (box)->border_width; + break; + default: + g_assert_not_reached(); + break; + } + + + x = allocation->x + (allocation->width - child_width) / 2; + childspace = child_height + childspacing; + + children = GTK_BOX (box)->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + child_allocation.width = child_width; + child_allocation.height = child_height; + child_allocation.x = x; + child_allocation.y = y; + gtk_widget_size_allocate (child->widget, &child_allocation); + y += childspace; + } + } +} + + diff --git a/gtk/gtkvbbox.h b/gtk/gtkvbbox.h new file mode 100644 index 000000000..310553d2a --- /dev/null +++ b/gtk/gtkvbbox.h @@ -0,0 +1,66 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_VBUTTON_BOX_H__ +#define __GTK_VBUTTON_BOX_H__ + + +#include "gtkbbox.h" + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VBUTTON_BOX(obj) GTK_CHECK_CAST (obj, gtk_vbutton_box_get_type (), GtkVButtonBox) +#define GTK_VBUTTON_BOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vbutton_box_get_type (), GtkVButtonBoxClass) +#define GTK_IS_VBUTTON_BOX(obj) GTK_CHECK_TYPE (obj, gtk_vbutton_box_get_type ()) + + +typedef struct _GtkVButtonBox GtkVButtonBox; +typedef struct _GtkVButtonBoxClass GtkVButtonBoxClass; + +struct _GtkVButtonBox +{ + GtkButtonBox button_box; +}; + +struct _GtkVButtonBoxClass +{ + GtkButtonBoxClass parent_class; +}; + + +guint gtk_vbutton_box_get_type (void); +GtkWidget *gtk_vbutton_box_new (void); + +/* buttons can be added by gtk_container_add() */ + +gint gtk_vbutton_box_get_spacing_default (void); +void gtk_vbutton_box_set_spacing_default (gint spacing); + +void gtk_vbutton_box_set_spacing_default (gint spacing); +void gtk_vbutton_box_set_layout_default (gint layout); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VBUTTON_BOX_H__ */ diff --git a/gtk/gtkvbox.c b/gtk/gtkvbox.c new file mode 100644 index 000000000..585e99b87 --- /dev/null +++ b/gtk/gtkvbox.c @@ -0,0 +1,306 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkvbox.h" + + +static void gtk_vbox_class_init (GtkVBoxClass *klass); +static void gtk_vbox_init (GtkVBox *box); +static void gtk_vbox_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_vbox_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + + +guint +gtk_vbox_get_type () +{ + static guint vbox_type = 0; + + if (!vbox_type) + { + GtkTypeInfo vbox_info = + { + "GtkVBox", + sizeof (GtkVBox), + sizeof (GtkVBoxClass), + (GtkClassInitFunc) gtk_vbox_class_init, + (GtkObjectInitFunc) gtk_vbox_init, + (GtkArgFunc) NULL, + }; + + vbox_type = gtk_type_unique (gtk_box_get_type (), &vbox_info); + } + + return vbox_type; +} + +static void +gtk_vbox_class_init (GtkVBoxClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_vbox_size_request; + widget_class->size_allocate = gtk_vbox_size_allocate; +} + +static void +gtk_vbox_init (GtkVBox *vbox) +{ +} + +GtkWidget* +gtk_vbox_new (gint homogeneous, + gint spacing) +{ + GtkVBox *vbox; + + vbox = gtk_type_new (gtk_vbox_get_type ()); + + GTK_BOX (vbox)->spacing = spacing; + GTK_BOX (vbox)->homogeneous = homogeneous ? TRUE : FALSE; + + return GTK_WIDGET (vbox); +} + + +static void +gtk_vbox_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + gint nvis_children; + gint height; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VBOX (widget)); + g_return_if_fail (requisition != NULL); + + box = GTK_BOX (widget); + requisition->width = 0; + requisition->height = 0; + nvis_children = 0; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + gtk_widget_size_request (child->widget, &child->widget->requisition); + + if (box->homogeneous) + { + height = child->widget->requisition.height + child->padding * 2; + requisition->height = MAX (requisition->height, height); + } + else + { + requisition->height += child->widget->requisition.height + child->padding * 2; + } + + requisition->width = MAX (requisition->width, child->widget->requisition.width); + + nvis_children += 1; + } + } + + if (nvis_children > 0) + { + if (box->homogeneous) + requisition->height *= nvis_children; + requisition->height += (nvis_children - 1) * box->spacing; + } + + requisition->width += GTK_CONTAINER (box)->border_width * 2; + requisition->height += GTK_CONTAINER (box)->border_width * 2; +} + +static void +gtk_vbox_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBox *box; + GtkBoxChild *child; + GList *children; + GtkAllocation child_allocation; + gint nvis_children; + gint nexpand_children; + gint child_height; + gint height; + gint extra; + gint y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VBOX (widget)); + g_return_if_fail (allocation != NULL); + + box = GTK_BOX (widget); + widget->allocation = *allocation; + + nvis_children = 0; + nexpand_children = 0; + children = box->children; + + while (children) + { + child = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (child->widget)) + { + nvis_children += 1; + if (child->expand) + nexpand_children += 1; + } + } + + if (nvis_children > 0) + { + if (box->homogeneous) + { + height = (allocation->height - + GTK_CONTAINER (box)->border_width * 2 - + (nvis_children - 1) * box->spacing); + extra = height / nvis_children; + } + else if (nexpand_children > 0) + { + height = allocation->height - widget->requisition.height; + extra = height / nexpand_children; + } + else + { + height = 0; + extra = 0; + } + + y = allocation->y + GTK_CONTAINER (box)->border_width; + child_allocation.x = allocation->x + GTK_CONTAINER (box)->border_width; + child_allocation.width = allocation->width - GTK_CONTAINER (box)->border_width * 2; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget)) + { + if (box->homogeneous) + { + if (nvis_children == 1) + child_height = height; + else + child_height = extra; + + nvis_children -= 1; + height -= extra; + } + else + { + child_height = child->widget->requisition.height + child->padding * 2; + + if (child->expand) + { + if (nexpand_children == 1) + child_height += height; + else + child_height += extra; + + nexpand_children -= 1; + height -= extra; + } + } + + if (child->fill) + { + child_allocation.height = child_height - child->padding * 2; + child_allocation.y = y + child->padding; + } + else + { + child_allocation.height = child->widget->requisition.height; + child_allocation.y = y + (child_height - child_allocation.height) / 2; + } + + gtk_widget_size_allocate (child->widget, &child_allocation); + + y += child_height + box->spacing; + } + } + + y = allocation->y + allocation->height - GTK_CONTAINER (box)->border_width; + + children = box->children; + while (children) + { + child = children->data; + children = children->next; + + if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget)) + { + if (box->homogeneous) + { + if (nvis_children == 1) + child_height = height; + else + child_height = extra; + + nvis_children -= 1; + height -= extra; + } + else + { + child_height = child->widget->requisition.height + child->padding * 2; + + if (child->expand) + { + if (nexpand_children == 1) + child_height += height; + else + child_height += extra; + + nexpand_children -= 1; + height -= extra; + } + } + + if (child->fill) + { + child_allocation.height = child_height - child->padding * 2; + child_allocation.y = y + child->padding - child_height; + } + else + { + child_allocation.height = child->widget->requisition.height; + child_allocation.y = y + (child_height - child_allocation.height) / 2 - child_height; + } + + gtk_widget_size_allocate (child->widget, &child_allocation); + + y -= (child_height + box->spacing); + } + } + } +} diff --git a/gtk/gtkvbox.h b/gtk/gtkvbox.h new file mode 100644 index 000000000..aad32c914 --- /dev/null +++ b/gtk/gtkvbox.h @@ -0,0 +1,60 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_VBOX_H__ +#define __GTK_VBOX_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VBOX(obj) GTK_CHECK_CAST (obj, gtk_vbox_get_type (), GtkVBox) +#define GTK_VBOX_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vbox_get_type (), GtkVBoxClass) +#define GTK_IS_VBOX(obj) GTK_CHECK_TYPE (obj, gtk_vbox_get_type ()) + + +typedef struct _GtkVBox GtkVBox; +typedef struct _GtkVBoxClass GtkVBoxClass; + +struct _GtkVBox +{ + GtkBox box; +}; + +struct _GtkVBoxClass +{ + GtkBoxClass parent_class; +}; + + +guint gtk_vbox_get_type (void); +GtkWidget* gtk_vbox_new (gint homogeneous, + gint spacing); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VBOX_H__ */ diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c new file mode 100644 index 000000000..dfa00c4b0 --- /dev/null +++ b/gtk/gtkviewport.c @@ -0,0 +1,616 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtksignal.h" +#include "gtkviewport.h" + + +static void gtk_viewport_class_init (GtkViewportClass *klass); +static void gtk_viewport_init (GtkViewport *viewport); +static void gtk_viewport_map (GtkWidget *widget); +static void gtk_viewport_unmap (GtkWidget *widget); +static void gtk_viewport_realize (GtkWidget *widget); +static void gtk_viewport_unrealize (GtkWidget *widget); +static void gtk_viewport_paint (GtkWidget *widget, + GdkRectangle *area); +static void gtk_viewport_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_viewport_expose (GtkWidget *widget, + GdkEventExpose *event); +static void gtk_viewport_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_viewport_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_viewport_need_resize (GtkContainer *container); +static void gtk_viewport_adjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); + + +guint +gtk_viewport_get_type () +{ + static guint viewport_type = 0; + + if (!viewport_type) + { + GtkTypeInfo viewport_info = + { + "GtkViewport", + sizeof (GtkViewport), + sizeof (GtkViewportClass), + (GtkClassInitFunc) gtk_viewport_class_init, + (GtkObjectInitFunc) gtk_viewport_init, + (GtkArgFunc) NULL, + }; + + viewport_type = gtk_type_unique (gtk_bin_get_type (), &viewport_info); + } + + return viewport_type; +} + +static void +gtk_viewport_class_init (GtkViewportClass *class) +{ + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + widget_class->map = gtk_viewport_map; + widget_class->unmap = gtk_viewport_unmap; + widget_class->realize = gtk_viewport_realize; + widget_class->unrealize = gtk_viewport_unrealize; + widget_class->draw = gtk_viewport_draw; + widget_class->expose_event = gtk_viewport_expose; + widget_class->size_request = gtk_viewport_size_request; + widget_class->size_allocate = gtk_viewport_size_allocate; + + container_class->need_resize = gtk_viewport_need_resize; +} + +static void +gtk_viewport_init (GtkViewport *viewport) +{ + GTK_WIDGET_UNSET_FLAGS (viewport, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (viewport, GTK_BASIC); + + viewport->shadow_type = GTK_SHADOW_IN; + viewport->main_window = NULL; + viewport->view_window = NULL; + viewport->hadjustment = NULL; + viewport->vadjustment = NULL; +} + +GtkWidget* +gtk_viewport_new (GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment) +{ + GtkViewport *viewport; + + viewport = gtk_type_new (gtk_viewport_get_type ()); + + if (!hadjustment) + hadjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + if (!vadjustment) + vadjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_viewport_set_hadjustment (viewport, hadjustment); + gtk_viewport_set_vadjustment (viewport, vadjustment); + + return GTK_WIDGET (viewport); +} + +GtkAdjustment* +gtk_viewport_get_hadjustment (GtkViewport *viewport) +{ + g_return_val_if_fail (viewport != NULL, NULL); + g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL); + + return viewport->hadjustment; +} + +GtkAdjustment* +gtk_viewport_get_vadjustment (GtkViewport *viewport) +{ + g_return_val_if_fail (viewport != NULL, NULL); + g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL); + + return viewport->vadjustment; +} + +void +gtk_viewport_set_hadjustment (GtkViewport *viewport, + GtkAdjustment *adjustment) +{ + g_return_if_fail (viewport != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (viewport)); + g_return_if_fail (adjustment != NULL); + + if (viewport->hadjustment) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->hadjustment), (gpointer) viewport); + gtk_object_unref (GTK_OBJECT (viewport->hadjustment)); + } + + viewport->hadjustment = adjustment; + gtk_object_ref (GTK_OBJECT (viewport->hadjustment)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) gtk_viewport_adjustment_changed, + (gpointer) viewport); + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) gtk_viewport_adjustment_value_changed, + (gpointer) viewport); + + gtk_viewport_adjustment_changed (adjustment, (gpointer) viewport); +} + +void +gtk_viewport_set_vadjustment (GtkViewport *viewport, + GtkAdjustment *adjustment) +{ + g_return_if_fail (viewport != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (viewport)); + g_return_if_fail (adjustment != NULL); + + if (viewport->vadjustment) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->vadjustment), (gpointer) viewport); + gtk_object_unref (GTK_OBJECT (viewport->vadjustment)); + } + + viewport->vadjustment = adjustment; + gtk_object_ref (GTK_OBJECT (viewport->vadjustment)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) gtk_viewport_adjustment_changed, + (gpointer) viewport); + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) gtk_viewport_adjustment_value_changed, + (gpointer) viewport); + + gtk_viewport_adjustment_changed (adjustment, (gpointer) viewport); +} + +void +gtk_viewport_set_shadow_type (GtkViewport *viewport, + GtkShadowType type) +{ + g_return_if_fail (viewport != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (viewport)); + + if ((GtkShadowType) viewport->shadow_type != type) + { + viewport->shadow_type = type; + + if (GTK_WIDGET_VISIBLE (viewport)) + { + gtk_widget_size_allocate (GTK_WIDGET (viewport), &(GTK_WIDGET (viewport)->allocation)); + gtk_widget_queue_draw (GTK_WIDGET (viewport)); + } + } +} + + +static void +gtk_viewport_map (GtkWidget *widget) +{ + GtkViewport *viewport; + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + gdk_window_show (viewport->main_window); + + if (bin->child && + GTK_WIDGET_VISIBLE (bin->child) && + !GTK_WIDGET_MAPPED (bin->child)) + gtk_widget_map (bin->child); +} + +static void +gtk_viewport_unmap (GtkWidget *widget) +{ + GtkViewport *viewport; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + viewport = GTK_VIEWPORT (widget); + + gdk_window_hide (viewport->main_window); +} + +static void +gtk_viewport_realize (GtkWidget *widget) +{ + GtkViewport *viewport; + GdkWindowAttr attributes; + GtkRequisition *child_requisition; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + + viewport = GTK_VIEWPORT (widget); + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.x = widget->allocation.x + GTK_CONTAINER (widget)->border_width; + attributes.y = widget->allocation.y + GTK_CONTAINER (widget)->border_width; + attributes.width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2; + attributes.height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + viewport->main_window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (viewport->main_window, viewport); + + attributes.x += widget->style->klass->xthickness; + attributes.y += widget->style->klass->ythickness; + attributes.width -= widget->style->klass->xthickness * 2; + attributes.height -= widget->style->klass->ythickness * 2; + + viewport->view_window = gdk_window_new (viewport->main_window, &attributes, attributes_mask); + gdk_window_set_user_data (viewport->view_window, viewport); + + attributes.x = 0; + attributes.y = 0; + + if (GTK_BIN (viewport)->child) + { + child_requisition = >K_WIDGET (GTK_BIN (viewport)->child)->requisition; + attributes.width = child_requisition->width; + attributes.height = child_requisition->height; + } + + widget->window = gdk_window_new (viewport->view_window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, viewport); + + widget->style = gtk_style_attach (widget->style, viewport->main_window); + gtk_style_set_background (widget->style, viewport->main_window, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + + gdk_window_show (widget->window); + gdk_window_show (viewport->view_window); +} + +static void +gtk_viewport_unrealize (GtkWidget *widget) +{ + GtkViewport *viewport; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + + viewport = GTK_VIEWPORT (widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + + gdk_window_destroy (widget->window); + gdk_window_destroy (viewport->view_window); + gdk_window_destroy (viewport->main_window); + + widget->window = NULL; + viewport->view_window = NULL; + viewport->main_window = NULL; +} + +static void +gtk_viewport_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkViewport *viewport; + GtkStateType state; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + viewport = GTK_VIEWPORT (widget); + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + x = GTK_CONTAINER (viewport)->border_width; + y = GTK_CONTAINER (viewport)->border_width; + + gtk_draw_shadow (widget->style, viewport->main_window, + GTK_STATE_NORMAL, viewport->shadow_type, + 0, 0, -1, -1); + } +} + +static void +gtk_viewport_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkViewport *viewport; + GtkBin *bin; + GdkRectangle tmp_area; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + gtk_viewport_paint (widget, area); + + if (bin->child) + { + tmp_area = *area; + tmp_area.x += viewport->hadjustment->value; + tmp_area.y += viewport->vadjustment->value; + + if (gtk_widget_intersect (bin->child, &tmp_area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } + } +} + +static gint +gtk_viewport_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkViewport *viewport; + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VIEWPORT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + if (event->window == viewport->main_window) + gtk_viewport_paint (widget, &event->area); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static void +gtk_viewport_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkViewport *viewport; + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (requisition != NULL); + + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->xthickness) * 2 + 5; + + requisition->height = (GTK_CONTAINER (widget)->border_width * 2 + + GTK_WIDGET (widget)->style->klass->ythickness) * 2 + 5; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + gtk_widget_size_request (bin->child, &bin->child->requisition); +} + +static void +gtk_viewport_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkViewport *viewport; + GtkBin *bin; + GtkAllocation child_allocation; + gint hval, vval; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + child_allocation.x = GTK_WIDGET (viewport)->style->klass->xthickness; + child_allocation.width = allocation->width - child_allocation.x * 2; + + child_allocation.y = GTK_WIDGET (viewport)->style->klass->ythickness; + child_allocation.height = allocation->height - child_allocation.y * 2; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (viewport->main_window, + allocation->x + GTK_CONTAINER (viewport)->border_width, + allocation->y + GTK_CONTAINER (viewport)->border_width, + allocation->width - GTK_CONTAINER (viewport)->border_width * 2, + allocation->height - GTK_CONTAINER (viewport)->border_width * 2); + + gdk_window_move_resize (viewport->view_window, + child_allocation.x, + child_allocation.y, + child_allocation.width, + child_allocation.height); + } + + viewport->hadjustment->page_size = child_allocation.width; + viewport->hadjustment->page_increment = viewport->hadjustment->page_size / 2; + viewport->hadjustment->step_increment = 10; + + viewport->vadjustment->page_size = child_allocation.height; + viewport->vadjustment->page_increment = viewport->vadjustment->page_size / 2; + viewport->vadjustment->step_increment = 10; + + hval = viewport->hadjustment->value; + vval = viewport->vadjustment->value; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + viewport->hadjustment->lower = 0; + viewport->hadjustment->upper = MAX (bin->child->requisition.width, + child_allocation.width); + + hval = CLAMP (hval, 0, + viewport->hadjustment->upper - + viewport->hadjustment->page_size); + + viewport->vadjustment->lower = 0; + viewport->vadjustment->upper = MAX (bin->child->requisition.height, + child_allocation.height); + + vval = CLAMP (vval, 0, + viewport->vadjustment->upper - + viewport->vadjustment->page_size); + } + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + child_allocation.x = 0; + child_allocation.y = 0; + + child_allocation.width = viewport->hadjustment->upper; + child_allocation.height = viewport->vadjustment->upper; + + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + gdk_window_resize (widget->window, + child_allocation.width, + child_allocation.height); + + child_allocation.x = 0; + child_allocation.y = 0; + gtk_widget_size_allocate (bin->child, &child_allocation); + } + + gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "changed"); + gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "changed"); + if (viewport->hadjustment->value != hval) + { + viewport->hadjustment->value = hval; + gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "value_changed"); + } + if (viewport->vadjustment->value != vval) + { + viewport->vadjustment->value = vval; + gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "value_changed"); + } +} + +static gint +gtk_viewport_need_resize (GtkContainer *container) +{ + GtkBin *bin; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VIEWPORT (container), FALSE); + + if (GTK_WIDGET_REALIZED (container)) + { + bin = GTK_BIN (container); + + gtk_widget_size_request (bin->child, &bin->child->requisition); + + gtk_widget_size_allocate (GTK_WIDGET (container), + &(GTK_WIDGET (container)->allocation)); + } + + return FALSE; +} + +static void +gtk_viewport_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkViewport *viewport; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (data)); + + viewport = GTK_VIEWPORT (data); +} + +static void +gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkViewport *viewport; + GtkBin *bin; + GtkAllocation child_allocation; + gint width, height; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (data)); + + viewport = GTK_VIEWPORT (data); + bin = GTK_BIN (data); + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gdk_window_get_size (viewport->view_window, &width, &height); + + child_allocation.x = 0; + child_allocation.y = 0; + + if (viewport->hadjustment->lower != (viewport->hadjustment->upper - + viewport->hadjustment->page_size)) + child_allocation.x = viewport->hadjustment->lower - viewport->hadjustment->value; + + if (viewport->vadjustment->lower != (viewport->vadjustment->upper - + viewport->vadjustment->page_size)) + child_allocation.y = viewport->vadjustment->lower - viewport->vadjustment->value; + + if (GTK_WIDGET_REALIZED (viewport)) + gdk_window_move (GTK_WIDGET (viewport)->window, + child_allocation.x, + child_allocation.y); + } +} diff --git a/gtk/gtkviewport.h b/gtk/gtkviewport.h new file mode 100644 index 000000000..9af4e8720 --- /dev/null +++ b/gtk/gtkviewport.h @@ -0,0 +1,75 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_VIEWPORT_H__ +#define __GTK_VIEWPORT_H__ + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VIEWPORT(obj) GTK_CHECK_CAST (obj, gtk_viewport_get_type (), GtkViewport) +#define GTK_VIEWPORT_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_viewport_get_type (), GtkViewportClass) +#define GTK_IS_VIEWPORT(obj) GTK_CHECK_TYPE (obj, gtk_viewport_get_type ()) + + +typedef struct _GtkViewport GtkViewport; +typedef struct _GtkViewportClass GtkViewportClass; + +struct _GtkViewport +{ + GtkBin bin; + + gint shadow_type; + GdkWindow *main_window; + GdkWindow *view_window; + GtkAdjustment *hadjustment; + GtkAdjustment *vadjustment; +}; + +struct _GtkViewportClass +{ + GtkBinClass parent_class; +}; + + +guint gtk_viewport_get_type (void); +GtkWidget* gtk_viewport_new (GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment); +GtkAdjustment* gtk_viewport_get_hadjustment (GtkViewport *viewport); +GtkAdjustment* gtk_viewport_get_vadjustment (GtkViewport *viewport); +void gtk_viewport_set_hadjustment (GtkViewport *viewport, + GtkAdjustment *adjustment); +void gtk_viewport_set_vadjustment (GtkViewport *viewport, + GtkAdjustment *adjustment); +void gtk_viewport_set_shadow_type (GtkViewport *viewport, + GtkShadowType type); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VIEWPORT_H__ */ diff --git a/gtk/gtkvpaned.c b/gtk/gtkvpaned.c new file mode 100644 index 000000000..2dae03209 --- /dev/null +++ b/gtk/gtkvpaned.c @@ -0,0 +1,356 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkvpaned.h" +#include "gtkmain.h" +#include "gtksignal.h" + +static void gtk_vpaned_class_init (GtkVPanedClass *klass); +static void gtk_vpaned_init (GtkVPaned *vpaned); +static void gtk_vpaned_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_vpaned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_vpaned_draw (GtkWidget *widget, + GdkRectangle *area); +static void gtk_vpaned_xor_line (GtkPaned *paned); +static gint gtk_vpaned_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_vpaned_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_vpaned_motion (GtkWidget *widget, + GdkEventMotion *event); + +guint +gtk_vpaned_get_type () +{ + static guint vpaned_type = 0; + + if (!vpaned_type) + { + GtkTypeInfo vpaned_info = + { + "GtkVPaned", + sizeof (GtkVPaned), + sizeof (GtkVPanedClass), + (GtkClassInitFunc) gtk_vpaned_class_init, + (GtkObjectInitFunc) gtk_vpaned_init, + (GtkArgFunc) NULL, + }; + + vpaned_type = gtk_type_unique (gtk_paned_get_type (), &vpaned_info); + } + + return vpaned_type; +} + +static void +gtk_vpaned_class_init (GtkVPanedClass *class) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) class; + + widget_class->size_request = gtk_vpaned_size_request; + widget_class->size_allocate = gtk_vpaned_size_allocate; + widget_class->draw = gtk_vpaned_draw; + widget_class->button_press_event = gtk_vpaned_button_press; + widget_class->button_release_event = gtk_vpaned_button_release; + widget_class->motion_notify_event = gtk_vpaned_motion; +} + +static void +gtk_vpaned_init (GtkVPaned *vpaned) +{ +} + +GtkWidget* +gtk_vpaned_new () +{ + GtkVPaned *vpaned; + + vpaned = gtk_type_new (gtk_vpaned_get_type ()); + + return GTK_WIDGET (vpaned); +} + +static void +gtk_vpaned_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkPaned *paned; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VPANED (widget)); + g_return_if_fail (requisition != NULL); + + paned = GTK_PANED (widget); + requisition->width = 0; + requisition->height = 0; + + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + { + gtk_widget_size_request (paned->child1, &paned->child1->requisition); + + requisition->height = paned->child1->requisition.height; + requisition->width = paned->child1->requisition.width; + } + + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + { + gtk_widget_size_request (paned->child2, &paned->child2->requisition); + + requisition->width = MAX (requisition->width, + paned->child2->requisition.width); + requisition->height += paned->child2->requisition.height; + } + + requisition->height += GTK_CONTAINER (paned)->border_width * 2 + paned->gutter_size; + requisition->width += GTK_CONTAINER (paned)->border_width * 2; +} + +static void +gtk_vpaned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkPaned *paned; + GtkAllocation child1_allocation; + GtkAllocation child2_allocation; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VPANED (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + + paned = GTK_PANED (widget); + border_width = GTK_CONTAINER (paned)->border_width; + + if (!paned->position_set) + { + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + paned->child1_size = paned->child1->requisition.height; + else + paned->child1_size = 0; + } + + /* Move the handle first so we don't get extra expose events */ + + paned->handle_xpos = allocation->x + allocation->width - border_width - 2 * paned->handle_size; + paned->handle_ypos = allocation->y + paned->child1_size + border_width + paned->gutter_size / 2 - paned->handle_size / 2; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move (paned->handle, paned->handle_xpos, paned->handle_ypos); + gdk_window_raise (paned->handle); + } + + if (GTK_WIDGET_MAPPED (widget)) + { + gdk_window_clear_area (widget->window, + paned->groove_rectangle.x, + paned->groove_rectangle.y, + paned->groove_rectangle.width, + paned->groove_rectangle.height); + } + + child1_allocation.width = child2_allocation.width = allocation->width - border_width * 2; + child1_allocation.height = paned->child1_size; + child1_allocation.x = child2_allocation.x = allocation->x + border_width; + child1_allocation.y = allocation->y + border_width; + + paned->groove_rectangle.y = child1_allocation.y + + child1_allocation.height + paned->gutter_size / 2 - 1; + paned->groove_rectangle.x = allocation->x; + paned->groove_rectangle.height = 2; + paned->groove_rectangle.width = allocation->width; + + child2_allocation.y = paned->groove_rectangle.y + paned->gutter_size / 2 + 1; + child2_allocation.height = allocation->y + allocation->height + - child2_allocation.y - border_width; + + /* Now allocate the childen, making sure, when resizing not to + * overlap the windows */ + if (GTK_WIDGET_MAPPED(widget) && + paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) && + paned->child1->allocation.height < child1_allocation.height) + { + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + gtk_widget_size_allocate (paned->child2, &child2_allocation); + gtk_widget_size_allocate (paned->child1, &child1_allocation); + } + else + { + if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1)) + gtk_widget_size_allocate (paned->child1, &child1_allocation); + if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2)) + gtk_widget_size_allocate (paned->child2, &child2_allocation); + } +} + +static void +gtk_vpaned_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkPaned *paned; + GdkRectangle child_area; + guint16 border_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_PANED (widget)); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)) + { + paned = GTK_PANED (widget); + border_width = GTK_CONTAINER (paned)->border_width; + + if (paned->child1 && + gtk_widget_intersect (paned->child1, area, &child_area)) + gtk_widget_draw (paned->child1, &child_area); + if (paned->child2 && + gtk_widget_intersect (paned->child2, area, &child_area)) + gtk_widget_draw (paned->child2, &child_area); + + gdk_draw_line (widget->window, + widget->style->dark_gc[widget->state], + widget->allocation.x, + widget->allocation.y + border_width + paned->child1_size + paned->gutter_size / 2 - 1, + widget->allocation.x + widget->allocation.width - 1, + widget->allocation.y + border_width + paned->child1_size + paned->gutter_size / 2 - 1); + gdk_draw_line (widget->window, + widget->style->light_gc[widget->state], + widget->allocation.x, + widget->allocation.y + border_width + paned->child1_size + paned->gutter_size / 2, + widget->allocation.x + widget->allocation.width - 1, + widget->allocation.y + border_width + paned->child1_size + paned->gutter_size / 2); + } +} + +static void +gtk_vpaned_xor_line (GtkPaned *paned) +{ + GtkWidget *widget; + GdkGCValues values; + guint16 ypos; + + widget = GTK_WIDGET(paned); + + if (!paned->xor_gc) + { + values.foreground = widget->style->white; + values.function = GDK_XOR; + values.subwindow_mode = GDK_INCLUDE_INFERIORS; + paned->xor_gc = gdk_gc_new_with_values (widget->window, + &values, + GDK_GC_FOREGROUND | + GDK_GC_FUNCTION | + GDK_GC_SUBWINDOW); + } + + ypos = widget->allocation.y + paned->child1_size + + GTK_CONTAINER (paned)->border_width + paned->gutter_size / 2; + + gdk_draw_line (widget->window, paned->xor_gc, + widget->allocation.x, + ypos, + widget->allocation.x + widget->allocation.width - 1, + ypos); +} + +static gint +gtk_vpaned_button_press (GtkWidget *widget, GdkEventButton *event) +{ + GtkPaned *paned; + + g_return_val_if_fail (widget != NULL,FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget),FALSE); + + paned = GTK_PANED (widget); + + if (!paned->in_drag && + (event->window == paned->handle) && (event->button == 1)) + { + paned->in_drag = TRUE; + /* We need a server grab here, not gtk_grab_add(), since + * we don't want to pass events on to the widget's children */ + gdk_pointer_grab (paned->handle, FALSE, + GDK_POINTER_MOTION_HINT_MASK + | GDK_BUTTON1_MOTION_MASK + | GDK_BUTTON_RELEASE_MASK, + NULL, NULL, event->time); + paned->child1_size += event->y - paned->handle_size / 2; + paned->child1_size = CLAMP (paned->child1_size, 0, + widget->allocation.height - paned->gutter_size + - 2 * GTK_CONTAINER (paned)->border_width); + gtk_vpaned_xor_line (paned); + } + + return TRUE; +} + +static gint +gtk_vpaned_button_release (GtkWidget *widget, GdkEventButton *event) +{ + GtkPaned *paned; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget), FALSE); + + paned = GTK_PANED (widget); + + if (paned->in_drag && (event->button == 1)) + { + gtk_vpaned_xor_line (paned); + paned->in_drag = FALSE; + paned->position_set = TRUE; + gdk_pointer_ungrab (event->time); + gtk_widget_queue_resize (GTK_WIDGET (paned)); + } + + return TRUE; +} + +static gint +gtk_vpaned_motion (GtkWidget *widget, GdkEventMotion *event) +{ + GtkPaned *paned; + gint y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_PANED (widget), FALSE); + + if (event->is_hint || event->window != widget->window) + gtk_widget_get_pointer(widget, NULL, &y); + else + y = event->y; + + paned = GTK_PANED (widget); + + if (paned->in_drag) + { + gtk_vpaned_xor_line (paned); + paned->child1_size = y - GTK_CONTAINER (paned)->border_width - + paned->gutter_size/2; + paned->child1_size = CLAMP (paned->child1_size, 0, + widget->allocation.height - paned->gutter_size + - 2 * GTK_CONTAINER (paned)->border_width); + gtk_vpaned_xor_line (paned); + } + + return TRUE; +} diff --git a/gtk/gtkvpaned.h b/gtk/gtkvpaned.h new file mode 100644 index 000000000..9e66c1255 --- /dev/null +++ b/gtk/gtkvpaned.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_VPANED_H__ +#define __GTK_VPANED_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VPANED(obj) GTK_CHECK_CAST (obj, gtk_vpaned_get_type (), GtkVPaned) +#define GTK_VPANED_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vpaned_get_type (), GtkVPanedClass) +#define GTK_IS_VPANED(obj) GTK_CHECK_TYPE (obj, gtk_vpaned_get_type ()) + + +typedef struct _GtkVPaned GtkVPaned; +typedef struct _GtkVPanedClass GtkVPanedClass; + +struct _GtkVPaned +{ + GtkPaned paned; +}; + +struct _GtkVPanedClass +{ + GtkPanedClass parent_class; +}; + + +guint gtk_vpaned_get_type (void); +GtkWidget* gtk_vpaned_new (); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VPANED_H__ */ diff --git a/gtk/gtkvruler.c b/gtk/gtkvruler.c new file mode 100644 index 000000000..43fe16bb7 --- /dev/null +++ b/gtk/gtkvruler.c @@ -0,0 +1,282 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "gtkvruler.h" + + +#define RULER_WIDTH 14 +#define MINIMUM_INCR 5 +#define MAXIMUM_SUBDIVIDE 5 +#define MAXIMUM_SCALES 10 + +#define ROUND(x) ((int) ((x) + 0.5)) + + +static void gtk_vruler_class_init (GtkVRulerClass *klass); +static void gtk_vruler_init (GtkVRuler *vruler); +static gint gtk_vruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static void gtk_vruler_draw_ticks (GtkRuler *ruler); +static void gtk_vruler_draw_pos (GtkRuler *ruler); + + +guint +gtk_vruler_get_type () +{ + static guint vruler_type = 0; + + if (!vruler_type) + { + GtkTypeInfo vruler_info = + { + "GtkVRuler", + sizeof (GtkVRuler), + sizeof (GtkVRulerClass), + (GtkClassInitFunc) gtk_vruler_class_init, + (GtkObjectInitFunc) gtk_vruler_init, + (GtkArgFunc) NULL, + }; + + vruler_type = gtk_type_unique (gtk_ruler_get_type (), &vruler_info); + } + + return vruler_type; +} + +static void +gtk_vruler_class_init (GtkVRulerClass *klass) +{ + GtkWidgetClass *widget_class; + GtkRulerClass *ruler_class; + + widget_class = (GtkWidgetClass*) klass; + ruler_class = (GtkRulerClass*) klass; + + widget_class->motion_notify_event = gtk_vruler_motion_notify; + + ruler_class->draw_ticks = gtk_vruler_draw_ticks; + ruler_class->draw_pos = gtk_vruler_draw_pos; +} + +static void +gtk_vruler_init (GtkVRuler *vruler) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (vruler); + widget->requisition.width = widget->style->klass->xthickness * 2 + RULER_WIDTH; + widget->requisition.height = widget->style->klass->ythickness * 2 + 1; +} + +GtkWidget* +gtk_vruler_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_vruler_get_type ())); +} + + +static gint +gtk_vruler_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkRuler *ruler; + gint y; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VRULER (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + ruler = GTK_RULER (widget); + + if (event->is_hint) + gdk_window_get_pointer (widget->window, NULL, &y, NULL); + else + y = event->y; + + ruler->position = ruler->lower + ((ruler->upper - ruler->lower) * y) / widget->allocation.height; + + /* Make sure the ruler has been allocated already */ + if (ruler->backing_store != NULL) + gtk_ruler_draw_pos (ruler); + + return FALSE; +} + +static void +gtk_vruler_draw_ticks (GtkRuler *ruler) +{ + GtkWidget *widget; + GdkGC *gc; + gint i, j; + gint width, height; + gint xthickness; + gint ythickness; + gint length; + gfloat subd_incr; + gfloat step_incr; + gfloat increment; + gfloat start, end, cur; + gchar unit_str[12]; + gchar digit_str[2] = { '\0', '\0' }; + gint text_height; + gint digit_height; + gint pos; + gint scale; + + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_VRULER (ruler)); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + widget = GTK_WIDGET (ruler); + + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + xthickness = widget->style->klass->xthickness; + ythickness = widget->style->klass->ythickness; + digit_height = widget->style->font->ascent; + + width = widget->allocation.height; + height = widget->allocation.width - ythickness * 2; + gdk_draw_line (ruler->backing_store, gc, + height + xthickness, + ythickness, + height + xthickness, + widget->allocation.height - ythickness); + + if ((ruler->upper - ruler->lower) == 0) + return; + + increment = (gfloat) width * ruler->metric->pixels_per_unit / (ruler->upper - ruler->lower); + + /* determine the scale + * use the maximum extents of the ruler to determine the largest possible + * number to be displayed. calculate the height in pixels of this displayed + * text as for the vertical ruler case. use this height to find a scale + * which leaves sufficient room for drawing the ruler. + */ + scale = ceil (ruler->max_size / ruler->metric->pixels_per_unit); + sprintf (unit_str, "%d", scale); + text_height = strlen (unit_str) * digit_height + 1; + + for (scale = 0; scale < MAXIMUM_SCALES; scale++) + if (ruler->metric->ruler_scale[scale] * increment > 2 * text_height) + break; + + if (scale == MAXIMUM_SCALES) + scale = MAXIMUM_SCALES - 1; + + for (i = 0; i < MAXIMUM_SUBDIVIDE; i++) + { + subd_incr = (gfloat) ruler->metric->ruler_scale[scale] / (gfloat) ruler->metric->subdivide[i]; + step_incr = subd_incr * increment; + if (step_incr <= MINIMUM_INCR) + break; + + start = floor ((ruler->lower / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr; + end = ceil ((ruler->upper / ruler->metric->pixels_per_unit) / subd_incr) * subd_incr; + + length = height / (i + 1) - 1; + + cur = start; + while (cur <= end) + { + pos = ROUND ((cur - (ruler->lower / ruler->metric->pixels_per_unit)) * increment); + + gdk_draw_line (ruler->backing_store, gc, + height + xthickness - length, + pos, + height + xthickness, + pos); + + if (i == 0) + { + sprintf (unit_str, "%d", (int) cur); + for (j = 0; j < (int) strlen (unit_str); j++) + { + digit_str[0] = unit_str[j]; + gdk_draw_string (ruler->backing_store, widget->style->font, gc, + xthickness + 1, + pos + digit_height * (j + 1) + 1, + digit_str); + } + } + + cur += subd_incr; + } + } + } +} + +static void +gtk_vruler_draw_pos (GtkRuler *ruler) +{ + GtkWidget *widget; + GdkGC *gc; + int i; + gint x, y; + gint width, height; + gint bs_width, bs_height; + gint xthickness; + gint ythickness; + gfloat increment; + + g_return_if_fail (ruler != NULL); + g_return_if_fail (GTK_IS_VRULER (ruler)); + + if (GTK_WIDGET_DRAWABLE (ruler)) + { + widget = GTK_WIDGET (ruler); + + gc = widget->style->fg_gc[GTK_STATE_NORMAL]; + xthickness = widget->style->klass->xthickness; + ythickness = widget->style->klass->ythickness; + width = widget->allocation.width - xthickness * 2; + height = widget->allocation.height; + + bs_height = width / 2; + bs_height |= 1; /* make sure it's odd */ + bs_width = bs_height / 2 + 1; + + if ((bs_width > 0) && (bs_height > 0)) + { + /* If a backing store exists, restore the ruler */ + if (ruler->backing_store && ruler->non_gr_exp_gc) + gdk_draw_pixmap (ruler->widget.window, + ruler->non_gr_exp_gc, + ruler->backing_store, + ruler->xsrc, ruler->ysrc, + ruler->xsrc, ruler->ysrc, + bs_width, bs_height); + + increment = (gfloat) height / (ruler->upper - ruler->lower); + + x = (width + bs_width) / 2 + xthickness; + y = ROUND ((ruler->position - ruler->lower) * increment) + (ythickness - bs_height) / 2 - 1; + + for (i = 0; i < bs_width; i++) + gdk_draw_line (widget->window, gc, + x + i, y + i, + x + i, y + bs_height - 1 - i); + + ruler->xsrc = x; + ruler->ysrc = y; + } + } +} diff --git a/gtk/gtkvruler.h b/gtk/gtkvruler.h new file mode 100644 index 000000000..22bef7164 --- /dev/null +++ b/gtk/gtkvruler.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_VRULER_H__ +#define __GTK_VRULER_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VRULER(obj) GTK_CHECK_CAST (obj, gtk_vruler_get_type (), GtkVRuler) +#define GTK_VRULER_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vruler_get_type (), GtkVRulerClass) +#define GTK_IS_VRULER(obj) GTK_CHECK_TYPE (obj, gtk_vruler_get_type ()) + + +typedef struct _GtkVRuler GtkVRuler; +typedef struct _GtkVRulerClass GtkVRulerClass; + +struct _GtkVRuler +{ + GtkRuler ruler; +}; + +struct _GtkVRulerClass +{ + GtkRulerClass parent_class; +}; + + +guint gtk_vruler_get_type (void); +GtkWidget* gtk_vruler_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VRULER_H__ */ diff --git a/gtk/gtkvscale.c b/gtk/gtkvscale.c new file mode 100644 index 000000000..9c2e3058f --- /dev/null +++ b/gtk/gtkvscale.c @@ -0,0 +1,441 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "gtkvscale.h" +#include "gtksignal.h" +#include "gdk/gdkkeysyms.h" + + +#define SCALE_CLASS(w) GTK_SCALE_CLASS (GTK_OBJECT (w)->klass) +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_vscale_class_init (GtkVScaleClass *klass); +static void gtk_vscale_init (GtkVScale *vscale); +static void gtk_vscale_realize (GtkWidget *widget); +static void gtk_vscale_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_vscale_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_vscale_pos_trough (GtkVScale *vscale, + gint *x, + gint *y, + gint *w, + gint *h); +static void gtk_vscale_draw_slider (GtkRange *range); +static void gtk_vscale_draw_value (GtkScale *scale); +static gint gtk_vscale_trough_keys (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos); + + +guint +gtk_vscale_get_type () +{ + static guint vscale_type = 0; + + if (!vscale_type) + { + GtkTypeInfo vscale_info = + { + "GtkVScale", + sizeof (GtkVScale), + sizeof (GtkVScaleClass), + (GtkClassInitFunc) gtk_vscale_class_init, + (GtkObjectInitFunc) gtk_vscale_init, + (GtkArgFunc) NULL, + }; + + vscale_type = gtk_type_unique (gtk_scale_get_type (), &vscale_info); + } + + return vscale_type; +} + +static void +gtk_vscale_class_init (GtkVScaleClass *class) +{ + GtkWidgetClass *widget_class; + GtkRangeClass *range_class; + GtkScaleClass *scale_class; + + widget_class = (GtkWidgetClass*) class; + range_class = (GtkRangeClass*) class; + scale_class = (GtkScaleClass*) class; + + widget_class->realize = gtk_vscale_realize; + widget_class->size_request = gtk_vscale_size_request; + widget_class->size_allocate = gtk_vscale_size_allocate; + + range_class->slider_update = gtk_range_default_vslider_update; + range_class->trough_click = gtk_range_default_vtrough_click; + range_class->motion = gtk_range_default_vmotion; + range_class->draw_slider = gtk_vscale_draw_slider; + range_class->trough_keys = gtk_vscale_trough_keys; + + scale_class->draw_value = gtk_vscale_draw_value; +} + +static void +gtk_vscale_init (GtkVScale *vscale) +{ +} + +GtkWidget* +gtk_vscale_new (GtkAdjustment *adjustment) +{ + GtkVScale *vscale; + + vscale = gtk_type_new (gtk_vscale_get_type ()); + + if (!adjustment) + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_range_set_adjustment (GTK_RANGE (vscale), adjustment); + + return GTK_WIDGET (vscale); +} + + +static void +gtk_vscale_realize (GtkWidget *widget) +{ + GtkRange *range; + GdkWindowAttr attributes; + gint attributes_mask; + gint x, y, w, h; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCALE (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + + gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &w, &h); + attributes.x = x; + attributes.y = y; + attributes.width = w; + attributes.height = h; + attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + range->trough = gdk_window_new (widget->window, &attributes, attributes_mask); + + attributes.width = RANGE_CLASS (range)->slider_width; + attributes.height = SCALE_CLASS (range)->slider_length; + attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (widget->window, widget); + gdk_window_set_user_data (range->trough, widget); + gdk_window_set_user_data (range->slider, widget); + + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); + + gtk_range_slider_update (GTK_RANGE (widget)); + + gdk_window_show (range->slider); + gdk_window_show (range->trough); +} + +static void +gtk_vscale_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkScale *scale; + gint value_width; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCALE (widget)); + g_return_if_fail (requisition != NULL); + + scale = GTK_SCALE (widget); + + requisition->width = (RANGE_CLASS (scale)->slider_width + + widget->style->klass->ythickness * 2); + requisition->height = (SCALE_CLASS (scale)->slider_length + + widget->style->klass->xthickness) * 2; + + if (scale->draw_value) + { + value_width = gtk_scale_value_width (scale); + + if ((scale->value_pos == GTK_POS_LEFT) || + (scale->value_pos == GTK_POS_RIGHT)) + { + requisition->width += value_width + SCALE_CLASS (scale)->value_spacing; + if (requisition->height < (widget->style->font->ascent + widget->style->font->descent)) + requisition->height = widget->style->font->ascent + widget->style->font->descent; + } + else if ((scale->value_pos == GTK_POS_TOP) || + (scale->value_pos == GTK_POS_BOTTOM)) + { + if (requisition->width < value_width) + requisition->width = value_width; + requisition->height += widget->style->font->ascent + widget->style->font->descent; + } + } +} + +static void +gtk_vscale_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRange *range; + GtkScale *scale; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCALE (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + range = GTK_RANGE (widget); + scale = GTK_SCALE (widget); + + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &width, &height); + + gdk_window_move_resize (range->trough, x, y, width, height); + gtk_range_slider_update (GTK_RANGE (widget)); + } +} + +static void +gtk_vscale_pos_trough (GtkVScale *vscale, + gint *x, + gint *y, + gint *w, + gint *h) +{ + GtkWidget *widget; + GtkScale *scale; + + g_return_if_fail (vscale != NULL); + g_return_if_fail (GTK_IS_VSCALE (vscale)); + g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL)); + + widget = GTK_WIDGET (vscale); + scale = GTK_SCALE (vscale); + + *w = (RANGE_CLASS (scale)->slider_width + + widget->style->klass->xthickness * 2); + *h = widget->allocation.height; + + if (scale->draw_value) + { + *x = 0; + *y = 0; + + switch (scale->value_pos) + { + case GTK_POS_LEFT: + *x = (gtk_scale_value_width (scale) + + (widget->allocation.width - widget->requisition.width) / 2); + break; + case GTK_POS_RIGHT: + *x = (widget->allocation.width - widget->requisition.width) / 2; + break; + case GTK_POS_TOP: + *x = (widget->allocation.width - *w) / 2; + *y = widget->style->font->ascent + widget->style->font->descent; + *h -= *y; + break; + case GTK_POS_BOTTOM: + *x = (widget->allocation.width - *w) / 2; + *h -= widget->style->font->ascent + widget->style->font->descent; + break; + } + } + else + { + *x = (widget->allocation.width - *w) / 2; + *y = 0; + } + *y += 1; + *h -= 2; +} + +static void +gtk_vscale_draw_slider (GtkRange *range) +{ + GtkStateType state_type; + gint width, height; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_VSCALE (range)); + + if (range->slider) + { + if ((range->in_child == RANGE_CLASS (range)->slider) || + (range->click_child == RANGE_CLASS (range)->slider)) + state_type = GTK_STATE_PRELIGHT; + else + state_type = GTK_STATE_NORMAL; + + gtk_style_set_background (GTK_WIDGET (range)->style, range->slider, state_type); + gdk_window_clear (range->slider); + + gdk_window_get_size (range->slider, &width, &height); + gtk_draw_hline (GTK_WIDGET (range)->style, range->slider, + state_type, 1, width - 2, height / 2); + + gtk_draw_shadow (GTK_WIDGET (range)->style, range->slider, + state_type, GTK_SHADOW_OUT, + 0, 0, -1, -1); + } +} + +static void +gtk_vscale_draw_value (GtkScale *scale) +{ + GtkStateType state_type; + gchar buffer[16]; + gint text_width; + gint width, height; + gint x, y; + + g_return_if_fail (scale != NULL); + g_return_if_fail (GTK_IS_VSCALE (scale)); + + if (scale->draw_value) + { + gdk_window_get_size (GTK_WIDGET (scale)->window, &width, &height); + gdk_window_clear_area (GTK_WIDGET (scale)->window, 1, 1, width - 3, height - 3); + + sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value); + text_width = gdk_string_measure (GTK_WIDGET (scale)->style->font, buffer); + + switch (scale->value_pos) + { + case GTK_POS_LEFT: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL); + gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y); + gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height); + + x -= SCALE_CLASS (scale)->value_spacing + text_width; + y += ((height - + (GTK_WIDGET (scale)->style->font->ascent + + GTK_WIDGET (scale)->style->font->descent)) / 2 + + GTK_WIDGET (scale)->style->font->ascent); + break; + case GTK_POS_RIGHT: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL); + gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y); + gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height); + + x += width + SCALE_CLASS (scale)->value_spacing; + y += ((height - + (GTK_WIDGET (scale)->style->font->ascent + + GTK_WIDGET (scale)->style->font->descent)) / 2 + + GTK_WIDGET (scale)->style->font->ascent); + break; + case GTK_POS_TOP: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); + gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); + + x += (width - text_width) / 2; + y -= GTK_WIDGET (scale)->style->font->descent; + break; + case GTK_POS_BOTTOM: + gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y); + gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL); + gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height); + + x += (width - text_width) / 2; + y += height + GTK_WIDGET (scale)->style->font->ascent; + break; + } + + state_type = GTK_STATE_NORMAL; + if (!GTK_WIDGET_IS_SENSITIVE (scale)) + state_type = GTK_STATE_INSENSITIVE; + + gtk_draw_string (GTK_WIDGET (scale)->style, + GTK_WIDGET (scale)->window, + state_type, x, y, buffer); + } +} + +static gint +gtk_vscale_trough_keys(GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos) +{ + gint return_val = FALSE; + switch (key->keyval) + { + case GDK_Up: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_BACKWARD; + break; + case GDK_Down: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_FORWARD; + break; + case GDK_Page_Up: + return_val = TRUE; + *scroll = GTK_SCROLL_PAGE_BACKWARD; + break; + case GDK_Page_Down: + return_val = TRUE; + *scroll = GTK_SCROLL_PAGE_FORWARD; + break; + case GDK_Home: + return_val = TRUE; + *pos = GTK_TROUGH_START; + break; + case GDK_End: + return_val = TRUE; + *pos = GTK_TROUGH_END; + break; + } + return return_val; +} diff --git a/gtk/gtkvscale.h b/gtk/gtkvscale.h new file mode 100644 index 000000000..75862d389 --- /dev/null +++ b/gtk/gtkvscale.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_VSCALE_H__ +#define __GTK_VSCALE_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GTK_VSCALE(obj) GTK_CHECK_CAST (obj, gtk_vscale_get_type (), GtkVScale) +#define GTK_VSCALE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vscale_get_type (), GtkVScaleClass) +#define GTK_IS_VSCALE(obj) GTK_CHECK_TYPE (obj, gtk_vscale_get_type ()) + + +typedef struct _GtkVScale GtkVScale; +typedef struct _GtkVScaleClass GtkVScaleClass; + +struct _GtkVScale +{ + GtkScale scale; +}; + +struct _GtkVScaleClass +{ + GtkScaleClass parent_class; +}; + + +guint gtk_vscale_get_type (void); +GtkWidget* gtk_vscale_new (GtkAdjustment *adjustment); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VSCALE_H__ */ diff --git a/gtk/gtkvscrollbar.c b/gtk/gtkvscrollbar.c new file mode 100644 index 000000000..87421c7bf --- /dev/null +++ b/gtk/gtkvscrollbar.c @@ -0,0 +1,387 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkvscrollbar.h" +#include "gtksignal.h" +#include "gdk/gdkkeysyms.h" + + +#define EPSILON 0.01 + +#define RANGE_CLASS(w) GTK_RANGE_CLASS (GTK_OBJECT (w)->klass) + + +static void gtk_vscrollbar_class_init (GtkVScrollbarClass *klass); +static void gtk_vscrollbar_init (GtkVScrollbar *vscrollbar); +static void gtk_vscrollbar_realize (GtkWidget *widget); +static void gtk_vscrollbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void gtk_vscrollbar_draw_step_forw (GtkRange *range); +static void gtk_vscrollbar_draw_step_back (GtkRange *range); +static void gtk_vscrollbar_slider_update (GtkRange *range); +static void gtk_vscrollbar_calc_slider_size (GtkVScrollbar *vscrollbar); +static gint gtk_vscrollbar_trough_keys (GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos); + +guint +gtk_vscrollbar_get_type () +{ + static guint vscrollbar_type = 0; + + if (!vscrollbar_type) + { + GtkTypeInfo vscrollbar_info = + { + "GtkVScrollbar", + sizeof (GtkVScrollbar), + sizeof (GtkVScrollbarClass), + (GtkClassInitFunc) gtk_vscrollbar_class_init, + (GtkObjectInitFunc) gtk_vscrollbar_init, + (GtkArgFunc) NULL, + }; + + vscrollbar_type = gtk_type_unique (gtk_scrollbar_get_type (), &vscrollbar_info); + } + + return vscrollbar_type; +} + +static void +gtk_vscrollbar_class_init (GtkVScrollbarClass *klass) +{ + GtkWidgetClass *widget_class; + GtkRangeClass *range_class; + + widget_class = (GtkWidgetClass*) klass; + range_class = (GtkRangeClass*) klass; + + widget_class->realize = gtk_vscrollbar_realize; + widget_class->size_allocate = gtk_vscrollbar_size_allocate; + + range_class->draw_step_forw = gtk_vscrollbar_draw_step_forw; + range_class->draw_step_back = gtk_vscrollbar_draw_step_back; + range_class->slider_update = gtk_vscrollbar_slider_update; + range_class->trough_click = gtk_range_default_vtrough_click; + range_class->trough_keys = gtk_vscrollbar_trough_keys; + range_class->motion = gtk_range_default_vmotion; +} + +static void +gtk_vscrollbar_init (GtkVScrollbar *vscrollbar) +{ + GtkWidget *widget; + GtkRequisition *requisition; + + widget = GTK_WIDGET (vscrollbar); + requisition = &widget->requisition; + + requisition->width = (RANGE_CLASS (widget)->slider_width + + widget->style->klass->xthickness * 2); + requisition->height = (RANGE_CLASS (widget)->min_slider_size + + RANGE_CLASS (widget)->stepper_size + + RANGE_CLASS (widget)->stepper_slider_spacing + + widget->style->klass->ythickness) * 2; +} + +GtkWidget* +gtk_vscrollbar_new (GtkAdjustment *adjustment) +{ + GtkVScrollbar *vscrollbar; + + vscrollbar = gtk_type_new (gtk_vscrollbar_get_type ()); + + if (!adjustment) + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_range_set_adjustment (GTK_RANGE (vscrollbar), adjustment); + + return GTK_WIDGET (vscrollbar); +} + + +static void +gtk_vscrollbar_realize (GtkWidget *widget) +{ + GtkRange *range; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + range = GTK_RANGE (widget); + + attributes.x = widget->allocation.x + (widget->allocation.width - widget->requisition.width) / 2; + attributes.y = widget->allocation.y; + attributes.width = widget->requisition.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + range->trough = widget->window; + + attributes.x = widget->style->klass->xthickness; + attributes.y = widget->style->klass->ythickness; + attributes.width = RANGE_CLASS (widget)->stepper_size; + attributes.height = RANGE_CLASS (widget)->stepper_size; + + range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask); + + attributes.y = (widget->allocation.height - + widget->style->klass->ythickness - + RANGE_CLASS (widget)->stepper_size); + + range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask); + + attributes.x = widget->style->klass->ythickness; + attributes.y = 0; + attributes.width = RANGE_CLASS (widget)->slider_width; + attributes.height = RANGE_CLASS (widget)->min_slider_size; + attributes.event_mask |= (GDK_BUTTON_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK); + + range->slider = gdk_window_new (range->trough, &attributes, attributes_mask); + + gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (widget)); + gtk_range_slider_update (GTK_RANGE (widget)); + + widget->style = gtk_style_attach (widget->style, widget->window); + + gdk_window_set_user_data (range->trough, widget); + gdk_window_set_user_data (range->slider, widget); + gdk_window_set_user_data (range->step_forw, widget); + gdk_window_set_user_data (range->step_back, widget); + + gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE); + gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE); + + gdk_window_show (range->slider); + gdk_window_show (range->step_forw); + gdk_window_show (range->step_back); +} + +static void +gtk_vscrollbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkRange *range; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + { + range = GTK_RANGE (widget); + + gdk_window_move_resize (range->trough, + allocation->x + (allocation->width - widget->requisition.width) / 2, + allocation->y, + widget->requisition.width, allocation->height); + gdk_window_move_resize (range->step_back, + widget->style->klass->xthickness, + widget->style->klass->ythickness, + widget->requisition.width - widget->style->klass->xthickness * 2, + RANGE_CLASS (widget)->stepper_size); + gdk_window_move_resize (range->step_forw, + widget->style->klass->xthickness, + allocation->height - widget->style->klass->ythickness - + RANGE_CLASS (widget)->stepper_size, + widget->requisition.width - widget->style->klass->xthickness * 2, + RANGE_CLASS (widget)->stepper_size); + gdk_window_resize (range->slider, + widget->requisition.width - widget->style->klass->xthickness * 2, + RANGE_CLASS (range)->min_slider_size); + + gtk_range_slider_update (GTK_RANGE (widget)); + } +} + +static void +gtk_vscrollbar_draw_step_forw (GtkRange *range) +{ + GtkStateType state_type; + GtkShadowType shadow_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (range)); + + if (GTK_WIDGET_DRAWABLE (range)) + { + if (range->in_child == RANGE_CLASS (range)->step_forw) + { + if (range->click_child == RANGE_CLASS (range)->step_forw) + state_type = GTK_STATE_ACTIVE; + else + state_type = GTK_STATE_PRELIGHT; + } + else + state_type = GTK_STATE_NORMAL; + + if (range->click_child == RANGE_CLASS (range)->step_forw) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_forw, + state_type, shadow_type, GTK_ARROW_DOWN, + TRUE, 0, 0, -1, -1); + } +} + +static void +gtk_vscrollbar_draw_step_back (GtkRange *range) +{ + GtkStateType state_type; + GtkShadowType shadow_type; + + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (range)); + + if (GTK_WIDGET_DRAWABLE (range)) + { + if (range->in_child == RANGE_CLASS (range)->step_back) + { + if (range->click_child == RANGE_CLASS (range)->step_back) + state_type = GTK_STATE_ACTIVE; + else + state_type = GTK_STATE_PRELIGHT; + } + else + state_type = GTK_STATE_NORMAL; + + if (range->click_child == RANGE_CLASS (range)->step_back) + shadow_type = GTK_SHADOW_IN; + else + shadow_type = GTK_SHADOW_OUT; + + gtk_draw_arrow (GTK_WIDGET (range)->style, range->step_back, + state_type, shadow_type, GTK_ARROW_UP, + TRUE, 0, 0, -1, -1); + } +} + +static void +gtk_vscrollbar_slider_update (GtkRange *range) +{ + g_return_if_fail (range != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (range)); + + gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (range)); + gtk_range_default_vslider_update (range); +} + +static void +gtk_vscrollbar_calc_slider_size (GtkVScrollbar *vscrollbar) +{ + GtkRange *range; + gint step_back_y; + gint step_back_height; + gint step_forw_y; + gint slider_width; + gint slider_height; + gint top, bottom; + gint height; + + g_return_if_fail (vscrollbar != NULL); + g_return_if_fail (GTK_IS_VSCROLLBAR (vscrollbar)); + + if (GTK_WIDGET_REALIZED (vscrollbar)) + { + range = GTK_RANGE (vscrollbar); + + gdk_window_get_size (range->step_back, NULL, &step_back_height); + gdk_window_get_position (range->step_back, NULL, &step_back_y); + gdk_window_get_position (range->step_forw, NULL, &step_forw_y); + + top = (step_back_y + + step_back_height + + RANGE_CLASS (vscrollbar)->stepper_slider_spacing); + bottom = step_forw_y - RANGE_CLASS (vscrollbar)->stepper_slider_spacing; + height = bottom - top; + + if ((range->adjustment->page_size > 0) && + (range->adjustment->lower != range->adjustment->upper)) + { + if (range->adjustment->page_size > + (range->adjustment->upper - range->adjustment->lower)) + range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower; + + height = (height * range->adjustment->page_size / + (range->adjustment->upper - range->adjustment->lower)); + + if (height < RANGE_CLASS (vscrollbar)->min_slider_size) + height = RANGE_CLASS (vscrollbar)->min_slider_size; + } + + gdk_window_get_size (range->slider, &slider_width, &slider_height); + + if (slider_height != height) + gdk_window_resize (range->slider, slider_width, height); + } +} + +static gint +gtk_vscrollbar_trough_keys(GtkRange *range, + GdkEventKey *key, + GtkScrollType *scroll, + GtkTroughType *pos) +{ + gint return_val = FALSE; + switch (key->keyval) + { + case GDK_Up: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_BACKWARD; + break; + case GDK_Down: + return_val = TRUE; + *scroll = GTK_SCROLL_STEP_FORWARD; + break; + case GDK_Page_Up: + return_val = TRUE; + if (key->state & GDK_CONTROL_MASK) + *pos = GTK_TROUGH_START; + else + *scroll = GTK_SCROLL_PAGE_BACKWARD; + break; + case GDK_Page_Down: + return_val = TRUE; + if (key->state & GDK_CONTROL_MASK) + *pos = GTK_TROUGH_END; + else + *scroll = GTK_SCROLL_PAGE_FORWARD; + break; + } + return return_val; +} diff --git a/gtk/gtkvscrollbar.h b/gtk/gtkvscrollbar.h new file mode 100644 index 000000000..3160fc075 --- /dev/null +++ b/gtk/gtkvscrollbar.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_VSCROLLBAR_H__ +#define __GTK_VSCROLLBAR_H__ + + +#include +#include + + +#define GTK_VSCROLLBAR(obj) GTK_CHECK_CAST (obj, gtk_vscrollbar_get_type (), GtkVScrollbar) +#define GTK_VSCROLLBAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vscrollbar_get_type (), GtkVScrollbarClass) +#define GTK_IS_VSCROLLBAR(obj) GTK_CHECK_TYPE (obj, gtk_vscrollbar_get_type ()) + + +typedef struct _GtkVScrollbar GtkVScrollbar; +typedef struct _GtkVScrollbarClass GtkVScrollbarClass; + +struct _GtkVScrollbar +{ + GtkScrollbar scrollbar; +}; + +struct _GtkVScrollbarClass +{ + GtkScrollbarClass parent_class; +}; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +guint gtk_vscrollbar_get_type (void); +GtkWidget* gtk_vscrollbar_new (GtkAdjustment *adjustment); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_VSCROLLBAR_H__ */ diff --git a/gtk/gtkvseparator.c b/gtk/gtkvseparator.c new file mode 100644 index 000000000..fbbba19ff --- /dev/null +++ b/gtk/gtkvseparator.c @@ -0,0 +1,90 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "gtkvseparator.h" + + +static void gtk_vseparator_class_init (GtkVSeparatorClass *klass); +static void gtk_vseparator_init (GtkVSeparator *vseparator); +static gint gtk_vseparator_expose (GtkWidget *widget, + GdkEventExpose *event); + + +guint +gtk_vseparator_get_type () +{ + static guint vseparator_type = 0; + + if (!vseparator_type) + { + GtkTypeInfo vseparator_info = + { + "GtkVSeparator", + sizeof (GtkVSeparator), + sizeof (GtkVSeparatorClass), + (GtkClassInitFunc) gtk_vseparator_class_init, + (GtkObjectInitFunc) gtk_vseparator_init, + (GtkArgFunc) NULL, + }; + + vseparator_type = gtk_type_unique (gtk_separator_get_type (), &vseparator_info); + } + + return vseparator_type; +} + +static void +gtk_vseparator_class_init (GtkVSeparatorClass *klass) +{ + GtkWidgetClass *widget_class; + + widget_class = (GtkWidgetClass*) klass; + + widget_class->expose_event = gtk_vseparator_expose; +} + +static void +gtk_vseparator_init (GtkVSeparator *vseparator) +{ + GTK_WIDGET (vseparator)->requisition.width = GTK_WIDGET (vseparator)->style->klass->xthickness; + GTK_WIDGET (vseparator)->requisition.height = 1; +} + +GtkWidget* +gtk_vseparator_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_vseparator_get_type ())); +} + + +static gint +gtk_vseparator_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VSEPARATOR (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + gtk_draw_vline (widget->style, widget->window, GTK_STATE_NORMAL, + widget->allocation.y, + widget->allocation.y + widget->allocation.height, + widget->allocation.x + (widget->allocation.width - + widget->style->klass->xthickness) / 2); + + return FALSE; +} diff --git a/gtk/gtkvseparator.h b/gtk/gtkvseparator.h new file mode 100644 index 000000000..74d07dd68 --- /dev/null +++ b/gtk/gtkvseparator.h @@ -0,0 +1,59 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_VSEPARATOR_H__ +#define __GTK_VSEPARATOR_H__ + + +#include +#include + + +#define GTK_VSEPARATOR(obj) GTK_CHECK_CAST (obj, gtk_vseparator_get_type (), GtkVSeparator) +#define GTK_VSEPARATOR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_vseparator_get_type (), GtkVSeparatorClass) +#define GTK_IS_VSEPARATOR(obj) GTK_CHECK_TYPE (obj, gtk_vseparator_get_type ()) + + +typedef struct _GtkVSeparator GtkVSeparator; +typedef struct _GtkVSeparatorClass GtkVSeparatorClass; + +struct _GtkVSeparator +{ + GtkSeparator separator; +}; + +struct _GtkVSeparatorClass +{ + GtkSeparatorClass parent_class; +}; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +guint gtk_vseparator_get_type (void); +GtkWidget* gtk_vseparator_new (void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_SEPARATOR_H__ */ diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c new file mode 100644 index 000000000..26e0c9bbc --- /dev/null +++ b/gtk/gtkwidget.c @@ -0,0 +1,3390 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gtkcontainer.h" +#include "gtkmain.h" +#include "gtkrc.h" +#include "gtkselection.h" +#include "gtksignal.h" +#include "gtkwidget.h" +#include "gtkwindow.h" +#include "gdk/gdk.h" +#include "gdk/gdkx.h" + + +#define WIDGET_CLASS(w) GTK_WIDGET_CLASS (GTK_OBJECT (w)->klass) + + +enum { + SHOW, + HIDE, + MAP, + UNMAP, + REALIZE, + UNREALIZE, + DRAW, + DRAW_FOCUS, + DRAW_DEFAULT, + SIZE_REQUEST, + SIZE_ALLOCATE, + STATE_CHANGED, + INSTALL_ACCELERATOR, + REMOVE_ACCELERATOR, + EVENT, + BUTTON_PRESS_EVENT, + BUTTON_RELEASE_EVENT, + MOTION_NOTIFY_EVENT, + DELETE_EVENT, + DESTROY_EVENT, + EXPOSE_EVENT, + KEY_PRESS_EVENT, + KEY_RELEASE_EVENT, + ENTER_NOTIFY_EVENT, + LEAVE_NOTIFY_EVENT, + CONFIGURE_EVENT, + FOCUS_IN_EVENT, + FOCUS_OUT_EVENT, + MAP_EVENT, + UNMAP_EVENT, + PROPERTY_NOTIFY_EVENT, + SELECTION_CLEAR_EVENT, + SELECTION_REQUEST_EVENT, + SELECTION_NOTIFY_EVENT, + SELECTION_RECEIVED, + PROXIMITY_IN_EVENT, + PROXIMITY_OUT_EVENT, + DRAG_BEGIN_EVENT, + DRAG_REQUEST_EVENT, + DROP_ENTER_EVENT, + DROP_LEAVE_EVENT, + DROP_DATA_AVAILABLE_EVENT, + OTHER_EVENT, + LAST_SIGNAL +}; + + +typedef void (*GtkWidgetSignal1) (GtkObject *object, + gpointer arg1, + gpointer data); +typedef gint (*GtkWidgetSignal2) (GtkObject *object, + gpointer arg1, + gchar arg2, + gchar arg3, + gpointer data); +typedef void (*GtkWidgetSignal3) (GtkObject *object, + gpointer arg1, + gpointer data); +typedef gint (*GtkWidgetSignal4) (GtkObject *object, + gpointer arg1, + gpointer data); + + +static void gtk_widget_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_widget_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_widget_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +static void gtk_widget_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + +static void gtk_widget_class_init (GtkWidgetClass *klass); +static void gtk_widget_init (GtkWidget *widget); +static void gtk_widget_arg (GtkWidget *widget, + GtkArg *arg); +static void gtk_real_widget_destroy (GtkObject *object); +static void gtk_real_widget_show (GtkWidget *widget); +static void gtk_real_widget_hide (GtkWidget *widget); +static void gtk_real_widget_map (GtkWidget *widget); +static void gtk_real_widget_unmap (GtkWidget *widget); +static void gtk_real_widget_realize (GtkWidget *widget); +static void gtk_real_widget_unrealize (GtkWidget *widget); +static void gtk_real_widget_draw (GtkWidget *widget, + GdkRectangle *area); +static gint gtk_real_widget_queue_draw (GtkWidget *widget); +static gint gtk_real_widget_queue_resize (GtkWidget *widget); +static void gtk_real_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +static GdkColormap* gtk_widget_peek_colormap (void); +static GdkVisual* gtk_widget_peek_visual (void); +static GtkStyle* gtk_widget_peek_style (void); + +static void gtk_widget_set_parent_sensitive (GtkWidget *widget, + gpointer client_data); +static void gtk_widget_propagate_restore (GtkWidget *widget, + gpointer client_data); +static void gtk_widget_propagate_state (GtkWidget *widget, + gpointer client_data); +static void gtk_widget_draw_children_recurse (GtkWidget *widget, + gpointer client_data); +static void gtk_widget_set_style_internal (GtkWidget *widget, + GtkStyle *style); +static void gtk_widget_set_style_recurse (GtkWidget *widget, + gpointer client_data); + +extern GtkArg* gtk_object_collect_args (gint *nargs, + va_list args1, + va_list args2); + +static GtkWidgetAuxInfo* gtk_widget_aux_info_new (void); +static void gtk_widget_aux_info_destroy (GtkWidgetAuxInfo *aux_info); + +static GtkObjectClass *parent_class = NULL; +static gint widget_signals[LAST_SIGNAL] = { 0 }; + +static GMemChunk *aux_info_mem_chunk = NULL; + +static GdkColormap *default_colormap = NULL; +static GdkVisual *default_visual = NULL; +static GtkStyle *default_style = NULL; + +static GSList *colormap_stack = NULL; +static GSList *visual_stack = NULL; +static GSList *style_stack = NULL; + +static const char *aux_info_key = "aux_info"; +static const char *colormap_key = "colormap"; +static const char *visual_key = "visual"; +static const char *event_key = "event_mask"; +static const char *resize_widgets_key = "resize_widgets"; +static const char *extension_event_key = "extension_event_mode"; +static const char *redraw_handler_key = "redraw_handler_tag"; +static const char *resize_handler_key = "resize_handler_tag"; +static const char *shape_info_key = "shape_info"; + + + +/***************************************** + * gtk_widget_get_type: + * + * arguments: + * + * results: + *****************************************/ + +guint +gtk_widget_get_type () +{ + static guint widget_type = 0; + + if (!widget_type) + { + GtkTypeInfo widget_info = + { + "GtkWidget", + sizeof (GtkWidget), + sizeof (GtkWidgetClass), + (GtkClassInitFunc) gtk_widget_class_init, + (GtkObjectInitFunc) gtk_widget_init, + (GtkArgFunc) gtk_widget_arg, + }; + + widget_type = gtk_type_unique (gtk_object_get_type (), &widget_info); + } + + return widget_type; +} + +/***************************************** + * gtk_widget_class_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_class_init (GtkWidgetClass *klass) +{ + GtkObjectClass *object_class; + + object_class = (GtkObjectClass*) klass; + + parent_class = gtk_type_class (gtk_object_get_type ()); + + gtk_object_add_arg_type ("GtkWidget::x", GTK_TYPE_INT); + gtk_object_add_arg_type ("GtkWidget::y", GTK_TYPE_INT); + gtk_object_add_arg_type ("GtkWidget::width", GTK_TYPE_INT); + gtk_object_add_arg_type ("GtkWidget::height", GTK_TYPE_INT); + gtk_object_add_arg_type ("GtkWidget::visible", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkWidget::sensitive", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkWidget::events", GTK_TYPE_GDK_EVENT_MASK); + gtk_object_add_arg_type ("GtkWidget::extension_events", GTK_TYPE_GDK_EVENT_MASK); + gtk_object_add_arg_type ("GtkWidget::name", GTK_TYPE_STRING); + gtk_object_add_arg_type ("GtkWidget::style", GTK_TYPE_STYLE); + gtk_object_add_arg_type ("GtkWidget::parent", GTK_TYPE_CONTAINER); + + widget_signals[SHOW] = + gtk_signal_new ("show", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, show), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[HIDE] = + gtk_signal_new ("hide", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, hide), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[MAP] = + gtk_signal_new ("map", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, map), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[UNMAP] = + gtk_signal_new ("unmap", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, unmap), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[REALIZE] = + gtk_signal_new ("realize", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, realize), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[UNREALIZE] = + gtk_signal_new ("unrealize", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, unrealize), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[DRAW] = + gtk_signal_new ("draw", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, draw), + gtk_widget_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_POINTER); + widget_signals[DRAW_FOCUS] = + gtk_signal_new ("draw_focus", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, draw_focus), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[DRAW_DEFAULT] = + gtk_signal_new ("draw_default", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, draw_default), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[SIZE_REQUEST] = + gtk_signal_new ("size_request", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, size_request), + gtk_widget_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_POINTER); + widget_signals[SIZE_ALLOCATE] = + gtk_signal_new ("size_allocate", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, size_allocate), + gtk_widget_marshal_signal_1, + GTK_TYPE_NONE, 1, + GTK_TYPE_POINTER); + widget_signals[STATE_CHANGED] = + gtk_signal_new ("state_changed", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, state_changed), + gtk_signal_default_marshaller, + GTK_TYPE_NONE, 0); + widget_signals[INSTALL_ACCELERATOR] = + gtk_signal_new ("install_accelerator", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, install_accelerator), + gtk_widget_marshal_signal_2, + GTK_TYPE_BOOL, 3, + GTK_TYPE_STRING, + GTK_TYPE_CHAR, + GTK_TYPE_INT); + widget_signals[REMOVE_ACCELERATOR] = + gtk_signal_new ("remove_accelerator", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, remove_accelerator), + gtk_widget_marshal_signal_3, + GTK_TYPE_NONE, 1, + GTK_TYPE_STRING); + widget_signals[EVENT] = + gtk_signal_new ("event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[BUTTON_PRESS_EVENT] = + gtk_signal_new ("button_press_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, button_press_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[BUTTON_RELEASE_EVENT] = + gtk_signal_new ("button_release_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, button_release_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[MOTION_NOTIFY_EVENT] = + gtk_signal_new ("motion_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, motion_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DELETE_EVENT] = + gtk_signal_new ("delete_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, delete_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DESTROY_EVENT] = + gtk_signal_new ("destroy_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, destroy_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[EXPOSE_EVENT] = + gtk_signal_new ("expose_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, expose_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[KEY_PRESS_EVENT] = + gtk_signal_new ("key_press_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, key_press_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[KEY_RELEASE_EVENT] = + gtk_signal_new ("key_release_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, key_release_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[ENTER_NOTIFY_EVENT] = + gtk_signal_new ("enter_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, enter_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[LEAVE_NOTIFY_EVENT] = + gtk_signal_new ("leave_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, leave_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[CONFIGURE_EVENT] = + gtk_signal_new ("configure_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, configure_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[FOCUS_IN_EVENT] = + gtk_signal_new ("focus_in_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, focus_in_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[FOCUS_OUT_EVENT] = + gtk_signal_new ("focus_out_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, focus_out_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[MAP_EVENT] = + gtk_signal_new ("map_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, map_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[UNMAP_EVENT] = + gtk_signal_new ("unmap_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, unmap_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[PROPERTY_NOTIFY_EVENT] = + gtk_signal_new ("property_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, property_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[SELECTION_CLEAR_EVENT] = + gtk_signal_new ("selection_clear_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, selection_clear_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[SELECTION_REQUEST_EVENT] = + gtk_signal_new ("selection_request_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, selection_request_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[SELECTION_NOTIFY_EVENT] = + gtk_signal_new ("selection_notify_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, selection_notify_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[SELECTION_RECEIVED] = + gtk_signal_new ("selection_received", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, selection_received), + gtk_widget_marshal_signal_1, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[PROXIMITY_IN_EVENT] = + gtk_signal_new ("proximity_in_event", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, proximity_in_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[PROXIMITY_OUT_EVENT] = + gtk_signal_new ("proximity_out_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, proximity_out_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DRAG_BEGIN_EVENT] = + gtk_signal_new ("drag_begin_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, drag_begin_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DRAG_REQUEST_EVENT] = + gtk_signal_new ("drag_request_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, drag_request_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DROP_ENTER_EVENT] = + gtk_signal_new ("drop_enter_event", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, drop_enter_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DROP_LEAVE_EVENT] = + gtk_signal_new ("drop_leave_event", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, drop_leave_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[DROP_DATA_AVAILABLE_EVENT] = + gtk_signal_new ("drop_data_available_event", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, + drop_data_available_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + widget_signals[OTHER_EVENT] = + gtk_signal_new ("other_event", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWidgetClass, other_event), + gtk_widget_marshal_signal_4, + GTK_TYPE_BOOL, 1, + GTK_TYPE_GDK_EVENT); + + gtk_object_class_add_signals (object_class, widget_signals, LAST_SIGNAL); + + object_class->destroy = gtk_real_widget_destroy; + + klass->activate_signal = 0; + klass->show = gtk_real_widget_show; + klass->hide = gtk_real_widget_hide; + klass->map = gtk_real_widget_map; + klass->unmap = gtk_real_widget_unmap; + klass->realize = gtk_real_widget_realize; + klass->unrealize = gtk_real_widget_unrealize; + klass->draw = gtk_real_widget_draw; + klass->draw_focus = NULL; + klass->size_request = NULL; + klass->size_allocate = gtk_real_widget_size_allocate; + klass->state_changed = NULL; + klass->install_accelerator = NULL; + klass->remove_accelerator = NULL; + klass->event = NULL; + klass->button_press_event = NULL; + klass->button_release_event = NULL; + klass->motion_notify_event = NULL; + klass->delete_event = NULL; + klass->destroy_event = NULL; + klass->expose_event = NULL; + klass->key_press_event = NULL; + klass->key_release_event = NULL; + klass->enter_notify_event = NULL; + klass->leave_notify_event = NULL; + klass->configure_event = NULL; + klass->focus_in_event = NULL; + klass->focus_out_event = NULL; + klass->map_event = NULL; + klass->unmap_event = NULL; + klass->property_notify_event = gtk_selection_property_notify; + klass->selection_clear_event = gtk_selection_clear; + klass->selection_request_event = gtk_selection_request; + klass->selection_notify_event = gtk_selection_notify; + klass->selection_received = NULL; + klass->proximity_in_event = NULL; + klass->proximity_out_event = NULL; + klass->drag_begin_event = NULL; + klass->drag_request_event = NULL; + klass->drop_enter_event = NULL; + klass->drop_leave_event = NULL; + klass->drop_data_available_event = NULL; + klass->other_event = NULL; +} + +/***************************************** + * gtk_widget_arg: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_arg (GtkWidget *widget, + GtkArg *arg) +{ + if (strcmp (arg->name, "x") == 0) + { + gtk_widget_set_uposition (widget, GTK_VALUE_INT(*arg), -2); + } + else if (strcmp (arg->name, "y") == 0) + { + gtk_widget_set_uposition (widget, -2, GTK_VALUE_INT(*arg)); + } + else if (strcmp (arg->name, "width") == 0) + { + gtk_widget_set_usize (widget, GTK_VALUE_INT(*arg), -1); + } + else if (strcmp (arg->name, "height") == 0) + { + gtk_widget_set_usize (widget, -1, GTK_VALUE_INT(*arg)); + } + else if (strcmp (arg->name, "visible") == 0) + { + if (GTK_VALUE_BOOL(*arg)) + gtk_widget_show (widget); + else + gtk_widget_hide (widget); + } + else if (strcmp (arg->name, "sensitive") == 0) + { + gtk_widget_set_sensitive (widget, GTK_VALUE_BOOL(*arg)); + } + else if (strcmp (arg->name, "events") == 0) + { + gtk_widget_set_events (widget, GTK_VALUE_FLAGS(*arg)); + } + else if (strcmp (arg->name, "extension_events") == 0) + { + gtk_widget_set_extension_events (widget, GTK_VALUE_FLAGS(*arg)); + } + else if (strcmp (arg->name, "name") == 0) + { + gtk_widget_set_name (widget, GTK_VALUE_STRING(*arg)); + } + else if (strcmp (arg->name, "style") == 0) + { + gtk_widget_set_style (widget, (GtkStyle*)GTK_VALUE_BOXED(*arg)); + } + else if (strcmp (arg->name, "parent") == 0) + { + gtk_container_add (GTK_CONTAINER (GTK_VALUE_OBJECT(*arg)), widget); + } +} + +/***************************************** + * gtk_widget_init: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_init (GtkWidget *widget) +{ + GdkColormap *colormap; + GdkVisual *visual; + + GTK_OBJECT_FLAGS (widget) = GTK_SENSITIVE | GTK_PARENT_SENSITIVE; + widget->state = GTK_STATE_NORMAL; + widget->saved_state = GTK_STATE_NORMAL; + widget->name = NULL; + widget->requisition.width = 0; + widget->requisition.height = 0; + widget->allocation.x = -1; + widget->allocation.y = -1; + widget->allocation.width = 1; + widget->allocation.height = 1; + widget->window = NULL; + widget->parent = NULL; + + widget->style = gtk_widget_peek_style (); + gtk_style_ref (widget->style); + + colormap = gtk_widget_peek_colormap (); + visual = gtk_widget_peek_visual (); + + if (colormap != gtk_widget_get_default_colormap ()) + gtk_object_set_data (GTK_OBJECT (widget), colormap_key, colormap); + + if (visual != gtk_widget_get_default_visual ()) + gtk_object_set_data (GTK_OBJECT (widget), visual_key, visual); +} + +/***************************************** + * gtk_widget_new: + * + * arguments: + * + * results: + *****************************************/ + +GtkWidget* +gtk_widget_new (guint type, + ...) +{ + GtkObject *obj; + GtkArg *args; + gint nargs; + va_list args1; + va_list args2; + + g_return_val_if_fail (gtk_type_is_a (type, gtk_widget_get_type ()), NULL); + + obj = gtk_type_new (type); + + va_start (args1, type); + va_start (args2, type); + + args = gtk_object_collect_args (&nargs, args1, args2); + gtk_object_setv (obj, nargs, args); + g_free (args); + + va_end (args1); + va_end (args2); + + return GTK_WIDGET (obj); +} + +/***************************************** + * gtk_widget_newv: + * + * arguments: + * + * results: + *****************************************/ + +GtkWidget* +gtk_widget_newv (guint type, + gint nargs, + GtkArg *args) +{ + g_return_val_if_fail (gtk_type_is_a (type, gtk_widget_get_type ()), NULL); + + return GTK_WIDGET (gtk_object_newv (type, nargs, args)); +} + +/***************************************** + * gtk_widget_set: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set (GtkWidget *widget, + ...) +{ + GtkArg *args; + gint nargs; + va_list args1; + va_list args2; + + g_return_if_fail (widget != NULL); + + va_start (args1, widget); + va_start (args2, widget); + + args = gtk_object_collect_args (&nargs, args1, args2); + gtk_object_setv (GTK_OBJECT (widget), nargs, args); + g_free (args); + + va_end (args1); + va_end (args2); +} + +/***************************************** + * gtk_widget_setv: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_setv (GtkWidget *widget, + gint nargs, + GtkArg *args) +{ + gtk_object_setv (GTK_OBJECT (widget), nargs, args); +} + +/***************************************** + * gtk_widget_destroy: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_destroy (GtkWidget *widget) +{ + GSList *resize_widgets; + GSList *tmp_list; + gint tag; + + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_REDRAW_PENDING (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REDRAW_PENDING); + gtk_object_unref (GTK_OBJECT (widget)); + tag = (gint) gtk_object_get_data (GTK_OBJECT (widget), redraw_handler_key); + gtk_idle_remove (tag); + gtk_object_set_data (GTK_OBJECT (widget), redraw_handler_key, (gpointer) 0); + } + + if (GTK_WIDGET_ANCHORED (widget) && + GTK_WIDGET_RESIZE_PENDING (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_PENDING); + gtk_object_unref (GTK_OBJECT (widget)); + tag = (gint) gtk_object_get_data (GTK_OBJECT (widget), resize_handler_key); + gtk_idle_remove (tag); + gtk_object_set_data (GTK_OBJECT (widget), resize_handler_key, (gpointer) 0); + + resize_widgets = gtk_object_get_data (GTK_OBJECT (widget), resize_widgets_key); + + tmp_list = resize_widgets; + while (tmp_list) + { + GtkWidget *child; + + child = tmp_list->data; + tmp_list = tmp_list->next; + + /* referencing needed? */ + GTK_WIDGET_UNSET_FLAGS (child, GTK_RESIZE_NEEDED); + gtk_object_unref (GTK_OBJECT (child)); + } + + if (resize_widgets) + { + gtk_object_set_data (GTK_OBJECT (widget), resize_widgets_key, NULL); + g_slist_free (resize_widgets); + } + } + + if (GTK_WIDGET_RESIZE_NEEDED (widget)) + { + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (widget); + resize_widgets = gtk_object_get_data (GTK_OBJECT (toplevel), resize_widgets_key); + + if (resize_widgets) + { + resize_widgets = g_slist_remove (resize_widgets, widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_NEEDED); + gtk_object_unref (GTK_OBJECT (widget)); + + gtk_object_set_data (GTK_OBJECT (toplevel), resize_widgets_key, resize_widgets); + } + } + + + if (widget->parent) + { + if (!GTK_OBJECT_BEING_DESTROYED (widget->parent)) + gtk_container_remove (GTK_CONTAINER (widget->parent), widget); + else + gtk_object_unref (GTK_OBJECT (widget)); + } + gtk_object_destroy (GTK_OBJECT (widget)); +} + +/***************************************** + * gtk_widget_unparent: do any cleanup necessary necessary before + * setting parent = NULL. In particular, remove + * the focus properly. + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_unparent (GtkWidget *widget) +{ + GtkWidget *toplevel; + GtkWidget *child; + + g_return_if_fail (widget != NULL); + + toplevel = gtk_widget_get_toplevel (widget); + if (GTK_IS_WINDOW (toplevel)) + { + child = GTK_WINDOW (toplevel)->focus_widget; + + while (child && child != widget) + child = child->parent; + + if (child == widget) + gtk_window_set_focus (GTK_WINDOW (toplevel), NULL); + } + + if (widget->window && + GTK_WIDGET_NO_WINDOW (widget) && + GTK_WIDGET_DRAWABLE (widget)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + + widget->parent = NULL; + + gtk_object_unref (GTK_OBJECT (widget)); +} + +/***************************************** + * gtk_widget_show: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_show (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (!GTK_WIDGET_VISIBLE (widget)) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[SHOW]); +} + +/***************************************** + * gtk_widget_hide: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_hide (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_VISIBLE (widget)) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[HIDE]); +} + +/***************************************** + * gtk_widget_map: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_map (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (!GTK_WIDGET_MAPPED (widget)) + { + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[MAP]); + } +} + +/***************************************** + * gtk_widget_unmap: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_MAPPED (widget)) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[UNMAP]); +} + +/***************************************** + * gtk_widget_realize: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_realize (GtkWidget *widget) +{ + GtkStyle *new_style; + gint events; + GdkExtensionMode mode; + GtkWidgetShapeInfo *shape_info; + + g_return_if_fail (widget != NULL); + + if (!GTK_WIDGET_REALIZED (widget)) + { + /* + if (GTK_IS_CONTAINER (widget) && !GTK_WIDGET_NO_WINDOW (widget)) + g_print ("%s\n", gtk_type_name (GTK_WIDGET_TYPE (widget))); + */ + + if (widget->parent && !GTK_WIDGET_REALIZED (widget->parent)) + gtk_widget_realize (widget->parent); + + if (!GTK_WIDGET_USER_STYLE (widget)) + { + new_style = gtk_rc_get_style (widget); + if (new_style != widget->style) + gtk_widget_set_style_internal (widget, new_style); + } + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[REALIZE]); + + if (GTK_WIDGET_HAS_SHAPE_MASK(widget)) + { + shape_info = gtk_object_get_data (GTK_OBJECT (widget), + shape_info_key); + g_assert (shape_info != 0); + gdk_window_shape_combine_mask (widget->window, + shape_info->shape_mask, + shape_info->offset_x, + shape_info->offset_y); + } + + if (!GTK_WIDGET_NO_WINDOW (widget)) + { + mode = gtk_widget_get_extension_events (widget); + if (mode != GDK_EXTENSION_EVENTS_NONE) + { + events = gtk_widget_get_events (widget); + gdk_input_set_extension_events (widget->window, events, mode); + } + } + + } +} + +/***************************************** + * gtk_widget_unrealize: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_unrealize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_REALIZED (widget)) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[UNREALIZE]); +} + +/***************************************** + * gtk_widget_queue_draw: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_queue_draw (GtkWidget *widget) +{ + GtkWidget *parent; + gint tag; + + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + /* We queue the redraw if: + * a) the widget is not already queued for redraw and + * b) non of the widgets ancestors are queued for redraw. + */ + parent = widget; + while (parent) + { + if (GTK_WIDGET_REDRAW_PENDING (parent)) + return; + parent = parent->parent; + } + + GTK_WIDGET_SET_FLAGS (widget, GTK_REDRAW_PENDING); + gtk_object_ref (GTK_OBJECT (widget)); + tag = gtk_idle_add ((GtkFunction) gtk_real_widget_queue_draw, widget); + gtk_object_set_data (GTK_OBJECT (widget), redraw_handler_key, (gpointer) tag); + } +} + +/***************************************** + * gtk_widget_queue_resize: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_queue_resize (GtkWidget *widget) +{ + GtkWidget *toplevel; + GSList *resize_widgets; + gint tag; + + g_return_if_fail (widget != NULL); + + toplevel = gtk_widget_get_toplevel (widget); + if (GTK_WIDGET_ANCHORED (toplevel)) + { + if (GTK_WIDGET_VISIBLE (toplevel)) + { + if (!GTK_WIDGET_RESIZE_PENDING (toplevel)) + { + GTK_WIDGET_SET_FLAGS (toplevel, GTK_RESIZE_PENDING); + gtk_object_ref (GTK_OBJECT (toplevel)); + tag = gtk_idle_add ((GtkFunction) gtk_real_widget_queue_resize, toplevel); + gtk_object_set_data (GTK_OBJECT (toplevel), resize_handler_key, (gpointer) tag); + } + + resize_widgets = gtk_object_get_data (GTK_OBJECT (toplevel), resize_widgets_key); + if (g_slist_find (resize_widgets, widget) == NULL) + { + /* referencing needed? */ + GTK_WIDGET_SET_FLAGS (widget, GTK_RESIZE_NEEDED); + gtk_object_ref (GTK_OBJECT (widget)); + resize_widgets = g_slist_prepend (resize_widgets, widget); + + gtk_object_set_data (GTK_OBJECT (toplevel), resize_widgets_key, resize_widgets); + } + } + else + { + gtk_container_need_resize (GTK_CONTAINER (toplevel)); + } + } +} + +/***************************************** + * gtk_widget_draw: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GdkRectangle temp_area; + + g_return_if_fail (widget != NULL); + + if (GTK_WIDGET_DRAWABLE (widget) && + !GTK_WIDGET_REDRAW_PENDING (widget)) + { + if (!area) + { + if (GTK_WIDGET_NO_WINDOW (widget)) + { + temp_area.x = widget->allocation.x; + temp_area.y = widget->allocation.y; + } + else + { + temp_area.x = 0; + temp_area.y = 0; + } + + temp_area.width = widget->allocation.width; + temp_area.height = widget->allocation.height; + area = &temp_area; + } + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[DRAW], area); + } +} + +/***************************************** + * gtk_widget_draw_focus: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_draw_focus (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[DRAW_FOCUS]); +} + +/***************************************** + * gtk_widget_draw_default: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_draw_default (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[DRAW_DEFAULT]); +} + +/***************************************** + * gtk_widget_draw_children: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_draw_children (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_draw_children_recurse, + NULL); +} + +/***************************************** + * gtk_widget_size_request: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkWidgetAuxInfo *aux_info; + + g_return_if_fail (widget != NULL); + + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[SIZE_REQUEST], requisition)) + { + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + if (aux_info) + { + if (aux_info->width > 0) + requisition->width = aux_info->width; + if (aux_info->height > 0) + requisition->height = aux_info->height; + } + } +} + +/***************************************** + * gtk_widget_size_allocate: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWidgetAuxInfo *aux_info; + GtkAllocation real_allocation; + + g_return_if_fail (widget != NULL); + + real_allocation = *allocation; + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + + if (aux_info) + { + if (aux_info->x != -1) + real_allocation.x = aux_info->x; + if (aux_info->y != -1) + real_allocation.y = aux_info->y; + } + + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[SIZE_ALLOCATE], &real_allocation); +} + +/***************************************** + * gtk_widget_install_accelerator: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_install_accelerator (GtkWidget *widget, + GtkAcceleratorTable *table, + const gchar *signal_name, + gchar key, + guint8 modifiers) +{ + gint return_val; + + g_return_if_fail (widget != NULL); + + return_val = TRUE; + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[INSTALL_ACCELERATOR], + signal_name, key, modifiers, &return_val) && return_val) + gtk_accelerator_table_install (table, GTK_OBJECT (widget), signal_name, key, modifiers); +} + +/***************************************** + * gtk_widget_remove_accelerator: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_remove_accelerator (GtkWidget *widget, + GtkAcceleratorTable *table, + const gchar *signal_name) +{ + g_return_if_fail (widget != NULL); + + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[REMOVE_ACCELERATOR], signal_name)) + gtk_accelerator_table_remove (table, GTK_OBJECT (widget), signal_name); +} + +/***************************************** + * gtk_widget_event: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_event (GtkWidget *widget, + GdkEvent *event) +{ + gint return_val; + gint signal_num; + + g_return_val_if_fail (widget != NULL, FALSE); + + return_val = FALSE; + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[EVENT], event, &return_val)) + { + if (return_val) + return TRUE; + + switch (event->type) + { + case GDK_NOTHING: + signal_num = -1; + break; + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + signal_num = BUTTON_PRESS_EVENT; + break; + case GDK_BUTTON_RELEASE: + signal_num = BUTTON_RELEASE_EVENT; + break; + case GDK_MOTION_NOTIFY: + signal_num = MOTION_NOTIFY_EVENT; + break; + case GDK_DELETE: + signal_num = DELETE_EVENT; + break; + case GDK_DESTROY: + signal_num = DESTROY_EVENT; + break; + case GDK_EXPOSE: + signal_num = EXPOSE_EVENT; + break; + case GDK_KEY_PRESS: + signal_num = KEY_PRESS_EVENT; + break; + case GDK_KEY_RELEASE: + signal_num = KEY_RELEASE_EVENT; + break; + case GDK_ENTER_NOTIFY: + signal_num = ENTER_NOTIFY_EVENT; + break; + case GDK_LEAVE_NOTIFY: + signal_num = LEAVE_NOTIFY_EVENT; + break; + case GDK_FOCUS_CHANGE: + if (event->focus_change.in) + signal_num = FOCUS_IN_EVENT; + else + signal_num = FOCUS_OUT_EVENT; + break; + case GDK_CONFIGURE: + signal_num = CONFIGURE_EVENT; + break; + case GDK_MAP: + signal_num = MAP_EVENT; + break; + case GDK_UNMAP: + signal_num = UNMAP_EVENT; + break; + case GDK_PROPERTY_NOTIFY: + signal_num = PROPERTY_NOTIFY_EVENT; + break; + case GDK_SELECTION_CLEAR: + signal_num = SELECTION_CLEAR_EVENT; + break; + case GDK_SELECTION_REQUEST: + signal_num = SELECTION_REQUEST_EVENT; + break; + case GDK_SELECTION_NOTIFY: + signal_num = SELECTION_NOTIFY_EVENT; + break; + case GDK_PROXIMITY_IN: + signal_num = PROXIMITY_IN_EVENT; + break; + case GDK_PROXIMITY_OUT: + signal_num = PROXIMITY_OUT_EVENT; + break; + case GDK_DRAG_BEGIN: + signal_num = DRAG_BEGIN_EVENT; + break; + case GDK_DRAG_REQUEST: + signal_num = DRAG_REQUEST_EVENT; + break; + case GDK_DROP_ENTER: + signal_num = DROP_ENTER_EVENT; + break; + case GDK_DROP_LEAVE: + signal_num = DROP_LEAVE_EVENT; + break; + case GDK_DROP_DATA_AVAIL: + signal_num = DROP_DATA_AVAILABLE_EVENT; + break; + case GDK_OTHER_EVENT: + signal_num = OTHER_EVENT; + break; + default: + g_warning ("could not determine signal number for event: %d", event->type); + return return_val; + } + + if (signal_num != -1) + gtk_signal_emit (GTK_OBJECT (widget), widget_signals[signal_num], event, &return_val); + } + + return return_val; +} + +/***************************************** + * gtk_widget_activate: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_activate (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (WIDGET_CLASS (widget)->activate_signal) + gtk_signal_emit (GTK_OBJECT (widget), WIDGET_CLASS (widget)->activate_signal); +} + +/***************************************** + * gtk_widget_reparent: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_reparent (GtkWidget *widget, + GtkWidget *new_parent) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (new_parent != NULL); + g_return_if_fail (GTK_IS_CONTAINER (new_parent)); + + if (widget->parent != new_parent) + { + gtk_container_remove (GTK_CONTAINER (widget->parent), widget); + gtk_container_add (GTK_CONTAINER (new_parent), widget); + + if (GTK_WIDGET_REALIZED (widget)) + { + if (GTK_WIDGET_REALIZED (new_parent) && !GTK_WIDGET_NO_WINDOW (widget)) + { + gdk_window_reparent (widget->window, widget->parent->window, 0, 0); + } + else + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + if (!GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_destroy (widget->window); + widget->window = NULL; + + if (GTK_WIDGET_REALIZED (new_parent)) + gtk_widget_realize (widget); + if (GTK_WIDGET_MAPPED (new_parent)) + gtk_widget_map (widget); + } + } + + if (!GTK_WIDGET_REALIZED (widget) && GTK_WIDGET_REALIZED (new_parent)) + gtk_widget_realize (widget); + if (!GTK_WIDGET_MAPPED (widget) && GTK_WIDGET_MAPPED (new_parent)) + gtk_widget_map (widget); + + gtk_widget_queue_resize (widget); + } +} + +/***************************************** + * gtk_widget_popup: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_popup (GtkWidget *widget, + gint x, + gint y) +{ + g_return_if_fail (widget != NULL); + + if (!GTK_WIDGET_VISIBLE (widget)) + { + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + if (!GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_move (widget->window, x, y); + gtk_widget_show (widget); + } +} + +/***************************************** + * gtk_widget_intersect: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_intersect (GtkWidget *widget, + GdkRectangle *area, + GdkRectangle *intersection) +{ + GdkRectangle *dest; + GdkRectangle tmp; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (area != NULL, FALSE); + + if (intersection) + dest = intersection; + else + dest = &tmp; + + return_val = gdk_rectangle_intersect ((GdkRectangle*) &widget->allocation, area, dest); + + if (return_val && intersection && !GTK_WIDGET_NO_WINDOW (widget)) + { + intersection->x -= widget->allocation.x; + intersection->y -= widget->allocation.y; + } + + return return_val; +} + + +gint +gtk_widget_basic (GtkWidget *widget) +{ + GList *children; + GList *tmp_list; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + + if (!GTK_WIDGET_BASIC (widget)) + return FALSE; + else if (GTK_IS_CONTAINER (widget)) + { + children = gtk_container_children (GTK_CONTAINER (widget)); + if (children) + { + return_val = TRUE; + tmp_list = children; + + while (tmp_list) + { + if (!gtk_widget_basic (GTK_WIDGET (tmp_list->data))) + { + return_val = FALSE; + break; + } + + tmp_list = tmp_list->next; + } + + g_list_free (children); + return return_val; + } + } + + return TRUE; +} + + +/***************************************** + * gtk_widget_grab_focus: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_grab_focus (GtkWidget *widget) +{ + GtkWidget *window; + GtkWidget *child; + gint window_type; + + g_return_if_fail (widget != NULL); + + window_type = gtk_window_get_type (); + window = widget->parent; + child = widget; + + while (window && !gtk_type_is_a (GTK_WIDGET_TYPE (window), window_type)) + { + GTK_CONTAINER (window)->focus_child = child; + child = window; + window = window->parent; + } + + if (window && gtk_type_is_a (GTK_WIDGET_TYPE (window), window_type)) + { + GTK_CONTAINER (window)->focus_child = child; + gtk_window_set_focus (GTK_WINDOW (window), widget); + } +} + +/***************************************** + * gtk_widget_grab_default: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_grab_default (GtkWidget *widget) +{ + GtkWidget *window; + gint window_type; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (widget)); + + window_type = gtk_window_get_type (); + window = widget->parent; + + while (window && !gtk_type_is_a (GTK_WIDGET_TYPE (window), window_type)) + window = window->parent; + + if (window && gtk_type_is_a (GTK_WIDGET_TYPE (window), window_type)) + gtk_window_set_default (GTK_WINDOW (window), widget); +} + +/***************************************** + * gtk_widget_restore_state: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_restore_state (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + + widget->state = widget->saved_state; + if (gtk_signal_emit (GTK_OBJECT (widget), widget_signals[STATE_CHANGED])) + { + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_propagate_restore, + NULL); + } +} + +/***************************************** + * gtk_widget_set_name: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_name (GtkWidget *widget, + const gchar *name) +{ + GtkStyle *new_style; + + g_return_if_fail (widget != NULL); + + if (widget->name) + g_free (widget->name); + widget->name = g_strdup (name); + + if (!GTK_WIDGET_USER_STYLE (widget)) + { + new_style = gtk_rc_get_style (widget); + gtk_widget_set_style_internal (widget, new_style); + } +} + +/***************************************** + * gtk_widget_get_name: + * + * arguments: + * + * results: + *****************************************/ + +gchar* +gtk_widget_get_name (GtkWidget *widget) +{ + g_return_val_if_fail (widget != NULL, NULL); + + if (widget->name) + return widget->name; + return gtk_type_name (GTK_WIDGET_TYPE (widget)); +} + +/***************************************** + * gtk_widget_set_state: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_state (GtkWidget *widget, + GtkStateType state) +{ + g_return_if_fail (widget != NULL); + + if (widget->state != state) + { + widget->saved_state = widget->state; + widget->state = state; + + if (!gtk_signal_emit (GTK_OBJECT (widget), widget_signals[STATE_CHANGED])) + return; + } + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_propagate_state, + (gpointer) &state); +} + +/***************************************** + * gtk_widget_set_sensitive: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_sensitive (GtkWidget *widget, + gint sensitive) +{ + GtkWidget *window; + gint old_val; + + g_return_if_fail (widget != NULL); + + old_val = GTK_WIDGET_IS_SENSITIVE (widget); + + if (sensitive) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_SENSITIVE); + } + else + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_SENSITIVE); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + window = gtk_widget_get_ancestor (widget, gtk_window_get_type ()); + if (window) + gtk_window_set_focus (GTK_WINDOW (window), NULL); + } + } + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_parent_sensitive, + &sensitive); + + if (old_val != GTK_WIDGET_IS_SENSITIVE (widget)) + gtk_widget_queue_draw (widget); +} + +/***************************************** + * gtk_widget_set_parent: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_parent (GtkWidget *widget, + GtkWidget *parent) +{ + GtkStyle *style; + gint sensitive; + + g_return_if_fail (widget != NULL); + g_return_if_fail (parent != NULL); + + gtk_object_ref (GTK_OBJECT (widget)); + + widget->parent = parent; + + sensitive = GTK_WIDGET_IS_SENSITIVE (parent); + gtk_widget_set_parent_sensitive (widget, &sensitive); + + if ((widget->parent->state != GTK_STATE_NORMAL) && + (widget->parent->state != widget->state)) + gtk_widget_set_state (widget, widget->parent->state); + + while (parent->parent != NULL) + parent = parent->parent; + + if (GTK_WIDGET_ANCHORED (parent)) + { + if (!GTK_WIDGET_USER_STYLE (widget)) + { + style = gtk_rc_get_style (widget); + if (style != widget->style) + gtk_widget_set_style_internal (widget, style); + } + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_style_recurse, + NULL); + } +} + +/***************************************** + * gtk_widget_set_style: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_style (GtkWidget *widget, + GtkStyle *style) +{ + g_return_if_fail (widget != NULL); + + GTK_WIDGET_SET_FLAGS (widget, GTK_USER_STYLE); + gtk_widget_set_style_internal (widget, style); +} + +/***************************************** + * gtk_widget_set_uposition: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_uposition (GtkWidget *widget, + gint x, + gint y) +{ + GtkWidgetAuxInfo *aux_info; + + g_return_if_fail (widget != NULL); + + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + if (!aux_info) + { + aux_info = gtk_widget_aux_info_new (); + gtk_object_set_data (GTK_OBJECT (widget), aux_info_key, aux_info); + } + + if (x > -2) + aux_info->x = x; + if (y > -2) + aux_info->y = y; + + if (GTK_WIDGET_REALIZED (widget) && GTK_IS_WINDOW (widget) && + (aux_info->x != -1) && (aux_info->y != -1)) + { + gdk_window_set_hints (widget->window, aux_info->x, aux_info->y, 0, 0, 0, 0, GDK_HINT_POS); + gdk_window_move (widget->window, aux_info->x, aux_info->y); + } + + if (GTK_WIDGET_VISIBLE (widget) && widget->parent) + gtk_widget_size_allocate (widget, &widget->allocation); +} + +/***************************************** + * gtk_widget_set_usize: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_usize (GtkWidget *widget, + gint width, + gint height) +{ + GtkWidgetAuxInfo *aux_info; + + g_return_if_fail (widget != NULL); + + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + if (!aux_info) + { + aux_info = gtk_widget_aux_info_new (); + gtk_object_set_data (GTK_OBJECT (widget), aux_info_key, aux_info); + } + + if (width > -1) + aux_info->width = width; + if (height > -1) + aux_info->height = height; + + if (GTK_WIDGET_VISIBLE (widget)) + gtk_widget_queue_resize (widget); +} + +/***************************************** + * gtk_widget_set_events: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_events (GtkWidget *widget, + gint events) +{ + gint *eventp; + + g_return_if_fail (widget != NULL); + g_return_if_fail (!GTK_WIDGET_NO_WINDOW (widget)); + g_return_if_fail (!GTK_WIDGET_REALIZED (widget)); + + eventp = gtk_object_get_data (GTK_OBJECT (widget), event_key); + + if (events) + { + if (!eventp) + eventp = g_new (gint, 1); + + *eventp = events; + gtk_object_set_data (GTK_OBJECT (widget), event_key, eventp); + } + else + { + if (eventp) + g_free (eventp); + + gtk_object_remove_data (GTK_OBJECT (widget), event_key); + } +} + +/***************************************** + * gtk_widget_set_extension_events: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_extension_events (GtkWidget *widget, + GdkExtensionMode mode) +{ + GdkExtensionMode *modep; + + g_return_if_fail (widget != NULL); + + modep = gtk_object_get_data (GTK_OBJECT (widget), extension_event_key); + + if (!modep) + modep = g_new (GdkExtensionMode, 1); + + *modep = mode; + gtk_object_set_data (GTK_OBJECT (widget), extension_event_key, modep); +} + + +/***************************************** + * gtk_widget_get_toplevel: + * + * arguments: + * + * results: + *****************************************/ + +GtkWidget* +gtk_widget_get_toplevel (GtkWidget *widget) +{ + g_return_val_if_fail (widget != NULL, NULL); + + while (widget->parent) + widget = widget->parent; + + return widget; +} + +/***************************************** + * gtk_widget_get_ancestor: + * + * arguments: + * + * results: + *****************************************/ + +GtkWidget* +gtk_widget_get_ancestor (GtkWidget *widget, + gint type) +{ + g_return_val_if_fail (widget != NULL, NULL); + + while (widget && !gtk_type_is_a (GTK_WIDGET_TYPE (widget), type)) + widget = widget->parent; + + if (!(widget && gtk_type_is_a (GTK_WIDGET_TYPE (widget), type))) + return NULL; + + return widget; +} + +/***************************************** + * gtk_widget_get_colormap: + * + * arguments: + * + * results: + *****************************************/ + +GdkColormap* +gtk_widget_get_colormap (GtkWidget *widget) +{ + GdkColormap *colormap; + + g_return_val_if_fail (widget != NULL, NULL); + + if (!widget->window) + { + colormap = gtk_object_get_data (GTK_OBJECT (widget), colormap_key); + if (colormap) + return colormap; + return gtk_widget_get_default_colormap (); + } + + return gdk_window_get_colormap (widget->window); +} + +/***************************************** + * gtk_widget_get_visual: + * + * arguments: + * + * results: + *****************************************/ + +GdkVisual* +gtk_widget_get_visual (GtkWidget *widget) +{ + GdkVisual *visual; + + g_return_val_if_fail (widget != NULL, NULL); + + if (!widget->window) + { + visual = gtk_object_get_data (GTK_OBJECT (widget), visual_key); + if (visual) + return visual; + return gtk_widget_get_default_visual (); + } + + return gdk_window_get_visual (widget->window); +} + +/***************************************** + * gtk_widget_get_style: + * + * arguments: + * + * results: + *****************************************/ + +GtkStyle* +gtk_widget_get_style (GtkWidget *widget) +{ + g_return_val_if_fail (widget != NULL, NULL); + + return widget->style; +} + +/***************************************** + * gtk_widget_get_events: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_get_events (GtkWidget *widget) +{ + gint *events; + + g_return_val_if_fail (widget != NULL, 0); + + events = gtk_object_get_data (GTK_OBJECT (widget), event_key); + if (events) + return *events; + + return 0; +} + +/***************************************** + * gtk_widget_get_extension_events: + * + * arguments: + * + * results: + *****************************************/ + +GdkExtensionMode +gtk_widget_get_extension_events (GtkWidget *widget) +{ + GdkExtensionMode *mode; + + g_return_val_if_fail (widget != NULL, 0); + + mode = gtk_object_get_data (GTK_OBJECT (widget), extension_event_key); + if (mode) + return *mode; + + return 0; +} + +/***************************************** + * gtk_widget_get_pointer: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_get_pointer (GtkWidget *widget, + gint *x, + gint *y) +{ + g_return_if_fail (widget != NULL); + + if (x) + *x = -1; + if (y) + *y = -1; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_get_pointer (widget->window, x, y, NULL); + + if (GTK_WIDGET_NO_WINDOW (widget)) + { + if (x) + *x -= widget->allocation.x; + if (y) + *y -= widget->allocation.y; + } + } +} + +/***************************************** + * gtk_widget_is_ancestor: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_is_ancestor (GtkWidget *widget, + GtkWidget *ancestor) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (ancestor != NULL, FALSE); + + while (widget) + { + if (widget->parent == ancestor) + return TRUE; + widget = widget->parent; + } + + return FALSE; +} + +/***************************************** + * gtk_widget_is_child: + * + * arguments: + * + * results: + *****************************************/ + +gint +gtk_widget_is_child (GtkWidget *widget, + GtkWidget *child) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (child != NULL, FALSE); + + return (child->parent == widget); +} + +/***************************************** + * gtk_widget_push_colormap: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_push_colormap (GdkColormap *cmap) +{ + colormap_stack = g_slist_prepend (colormap_stack, cmap); +} + +/***************************************** + * gtk_widget_push_visual: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_push_visual (GdkVisual *visual) +{ + visual_stack = g_slist_prepend (visual_stack, visual); +} + +/***************************************** + * gtk_widget_push_style: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_push_style (GtkStyle *style) +{ + gtk_style_ref (style); + style_stack = g_slist_prepend (style_stack, style); +} + +/***************************************** + * gtk_widget_pop_colormap: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_pop_colormap () +{ + GSList *tmp; + + if (colormap_stack) + { + tmp = colormap_stack; + colormap_stack = colormap_stack->next; + g_slist_free_1 (tmp); + } +} + +/***************************************** + * gtk_widget_pop_visual: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_pop_visual () +{ + GSList *tmp; + + if (visual_stack) + { + tmp = visual_stack; + visual_stack = visual_stack->next; + g_slist_free_1 (tmp); + } +} + +/***************************************** + * gtk_widget_pop_style: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_pop_style () +{ + GSList *tmp; + + if (style_stack) + { + tmp = style_stack; + style_stack = style_stack->next; + gtk_style_unref ((GtkStyle*) tmp->data); + g_slist_free_1 (tmp); + } +} + +/***************************************** + * gtk_widget_set_default_colormap: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_default_colormap (GdkColormap *colormap) +{ + if (default_colormap && (default_colormap != colormap)) + gdk_colormap_destroy (default_colormap); + default_colormap = colormap; +} + +/***************************************** + * gtk_widget_set_default_visual: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_default_visual (GdkVisual *visual) +{ + default_visual = visual; +} + +/***************************************** + * gtk_widget_set_default_style: + * + * arguments: + * + * results: + *****************************************/ + +void +gtk_widget_set_default_style (GtkStyle *style) +{ + if (default_style) + gtk_style_unref (default_style); + + default_style = style; + gtk_style_ref (default_style); +} + +/* Basically, send a message to all toplevel windows telling them + that a new _GTK_STYLE_COLORS property is available on the root + window */ +void +gtk_widget_propagate_default_style(void) +{ + GdkEventClient sev; + int i; + + /* Set the property on the root window */ + gdk_property_change(GDK_ROOT_PARENT(), + gdk_atom_intern("_GTK_DEFAULT_COLORS", FALSE), + GDK_NONE, sizeof(gushort), + GDK_PROP_MODE_REPLACE, + gtk_widget_get_default_style(), + GTK_STYLE_NUM_STYLECOLORS() * sizeof(GdkColor)); + + for(i = 0; i < 5; i++) sev.data.l[i] = 0; + sev.data_format = 32; + sev.message_type = gdk_atom_intern("_GTK_STYLE_CHANGED", FALSE); + gdk_event_send_clientmessage_toall(&sev); +} + +/***************************************** + * gtk_widget_get_default_colormap: + * + * arguments: + * + * results: + *****************************************/ + +GdkColormap* +gtk_widget_get_default_colormap () +{ + if (!default_colormap) + default_colormap = gdk_colormap_get_system (); + + return default_colormap; +} + +/***************************************** + * gtk_widget_get_default_visual: + * + * arguments: + * + * results: + *****************************************/ + +GdkVisual* +gtk_widget_get_default_visual () +{ + if (!default_visual) + default_visual = gdk_visual_get_system (); + + return default_visual; +} + +/***************************************** + * gtk_widget_get_default_style: + * + * arguments: + * + * results: + *****************************************/ + +GtkStyle* +gtk_widget_get_default_style () +{ + if (!default_style) + { + default_style = gtk_style_new (); + gtk_style_ref (default_style); + } + + return default_style; +} + + +/***************************************** + * gtk_widget_marshal_signal_1: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWidgetSignal1 rfunc; + + rfunc = (GtkWidgetSignal1) func; + + (* rfunc) (object, GTK_VALUE_POINTER (args[0]), func_data); +} + +/***************************************** + * gtk_widget_marshal_signal_2: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_marshal_signal_2 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWidgetSignal2 rfunc; + gint *return_val; + + rfunc = (GtkWidgetSignal2) func; + return_val = GTK_RETLOC_BOOL (args[3]); + + *return_val = (* rfunc) (object, GTK_VALUE_STRING (args[0]), + GTK_VALUE_CHAR (args[1]), GTK_VALUE_INT (args[2]), + func_data); +} + +/***************************************** + * gtk_widget_marshal_signal_3: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_marshal_signal_3 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWidgetSignal3 rfunc; + + rfunc = (GtkWidgetSignal3) func; + + (* rfunc) (object, GTK_VALUE_STRING (args[0]), func_data); +} + +/***************************************** + * gtk_widget_marshal_signal_4: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_marshal_signal_4 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWidgetSignal4 rfunc; + gint *return_val; + + rfunc = (GtkWidgetSignal4) func; + return_val = GTK_RETLOC_BOOL (args[1]); + + *return_val = (* rfunc) (object, GTK_VALUE_BOXED (args[0]), func_data); +} + +/***************************************** + * gtk_real_widget_destroy: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_destroy (GtkObject *object) +{ + GtkWidget *widget; + GtkWidgetAuxInfo *aux_info; + gint *events; + GdkExtensionMode *mode; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_WIDGET (object)); + + widget = GTK_WIDGET (object); + + if (GTK_WIDGET_REDRAW_PENDING (widget)) + g_warning ("redraw pending\n"); + if (GTK_WIDGET_RESIZE_PENDING (widget)) + g_warning ("resize pending\n"); + if (GTK_WIDGET_RESIZE_NEEDED (widget)) + g_warning ("resize needed\n"); + + gtk_grab_remove (widget); + + gtk_selection_remove_all (widget); + + if (widget->name) + g_free (widget->name); + + aux_info = gtk_object_get_data (GTK_OBJECT (widget), aux_info_key); + if (aux_info) + { + gtk_widget_aux_info_destroy (aux_info); + gtk_object_remove_data (GTK_OBJECT (widget), aux_info_key); + } + + events = gtk_object_get_data (GTK_OBJECT (object), event_key); + if (events) + g_free (events); + + mode = gtk_object_get_data (GTK_OBJECT (object), extension_event_key); + if (mode) + g_free (mode); + + if (GTK_WIDGET_REALIZED (widget)) + gtk_widget_unrealize (widget); + gtk_style_unref (widget->style); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +/***************************************** + * gtk_real_widget_show: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_show (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (!GTK_WIDGET_VISIBLE (widget)) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); + + if (widget->parent) + { + gtk_widget_queue_resize (widget); + + if (GTK_WIDGET_MAPPED (widget->parent)) + gtk_widget_map (widget); + } + } +} + +/***************************************** + * gtk_real_widget_hide: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_hide (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_VISIBLE (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE); + + if (GTK_WIDGET_MAPPED (widget)) + gtk_widget_unmap (widget); + + if (widget->parent) + gtk_widget_queue_resize (widget); + } +} + +/***************************************** + * gtk_real_widget_map: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_map (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + if (!GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_show (widget->window); + else + gtk_widget_queue_draw (widget); + } +} + +/***************************************** + * gtk_real_widget_unmap: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_MAPPED (widget)) + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + + if (GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + else + gdk_window_hide (widget->window); + } +} + +/***************************************** + * gtk_real_widget_realize: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_realize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + if(widget->parent) + widget->window = widget->parent->window; + widget->style = gtk_style_attach (widget->style, widget->window); +} + +/***************************************** + * gtk_real_widget_unrealize: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_unrealize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + if (!GTK_WIDGET_NO_WINDOW (widget)) + { + gdk_window_set_user_data (widget->window, NULL); + gdk_window_destroy (widget->window); + } + widget->window = NULL; +} + +/***************************************** + * gtk_real_widget_draw: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GdkEventExpose event; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + event.type = GDK_EXPOSE; + event.window = widget->window; + event.area = *area; + + gtk_widget_event (widget, (GdkEvent*) &event); + } +} + +/***************************************** + * gtk_real_widget_queue_draw: + * + * arguments: + * + * results: + *****************************************/ + +static gint +gtk_real_widget_queue_draw (GtkWidget *widget) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REDRAW_PENDING); + + gtk_object_unref (GTK_OBJECT (widget)); + if (GTK_OBJECT_NEED_DESTROY (widget) && + (GTK_OBJECT (widget)->ref_count == 0)) + gtk_widget_destroy (widget); + else + gtk_widget_draw (widget, NULL); + + return FALSE; +} + +/***************************************** + * gtk_real_widget_queue_resize: + * + * arguments: + * + * results: + *****************************************/ + +static gint +gtk_real_widget_queue_resize (GtkWidget *widget) +{ + GSList *resize_widgets; + GSList *tmp_list; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_PENDING); + + gtk_object_unref (GTK_OBJECT (widget)); + if (GTK_OBJECT_NEED_DESTROY (widget) && + (GTK_OBJECT (widget)->ref_count == 0)) + { + gtk_widget_destroy (widget); + } + else + { + gtk_container_need_resize (GTK_CONTAINER (widget)); + + if (!GTK_WIDGET_RESIZE_PENDING (widget)) + { + resize_widgets = gtk_object_get_data (GTK_OBJECT (widget), resize_widgets_key); + + tmp_list = resize_widgets; + while (tmp_list) + { + GtkWidget *child; + + child = tmp_list->data; + tmp_list = tmp_list->next; + + /* referencing needed? */ + GTK_WIDGET_UNSET_FLAGS (child, GTK_RESIZE_NEEDED); + gtk_object_unref (GTK_OBJECT (child)); + } + + if (resize_widgets) + { + gtk_object_set_data (GTK_OBJECT (widget), resize_widgets_key, NULL); + g_slist_free (resize_widgets); + } + } + } + + return FALSE; +} + +/***************************************** + * gtk_real_widget_size_allocate: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_real_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + if (GTK_WIDGET_NO_WINDOW (widget) && + GTK_WIDGET_MAPPED (widget) && + ((widget->allocation.x != allocation->x) || + (widget->allocation.y != allocation->y) || + (widget->allocation.width != allocation->width) || + (widget->allocation.height != allocation->height)) && + (widget->allocation.width != 0) && + (widget->allocation.height != 0)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + + widget->allocation = *allocation; + + if (GTK_WIDGET_REALIZED (widget) && + !GTK_WIDGET_NO_WINDOW (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); +} + +/***************************************** + * gtk_widget_peek_colormap: + * + * arguments: + * + * results: + *****************************************/ + +static GdkColormap* +gtk_widget_peek_colormap () +{ + if (colormap_stack) + return (GdkColormap*) colormap_stack->data; + return gtk_widget_get_default_colormap (); +} + +/***************************************** + * gtk_widget_peek_visual: + * + * arguments: + * + * results: + *****************************************/ + +static GdkVisual* +gtk_widget_peek_visual () +{ + if (visual_stack) + return (GdkVisual*) visual_stack->data; + return gtk_widget_get_default_visual (); +} + +/***************************************** + * gtk_widget_peek_style: + * + * arguments: + * + * results: + *****************************************/ + +static GtkStyle* +gtk_widget_peek_style () +{ + if (style_stack) + return (GtkStyle*) style_stack->data; + return gtk_widget_get_default_style (); +} + + +/***************************************** + * gtk_widget_set_parent_sensitive: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_set_parent_sensitive (GtkWidget *widget, + gpointer client_data) +{ + GtkWidget *window; + gint *sensitive; + + sensitive = client_data; + if (*sensitive) + { + GTK_WIDGET_SET_FLAGS (widget, GTK_PARENT_SENSITIVE); + + if (GTK_IS_CONTAINER (widget) && GTK_WIDGET_SENSITIVE (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_parent_sensitive, + client_data); + } + else + { + GTK_WIDGET_UNSET_FLAGS (widget, GTK_PARENT_SENSITIVE); + + if (GTK_WIDGET_HAS_FOCUS (widget)) + { + window = gtk_widget_get_ancestor (widget, gtk_window_get_type ()); + if (window) + gtk_window_set_focus (GTK_WINDOW (window), NULL); + } + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_parent_sensitive, + client_data); + } +} + +/***************************************** + * gtk_widget_propagate_restore: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_propagate_restore (GtkWidget *widget, + gpointer client_data) +{ + gtk_widget_restore_state (widget); +} + +/***************************************** + * gtk_widget_propagate_state: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_propagate_state (GtkWidget *widget, + gpointer client_data) +{ + GtkStateType *state; + + state = (GtkStateType*) client_data; + gtk_widget_set_state (widget, *state); +} + +/***************************************** + * gtk_widget_draw_children_recurse: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_draw_children_recurse (GtkWidget *widget, + gpointer client_data) +{ + gtk_widget_draw (widget, NULL); + gtk_widget_draw_children (widget); +} + +/***************************************** + * gtk_widget_set_style_internal: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_set_style_internal (GtkWidget *widget, + GtkStyle *style) +{ + GtkRequisition old_requisition; + + g_return_if_fail (widget != NULL); + + if (widget->style != style) + { + if (GTK_WIDGET_REALIZED (widget)) + gtk_style_detach (widget->style); + + gtk_style_unref (widget->style); + + widget->style = style; + gtk_style_ref (widget->style); + + if (GTK_WIDGET_REALIZED (widget)) + widget->style = gtk_style_attach (widget->style, widget->window); + + if (widget->parent) + { + old_requisition = widget->requisition; + gtk_widget_size_request (widget, &widget->requisition); + + if ((old_requisition.width != widget->requisition.width) || + (old_requisition.height != widget->requisition.height)) + gtk_widget_queue_resize (widget); + else if (GTK_WIDGET_DRAWABLE (widget)) + gtk_widget_queue_draw (widget); + } + } +} + +/***************************************** + * gtk_widget_set_style_recurse: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_set_style_recurse (GtkWidget *widget, + gpointer client_data) +{ + GtkStyle *style; + + style = gtk_rc_get_style (widget); + if (style != widget->style) + gtk_widget_set_style_internal (widget, style); + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_widget_set_style_recurse, + NULL); +} + +/***************************************** + * gtk_widget_aux_info_new: + * + * arguments: + * + * results: + *****************************************/ + +static GtkWidgetAuxInfo* +gtk_widget_aux_info_new () +{ + GtkWidgetAuxInfo *aux_info; + + if (!aux_info_mem_chunk) + aux_info_mem_chunk = g_mem_chunk_new ("widget aux info mem chunk", + sizeof (GtkWidgetAuxInfo), + 1024, G_ALLOC_AND_FREE); + + aux_info = g_chunk_new (GtkWidgetAuxInfo, aux_info_mem_chunk); + + aux_info->x = -1; + aux_info->y = -1; + aux_info->width = 0; + aux_info->height = 0; + + return aux_info; +} + +/***************************************** + * gtk_widget_aux_info_destroy: + * + * arguments: + * + * results: + *****************************************/ + +static void +gtk_widget_aux_info_destroy (GtkWidgetAuxInfo *aux_info) +{ + g_return_if_fail (aux_info != NULL); + + g_mem_chunk_free (aux_info_mem_chunk, aux_info); +} + +/***************************************** + * gtk_widget_shape_combine_mask: + * set a shape for this widgets' gdk window, this allows for + * transparent windows etc., see gdk_window_shape_combine_mask + * for more information + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_shape_combine_mask (GtkWidget *widget, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y) +{ + GtkWidgetShapeInfo* shape_info; + + g_return_if_fail (widget != NULL); + g_return_if_fail (shape_mask != NULL); + /* set_shape doesn't work on widgets without gdk window */ + g_return_if_fail (!GTK_WIDGET_NO_WINDOW (widget)); + + /* + * remember shape mask for later gtk_widget_realize's + */ + shape_info = gtk_object_get_data (GTK_OBJECT (widget), shape_info_key); + if (!shape_info) + { + shape_info = g_new (GtkWidgetShapeInfo, 1); + gtk_object_set_data (GTK_OBJECT (widget), shape_info_key, shape_info); + } + shape_info->shape_mask = shape_mask; + shape_info->offset_x = offset_x; + shape_info->offset_y = offset_y; + GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_SHAPE_MASK); + + /* + * set shape if widget has a gdk window allready. + * otherwise the shape is scheduled to be set by gtk_widget_realize. + */ + if (widget->window) + gdk_window_shape_combine_mask (widget->window, shape_mask, + offset_x, offset_y); + +} + +/***************************************** + * gtk_widget_dnd_drag_add: + * when you get a DRAG_ENTER event, you can use this + * to tell Gtk ofother widgets that are to be dragged as well + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_dnd_drag_add (GtkWidget *widget) +{ +} + +/***************************************** + * gtk_widget_dnd_drag_set: + * these two functions enable drag and/or drop on a + * widget and also let Gtk know what data types will be accepted + * use MIME type naming,plus tacking "URL:" on the front for link + * dragging + * + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_dnd_drag_set (GtkWidget *widget, + guint8 drag_enable, + gchar **type_accept_list, + guint numtypes) +{ + g_return_if_fail(widget != NULL); + + if (!widget->window) + gtk_widget_realize (widget); + + g_return_if_fail (widget->window != NULL); + gdk_window_dnd_drag_set (widget->window, + drag_enable, + type_accept_list, + numtypes); +} + +/***************************************** + * gtk_widget_dnd_drop_set: + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_dnd_drop_set (GtkWidget *widget, + guint8 drop_enable, + gchar **type_accept_list, + guint numtypes, + guint8 is_destructive_operation) +{ + g_return_if_fail(widget != NULL); + + if (!widget->window) + gtk_widget_realize (widget); + + g_return_if_fail (widget->window != NULL); + gdk_window_dnd_drop_set (widget->window, + drop_enable, + type_accept_list, + numtypes, + is_destructive_operation); +} + +/***************************************** + * gtk_widget_dnd_data_set: + * + * arguments: + * + * results: + *****************************************/ +void +gtk_widget_dnd_data_set (GtkWidget *widget, + GdkEvent *event, + gpointer data, + gulong data_numbytes) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (widget->window != NULL); + + gdk_window_dnd_data_set (widget->window, event, data, data_numbytes); +} + diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h new file mode 100644 index 000000000..51ea9940c --- /dev/null +++ b/gtk/gtkwidget.h @@ -0,0 +1,505 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_WIDGET_H__ +#define __GTK_WIDGET_H__ + + +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* The flags that are used in the flags member of the GtkObject + * structure. + */ +enum +{ + GTK_VISIBLE = 1 << 3, + GTK_MAPPED = 1 << 4, + GTK_UNMAPPED = 1 << 5, + GTK_REALIZED = 1 << 6, + GTK_SENSITIVE = 1 << 7, + GTK_PARENT_SENSITIVE = 1 << 8, + GTK_NO_WINDOW = 1 << 9, + GTK_HAS_FOCUS = 1 << 10, + GTK_CAN_FOCUS = 1 << 11, + GTK_HAS_DEFAULT = 1 << 12, + GTK_CAN_DEFAULT = 1 << 13, + GTK_PROPAGATE_STATE = 1 << 14, + GTK_ANCHORED = 1 << 15, + GTK_BASIC = 1 << 16, + GTK_USER_STYLE = 1 << 17, + GTK_GRAB_ALL = 1 << 18, + GTK_REDRAW_PENDING = 1 << 19, + GTK_RESIZE_PENDING = 1 << 20, + GTK_RESIZE_NEEDED = 1 << 21, + GTK_HAS_SHAPE_MASK = 1 << 22 +}; + + +/* Macro for casting a pointer to a GtkWidget pointer. + */ +#define GTK_WIDGET(obj) GTK_CHECK_CAST (obj, gtk_widget_get_type (), GtkWidget) + +/* Macro for casting the "class" field of an object to + * a GtkWidgetClass pointer. + */ +#define GTK_WIDGET_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_widget_get_type (), GtkWidgetClass) + +/* Macros for extracting various fields from GtkWidget and + * GtkWidgetClass structures. + */ +#define GTK_WIDGET_TYPE(obj) (GTK_OBJECT_TYPE (obj)) +#define GTK_WIDGET_STATE(obj) (GTK_WIDGET (obj)->state) +#define GTK_WIDGET_SAVED_STATE(obj) (GTK_WIDGET (obj)->saved_state) +#define GTK_WIDGET_VISIBLE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_VISIBLE) +#define GTK_WIDGET_MAPPED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_MAPPED) +#define GTK_WIDGET_UNMAPPED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_UNMAPPED) +#define GTK_WIDGET_REALIZED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_REALIZED) +#define GTK_WIDGET_SENSITIVE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_SENSITIVE) +#define GTK_WIDGET_PARENT_SENSITIVE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_PARENT_SENSITIVE) +#define GTK_WIDGET_IS_SENSITIVE(obj) ((GTK_WIDGET_SENSITIVE (obj) && \ + GTK_WIDGET_PARENT_SENSITIVE (obj)) != 0) +#define GTK_WIDGET_NO_WINDOW(obj) (GTK_OBJECT_FLAGS (obj) & GTK_NO_WINDOW) +#define GTK_WIDGET_HAS_FOCUS(obj) (GTK_OBJECT_FLAGS (obj) & GTK_HAS_FOCUS) +#define GTK_WIDGET_CAN_FOCUS(obj) (GTK_OBJECT_FLAGS (obj) & GTK_CAN_FOCUS) +#define GTK_WIDGET_HAS_DEFAULT(obj) (GTK_OBJECT_FLAGS (obj) & GTK_HAS_DEFAULT) +#define GTK_WIDGET_CAN_DEFAULT(obj) (GTK_OBJECT_FLAGS (obj) & GTK_CAN_DEFAULT) +#define GTK_WIDGET_PROPAGATE_STATE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_PROPAGATE_STATE) +#define GTK_WIDGET_DRAWABLE(obj) (GTK_WIDGET_VISIBLE (obj) && GTK_WIDGET_MAPPED (obj)) +#define GTK_WIDGET_ANCHORED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_ANCHORED) +#define GTK_WIDGET_BASIC(obj) (GTK_OBJECT_FLAGS (obj) & GTK_BASIC) +#define GTK_WIDGET_USER_STYLE(obj) (GTK_OBJECT_FLAGS (obj) & GTK_USER_STYLE) +#define GTK_WIDGET_GRAB_ALL(obj) (GTK_OBJECT_FLAGS (obj) & GTK_GRAB_ALL) +#define GTK_WIDGET_REDRAW_PENDING(obj) (GTK_OBJECT_FLAGS (obj) & GTK_REDRAW_PENDING) +#define GTK_WIDGET_RESIZE_PENDING(obj) (GTK_OBJECT_FLAGS (obj) & GTK_RESIZE_PENDING) +#define GTK_WIDGET_RESIZE_NEEDED(obj) (GTK_OBJECT_FLAGS (obj) & GTK_RESIZE_NEEDED) +#define GTK_WIDGET_HAS_SHAPE_MASK(obj) (GTK_OBJECT_FLAGS (obj) & GTK_HAS_SHAPE_MASK) + +#define GTK_TYPE_WIDGET (gtk_widget_get_type ()) + +/* Macro for testing whether "obj" is of type GtkWidget. + */ +#define GTK_IS_WIDGET(obj) GTK_CHECK_TYPE (obj, GTK_TYPE_WIDGET) + +/* Macros for setting and clearing widget flags. Notice + * that these are only wrappers for the macros which + * set and clear the flags in the GtkObject structure. + */ +#define GTK_WIDGET_SET_FLAGS(obj,flag) (GTK_OBJECT_SET_FLAGS (obj, flag)) +#define GTK_WIDGET_UNSET_FLAGS(obj,flag) (GTK_OBJECT_UNSET_FLAGS (obj, flag)) + + + +typedef struct _GtkRequisition GtkRequisition; +typedef struct _GtkAllocation GtkAllocation; +typedef struct _GtkSelectionData GtkSelectionData; +typedef struct _GtkWidget GtkWidget; +typedef struct _GtkWidgetClass GtkWidgetClass; +typedef struct _GtkWidgetAuxInfo GtkWidgetAuxInfo; +typedef struct _GtkWidgetShapeInfo GtkWidgetShapeInfo; + +typedef void (*GtkCallback) (GtkWidget *widget, + gpointer data); + +/* A requisition is a desired amount of space which a + * widget may request. + */ +struct _GtkRequisition +{ + guint16 width; + guint16 height; +}; + +/* An allocation is a size and position. Where a widget + * can ask for a desired size, it is actually given + * this amount of space at the specified position. + */ +struct _GtkAllocation +{ + gint16 x; + gint16 y; + guint16 width; + guint16 height; +}; + +/* The contents of a selection are returned in a GtkSelectionData + structure. selection/target identify the request. + type specifies the type of the return; if length < 0, and + the data should be ignored. This structure has object semantics - + no fields should be modified directly, they should not be created + directly, and pointers to them should not be stored beyond the duration of + a callback. (If the last is changed, we'll need to add reference + counting) */ + +struct _GtkSelectionData +{ + GdkAtom selection; + GdkAtom target; + GdkAtom type; + gint format; + guchar *data; + gint length; +}; + +/* The widget is the base of the tree for displayable objects. + * (A displayable object is one which takes up some amount + * of screen real estate). It provides a common base and interface + * which actual widgets must adhere to. + */ +struct _GtkWidget +{ + /* The object structure needs to be the first + * element in the widget structure in order for + * the object mechanism to work correctly. This + * allows a GtkWidget pointer to be cast to a + * GtkObject pointer. + */ + GtkObject object; + + /* The state of the widget. There are actually only + * 5 widget states (defined in "gtkenums.h"). + */ + guint8 state; + + /* The saved state of the widget. When a widgets state + * is changed via "gtk_widget_set_state" the old state + * is kept around in this field. The state may be + * restored using "gtk_widget_restore_state". + */ + guint8 saved_state; + + /* The widgets name. If the widget does not have a name + * (the name is NULL), then its name (as returned by + * "gtk_widget_get_name") is its classes name. + * The widget name is used to determine the style to + * use for a widget. + */ + gchar *name; + + /* The style for the widget. The style contains the + * colors the widget should be drawn in for each state + * along with graphics contexts used to draw with and + * the font to use for text. + */ + GtkStyle *style; + + /* The widgets desired size. + */ + GtkRequisition requisition; + + /* The widgets allocated size. + */ + GtkAllocation allocation; + + /* The widgets window or its parent window if it does + * not have a window. (Which will be indicated by the + * GTK_NO_WINDOW flag being set). + */ + GdkWindow *window; + + /* The widgets parent. + */ + GtkWidget *parent; +}; + +struct _GtkWidgetClass +{ + /* The object class structure needs to be the first + * element in the widget class structure in order for + * the class mechanism to work correctly. This allows a + * GtkWidgetClass pointer to be cast to a GtkObjectClass + * pointer. + */ + GtkObjectClass parent_class; + + /* The signal to emit when an object of this class is activated. + * This is used when activating the current focus widget and + * the default widget. + */ + gint activate_signal; + + /* basics */ + void (* show) (GtkWidget *widget); + void (* hide) (GtkWidget *widget); + void (* map) (GtkWidget *widget); + void (* unmap) (GtkWidget *widget); + void (* realize) (GtkWidget *widget); + void (* unrealize) (GtkWidget *widget); + void (* draw) (GtkWidget *widget, + GdkRectangle *area); + void (* draw_focus) (GtkWidget *widget); + void (* draw_default) (GtkWidget *widget); + void (* size_request) (GtkWidget *widget, + GtkRequisition *requisition); + void (* size_allocate) (GtkWidget *widget, + GtkAllocation *allocation); + void (* state_changed) (GtkWidget *widget); + + /* accelerators */ + gint (* install_accelerator) (GtkWidget *widget, + const gchar *signal_name, + gchar key, + guint8 modifiers); + void (* remove_accelerator) (GtkWidget *widget, + const gchar *signal_name); + + /* events */ + gint (* event) (GtkWidget *widget, + GdkEvent *event); + gint (* button_press_event) (GtkWidget *widget, + GdkEventButton *event); + gint (* button_release_event) (GtkWidget *widget, + GdkEventButton *event); + gint (* motion_notify_event) (GtkWidget *widget, + GdkEventMotion *event); + gint (* delete_event) (GtkWidget *widget, + GdkEventAny *event); + gint (* destroy_event) (GtkWidget *widget, + GdkEventAny *event); + gint (* expose_event) (GtkWidget *widget, + GdkEventExpose *event); + gint (* key_press_event) (GtkWidget *widget, + GdkEventKey *event); + gint (* key_release_event) (GtkWidget *widget, + GdkEventKey *event); + gint (* enter_notify_event) (GtkWidget *widget, + GdkEventCrossing *event); + gint (* leave_notify_event) (GtkWidget *widget, + GdkEventCrossing *event); + gint (* configure_event) (GtkWidget *widget, + GdkEventConfigure *event); + gint (* focus_in_event) (GtkWidget *widget, + GdkEventFocus *event); + gint (* focus_out_event) (GtkWidget *widget, + GdkEventFocus *event); + gint (* map_event) (GtkWidget *widget, + GdkEventAny *event); + gint (* unmap_event) (GtkWidget *widget, + GdkEventAny *event); + gint (* property_notify_event) (GtkWidget *widget, + GdkEventProperty *event); + gint (* selection_clear_event) (GtkWidget *widget, + GdkEventSelection *event); + gint (* selection_request_event) (GtkWidget *widget, + GdkEventSelection *event); + gint (* selection_notify_event) (GtkWidget *widget, + GdkEventSelection *event); + gint (* proximity_in_event) (GtkWidget *widget, + GdkEventProximity *event); + gint (* proximity_out_event) (GtkWidget *widget, + GdkEventProximity *event); + gint (* drag_begin_event) (GtkWidget *widget, + GdkEventDragBegin *event); + gint (* drag_request_event) (GtkWidget *widget, + GdkEventDragRequest *event); + gint (* drop_enter_event) (GtkWidget *widget, + GdkEventDropEnter *event); + gint (* drop_leave_event) (GtkWidget *widget, + GdkEventDropLeave *event); + gint (* drop_data_available_event) (GtkWidget *widget, + GdkEventDropDataAvailable *event); + gint (* other_event) (GtkWidget *widget, + GdkEventOther *event); + + /* selection */ + void (* selection_received) (GtkWidget *widget, + GtkSelectionData *selection_data); + + gint (* client_event) (GtkWidget *widget, + GdkEventClient *event); +}; + +struct _GtkWidgetAuxInfo +{ + gint16 x; + gint16 y; + guint16 width; + guint16 height; +}; + +struct _GtkWidgetShapeInfo +{ + gint16 offset_x; + gint16 offset_y; + GdkBitmap *shape_mask; +}; + + +guint gtk_widget_get_type (void); +GtkWidget* gtk_widget_new (guint type, + ...); +GtkWidget* gtk_widget_newv (guint type, + gint nargs, + GtkArg *args); +void gtk_widget_set (GtkWidget *widget, + ...); +void gtk_widget_setv (GtkWidget *widget, + gint nargs, + GtkArg *args); +void gtk_widget_destroy (GtkWidget *widget); +void gtk_widget_unparent (GtkWidget *widget); +void gtk_widget_show (GtkWidget *widget); +void gtk_widget_hide (GtkWidget *widget); +void gtk_widget_map (GtkWidget *widget); +void gtk_widget_unmap (GtkWidget *widget); +void gtk_widget_realize (GtkWidget *widget); +void gtk_widget_unrealize (GtkWidget *widget); +void gtk_widget_queue_draw (GtkWidget *widget); +void gtk_widget_queue_resize (GtkWidget *widget); +void gtk_widget_draw (GtkWidget *widget, + GdkRectangle *area); +void gtk_widget_draw_focus (GtkWidget *widget); +void gtk_widget_draw_default (GtkWidget *widget); +void gtk_widget_draw_children (GtkWidget *widget); +void gtk_widget_size_request (GtkWidget *widget, + GtkRequisition *requisition); +void gtk_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +void gtk_widget_install_accelerator (GtkWidget *widget, + GtkAcceleratorTable *table, + const gchar *signal_name, + gchar key, + guint8 modifiers); +void gtk_widget_remove_accelerator (GtkWidget *widget, + GtkAcceleratorTable *table, + const gchar *signal_name); +gint gtk_widget_event (GtkWidget *widget, + GdkEvent *event); + +void gtk_widget_activate (GtkWidget *widget); +void gtk_widget_reparent (GtkWidget *widget, + GtkWidget *new_parent); +void gtk_widget_popup (GtkWidget *widget, + gint x, + gint y); +gint gtk_widget_intersect (GtkWidget *widget, + GdkRectangle *area, + GdkRectangle *intersection); +gint gtk_widget_basic (GtkWidget *widget); + +void gtk_widget_grab_focus (GtkWidget *widget); +void gtk_widget_grab_default (GtkWidget *widget); + +void gtk_widget_restore_state (GtkWidget *widget); +void gtk_widget_set_name (GtkWidget *widget, + const gchar *name); +gchar* gtk_widget_get_name (GtkWidget *widget); +void gtk_widget_set_state (GtkWidget *widget, + GtkStateType state); +void gtk_widget_set_sensitive (GtkWidget *widget, + gint sensitive); +void gtk_widget_set_parent (GtkWidget *widget, + GtkWidget *parent); +void gtk_widget_set_style (GtkWidget *widget, + GtkStyle *style); +void gtk_widget_set_uposition (GtkWidget *widget, + gint x, + gint y); +void gtk_widget_set_usize (GtkWidget *widget, + gint width, + gint height); +void gtk_widget_set_events (GtkWidget *widget, + gint events); +void gtk_widget_set_extension_events (GtkWidget *widget, + GdkExtensionMode mode); + +GtkWidget* gtk_widget_get_toplevel (GtkWidget *widget); +GtkWidget* gtk_widget_get_ancestor (GtkWidget *widget, + gint type); +GdkColormap* gtk_widget_get_colormap (GtkWidget *widget); +GdkVisual* gtk_widget_get_visual (GtkWidget *widget); +GtkStyle* gtk_widget_get_style (GtkWidget *widget); +gint gtk_widget_get_events (GtkWidget *widget); +GdkExtensionMode gtk_widget_get_extension_events (GtkWidget *widget); +void gtk_widget_get_pointer (GtkWidget *widget, + gint *x, + gint *y); + +gint gtk_widget_is_ancestor (GtkWidget *widget, + GtkWidget *ancestor); +gint gtk_widget_is_child (GtkWidget *widget, + GtkWidget *child); + +void gtk_widget_push_colormap (GdkColormap *cmap); +void gtk_widget_push_visual (GdkVisual *visual); +void gtk_widget_push_style (GtkStyle *style); + +void gtk_widget_pop_colormap (void); +void gtk_widget_pop_visual (void); +void gtk_widget_pop_style (void); + +void gtk_widget_set_default_colormap (GdkColormap *colormap); +void gtk_widget_set_default_visual (GdkVisual *visual); +void gtk_widget_set_default_style (GtkStyle *style); +/* Tells other Gtk applications to use the same default style */ +void gtk_widget_propagate_default_style(void); +GdkColormap* gtk_widget_get_default_colormap (void); +GdkVisual* gtk_widget_get_default_visual (void); +GtkStyle* gtk_widget_get_default_style (void); + +/* + * see gdk_window_shape_combine_mask + */ +void gtk_widget_shape_combine_mask (GtkWidget *widget, + GdkBitmap *shape_mask, + gint offset_x, + gint offset_y); + +/* + * When you get a drag_enter event, you can use this to tell Gtk of other + * items that are to be dragged as well... + */ +void gtk_widget_dnd_drag_add (GtkWidget *widget); + +/* + * These two functions enable drag and/or drop on a widget, + * and also let Gtk know what data types will be accepted (use MIME type + * naming, plus tacking "URL:" on the front for link dragging) + */ +void gtk_widget_dnd_drag_set (GtkWidget *widget, + guint8 drag_enable, + gchar **type_accept_list, + guint numtypes); +void gtk_widget_dnd_drop_set (GtkWidget *widget, + guint8 drop_enable, + gchar **type_accept_list, + guint numtypes, + guint8 is_destructive_operation); + +/* + * used to reply to a DRAG_REQUEST event - if you don't want to + * give the data then pass in NULL for it + */ +void gtk_widget_dnd_data_set (GtkWidget *widget, + GdkEvent *event, + gpointer data, + gulong data_numbytes); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_WIDGET_H__ */ diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c new file mode 100644 index 000000000..e97708a96 --- /dev/null +++ b/gtk/gtkwindow.c @@ -0,0 +1,1195 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gdk/gdk.h" +#include "gdk/gdkkeysyms.h" +#include "gdk/gdkx.h" +#include "gtksignal.h" +#include "gtkwindow.h" + +enum { + MOVE_RESIZE, + LAST_SIGNAL +}; + + +typedef gint (*GtkWindowSignal1) (GtkObject *object, + gpointer arg1, + gpointer arg2, + gint arg3, + gint arg4, + gpointer data); + + +static void gtk_window_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); + +static void gtk_window_class_init (GtkWindowClass *klass); +static void gtk_window_init (GtkWindow *window); +static void gtk_window_arg (GtkWindow *window, + GtkArg *arg); +static void gtk_window_destroy (GtkObject *object); +static void gtk_window_show (GtkWidget *widget); +static void gtk_window_hide (GtkWidget *widget); +static void gtk_window_map (GtkWidget *widget); +static void gtk_window_unmap (GtkWidget *widget); +static void gtk_window_realize (GtkWidget *widget); +static void gtk_window_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_window_expose_event (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_window_configure_event (GtkWidget *widget, + GdkEventConfigure *event); +static gint gtk_window_key_press_event (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_window_key_release_event (GtkWidget *widget, + GdkEventKey *event); +static gint gtk_window_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_window_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event); +static gint gtk_window_focus_in_event (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_window_focus_out_event (GtkWidget *widget, + GdkEventFocus *event); +static gint gtk_window_client_event (GtkWidget *widget, + GdkEvent *event); +static gint gtk_window_need_resize (GtkContainer *container); +static gint gtk_real_window_move_resize (GtkWindow *window, + gint *x, + gint *y, + gint width, + gint height); +static gint gtk_window_move_resize (GtkWidget *widget); +static void gtk_window_set_hints (GtkWidget *widget, + GtkRequisition *requisition); +static gint gtk_window_check_accelerator (GtkWindow *window, + gint key, + guint mods); + + +static GtkBinClass *parent_class = NULL; +static gint window_signals[LAST_SIGNAL] = { 0 }; + + +guint +gtk_window_get_type () +{ + static guint window_type = 0; + + if (!window_type) + { + GtkTypeInfo window_info = + { + "GtkWindow", + sizeof (GtkWindow), + sizeof (GtkWindowClass), + (GtkClassInitFunc) gtk_window_class_init, + (GtkObjectInitFunc) gtk_window_init, + (GtkArgFunc) gtk_window_arg, + }; + + window_type = gtk_type_unique (gtk_bin_get_type (), &window_info); + } + + return window_type; +} + +static void +gtk_window_class_init (GtkWindowClass *klass) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) klass; + widget_class = (GtkWidgetClass*) klass; + container_class = (GtkContainerClass*) klass; + + parent_class = gtk_type_class (gtk_bin_get_type ()); + + gtk_object_add_arg_type ("GtkWindow::type", GTK_TYPE_WINDOW_TYPE); + gtk_object_add_arg_type ("GtkWindow::title", GTK_TYPE_STRING); + gtk_object_add_arg_type ("GtkWindow::auto_shrink", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkWindow::allow_shrink", GTK_TYPE_BOOL); + gtk_object_add_arg_type ("GtkWindow::allow_grow", GTK_TYPE_BOOL); + + window_signals[MOVE_RESIZE] = + gtk_signal_new ("move_resize", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (GtkWindowClass, move_resize), + gtk_window_marshal_signal_1, + GTK_TYPE_BOOL, 4, + GTK_TYPE_POINTER, GTK_TYPE_POINTER, + GTK_TYPE_INT, GTK_TYPE_INT); + + gtk_object_class_add_signals (object_class, window_signals, LAST_SIGNAL); + + object_class->destroy = gtk_window_destroy; + + widget_class->show = gtk_window_show; + widget_class->hide = gtk_window_hide; + widget_class->map = gtk_window_map; + widget_class->unmap = gtk_window_unmap; + widget_class->realize = gtk_window_realize; + widget_class->size_request = gtk_window_size_request; + widget_class->size_allocate = gtk_window_size_allocate; + widget_class->expose_event = gtk_window_expose_event; + widget_class->configure_event = gtk_window_configure_event; + widget_class->key_press_event = gtk_window_key_press_event; + widget_class->key_release_event = gtk_window_key_release_event; + widget_class->enter_notify_event = gtk_window_enter_notify_event; + widget_class->leave_notify_event = gtk_window_leave_notify_event; + widget_class->focus_in_event = gtk_window_focus_in_event; + widget_class->focus_out_event = gtk_window_focus_out_event; + widget_class->client_event = gtk_window_client_event; + + container_class->need_resize = gtk_window_need_resize; + + klass->move_resize = gtk_real_window_move_resize; +} + +static void +gtk_window_init (GtkWindow *window) +{ + GTK_WIDGET_UNSET_FLAGS (window, GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (window, GTK_ANCHORED); + + window->title = NULL; + window->wmclass_name = NULL; + window->wmclass_class = NULL; + window->type = GTK_WINDOW_TOPLEVEL; + window->accelerator_tables = NULL; + window->focus_widget = NULL; + window->default_widget = NULL; + window->resize_count = 0; + window->need_resize = FALSE; + window->allow_shrink = FALSE; + window->allow_grow = TRUE; + window->auto_shrink = FALSE; + window->handling_resize = FALSE; + window->position = GTK_WIN_POS_NONE; + window->use_uposition = TRUE; +} + +static void +gtk_window_arg (GtkWindow *window, + GtkArg *arg) +{ + if (strcmp (arg->name, "type") == 0) + { + window->type = GTK_VALUE_ENUM(*arg); + } + else if (strcmp (arg->name, "title") == 0) + { + gtk_window_set_title (window, GTK_VALUE_STRING(*arg)); + } + else if (strcmp (arg->name, "auto_shrink") == 0) + { + window->auto_shrink = (GTK_VALUE_BOOL(*arg) != FALSE); + } + else if (strcmp (arg->name, "allow_shrink") == 0) + { + window->allow_shrink = (GTK_VALUE_BOOL(*arg) != FALSE); + } + else if (strcmp (arg->name, "allow_grow") == 0) + { + window->allow_grow = (GTK_VALUE_BOOL(*arg) != FALSE); + } +} + +GtkWidget* +gtk_window_new (GtkWindowType type) +{ + GtkWindow *window; + + window = gtk_type_new (gtk_window_get_type ()); + + window->type = type; + + return GTK_WIDGET (window); +} + +void +gtk_window_set_title (GtkWindow *window, + const gchar *title) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + if (window->title) + g_free (window->title); + window->title = g_strdup (title); + + if (GTK_WIDGET_REALIZED (window)) + gdk_window_set_title (GTK_WIDGET (window)->window, window->title); +} + +void +gtk_window_set_wmclass (GtkWindow *window, + gchar *wmclass_name, + gchar *wmclass_class) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + if (window->wmclass_name) + g_free (window->wmclass_name); + window->wmclass_name = g_strdup (wmclass_name); + + if (window->wmclass_class) + g_free (window->wmclass_class); + window->wmclass_class = g_strdup (wmclass_class); + + if (GTK_WIDGET_REALIZED (window)) + g_warning ("shouldn't set wmclass after window is realized!\n"); +} + +void +gtk_window_set_focus (GtkWindow *window, + GtkWidget *focus) +{ + GdkEventFocus event; + + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + if (focus && !GTK_WIDGET_CAN_FOCUS (focus)) + return; + + if (window->focus_widget != focus) + { + if (window->focus_widget) + { + event.type = GDK_FOCUS_CHANGE; + event.window = window->focus_widget->window; + event.in = FALSE; + + gtk_widget_event (window->focus_widget, (GdkEvent*) &event); + } + + window->focus_widget = focus; + + if (window->focus_widget) + { + event.type = GDK_FOCUS_CHANGE; + event.window = window->focus_widget->window; + event.in = TRUE; + + gtk_widget_event (window->focus_widget, (GdkEvent*) &event); + } + } +} + +void +gtk_window_set_default (GtkWindow *window, + GtkWidget *defaultw) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + g_return_if_fail (GTK_WIDGET_CAN_DEFAULT (defaultw)); + + if (window->default_widget != defaultw) + { + if (window->default_widget) + { + GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT); + gtk_widget_draw_default (window->default_widget); + } + + window->default_widget = defaultw; + + if (window->default_widget) + { + GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT); + gtk_widget_draw_default (window->default_widget); + } + } +} + +void +gtk_window_set_policy (GtkWindow *window, + gint allow_shrink, + gint allow_grow, + gint auto_shrink) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + window->allow_shrink = (allow_shrink != FALSE); + window->allow_grow = (allow_grow != FALSE); + window->auto_shrink = (auto_shrink != FALSE); +} + +void +gtk_window_add_accelerator_table (GtkWindow *window, + GtkAcceleratorTable *table) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + gtk_accelerator_table_ref (table); + window->accelerator_tables = g_list_prepend (window->accelerator_tables, table); +} + +void +gtk_window_remove_accelerator_table (GtkWindow *window, + GtkAcceleratorTable *table) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + window->accelerator_tables = g_list_remove (window->accelerator_tables, table); + gtk_accelerator_table_unref (table); +} + +void +gtk_window_position (GtkWindow *window, + GtkWindowPosition position) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GTK_IS_WINDOW (window)); + + window->position = position; +} + +static void +gtk_window_marshal_signal_1 (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args) +{ + GtkWindowSignal1 rfunc; + gint *return_val; + + rfunc = (GtkWindowSignal1) func; + return_val = GTK_RETLOC_BOOL (args[4]); + + *return_val = (* rfunc) (object, + GTK_VALUE_POINTER (args[0]), + GTK_VALUE_POINTER (args[1]), + GTK_VALUE_INT (args[2]), + GTK_VALUE_INT (args[3]), + func_data); +} + +static void +gtk_window_destroy (GtkObject *object) +{ + GtkWindow *window; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_WINDOW (object)); + + window = GTK_WINDOW (object); + g_free (window->title); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_window_show (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); + gtk_widget_map (widget); +} + +static void +gtk_window_hide (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE); + gtk_widget_unmap (widget); +} + +static void +gtk_window_map (GtkWidget *widget) +{ + GtkWindow *window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_UNMAPPED); + + gtk_window_move_resize (widget); + window = GTK_WINDOW (widget); + + if (window->bin.child && + GTK_WIDGET_VISIBLE (window->bin.child) && + !GTK_WIDGET_MAPPED (window->bin.child)) + gtk_widget_map (window->bin.child); + + gtk_window_set_hints (widget, &widget->requisition); + gdk_window_show (widget->window); +} + +static void +gtk_window_unmap (GtkWidget *widget) +{ + GtkWindow *window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + GTK_WIDGET_SET_FLAGS (widget, GTK_UNMAPPED); + gdk_window_hide (widget->window); + + window = GTK_WINDOW (widget); + window->use_uposition = TRUE; +} + +static void +gtk_window_realize (GtkWidget *widget) +{ + GtkWindow *window; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + window = GTK_WINDOW (widget); + + switch (window->type) + { + case GTK_WINDOW_TOPLEVEL: + attributes.window_type = GDK_WINDOW_TOPLEVEL; + break; + case GTK_WINDOW_DIALOG: + attributes.window_type = GDK_WINDOW_DIALOG; + break; + case GTK_WINDOW_POPUP: + attributes.window_type = GDK_WINDOW_TEMP; + break; + } + + attributes.title = window->title; + attributes.wmclass_name = window->wmclass_name; + attributes.wmclass_class = window->wmclass_class; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_KEY_PRESS_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_FOCUS_CHANGE_MASK | + GDK_STRUCTURE_MASK); + + attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes_mask |= (window->title ? GDK_WA_TITLE : 0); + attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0); + + widget->window = gdk_window_new (NULL, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, window); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_window_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkWindow *window; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + g_return_if_fail (requisition != NULL); + + window = GTK_WINDOW (widget); + + if (window->bin.child) + { + requisition->width = GTK_CONTAINER (window)->border_width * 2; + requisition->height = GTK_CONTAINER (window)->border_width * 2; + + gtk_widget_size_request (window->bin.child, &window->bin.child->requisition); + + requisition->width += window->bin.child->requisition.width; + requisition->height += window->bin.child->requisition.height; + } + else + { + if (!GTK_WIDGET_VISIBLE (window)) + window->need_resize = TRUE; + } +} + +static void +gtk_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkWindow *window; + GtkAllocation child_allocation; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + g_return_if_fail (allocation != NULL); + + window = GTK_WINDOW (widget); + widget->allocation = *allocation; + + if (window->bin.child && GTK_WIDGET_VISIBLE (window->bin.child)) + { + child_allocation.x = GTK_CONTAINER (window)->border_width; + child_allocation.y = GTK_CONTAINER (window)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + child_allocation.height = allocation->height - child_allocation.y * 2; + + gtk_widget_size_allocate (window->bin.child, &child_allocation); + } +} + +static gint +gtk_window_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (!GTK_WIDGET_UNMAPPED (widget)) + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + + if (GTK_WIDGET_DRAWABLE (widget)) + if (GTK_WIDGET_CLASS (parent_class)->expose_event) + return (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); + + return FALSE; +} + +static gint +gtk_window_configure_event (GtkWidget *widget, + GdkEventConfigure *event) +{ + GtkWindow *window; + GtkAllocation allocation; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + window = GTK_WINDOW (widget); + window->handling_resize = TRUE; + + allocation.x = 0; + allocation.y = 0; + allocation.width = event->width; + allocation.height = event->height; + + gtk_widget_size_allocate (widget, &allocation); + + if (window->bin.child && + GTK_WIDGET_VISIBLE (window->bin.child) && + !GTK_WIDGET_MAPPED (window->bin.child)) + gtk_widget_map (window->bin.child); + + window->resize_count -= 1; + if (window->resize_count == 0) + { + if ((event->width != widget->requisition.width) || + (event->height != widget->requisition.height)) + { + window->resize_count += 1; + gdk_window_resize (widget->window, + widget->requisition.width, + widget->requisition.height); + } + } + else if (window->resize_count < 0) + { + window->resize_count = 0; + } + + window->handling_resize = FALSE; + + return FALSE; +} + +static gint +gtk_window_key_press_event (GtkWidget *widget, + GdkEventKey *event) +{ + GtkWindow *window; + GtkDirectionType direction = 0; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + window = GTK_WINDOW (widget); + + return_val = FALSE; + if (window->focus_widget) + return_val = gtk_widget_event (window->focus_widget, (GdkEvent*) event); + + if (!return_val && gtk_window_check_accelerator (window, event->keyval, event->state)) + return_val = TRUE; + + if (!return_val) + { + switch (event->keyval) + { + case GDK_space: + if (window->focus_widget) + { + gtk_widget_activate (window->focus_widget); + return_val = TRUE; + } + break; + case GDK_Return: + case GDK_KP_Enter: + if (window->default_widget) + { + gtk_widget_activate (window->default_widget); + return_val = TRUE; + } + else if (window->focus_widget) + { + gtk_widget_activate (window->focus_widget); + return_val = TRUE; + } + break; + case GDK_Up: + case GDK_Down: + case GDK_Left: + case GDK_Right: + case GDK_Tab: + switch (event->keyval) + { + case GDK_Up: + direction = GTK_DIR_UP; + break; + case GDK_Down: + direction = GTK_DIR_DOWN; + break; + case GDK_Left: + direction = GTK_DIR_LEFT; + break; + case GDK_Right: + direction = GTK_DIR_RIGHT; + break; + case GDK_Tab: + if (event->state & GDK_SHIFT_MASK) + direction = GTK_DIR_TAB_BACKWARD; + else + direction = GTK_DIR_TAB_FORWARD; + break; + default : + direction = GTK_DIR_UP; /* never reached, but makes compiler happy */ + } + + gtk_container_focus (GTK_CONTAINER (widget), direction); + + if (!GTK_CONTAINER (window)->focus_child) + gtk_window_set_focus (GTK_WINDOW (widget), NULL); + else + return_val = TRUE; + break; + } + } + + return return_val; +} + +static gint +gtk_window_key_release_event (GtkWidget *widget, + GdkEventKey *event) +{ + GtkWindow *window; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + window = GTK_WINDOW (widget); + if (window->focus_widget) + return_val = gtk_widget_event (window->focus_widget, (GdkEvent*) event); + + return return_val; +} + +static gint +gtk_window_enter_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return FALSE; +} + +static gint +gtk_window_leave_notify_event (GtkWidget *widget, + GdkEventCrossing *event) +{ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + return FALSE; +} + +static gint +gtk_window_focus_in_event (GtkWidget *widget, + GdkEventFocus *event) +{ + GtkWindow *window; + GdkEventFocus fevent; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + /* It appears spurious focus in events can occur when + * the window is hidden. So we'll just check to see if + * the window is visible before actually handling the + * event + */ + if (GTK_WIDGET_VISIBLE (widget)) + { + window = GTK_WINDOW (widget); + if (window->focus_widget && !GTK_WIDGET_HAS_FOCUS (window->focus_widget)) + { + fevent.type = GDK_FOCUS_CHANGE; + fevent.window = window->focus_widget->window; + fevent.in = TRUE; + + gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent); + } + } + + return FALSE; +} + +static gint +gtk_window_focus_out_event (GtkWidget *widget, + GdkEventFocus *event) +{ + GtkWindow *window; + GdkEventFocus fevent; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + window = GTK_WINDOW (widget); + if (window->focus_widget && GTK_WIDGET_HAS_FOCUS (window->focus_widget)) + { + fevent.type = GDK_FOCUS_CHANGE; + fevent.window = window->focus_widget->window; + fevent.in = FALSE; + + gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent); + } + + return FALSE; +} + +static void +gtk_window_style_set_event (GtkWidget *widget, + GdkEventClient *event) +{ + GdkAtom atom_default_colors; + GtkStyle *style_newdefault; + GdkAtom realtype; + gint retfmt, retlen; + GdkColor *data, *stylecolors; + int i = 0, j; + GdkColormap *widget_cmap; + + atom_default_colors = gdk_atom_intern("_GTK_DEFAULT_COLORS", FALSE); + + if(gdk_property_get (GDK_ROOT_PARENT(), + atom_default_colors, + GDK_NONE, + 0, + sizeof(GdkColor) * GTK_STYLE_NUM_STYLECOLORS(), + FALSE, + &realtype, + &retfmt, + &retlen, + (guchar *)&data) != TRUE + || retfmt != sizeof(gushort)) { + g_warning("gdk_property_get() failed in _GTK_STYLE_CHANGED\n"); + return; + } + /* We have the color data, now let's interpret it */ + style_newdefault = gtk_widget_get_default_style(); + gtk_style_ref(style_newdefault); + stylecolors = (GdkColor *) style_newdefault; + + widget_cmap = gtk_widget_get_colormap(widget); + for(i = 0; i < GTK_STYLE_NUM_STYLECOLORS(); i++) { + stylecolors[i] = data[i]; + gdk_color_alloc(widget_cmap, &stylecolors[i]); + } + + gtk_widget_set_default_style(style_newdefault); + gtk_style_unref(style_newdefault); + + /* Now we need to redraw everything */ + gtk_widget_draw(widget, NULL); + gtk_widget_draw_children(widget); +} + +static gint +gtk_window_client_event (GtkWidget *widget, + GdkEvent *event) +{ + GdkAtom atom_styleset; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + atom_styleset = gdk_atom_intern("_GTK_STYLE_CHANGED", FALSE); + + if(event->client.message_type == atom_styleset) { + gtk_window_style_set_event(widget, event); + } + return FALSE; +} + +static gint +gtk_window_need_resize (GtkContainer *container) +{ + GtkWindow *window; + gint return_val; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (container), FALSE); + + return_val = FALSE; + + window = GTK_WINDOW (container); + if (window->handling_resize) + return return_val; + + if (GTK_WIDGET_VISIBLE (container)) + { + window->need_resize = TRUE; + return_val = gtk_window_move_resize (GTK_WIDGET (window)); + window->need_resize = FALSE; + } + + return return_val; +} + +static gint +gtk_real_window_move_resize (GtkWindow *window, + gint *x, + gint *y, + gint width, + gint height) +{ + GtkWidget *widget; + GtkWidget *resize_container; + GSList *resize_widgets; + GSList *resize_containers; + GSList *tmp_list; + gint return_val; + + g_return_val_if_fail (window != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE); + g_return_val_if_fail ((x != NULL) || (y != NULL), FALSE); + + return_val = FALSE; + + widget = GTK_WIDGET (window); + + if ((*x != -1) && (*y != -1)) + gdk_window_move (widget->window, *x, *y); + + if ((widget->requisition.width == 0) || + (widget->requisition.height == 0)) + { + widget->requisition.width = 200; + widget->requisition.height = 200; + } + + gdk_window_get_geometry (widget->window, NULL, NULL, &width, &height, NULL); + + resize_containers = NULL; + + if ((window->auto_shrink && + ((width != widget->requisition.width) || + (height != widget->requisition.height))) || + (width < widget->requisition.width) || + (height < widget->requisition.height)) + { + if (window->resize_count == 0) + { + window->resize_count += 1; + gdk_window_resize (widget->window, + widget->requisition.width, + widget->requisition.height); + } + } + else + { + /* The window hasn't changed size but one of its children + * queued a resize request. Which means that the allocation + * is not sufficient for the requisition of some child. + * We've already performed a size request at this point, + * so we simply need to run through the list of resize + * widgets and reallocate their sizes appropriately. We + * make the optimization of not performing reallocation + * for a widget who also has a parent in the resize widgets + * list. + */ + resize_widgets = gtk_object_get_data (GTK_OBJECT (window), "resize_widgets"); + gtk_object_set_data (GTK_OBJECT (window), "resize_widgets", NULL); + + tmp_list = resize_widgets; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + /* referencing needed? */ + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_NEEDED); + gtk_object_unref (GTK_OBJECT (widget)); + + widget = widget->parent; + + while (widget && + ((widget->allocation.width < widget->requisition.width) || + (widget->allocation.height < widget->requisition.height))) + widget = widget->parent; + + if (widget) + GTK_WIDGET_SET_FLAGS (widget, GTK_RESIZE_NEEDED); + } + + tmp_list = resize_widgets; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + resize_container = widget->parent; + while (resize_container && + !GTK_WIDGET_RESIZE_NEEDED (resize_container)) + resize_container = resize_container->parent; + + if (resize_container) + widget = resize_container->parent; + else + widget = NULL; + + while (widget) + { + if (GTK_WIDGET_RESIZE_NEEDED (widget)) + { + GTK_WIDGET_UNSET_FLAGS (resize_container, GTK_RESIZE_NEEDED); + resize_container = widget; + } + widget = widget->parent; + } + + if (resize_container && + !g_slist_find (resize_containers, resize_container)) + resize_containers = g_slist_prepend (resize_containers, resize_container); + } + + g_slist_free (resize_widgets); + + tmp_list = resize_containers; + while (tmp_list) + { + widget = tmp_list->data; + tmp_list = tmp_list->next; + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_RESIZE_NEEDED); + gtk_widget_size_allocate (widget, &widget->allocation); + gtk_widget_queue_draw (widget); + } + + g_slist_free (resize_containers); + } + + return return_val; +} + +static gint +gtk_window_move_resize (GtkWidget *widget) +{ + GtkWindow *window; + gint x, y; + gint width, height; + gint screen_width; + gint screen_height; + gint return_val; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE); + + return_val = FALSE; + + if (GTK_WIDGET_REALIZED (widget)) + { + window = GTK_WINDOW (widget); + + /* Remember old size, to know if we have to reset hints */ + width = widget->requisition.width; + height = widget->requisition.height; + gtk_widget_size_request (widget, &widget->requisition); + + if (GTK_WIDGET_MAPPED (widget) && + (width != widget->requisition.width || + height != widget->requisition.height)) + gtk_window_set_hints (widget, &widget->requisition); + + x = -1; + y = -1; + width = widget->requisition.width; + height = widget->requisition.height; + + if (window->use_uposition) + switch (window->position) + { + case GTK_WIN_POS_CENTER: + x = (gdk_screen_width () - width) / 2; + y = (gdk_screen_height () - height) / 2; + gtk_widget_set_uposition (widget, x, y); + break; + case GTK_WIN_POS_MOUSE: + gdk_window_get_pointer (NULL, &x, &y, NULL); + + x -= width / 2; + y -= height / 2; + + screen_width = gdk_screen_width (); + screen_height = gdk_screen_height (); + + if (x < 0) + x = 0; + else if (x > (screen_width - width)) + x = screen_width - width; + + if (y < 0) + y = 0; + else if (y > (screen_height - height)) + y = screen_height - height; + + gtk_widget_set_uposition (widget, x, y); + break; + } + + gtk_signal_emit (GTK_OBJECT (widget), window_signals[MOVE_RESIZE], + &x, &y, width, height, &return_val); + } + + return return_val; +} + +static void +gtk_window_set_hints (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkWindow *window; + GtkWidgetAuxInfo *aux_info; + gint flags; + gint ux, uy; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_WINDOW (widget)); + g_return_if_fail (requisition != NULL); + + if (GTK_WIDGET_REALIZED (widget)) + { + window = GTK_WINDOW (widget); + + flags = 0; + ux = 0; + uy = 0; + + aux_info = gtk_object_get_data (GTK_OBJECT (widget), "aux_info"); + if (aux_info && (aux_info->x != -1) && (aux_info->y != -1)) + { + ux = aux_info->x; + uy = aux_info->y; + flags |= GDK_HINT_POS; + } + if (!window->allow_shrink) + flags |= GDK_HINT_MIN_SIZE; + if (!window->allow_grow) + flags |= GDK_HINT_MAX_SIZE; + + gdk_window_set_hints (widget->window, ux, uy, + requisition->width, requisition->height, + requisition->width, requisition->height, + flags); + + if (window->use_uposition && (flags & GDK_HINT_POS)) + { + window->use_uposition = FALSE; + gdk_window_move (widget->window, ux, uy); + } + } +} + +static gint +gtk_window_check_accelerator (GtkWindow *window, + gint key, + guint mods) +{ + GtkAcceleratorTable *table; + GList *tmp; + + if ((key >= 0x20) && (key <= 0xFF)) + { + tmp = window->accelerator_tables; + while (tmp) + { + table = tmp->data; + tmp = tmp->next; + + if (gtk_accelerator_table_check (table, key, mods)) + return TRUE; + } + + if (gtk_accelerator_table_check (NULL, key, mods)) + return TRUE; + } + + return FALSE; +} diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h new file mode 100644 index 000000000..ff2252731 --- /dev/null +++ b/gtk/gtkwindow.h @@ -0,0 +1,105 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __GTK_WINDOW_H__ +#define __GTK_WINDOW_H__ + + +#include +#include +#include +#include +#include + + +#define GTK_WINDOW(obj) GTK_CHECK_CAST (obj, gtk_window_get_type (), GtkWindow) +#define GTK_WINDOW_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_window_get_type (), GtkWindowClass) +#define GTK_IS_WINDOW(obj) GTK_CHECK_TYPE (obj, gtk_window_get_type ()) + + +typedef struct _GtkWindow GtkWindow; +typedef struct _GtkWindowClass GtkWindowClass; + +struct _GtkWindow +{ + GtkBin bin; + + gchar *title; + gchar *wmclass_name; + gchar *wmclass_class; + GtkWindowType type; + GList *accelerator_tables; + + GtkWidget *focus_widget; + GtkWidget *default_widget; + + gshort resize_count; + guint need_resize : 1; + guint allow_shrink : 1; + guint allow_grow : 1; + guint auto_shrink : 1; + guint handling_resize : 1; + guint position : 2; + guint use_uposition : 1; +}; + +struct _GtkWindowClass +{ + GtkBinClass parent_class; + + gint (* move_resize) (GtkWindow *window, + gint *x, + gint *y, + gint width, + gint height); +}; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +guint gtk_window_get_type (void); +GtkWidget* gtk_window_new (GtkWindowType type); +void gtk_window_set_title (GtkWindow *window, + const gchar *title); +void gtk_window_set_wmclass (GtkWindow *window, + gchar *wmclass_name, + gchar *wmclass_class); +void gtk_window_set_focus (GtkWindow *window, + GtkWidget *focus); +void gtk_window_set_default (GtkWindow *window, + GtkWidget *defaultw); +void gtk_window_set_policy (GtkWindow *window, + gint allow_shrink, + gint allow_grow, + gint auto_shrink); +void gtk_window_add_accelerator_table (GtkWindow *window, + GtkAcceleratorTable *table); +void gtk_window_remove_accelerator_table (GtkWindow *window, + GtkAcceleratorTable *table); +void gtk_window_position (GtkWindow *window, + GtkWindowPosition position); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GTK_WINDOW_H__ */ diff --git a/gtk/line-arrow.xbm b/gtk/line-arrow.xbm new file mode 100644 index 000000000..493ecf325 --- /dev/null +++ b/gtk/line-arrow.xbm @@ -0,0 +1,4 @@ +#define line_arrow_width 6 +#define line_arrow_height 9 +static unsigned char line_arrow_bits[] = { + 0x00, 0x00, 0x04, 0x0c, 0x18, 0x3f, 0x18, 0x0c, 0x04}; diff --git a/gtk/line-wrap.xbm b/gtk/line-wrap.xbm new file mode 100644 index 000000000..82428037d --- /dev/null +++ b/gtk/line-wrap.xbm @@ -0,0 +1,4 @@ +#define line_wrap_width 6 +#define line_wrap_height 9 +static unsigned char line_wrap_bits[] = { + 0x1e, 0x3e, 0x30, 0x30, 0x39, 0x1f, 0x0f, 0x0f, 0x1f, }; diff --git a/gtk/marble.xpm b/gtk/marble.xpm new file mode 100644 index 000000000..1ef260761 --- /dev/null +++ b/gtk/marble.xpm @@ -0,0 +1,408 @@ +/* XPM */ +static char *granite07[] = { +/* width height num_colors chars_per_pixel */ +" 384 384 16 1", +/* colors */ +". c #000000", +"# c #111111", +"a c #222222", +"b c #333333", +"c c #444444", +"d c #555555", +"e c #666666", +"f c #777777", +"g c #888888", +"h c #999999", +"i c #aaaaaa", +"j c #bbbbbb", +"k c #cccccc", +"l c #dddddd", +"m c #eeeeee", +"n c #ffffff", +/* pixels */ +"aacfedbbcbbaaaaaaaaabaabaaaaabcbcbbbabbchfdcccbbabbbaaabaabcbaa#aa#######a#aaaabcddeefhec##dgbabbaaadabbcfbaa##########aaabbaaa#a#####a#aa###a#aaabbbbcbbbccdedaaaaa#aaaaa#a#abaaabbabbbeddbbaaaaaca##a#aaaba########aaaadcababbabdehd.##.a######.cgdcb###b##.##.##aaaaa####abcba######a##aac#a##a####aa#aa##babbbcfccbbbcdccccecbbbcbbbcdccddcbcdfeecbhhjihhgffc.aaa####.#######aaaaaaaabbaaaaa", +"aaacedccbbcbaaaaaa#bbaabbbaaaabcaabbbbbbafhfccbbbbbbabacbacbaaaaa##########a###abbcdeghhhcagb#ababaaccbacdfca#a####aa###aaaaabaaa#####aca#aabaababbcccccccbcdfdaaaa###aaaaaaaaaaabbbbbbccccccbbcbcaaa##aaaaabaaaa###abdaccceebaaaabehja####a######..#aeec#bb##########aa#####abba#########aaca########aa#aa###aaaabddbbbbbbbbbbccbbabbbbabbabbabcbcbcefhfeddccefhhijheecb#...a####aaaaaaaabaaaaa", +"aaabccccccdbabcbaaa#aaaaaaaaaaabbabbbbbccabefdccabcbbabacccbaaabaa######a######aaabceiiiihije#bbabbaaeaabcedcaabaa########aaaabaa##a###ab#aabcababbccccccdeeeecc#a##a##aaaaaaaaaabbbbbbbcccbbbdcbbcdaa#a#aabbaaaaa###acbaa#bccaa#abcfig.#######.#######acddgefdda#######a########a#######aaaaaa#a######aaaa#####aaacdcbabbaaabbbcaaaaaaaaabbbaaabbaabbbcbcbabbabcdeefghjkjgc#..####aaaaaaaaaaaa#", +"#aaaaaacbccbcabbbaaaaaabcaaaaabbbbbbabbbcbaabffccbccbccbbcbaaaabaaaa#aa#aa##a#aaaaabbikkjhijicabbbcc#faaacdebcbda#########aaaaaaaaa####aa##cacccabcccdccccdddfdcbaa##a##abbbabccbbcbbbccccaaa#abbaaba#a##abbbbbaaaaaaaaaaccaaca##aabcfic.###aa#######a####bddeeddb####.##.###aaa#########aaaa###aa####aaaa#######aabdbbbbcabbbaaaa#aaaaaaaaabaaabbbaabbbbdbbaaabccccccdcefhhkhda##aaaa#a#aaaaa##", +"#aaabaabcecbaa##bcaaaaaaaababbabaaabbabbaabb#chhfdccccbcbecaaabaaaaaaaaaa####aaaaaaabdgjkkijijdabbdcabfaabcecbbec###########a#aaaabaa#######abbaaaadddedddeeefeccaa###a#aabcccdcbcbbbbccbbbbaaaaa#aabbaaaabbbbbbaaaaaaabbbbbaaa####acegha##a#aabbb####a##adccdedbcc#######.###a###a#######aaa#a#aa##..#aa#########abdbaabbabbbaa###aaaaaaaaaaaaacbaaababbdbabbabcbbcbcbccbbdegjkgb#aa#aa#aaaaaaa", +"##aa#aabccccaaaaaaaa#aaaaaabbaabbbaaaaabbbcbbcfhhgfcccbbbbccbaabbaaaaaaabaa#aaaabaaaabbcehkljjdabacccbgbaaccdb#adea#########aa#abaaaaa#####ac#ba##accdedddefffeaba##a#aaaaacccccccbbbcccaabaaaaaaaaa#aaaaabcbbaaa#bbbbaaefccdbaaa#aaacdei##aa##aabbbaaa#a#cdcccccbcea.#########bbaaa######a###a#aaaa.#aaba####.###abcbaaabaabbbaa###aaaaaaaaaaaabbaaaaaaaaaaababcbbcbbaabbbdddeghheba##ab#abaa##", +"#####bbaaaaabaaaaa##aa#adccaabaaabbbbabbabbbabccbccfdbccbbbbbcaabcaabaaabbaaaaaaaaaaaabbbcglli#accbbbddgabcddbbaacea#a##########aaa#aaa##aaaa####aabcddeeefffgdbbaaaa###baabbbbbbcdabdcbcaaabaaaaaaa#aaaaaabcbbbbadfbbbaejhhebbccaaaaaccfi.aba##abaaaba####ecbbccba#fc.####.##.bba#a#######aaaaaaaaaaa##aaaa######abcdaa#aaaabaaa###aaaaabaaabbbaaba##aaababcbbcbbbbbcbaaabbccccddgggeb#aadca###", +"#####bcaaaaaabcbaaa#aaaabcccaaaaaaabaaabbbbbbbaacbabeeddddccbcbbcccbabaaaabaabaaaaaaaaabbbbglmdbcbaabebdgdbcecbbaabdbaa#########aabbaaaa#aa#a##a#aabbdceeedccdcbbaaaaa##aaabbcbbbabaaabbababbaaaa#aaaaaaaabcdccbbbabcbbbcfijfbcdcabb#abcbif#abb##aaabaaaa##fcccbbcaa#db#..##.##.aaa#########ab#aaaaaa#aabaaaaa#####abdbbaaaabbaaaa###b#a#aaaabaaaaaaaaaaaaaabbabbbbaabbbaaaabbbbbbbceffecccbaa##", +"#####abaaaaa#accbbbbaaabaaaaaaaaaaadcbaabbabbbabbdcaacgfddddcdddcadfcaaaabcbbabaaaaaabcabbbdjliacbababcbdfcdeeaaaaaabba########a##aa#aabaa##a######abddeggca#bcbaaaaaa####aaaaaabbbbbcbbbbbaaa##a#aaaaaaaabcbccbbaaaabaabfgfiecccccbbaaaccicbbbcbaaabaaabb#ceccccdca##aacdb######aaa###a###aabaaaaaa#aabca#abba#####abca##aaaaaaaaa##a##aaaaaaabaaaaaaabaaaacbcbacdbaaabaaaaaabaaaaabbcddccbaa##", +"####aa#aaaaaaabccbabbaaaaaaaaaaaaabfaaabbcbbbbbabdebaabdffddedefedccecccdcbbbbbccbccbbbbbbccekldaabaaabccbfaaaaaaaaaaaba########aaaaaaaaba##aaa###aabbccfgfaababbbaaaaa#aabbaabaaccaabcccbcbaa##aaaaaabaabbbccbbbaabbbbbbdddghdbbbcccb#abcdebcccbaabbbabbcbaecddddbaa##.#acdeca#######a#aaaaaaaaaaaaaaabba##abba####aacba##aaaaaaaaaaaaa##aba#abaaaaaaabaaaabbbbbbcbabbaabbaaaaabaaaaaaaaccbaa##", +".####aa#aabaa##bccbaabbbba#aaaaabbaefdaabbbbccbbbaddaaabadeeffhhhffdedddeecbbbbcccbbabcbabbcfjjlkeaaaaacdadcaa#aaaaaaa#ab######ba#aaabbabcaa#aa###babcddcedba##acbaaaaaa#ababbbacbbbcccdfffbaa#aaaacbaabcbabccbbcbbbbbbcbbccedbbbccdccbaabcgb#bccbbbababbbcccdededcb#a####...addcba##aabbbbbbbbaaaaabba#aaa##abba####abbaa###a#aa#aa##aaa#a##abaaaaaaaaabababbcdbcb#baaaaaaaaaaaaaaaaaa#aaaaa###", +"######a##aaaaaa#accbaaabbbaaa#aaababdcaaabbbbcccbbbdbabbbacdccgecadbbbcdccddeddcccccbaabcbbcgjhhjgeb#aacdcccaa#aa#aaa#a#aaa##aaaaa#aaabbaabb#aa###aabccddeccbbbaabcbbbcbbb#aacbbadbabcccddbaaa#aaaaabbbbabbbbcdbbbabbcddcbbbccaabbbccbbaaaadi##abbbbbbbaabbbacdeedbd######aa####bceda#aabbabaaaaaaaaba#aaaaa#aabaaa###acaaaa####aa##aaaaaaaa#aaaaaaaaaaababaaaaabcaaaaaaabbcbaaaaaaaaa###aaaa###", +"##########aabaa#accbbabbbbbba##aaaabbcbbbbbbbbcbaaabdbbbbbbddccbbbbaaaabbabbbbcefefdcbaadbcddje#debgfbabecdc####aa##a###a#aa#aa##a##aaabbcabbaa###aabbcceedbcbaaaabdcccbabaaabbbbabbccbbaaaaaa#aaaaaaaabbbbbcbccabcccccdcccbbbbabbababbba#abfe#aaaaaaaabccbbaaaedddc######adcaaaa##dfcaaaaaaaaaa#aaaaa##aabcaaabbaa#aaab###aa###aaaaaaaaaaaa##aaaaaaaaaabaaabaaabcabaaaaaaabcbaabaaa##a###aa####", +"#########aaaaaaabbcbbbbabcbaacbaa##aaabaaabccccccbaabecabbbcddbacdeba#aaaaabaaabbdfgedcbaccdcgica#aadghdbddd#aa#aaa#a###aaaabaa#####aaaaabbbbbba#aaabccceecbddbaa#bbccabcbbbbbacccdbbdabbaaaaaaa#aaaa#aabbbbcccdcbcbbccccccbcaababbdbabbba#bbgaabaaa#aaacccdcddbeedba#a##a#aba#aaaa##decbaaba#aaa###a#a###abba#bba###aaba####a####aaaaaaaaaaaa#aaabbbaaabbaabbaabbaaa#aa#a#abbaabbbaaa#aaaa#####", +"############aaaaaaacbbbbbbbaa#aaa#a##aaaaaaaacbbbbbbabdcabbbcdbaccdba#aaaaaababbcbbdddedccddefihaa#aaahiiiffd#aaaa#abaa##aaaaacaa##a#bcaaaabbbcaaaabccdddecabaaaaacbbbabbccccccbbdbdfdaabbaaa###a#aaaaaaaabbbbbbbaaabdcddccbbbbabbbccaabbbaabfdaaabaa#aa##aabbbbbddba##aa#a#aa##aaaaaabcdbbaaa##aa#####a#aaabbaaaaa##abb######aa###aaaaaaaaaaaaaaaaabaaaaaaaabbbbaaabaaa#aaaaaaabbbaaaaaaaaa####", +"###########aa#aa#aaaccabbaaaaaaabb#######a#aaabcbbbabbaeebbccbcbacdaaa##a#aabbbbccbbcbcdegifdfgifba##aaaagigha#aaaaabbaaaaaaaaabaaa##acaaaaabbbbbbabcdddefeba####abbaabccccbbbcbadcbcbaabba#aaaa#aaaaaababacccbaadbabbccedcccbbccbbabaaaaa##ade###abba#aa##abbba#cebb.#a####.#a#aaaaaaaaacfca#aaa###aa###abaabaaaaaaaabbaa#######aaaaa#aa#aaaaaaaaaaababdaaabbbbbababaaaaaa#aaaaaabbaaabaaaaa###", +"##########a#aaabaaaaccaaaaaaabaaaaaaba###a##abaaabbababaccbcbbcccaaba#a###aaabbccdccccccdeegggfigaabb#aaa#fffcba#abbaaaaaaaaaaa#abba##aaa##aabbbcbbbbcdeegfeb####aabaabacbbbcbccaabbabaaaaaaa##aa#aaaaababbabbcbcdbbcccbddcdcccabcbbababba###afba#aabba#acaaabbbbaddb##aa####.####aabbaaaabffcaaaaaa##a##bcabbaaaaaaabbbc#a#a#######aaaaa#####a##ababbbbbaaaabbcbaaaaaaaaaaa#aaaaaabaaababaaaaa#", +"#######a#####a#aaaaabcbaaaaaa#aabaaaaaa###abbabaaaaaccaaabdbccbccbaaca#####accddcccccccddeeefikjeabcca#a#abfifbaa#abbbbbaaaaaaaaa#bbba#bcaaaaaaaccbcccceffeccaa##aaabbbcabbacbddbbaabdbaaaaaaaaaaaaaaabbbaabbbbbbbbbcbbccccdcdcccabbbbbaaba###dcaaaabbaaabaabcbccaadba#aaa########aaaa##aaaacgdbaaaa####cfffda#a#aaaabbdbaa#aaa########aaaa#aa##aaabbabbbaaabbbaaaaaabaaaaaaaa#aaaaabaaaaaaaaa#a", +"a###########aaaaaaaabbaabaaa###abaaa#a##a###a#aaaaabacaaabccbbbcbbbcbb####a#bdfbbccccccdefecdgiiddaabbaaaabacfeaaaaaabcccbaaaaaaabaaacaa##aaaaaaabccddcfgfgbabaaa#aaabbcccbccbcddbbacabbbbbbbbaaacbaaaabcbabbbbbcbbcbccbccdccdccdcbaabbbaabaaade#aa#baaabaa##abbcbacdb#.#abbccc#.##aaa####aa#aeeaaaaaaabbabddfgfba#aabcd#aaaa########aa##a##aaaaaababbaabbbbbabccbababaaaaaaa##a#aaaabbaaaaaaaa#", +"#a###a######aaaaaaaacdaaaaaaaa#aaaaaaaaaa#####a###abbbbaaaaccbbbcbbbbaa#aaaaaeecabcccbccdedcdfgigeaaaacbaaabaacbaaaaaaabcbbbaaaaaaaaabccaaaaaaaaaacccceffffbabb#a####aaaabcccccddcdedbbbbaabcabbbccbccbcbcbbbbbbbbbcecbccccceccccdccbbaaaaaaabce#bbaaa###aaa##ababcacda#abb##a#######a#########bfdca#abcbaabaabcffddbabdc#aaaaa##########aa####aaaaaaabbabbbbbbbcbbbcbaaaaaaaa#aa#aaaaaabaa##b##", +"##a#########aabaaaabcdbabaaaaa##aaaaabaaba######a##ababbbbbabbbbcbcdddbbaa#abceecabccccccdddfedgjgdbaaabaaabbbaaba#aabaabaccaaaaaaaabbccbbbaaabaaabcddefgfebbbb#aa####aaaabbcccccbbfeccbbbaaababbbbbbbccba#abbbabbcdccdcbddcddcccdcddcbaaaaaabcfbadaa#######a#abbacbbcc###a#a########a######a##aabdcabccbbababaaaacdfededbbaa#aa##aa######ba#aa#aaabbabaababcbbcbcbbbabbaaaaaaaa##aaabaaacba#a##", +"##########a#abaaaaabbbcbbbcaa###a#aaaaa##aba#######aaaaaabbdccbaabccdddecaaaabccdbbacccddcdefdfgiifcba#bbaaabbaaaababbbbbbbabbaabaaaacbbbcbbaaaaaaaceeeefffbaaaa###a##aaaabbcbbbddcddddcbcbbaaabbbbababbabaaabababbbbcccdccddcddccccdecaaaa#abccfbbaaa#######aabbaacabe###a#aa#a#a##.aa#######a#aa#cfeecdcccccabbbabacggcabbaaabbaaaa####aabb#aaaabbababbbbbbcccbbbbbcccbbbaaaa#aaaaaababbaaaa##", +"######a####abcbaaaaabbccbcbaa###a##aaa##a###aa######aaaaaabdgebaaabbbccacbaaaaabbbaaabccddcdeeffgigbaaaaaabaabcaaababbbbaabbacbaaabbaaaababccbabbabbdffefhdcaaa###aaabba#aababcbdeeccceccccbababbbbabbabbaaaaaabbaabbcbcccccdcddddccccdcaaaababcdeaba#####.###aaabaab#b####a####a##aa#b########aaaaabedddcccccaaaabbcabeaaaabbccbaaa#abbaaabbbaaaabbbaaacbcbcbbdccbaabbacbbbbbaaaaaaaaabbaa#####", +"######aaa#abbcbaaaaabdccbbaaa#######aaa#####aaa##a#a##aaaababcbbaaaaabdebbbaaa##aaaaaaaabccddeefggieaaaaaaaacabaabbbabbbbaaaabbaaaaaaabbbabbccbaabbbdfgghebbbaa#####abba#aabbbcbccdcbbbcddcccbbbabbabbbabbabaaaaaaacbbabcbbccccddddccbcccaaaaaabbdcbc##########aaacbbaa####a####aa###a#aa###aaa###abbceddedcccbaaaacccdca##a#abbbabaaaabaaabbba#aabbbbbbccbbbbaaacccbbcbbaaabbbbbbabaaabaaaa####", +"#######aa#aaccabbabaabdecbb#a########aaaa####aaa#aba##a#aaaaaaabbdcaabdcbcaacb####abb#abaabccdeffghfdabaaaa#acbbbbcbabcabcbaaaabbbabaaaabbbbbcccbbbccdfedccbbb#########aaaababbacccbcbbbddbdcccccbbbbaaaabbaabbaaaaabaabbbbccdcceedccccacbaaaabbbbddb####aa######aabbaa####a####aa#aa###a#####aa#aabbddeccddccbbbabbbbceb###aa#aaaaaa##aa####aaaa#abbbbbccacccbaa#accbbbbbaaababbabaaaaaaaaa####", +"##a#####aaaaaabbbbabacdddccaa########aa#a#####aaa#aa#aaaaaaaaaaaabcabbcbbbbababa###baaaaaaabccdeeehifbabaaa###abbcbbcaccbcbbbaabbbbabaaabbbbbbbbcccccddbccbbbbba#######aaabbbaabbcccbdcbbdbbddcdcccbabaabaaaaaaaaaaaaaaaabbcccddecccbbacccbbbaabbbceca############aaaaa#############a#############aaaaabccddcbbbabbbbbbba#####a##a####aaa#######aaa#babaabbcbaaa##abbbaabbcbbbbaaaaaaaabbaaa####", +"#########abaaabbabbbbbddeccca##aa######a#aa####bbaaaaaaaaaaaaaaaaaabccbcccebacfdb#####aaaaaaabcdddcfgfccbaa##a##abcbbcbbdcccccabbabaababbbbbbbbbbcdccddbabbbbbba########aaababbbacdccccaabcbbcabddddbbaaabbabbbaaaaaaaaabbbddcddecbccbbbdcbabbbaabbcda#############abaaaa############a####bb##a####aaaaabcffdcccbbbbbbbb#######aaa###aaaa#######aabaaaabbcbaaaaaaaa#aaaaaabbccbbaaaaaabbbaaa####", +"#########aaabbabcbbbbbdddcbaaaaa###############aabaaaa#aaaaaaaaaaabbabbdefffccbba###aa##aaaaaabcdceecggdcbbaa##aa#aacbb#bcdddddabbbbbabbbabbbbbbbccfeedbbbbbbcbba#a#####a#acababbbdcbcbabbabaabaabeedcaaaaaaaabcbbaaaaaaabbcdfdddccbbbbcbccbabbbaaabcda########a#aaaaaaa#aa#####aaabaaaaaaacb##aaa#aaababbcdefddbbcbccbaa#####aaaaaaaab##a########aa#abbcccbaaaaaa###aaaaabaabccbbbaaaaaaaaa####", +"########aaaaaaabbbbbbcdedbbbbabaa##########aa###bbb###a##aaaaaaabbaabbbdfeedb##a#a##aa###aaabbbbccdefbfecbbbaaa####a#adb#acdecdfcbaabcbbbbcbbbbbbcdeffbcccabbcdbbba#a###a#aabaaaaaccccbaaaaabbbbaabdfedaaaababbbbbaaaaaaababbcedcccbbbbaccccbaaaccbbabeb######aaaaa#aaa###a######aaaaaaabacbca#aaaaaabbbbccdegfeccccccbcbaaa#####aaaa#aaaaa###a###aaaabbbcccb##a#aaa#aaaaaaaabbdeddcbabaaaaa####", +"#########a#aabbbbbbbbdddccbbba#aaaa##aa##a####a#bba#a#a#aaaabaabbbabbeedeeefdaaaa#####bb##aaabbabcddehgifffdcbaaaa#aa#aaaaaccdeddcabbbcbbbccbabbccdceeecdcaaaabbcccaaaaaaaaaaaaaabacdddbaabaabbbbcccccfdbaabbaabbcaaaaaaababbcccccbbbbbbbccbcca#acbbbbbda#####aaaa####ab##a######aaaaaaabaccbaaaaabbbbbbccceffcdeedcbbbbaaaa#aaaaaaaaa#aaabaaaaaa##aaaabbbcbbcbaa#####aaaaaabbbcccddcbbaaaaa####", +"##########a#aabbcbcbbcecccbbbabaaaaaa#####a#aaaabbaa##ba#acaaababbbbbbbcdcfgdbbbaa####aba##aaaabbbccdfefhfgedecaaa##abaaaaacbabebbbbbbbbcccbcbbbbddbedbddcaaaaaabdccaaba#aaaaaa#bbbbbaddccaaabcbbdcbbcbddabbbbbbbccaaaaaaaaabcddcbbbbbbbbbbbbbbaaaabbaabe#########a####bb#aa#####aa#aaaabccdbbbbabbcbbbccccdccbaaeffdbca#aaaa#aaaaaaa#aaaaabaaaa#aaaabaabbccbbcceb#bcaaaaaaaabbbbcdcbbbaaaaa####", +"#######aa#aaaaabbccbbcdccddcabaaaaaaaaa###aaa#aabcaaa#bba#aabaabbbbbbabcccdfedcaa##aaa######aaaabbbbcdddghhgfedcbaaaa#aaaaabcbbbccbbbbbbbcbccdcccccbeebccbbbaaaaaccccccba#aaaaaaabaaabbbddbbbbcccbcccbaceeacbbbcbccbaaabbabbbbceccbbbbbabbbbbbbab#aabbbbcc#.######a####.bcbcba####aaaa#bedccbbbbbbbaabccddedaaaaa##beeda#aaaaaaaaaaaaaaaaaaaaabba##babbabbbbcbbbccccbbaaaaabbabaabddcbbbaaaa####", +"##########aaaabbbbccccbcddddbaaaa##a#a#a###aaaa#baabbaaaaaaaabbbabcbaabccbddfebaaba#ba######aaaabbbbbcddfiiigggedbaaaaaaaaaabcbabccbbbbbbbcccddddccceecccccbbaaaabccddbbba#aaaaaaaaabcbbbcccdccbcbabcbabceecbabbbbbbaaaabaabbbcddbbbbbbbbaabbbcbbbbaaabcbdc########..####ccccba#abbaaaabddbabbbcabbbbcccceeca###aaa##aaa##a#aaaaaaaaaaaaaaaaaaaaa##aabcbbbbbbbccbbbbcddaaaaacbaaaabddbbaaaaaa###", +"############aaabbabcddccdbcdcbcbbbaaaaa##a##aaaa##abaaabaaaaaaabbaacaabddabcefc#aabaaa###a####aaabbbbbbddgihhfffgeaaaaaaaaaaaaabbbcbbbbbbbbbcddeeedceccdcccccaaaaabcbddbaa#a#ab#aaacbbbbbbddebbbbccbbbabbbedbaaaaaaaaaaaabbabbccecbbbbccbbbbaabbbbcc#aaabbcc######a#####.bccabbacbababaabdcabbbabbabbbcbdecabaa##aaaa####aaaaba##aaaaabaaababa##aa#aaabbbbbbbbcbbbbacbedbaaa#bbaaaabcbbbbaaaa#aa", +"#######a####aaaaabaabbcccbabbbbbbbcbaaa######a#aa######aaaa#aaa#acbbbabeeebabddbaaabaa####aa#a#aababbbbbcehhgeeffdca##aaaaaaaaaabbbbabbbbbbcdcdddfgfhcbbcbbbcbaaaaabcccdbba###baaaabcbbaabcdeecaaabbbbbbaabddecaaaaaaaabbbbbbbccfcbcbbbbbbbaaaaabbbcca#aabacc#######a####acdcbbbbbbaaaabbccaabbbbbbbabbceecabb#aa#aaaa#######aaa##aaaaaaabbaaaaaaaaaaaabbbaabccbbcbaaacgdaaaa#aababbbabbbbaaaaa#", +"###a#####a#aaaaaabcbacbbddcaaabbbbbbbaaaaaa##a#####a####aaaaa#aaabdbcbbedefcaaabaaaaabaaa#a##abaaaaababbbcfgggfeefea##aaaaaaaaaaabcbbbbbbbbcdcdddefgeabbbbaabccaabaaceddeeaaa##aaaaaabbbabbcdedbabbbaaaaaaaacfecaaaaabaabbbbbbcdfdbccbbbbbaaaaaabbbcdbaa#aabdb#########a#acdcccbaaab#aabccbbbbbbabbbceedccbcbbaaaa#baa#a###a#a##aa###aaaabaaaaaaaa##aaaabbaaabcbbbbbabbdfeaaaa#ababbcbbaabaaaaaa", +"#####a#####aaaaaabbbbbbbcddcbabccaaabbaaaaa#a##a##a######aaaaaabaaaaacbbbffeaaaababbabbbbbaa##bbaaaabbbbcccghghgeffbaaabbaaaaaabbabccbbbbbbcdddefggecccbabaaabbbacbabbdddecbaa####aabaababbcccdcabaa#aaa###abceedcaaaaabbbbccddefdccdccbcbbaaaaabbccdccdb#abbd###a#####a#a#cddcccaaaaaaaaabccbbbbdeefbba##aabaaa#aaaaaa#aa###aaa##a####aaaaaaaaaaaa##aaaabacbabbbbbcbbbbcfgbaaa#aa#abbab#aaaabba", +"##########abaaabbbbbcbcdcccdcbbbcbbbbbba#aaaaa#a############aa#aaaaaaababbdeaaaacbbbbbddcbaaa##abaaaabbbbcccghhhedecababcbaaaaaababcbbbbbccbddceggffecccbbbaaabca#aaaadddedcb#a##aaaabbbabbbbcccdd###aaaa#aa##bcefeddcddccefdddfdcccccccccbbaaaaaabccccdddaabbda########ab##bbbddcbbaa#aaaabcbbbcdddccaaaaa#abaaaaaaaaaa#aa#aaaabaa#####aaaaaaaa#######aabaacbabbbbbbcbbbbdfbbaaaa###baabaabaaba", +"###########aaaabbcbbbcccbddbcdccbbbbcabbaaaaaaaaa###a##aa###aaaabaaababbccbbdb#abccabddbbbba#aaaabdbbaabbbbcdehihbaabbbbcdcbbbbaababbedcbbaccdddeeefedabbabaaa#aaa#aa#beeeeffca###aaabbbcbbbbbbcced#a###a##aaa#abffgfedcccfhcbdebcbccdccccbbaaaaaabbcccccddbaabdcb#.#aa#aaa##abdddcbbbaaababbbbbcbdbabbbbbb##ababbbaaaaa#aa#aa##aaa######ababaaa#####a#aabcbbbabbbbbbcccbbbeabcbba###aaaaaaaaaab", +"b#########aaaaababbbbabbbbdebcccccbbbabaaaaaaaaaaaa########aa#abbaaabbabbdbcbbbaaadcbcbdbabba##aa##abcb#aaabcdcfhgdabbbccdcbcbbbbbbabcgdcbdbbdedeeehfgdbbbbbaaaa#aaa#abddddgeedcaaaaaabbbdccccccbceeaa###a###aaaacfghhgedccggefbccccccccccbbbbbbaabbcccccccdaabaaccb#aaa###a##adedccbcbaaabbbbcbbcddbaaabbbbaadbbaabbaaa##abaaa#aaaaaaaa#aaabaa########abbadccaaabbbcccccbbdcbcbbba###aaaaaaaabb", +"aa##########aaabbbbbbbaabbaccbceeebbaabbaabaaabbbbaaa###aaaba#aabaaaaababbccggcbaabccbbbccbca##aaaabdbbabbabbcdddghbabbccddcbbbcbbbbbccgfcbccceddddeddedddcbababaaaaaa#accdeffedbaaaaaaaacccccbbbccffb#a#####aaaaabfhgghhhhgghecbccbccccccccbbbbaaabbbbcbbbcdcbbabbcb#####abca#abccccccabbbbbbbbbdddbaaaaabab#cdba#aabaaaaaaaa#aaa#a#aa#####aaaa#######aabbbbccbbbabbdeddcbbeaabbcb###aaaaaaaaab", +"baaa######a#aaabaabdbbcbabbaccccedaaaaaaaaaaaaaaadbaa#aaaa##aaaaaaaaabbbcbcccdbaaaaabdcbacbcdcaaaaaaaabaaccbbccdddhgcabcccdecbcbbcbbabadedbbcdedcddeeccdddeeedcbbcbaabbbabbcddddec#aaaaaabbcccccbccdffc##a##a#aaaaaafheffhgeccefcbbcbcccccccbbbbaaabbbbccbbddedbabbcc.##a##abc###cdcccbcbbbabbbaddccababbbaaabaddba##aaaaaa#aaa#a#aaaaa##aa##aaaa#######abbbbccbcbbbbdefeeccecaaaaa####aabaaaaaa", +"bb#a########aabbbaaababcccdaacdbbaba#aaaaaa#aaa##acaa###aa#aaaaaaaaaaabcdcccaaaaaaaaadbcbbbbacc###aaaaaaaacbbccdcdfggbbbcccdecccddcbbbacdfdbcdebbbcccdcccccdcbefccbaaaaabcbbccabdfcaaaaaaabbdddccccccefe##a##aaaaaaaadfghhhdbbcccccbcbbccdccbbbcaaaabbbbdccddeeba#bbda######.acabbddccabcbbbbbbbddccaaaaaaaaaaabdca#a#aaa#aaaaa##a#aaaaa##aa##aaa#a##a##abbbbccbbdbbccefffeccd#a########abaaaaaa", +"aa##########aaaaabaabbaaccdcaacbbaab####aaaa#aaaaaa#a####abaaaaaaabcaaabddcacda#aaabacbbbbddddcbaaa##aaaaa#abbdcccdegfbbcdcdefccddccccbcbbfdccecabccbcbbbcdddcbffdcccb#aacbaabcbbeecaa#aaaabcedddccccddfeb#####aaaaaabbehhfcccbcccccbbccccccbcbcbbaaabbbcdcceddcbbabba########bcbbcdcbbbbbbbbaacccccaaaaaaaaaaaabcba####aba##aaaaaa#aaaaaa##a#aaaaaaa#aaabaabbcbbbbbbbdffffeeeaa########aabcaaaa", +"aba#a#aa####aaaaabbabbabbaccaaabaaaa#######a####aaaaa####aaa#bbaaaabaaacbddcbccaaaaaaaaaaacdeabcbba#a###a#aaabccccdeegfcbcdddeedcdccddccccfedddcbbccbbbbbbccddedecccdca#aaaaaaabacedcddcbabaabccccccccceccd####aaaaaabaacdghhfecccccbbccccccccbcbbbaabbbcccccddcddceaca########cdccdccbbbbbbbbbccbcdcaaaaaaaaaaaaaaba#####aaaaaaa###aaaaa##a####aaaa###aabbbbbbccbdbbbcdefffgaa#a#######aabaaaaa", +"aa#####aa###aaababbccccbbbbcbaaababa#######a#aabaaaaaa####aa#abbaaaabbaabbdcbbcdbbbbaaaaaabcddbcbba#####a#aaabcdccceefhgbbdcceeeeccccccddeefeeecccacccbcbabbccdefdbcebaaaabaababbbcdcdfffdabbbbbcccccccecade#aa#aabaaaabaackijkidbbbcbccccccccbcbbbbaabbccccccccddegfdaa#######ceedcbbcaacccccbcccccbaaaaaaaaaabaaaaaaaaa####aaa.baa######aaaa####baaa#aaaabbbbbccdcbbcddedfgfb##########abbaaa#", +"#a########aaaaaaccbbcdcccbbbba#aaaaaa#####aa#aaab#aaaa#.###aa#aabababcbabaccbccdedaaaa#aaaaabccacbaa#a######aacbcccdffhigeccccdeedddccbcddffdefcbabbbcdecbabbbbcddecddbbaaabbabbbcccddeeffabbabbbbcccccdecdedb#a#aaabbaaaaahifgikfcbcccccccccccbbaaabbcbbbccbbbbcccdhea#a#####aedfebccccbbcbcccccccbaaaaaabaa#aaaaaaaaaba#b###aaa#b#######a####aa##abbbabaaabbbbbcdecbbcdedefghc#########abcedcb", +"a############a#abcbbbcddccbbbcaaaaaa#a####a#a###ba#aa#######aaba#bbbbbccaabcccddeebaaaa##aaaabaaabaaaa#####a#aaaabcbdeggihfccccdddffdcbcccdfcbcbbbbbbccbbbbabaabcdfebcbbca##aabbbbcdcdfffeeaabbbccbbcccdeeddeed##aaabaaaaachgcccfijebbcccccccccbbaaaaabbbaabbaabbcbbcfecaaa#aaadcddbbdcccabbcccbbbabbaaaa#aaa###aaaaaaaaaaaaa##aaaaba######a######a#abbbbbbabbcbbbddcabcddddefgfa########aacedcc", +"#######aaa#####aaaccccddcdcccbbaaaaa####a####a#aaaa#aa#######abaaabbccacdaadccdddccba#aa#bbaaabaaabaaaaaa#aaaaaababbbdeffiiebcccdddeedcccdcfbcbbbbaabcbbbbbbaaaabcdeefeeddedbaaabcbdccefffffabbbbbbbbbcdcdddddefbaabbbbabaeidccddcejgbbccccccccbbbbaaabaaaaabaaabccccdffebaabbaaddcc#cdccabcccccbbbbbaaaaa#aaaa##aa#aaaaaaaaabaaaba#b##a####a#a#a##a#aabbabbaabbbbddecbbdcccddeega.##.#a##aab###", +"#########a#####ababccbbbdcccccabbb##aaaaaa#aaaaa##aaaaaa#..###aaaaaaccbbdcbbccdbccdaa##a#a#aaaaaa#ba###a#a#aaaaaaabbbcdeefhgeccedbbcdedeedgebbbbbbbbcdcbbbaabaaabacccddccccbdcaabbadddeefffgfbabbbbccccccccdddbggbaabbbbabhefcccddddihdccccccccbbbababaaa###aa#aabbbcdeeffa.##abcfedabccbcccabcbbbbbbabaaaaa###aaaaaaaabaaaaaaaaaaaaba#######aaab#####aaabaaaabbbaceffecbccddccdec#####.##aa#aa#", +"#aa########a####abbccbbccdcccbbbbba#a##aaaaabaa#aa####aaba#.##baaaabccdabdbabbbbbcccbaa####aaaaaaa#aaaa######aaaabbabccdfeehihfggfdbceedddeddfdccbbcbbbbbbbbbbaaabaccccbbccdddecababedefffffhgdaaabccbcccccdddbfhfbbbcbbackdeeccdddccfhgbccccbbbaabaaabba#####a#aabbbdeddeda.###aeddcbaaccccccccbbbbbabaaaaaaaaaa##aba##abbaaaaaaaaaab######aa##aa###aaabbbaaaaabbbeffffdcdcdeffda######.###aaa#", +"#aaa############aabcdcbcdcfedeecbbaba##aaaaabaa###b#a##aaaa####abaaacdcaacdaacbcaaaaaaaabc##aaaabaaaaaa######aaaaabbbdddeddfhhhhhhfcccffffdbaabcbdbabbbbbbbbbbaaaaabbcccbbbbcfdedbbadeddeefdefhffecbbcbcccccceddgibbbbbbdecccbbccccddddhidccccbbaacaaabba########aabccedddeda####cdcecbccccddddcbbbbbabbaaa#a#####a#######abaaaaaaa#aaaa#a##aaaa#a####aabaaaaaaaaabccddfgfddefge################", +"##aaaaa#aa######aaabdccbccdeefebbaccb###aaabcbaa########aa######aaba#bdbbbcabbbbbbaaba##aba#####ababaaa##a#a##aaaabbcddedddeeefhghfddccdhecbbbaaaababbbabbabcbaaaaaabbccbbbbbbeefdbbbddbddffdggihiebbbcbbcccccedeicbcbbcdccccccccddddddcfifccbbbbabbabbbaaa####aa#aabcedddefeb##.bdcdeccbcccdddcbabbbbaaaaaa#aa############abaa#aaaaa#aaaaaaaaaa#######aabaaaaaaaabbabbcefgecbcc############a#a#", +"##aaaa####aa##a##aaabcdcbbccdcdccbcaba##aaaabbbaa#aa#a####a######aabaaabaaaaaaaabbba#aa###a##a###abbbaa#aaaa#a##aabbcededddddeghggcdfedffddcbbbaaabbbbbccabbbbbcaaaaabccbbbbbbeccefdbcdbcbcefefhgghdbbcbcccccccdcefedbadccbbcccccddddddddeggcbbbaacaabbbaaa######aaaabdcdeedefbaa#deddcdcbbcdedccbbbcbaaaaaa##################aaaaa#aa##abaaaa#aaa#aa##aaaaaaaaaabaabbacdbacbaaba###############", +"##a#aaa####aa##a##aaabbbbbcdeccbbaaaaabbaaabbaabaa###aaaa#########aaab#aaaaaaaaabbaaaa#a#a#aa#a#aabaaaa###abb##aaaaabcdeeddefghhhebbbfebbdddccbbbbbaaabdcbcbcbacbaaabbabcbbcccddbbcefecdcbbbcddehgggcbbcbcccccccdddffbbdbbbbbccccddddddddddegcbbaabaaabbbaaa######aaabbbcdefdeca#ddedcdddbacadedccbbbbbabaaaa###############.####aaa##a###a##aaa#aaa#abaabaaaaaaaaaaaaabcdbaaaa#a########a##a###", +"a##a#aaaa#####aaaaaaabcccbbcdebbaaba#a#bbaaabbaaaa####aaa#####aa#abaaaaaaaabaaaaaabbbaaaaaa#aaaaaababaaa####aaaaaaaabcddddefedhhgbbbbcefbcdedcedabbbababbbcbbbbbbaaabbaabbbbbcbcddbbbcdcebbbbdcabehhebbbbcccccccceddhfddbbbbbccccddddddddddcdfdaaaaaababbaaaaaaaaaaabbbbccddcdfededffddddcbcabcddccbbcbbaaaaa#####################aa##a#a#######aa###aaaaaa###aaaaaaaaaabbccaabaaaa######a######", +"aaaabaa##aa####aaaaaabbccccbcccaabbba#a##aaaabbb######aaaaba##aaaaababb##aaaaaa#aabaaaa#aaa#aabaaaaaacbaa####aaaaaaabcdeddefefhheabbbbbdfgfgedcfaaabbbbbbaaaaaacabaa#baaabbabaabbdeeeccabdccbbbcaachifbbbcccccbcccddejkeabbbbccccddddddddddccceebabbaabaaaaaaa#aaaabbbcbbcccddefgedfedddcccbaabcdcccbcbcaabaaaa########.##.########aa###a########aaaaa#a###a###aaaaaaaaababccaabaa#########aa#a#", +"##aaaacb########aaaaabbbbcccbdcddbbcbc#aaaca##a#aba######abca#aaaa#aa###aa###aaaaaabbaaa#a###aaaaaaa##bcbba###a#aaaabbceedddehgfdaaabaccbfhiihffcaaaaccbaaaaaaacabaaabbaabcbbbbbbbcbdeffedfdb#acaabafjgbbcbcccbccccdefiicbbbbacccddddddddccccbbcfbbbbbabaaaaaaaaaabbbcbbbbccccdegfecfdbaabdabbbbcccdcccbbbbaaaa###################a#aa##a#a##a####a#aaaaa###########aaaaaabbbbbaabaa#######aa###", +"###aaacba#######abaabbdcbbcdcbbefcbabcbbaaaaa####aa#a#a#a#a##aaab###a#aa####abb#a#aacbaa####aaaaaaa#aaabdcbaaaaaaaaabaceefeeffffbaaabbabccehigfeeddefdbabaaaaabbbabaabaaaaabbbbbbabccbabdedda##aaabbachhbbcbccccbbcccdeghebbbaccddddddddddccccbacecbabaaaaaa#aaaaabbbccbbbbcccdcdgfdfebbbbbcccbcbcddccccccbbaaaaa################aabbaaaa####aa###a##aba#############aaaaabbbddbbaba##########.#", +"####aaaba#######aaaaabdfdbbcccbbdebbaaaab#aaa#a###aa###aaa###aba#####aaa#####aba#aaa#baaa#####aaaaa###aabcccaabbbbbcbbbdfffgeccebaaabbbbcbbeffedccfghhebaaaaaabbaaaaaaaabaabbabbbbbacbbbbcbdda####abbabghabbbccccbbccddddghdaabcddddeedddddcccbbabdfdaaaaa##aaaaaabccccccbbccddcbefdffdcbbbcdccbbccddcccccbbbaaaa################bbccbaabaa#aaaaaa#aabba##a#########a#aaaaabbccbcabaa###########", +"#####aaaba#######aaacccefcccbcdccbcbbaaaaa#abcba#########aaaaaaa######aaaa####aa##aaa#aaaaaaa##aaaaa##aaaccddcccdddddcceeffdccdccbaaaaabbbbcfggdddfffggfebaaaaaaaaaabaaabccbbbbbbbabccbbbbbcbdb###aabbbbghbacccccccccccdddfigdbcddddddeddddcccbbbabbfeabaa#####aaaabcccccbcbdddecegfffcccabbccccbbccdcccccbbbbaaaa############a#aaaababaaaaaaa#aaa##aaaa#aaa##########aaaaaabbcccbbdba#########.", +"#####aaaaa######aaabddefcccbabdccccbaaaaaa###aaa######aaabaabbba#######aaaa####a###aaaaaa#a##a#aaaaaaaaaabcddddcdeeedefgfefecdaabbaaaaabbbbbadfebcfdfgffeeecaaaaaaabaaacabdbaaabbbcdcbbbbbbbbccb#a###abbaegcabccccdcccccdddcfihfdccdddddddddcccbaaaaaddbaa######aaabccccbcbccdddhfcfgecccbbbbcbccbccbccbcccbbbbaaaa#a##########aaaaaabccbcba#aa#aa#aaaaa#aaaaa###########aaaabbaddedaa##a#.#####", +"####aaaaaa#######cffdabcbcdcbbadfbcbbaa###a#aaa#aaaaaaabaaaababaa#######a##a#########aaa##aa##aa#aaaaaaaaabdeddccddddddffeeeec#a#aaabbbaaabbbcggdcfeeeeegfdccbabccbbaaabbbcaaaaabbbcdbbbbccbbbdbaaa###abbccebabbccccbcccccddcdfhjhedddddddddccbbaaaaaabdda#######aaabbddccbbdddedccdgeeedccbbccdccbccbcbccccbbbaaaaa#########.##aaabbaabbbcbaaa###aaaaaaa#a#a#a########aaaaabbaccddeb###########", +"########aaa######acddbabcbbcccabcddcaabbaaa##aaaaaabbbcaaaabbaaaaaba########aaa#aa###aaa###aa##abaaaaaacbbbcdffeddeccdffffeddbaaaa#abbaaaabaabegebdfeddeffeddddcdddcabbacbcbccbaabbacccbcdbbbcdb#aa##aabbbbbffbbccccbccccccdddedfkkidddddddcccbbaaaaabbabdb#a#####abcccdbccccddfcccdfgeedccbbbcbccccbbabbcccbbbbbbaaa############a#a#aaaacacbaaa####aaa#aa###a##a######aaabaabbbbbbdfa##########", +"#################abbcbaacccccbccaacbcaaaaaaaaaaaaaaabccabbbbaaab##bb######a#aba##aa##aaaaa##a#a#acabbbacdcbcddffffdgeefefeddcb#a##aaaaabaaaaaaddfdcfdccccccdcbcbcccecbbabccdddddcbbbbccccccbbbceb#aa###aaaabbfgbacccbcccdcdddeedgjkihccddcccccbbaaaabaabaadca####aabbcccbcddccefdcdeeeedddcacbccccccbabaaabbbbbbbaaaa###########.#####aaaabacbba##aaaaaaa####a####a######abbabbcbcbcdb###a##.##.", +"###########aa#####bdbaaaaccddbbdcba#bbaa##aa#aaaabbbbbbaaabaaaaba##aa.####aaa##a#aaaaaabbbaa#####abaabbbbbccdddeefeffddefdccaa####aaaaaaaaaabaeefdedeccbabbbdddbbccccabbbbbbbbcdcccbcccccccccbaaaa#a####aaaabacgcabbcccdddefffedgijfehdcccccccbbbaa#aaaaaaabcbaaaaaabbccdcdddefgecddeefedccbbbabccbbbbaaaaaabbbbaaaaaa################aaabcbabbaa#aaaaa#aaa###a####a####aaabaabcbbbcbba###aa####", +"############a#####abaaaaaabddccbcdddbaaaa###aaaabaaabbbaaaabbabba###b######aa######a##aacbcbba##a##babbccccdddddeeefgfeedccdb####a#aaaaaaaaaaadefedecbabbbbbcddddbcddcaabaaaaaabbbbbaabbccdcccbbbcb#a##aa#aaabbbfdbbccddddeffffefggeedjhedcdcccbbaaaaaaaaaaabbcaaaaabbcdcccdeefgdcccdefeccbbbbbbbccbbbbaaaaaaabbbaaaaa#######aa######aaabbbcab#a#aaaaaaaa#a##a#####abaaa#abaabbbbbbdccc####aa#.#", +"###aaa###a#a#a####aabaaaaaabdbbbcecdcbaaaaaaaa#aaaaaaaaaaaaabccbb###a########a#a#aaaaa##aaaabca#a##aabbccccccdcccbbbbcbcabbbb#a#a#a#aaaabaaaabbeffddeabcbbbbcccccdccbbbaaaaa#abaaaaaaaaaababbbbbcbb#a##a##a#aaaabefcbdeeddeffffffeddfbchjieccccbbbaaaaaaaaaaaacfcabbbbcdddcdehggffeeddgfecbbccbbbccbcbbaaaaaaaaabaaa######a##aaa####aaaaaaabbaa##aaaaaaa#aaaa#####aabbaaaabbbbbbccccddbaaaa####.", +"####aaaaa#aaaa#aaaaaaabbaaabccbbbcddbbdcbaaaaaabaaaaaabbbbaaaaabaaa###############aaaaa##a#aaaaaaaaaaabbccccdcbbbaaaaaaaabaaa#######aaaaabbbabaacffffbbbbbbbbbbbbccccbaaaaaaaaaaaa##aaaaaaabbccca#######aa###aaaabcgfcdeeefgggggggeffcbbehkjebbcbbaa##aaaa#aaaadheabbbcdddcegfbccdfffgggedccccbbbbbabbbaaaaaaaaabaaaaaa######aaaaa#aa##aaaabaaaaaaaaaaaaa##aaa##aaa#acbaaabababbcccdecbaaaa###a#", +"#######a###abaaaaaaaaaaabbdccccbbbceefebcaaaaaa#aaaaaabbbcccaabaaa###aaa#######a###aaaba##aaaaaaa#aaaabccccccbbbaaaaaaaaabaa###a###a#aaaaacbababa#eeedbbbbcddbcbccbccccaaaaaaaa#a#aaaaaaaabbbbcba########aa####aabbbghdeeegggggghggfedbbbcdikgbbbbbaa#aaaaaaaaaabheaabccddegdccccdddccfffddbbabbbcbbbbbbbbbbbaaaaaaaa########a###aaaa#a#abaaaaaaaaaaabbabaaaaaaa#a##ccaaaaaaaaaabcccbacaaabaa###", +"##a#aa#####aaaaaaaaaa#aabbbabbcbbabcdeedcbbbaaaaaaabbbccdddccccbbccbdcbcca########aa####aa##a#aaa###aabbccdccbbbaaaaaabaaaaa#########aaaaabcaaabaa#dfcccbcccbcccccdccccdbbaaaaaa###aaaaaaabbbcb######aa###aaaa###abbcfheeffghhghhijifcbbbbbehjhcbbba##aaaa##aaa##afgdbbcefecdcdccddddddeedcbabbcbbabbcbbbaaaaaaaabaa######a#a#a###aaaa#aaabaaaaa#aaaaaaaaaaaaaaaa#a#bcaaaaabaaaaabbcccbcabbbaaa#", +"aaaaaaaaaa#aaaaaaaaaaaa#abaa#aaaaaaaaabcbbaabbbabbbbccddddddefdbcdccdecddcaa##aab######baaaa##ab###aaaabbbcccbbaaaaaaaaaaaaaa########aaaaaacdbaabaa#dcabccdddcccccdeeddddddbaaaaaa###aaaaabbbca#a#########a###a##aaabcegefgfhhggiiihddbbccbbfegihfb###aaaaa#aaaa##adgfefecbddccccddcedccefdcbabcdcaabbbbbbbaaaaaaaaaa#a####aaa#aa###aaaabaaaa#aaaaaaa#aaa##aaabaa##abcbaaa#aaaaaaabbbbdddbbbaaaa", +"aaaabbabaaaaabaaaaa#a#aaa#abaaaaabaaaaaaaaababbbbccdddeeefdfffedccbbbbcccccaaaaacb#abaab#aaba#aaa###a#aaaabccbaaaa##aaa#abaa###a##a#aa#aaaaacca#abaaadbabddddfededcbbcaaabcddcaaaaaa###aabbbcdca######a####aa##aaaaabbcdkgghhhhhgiigecabbbccffedgiida#aaaaaaa#aaaaaabfecbccccbbbabbbddddddccbaaacdcbbcbbbbbbbaaaaaaaaa##################baaaaaaaa######aa#aaaaa#a##abbbbaaaaabbaaaababbddcbbbbaa", +"aaaaabcccbbbaabaaaaa#aaaaa#aaaaaaaaaaaaabaaabaaabbbcdffefgffdcccdddcccccbaabaaacbab#aa##aaabb#a#a##aaaaaaabbbcaaa###aaaa#aaa#a###aaa#abaaaaaacccbaaaabcbaaccbbdccbbbababba#abccbaaaaaaaaaabdeabaa##########aa####aaaabbceghghhihiihhgcbbbbbbegdcdedhhdd#aaaaaaaaaaaaabdccccccaaabbbbcddddfeffdbbabcbbbbbbbbbaaaaaa###a#########aa#######acbaaa#####aaaa##aaaaaaaaa#a#aaaaaaaaaabbbbaabbccddbbbba", +"aaaababbbccbbcbaaaaaa#aaabba#aaaaabaaaaababbbbbaaaaaa#aabbcaaabbbbbbbbbcbaaaaaabaaaa####a##aaaa######aaaaaabbbbb#######a#aaa#a###a##a#aaa#aaacbbcbabbabcabbbcddbaaabbaaaa##aaaabbaaaaaaaabbcdbaaa###########a####aaaaabbbcfihghhhihhhdabbbbbbeeccccbdehfaa##aaaa#aaaaaabedccbaaaabcdcddcbfeffddeedccbbbbbbabbaaaaa#############aa########ababaa###aaaaa###aaaaaaaaa##abaaaaabbbbbbbbbbbbcdffabaa", +"aaaaabbacbbbabaaaa#aaa#aaaacba###aaabaaaaaababaaaaaaaaaa##aaaaaaaaababbccc###aabaaaa##a##aaaaa#aa##aa#abaaaacccb##a#a#a#aaaaa####aaaa###a#aa#ababdbbbabcbabbbbbbbbbcbbaaaaaaaaaaba#a###aaacbcdaaaa#########.#####aaaaaabbccfkjgfhhifdfdaaababbffcbbbbbacgda#aaaaaaaaaaaaaddcba#aabccccdbbdeefeddfdfecbbacaaaabbaa##############aaaaa#######a#aa###aaa####aaaaaabaaaaaaaba#aaababbbcccddddgihcabb", +"baaaaababccccbbaaa##aaaaaaa#cddb#####aabbbbaaaaaaaaaaa#####aaa##aa#aabadedca#abbaaaaaa####aaaa#a#aaaaa##aababcbca#aaaa#####aa###a#aa##aaaaa#a#aaacbaabbbcbabcccbbbbcbabba#aaaaaaaa#bbaaaaabbadb###################aaaaaabacbgkkihhggfedaaaaaaaceecbaaaaabffgeca#aaaaaa###acdca#aaacbbccbcbeeefffdabdfecabaaababbaa#a##########aaaaaa#######abaa##aaaa#####aaaaaaaaaaaaaabaaabaabbbbbcdegghffdabb", +"bbaaaaaabbcccccbbaaaaaaabaaaabccca###aabcceebaaaaaaaaaaa#a##a#####aa#aaaddbbaaabaaaaaaaaaaaaabb##abb#aaaaaaabcbba##aaa###aaa#########a#aaaaaaaaaaaaaabbbccbaabccbcbbbbbaaaaaaaaa##aaabaaaaccbed#################.##aaa#aaaaacekljihhhdbaaaaaaabdeedbaaaaaabceffdaaaaa#####abdd##abbbbccccbcedfeddbbbbdddbbaaababaaa#################aa#aa.###aa##ba##aa###aaaaaaabaaaaabaaaaababbabbbdfhjifeecba", +"bbbaaababaabbcccbaaaaaa#aaaaa#aaba##aaabcbbccbaaaaaaaaaaaaa#aa####aaaaaabccbaaa#aaaabaabaaaa#abdca#acaaaaabaabbaba#aaaaaaabba##aaaaaaaaaaaa##a#aabbbbbbbccbbbacbcbabbbbbaaa#aaa##aaaaaacbccccdbbba#a########a#.####aaaaabaaaaafklljhfcaaaaaaaa#dcgfcbbaaabccccdggcbaaaaa#aaaacdaabbbbbbbbcbddeeddccccbbcecbaaaaaaaa#a##############aaa##a####aa##b###aa#aaaaaaaaaaaaaa#aabaaaaaabaabbdggghhfbdeb", +"bbabbaaaaaabbcbccbabba#aaaa##a#aaa#a#aaabbabbbaaaaaabbabaaaa#a#####aaaaaadcba###aaaaaaaaaaaaaaabbaa#abaaaabbbcbaa#aaaaaaaaaaaa#aaaaaaaaaa#aaaaaaaabbbbbbbcbababbbcbbbbaaaa###a###aaaaaaaccddcddbaaba#aaaa####a#.#.#aaaaabbaaa##djlljc#aaaaaaaa#afdfebaaaabccccddegfdbaabbbbbbabddbbbbbbbbbadceedcdcccbbabdebaaaa#aaa#############aaaaaa#ab####a##ba#####aaaaaaaaaaaaaaaaaaaaaaaaaabcdfebbbabbbcc", +"ecabbaaaaababcdcccbbbcdbaaaabbaa#aaaa##aabcbbbaabaaabbaabaaa#aa###aaaaaabecbaa#a#a#aaaaaaaaaa#aaaaaaaaaaaabbcbaa###aaaaabaaaaaaa#a####aaa#aabaaaaaabbbbbbdcbbabbbcbbaaaaa####aaa#aa###aaabcccccbaabbba##a####aa#####aaaabaaaaa##ahlkfa#aaaaaaa##fbbecaaaabccbcdddceghecbbccccbbbccddbbabaa#ccedddddccbbaaacfbaa#a##a############a##aaaaaaaaa##a###ca#aa###aaaaaaaaabaaaacabbaaabbbbddea###aaaabc", +"abbcbbbbaaaabbccbbbbaaaa#a#aaaabcaaaaaa#aabbbbaabaaccbbabaaaaaaaaaaaabbabdcbaaaaa###aaaaaaaa#aaaaaabbbaabbbabaa#aaaaaa#aaacbbaaa##aa##aaaaabcbaaaaabacbccccabaabaacbcbaaa####aaaaa####aaaabdccdba#abbaaa#######a######aaaaaba#####dljfa#aaaaaaa#ddaadcbccbbbbccccdccehihfddccccccbbdfaaaabbbceefedddcbbbbaaaecaaaaa##a###a####a##a##aaaaaa####a###ba#aa###aaaaaaaaabbbbacbbbbbaaacccdd#####aaaab", +"babbbcccbbbaacdbccbbbaaaaa######aaaaaaaa##abbbbabaaabbaaaaaaaaaaaa##abbbdcccbaa#aa#####aa#aaaaaaaaaaabcbabbabaa##aaaaaab#accbaaaaa#aaaaaaabcddbaaaaabbbccccbaabbbbaabbbbaa###aaaaa#####a#abceeeaaa#aaaaba#######a#######aaaaaaa###.cgjgb#aaaaaaaafcaacdcdcbcbbcbbccdeefeeghfeccccbcddc#aabaaaeffeccccbbbbbaaacdcaaba##aa##a#aa#aaaa#aa###a####a####b#a##aaaaaaaaaaaaabbbbcababbbbcdddeb#a#####aa", +"bacbbcddcbbbbacddccbabbaaaaaa#a##aaaaaa####aabbaaaaaaabaaaaabaaaaaaaaabbcccbbabaaaaa#a#aaaaaaaaaaaaaaaabbccbbba##aaa#aaaaaabbbaaaa#aaa##abbaabbcbaabbcccccbbbbbabbbabbbbaa#############aaabbcedbaaaaaa#aaa######a########a#aaaa##a##adhjc#aaaaaaacdb##bddcbbbbaabbccefgecceffgfcbceccedabbaaacffdccbbbbbbbbbaabccbbaaa#aa####a###aaaaa#a##bb##a###ab##a###aaaaaaaaaaabaaabbbcbcbbbcefeb#####aa#a", +"aaccbcddcbbabcbcddcbbbcbaaaaaaaa#aaaabaa##a#aaaa##aaaaaaaaaaaaaa#aaaaaaaaabbccaaaaaaa#aaabbaaaaaaaaaa##aabccccbaa#aaaa#abaaaaaaaaaaaaaabbbbaabbaccbddedcbbbbbabbbcbcbbcaaaa############a#aacbcba##aaaaaa#aaa#a###########a###aaaaa####adid#aaaaa##eca##addcbbaaaabbcddefddefddgiedccccffbaaaaaefeccbbbbbbbbbaabacdbbba####aa#a##a##aaaaaaccbba###.aa#aa#ba#a#aa#aaaaabbabcbccbcbcccegc######ba#a", +"abcbbccdedcbbbabdddcbabbbbbaa##aa#aaabaa######aaaaaaaaaaaaaaa#aa#######aa#aabcbbaaaaaaaaabcaaa###abaaa#aaabcbcb#aa##aa#abbaaaaaaaabbcaaaaaabbgecbbbbccbbbbbabcabbcbbbbaaaaa##############aaabaaaa#aaba#######a###########ba#aaa#aaa###aabffcaaaaaabeb####cdcbaaaaaaabbccdeffeeegihfddddffcaaaabefeccaabbbbbbbaaaabdba#aa####aaaaa###aaaacccbbba#######aaaa#aa#a##aabbbbbbbccccccccddgf#aa##a#aaa", +"aabcdddddddbbbccabcdccbaaaaaa#####bbaaaa#######aaaaaaa###a#####a#########aaaacbbbaaaa#accdddba#a#aaaaaaaaabbbcbaaaaa#aaaabaaaaabba#bdaaaaabeecbbcbcbccbbbbabbbbbbbabbbbaa#aa####a########aaaaacaabaabaa#######aa########abbbbaa##aaaa###aaegfb#aa##dcaaaabddbaaa##a##aaabcdfgffgiggfffedefea#aabffccbaaabbaaabaaaaacbaaaaaaa####a##aaaaaabbabaaa##aa##aaaaa######aabcbaabbccccbbddedeeaaaaa#baaa", +"aabbdeedeedddaccbbbcbcccbaaaaaabbaccaaa#a#aa###aa#aaaa#########aa#a#####a##babbbbbcbbcfdccccbbaabaaaaabaabbbccbbaaaaaaaaaabaaaaaaaaacfcaaabcbbaaababbcaabbbabbbbbaaacbabaaa####a##.########a#abd##baaaaaa##.###aa#######abbadb#a#########aaeiib####bca#aabadcba########aabccdgghgfeddddeedegdaaabdedbbaaabbabbaaaaa#cbaaaaaaaa#a##a#aaa#abbbbaaa#aa##aaaaaaa#####aaabaabbbbccbbbcdecef######acaa", +"baabcccddedddbacccbccdcbbbbaa####aa##aaa###a###aaaa#a#####aaaa#a#aaa###aaaaabbbbbabcgjfdccbbbaaaaaaaaaaaabbacccba###aaaaaaab##aaaabbbdfdbaabdecbbbabaabbbbbbbbbbbbababbaaaaaa######.########a#acdb#aaaaaaa######aa######abbccb####aa######afiifa###bca#aaaabcbba#a######aaabcdeefcbcedccccceffaaaaacdbaaabbbaabbabaaabcbbaaaaaaaaa##a#a##abbaaaa#ba##aaa###a####aaaaaaaaaaccbbbcccdeff.######aaa", +"a#aabbbcdeddcccbcccccdcbbabaaaa##a###aa#a#a#####aa##a###a##aaa####aa#a#a#aaabbaabbbbbffdccbbbabbaaaabbbbbabcbbbaaa##aaaaaaaaa###aabcbbcdfdaacebbbbbaaabbbbbbbbbaaaaabbabaaaa###aa############abcdcaaaabbaaa######aa#####abbbdc#############adghf###cdaa##aaaabbaa##.##.##aaabcdecedbbcdecbbbccebaabacdaaaaabbbbbbbaaaaabdcbaaabaaaaa##aa#aaabaaa#bcaaaaaa###aa#a#a#aaaaaaaaababccdceec##########", +"###bbbbcdeddddcccccbccbccbbbaaa#####.#a##aa######a##aaaa###aaaaa##a###aaaaaabbbbbbbccddcdcbbbbbcdbbbadecccccbcb###a###aaaabaaaa###accbbccfhcacbbbabbabbbbbbbbaaabbbaabbbaa####aa#########.####aabcbaaaabbaaaa#####a#####aabacfb###############dhhc.ddb###a###bbca#.#....##aaabcdccecbbccedbbcccedbabbdcbaaaaaaaabaaabaaaacccaabaaaaaaaaaaa#abaaabbcaaaaaa###########aaaaaaababbbceeda.#####a###a", +"#baaabbcdeddddddddbbcccbcbbbbaaaa################aaababba####aaaaaa###aaaaaaabbaabbdecbccccccbbbccccbcbbbcbbddeeca###aaaabccaaaaaa##abbbbcdedbbabbaaaaabbbbbbbbaaaaaaabbaa#######aaa##########aabbbaaabbaabaaa########aaaaaabdfb####aa#########cghhceba###a##aabaa#.....###aaabcdceebbbbbddcbccbcdcabcedbbaaaaaaaabaaaaaa#cddbbbaaaaaaaaaaaaaaaaccbaaaaaba#a#a######a##a#aaaaaaccdeed####aa####a", +"aaabaabccceeddeedcabbbcbbcbbbbbbaaaaa#########a##aaaaabbcbaa#aa#aaaaa#aaaaaaaaaaabbcddcbbbbbbbbbbbbbabbbbbbaabbdgfba#aaaaabbaaa##aaaaaabbbcceedaaaaabbabbbabbbbbbaaaaaabba#######aba#########a##abbcaabcbaabbba########aabbaabddca#aaaaa#########adjhaaa#aa#####aaa#...####aaabbcccfdabbbbbddcccbbccacffccbaaaaaaaaababaaa##bccccbabaaaaaa#aaaaabdcaabbaaaaa#########a#a#aaa###bcddhga####aa####", +"##aabbbbcdffeddeebdcbbbbbcbbcbcbaaaaaa##.##aa######aabbbbaaaa#aaaaaaa##aaabb#aaaaacddfbcbabbccbccbbbaabbaaba#abadfdbbaaaabcaaaaaaaaabbbababbceedaaaabbabbbbbbbbbbaaaaaaaaa##.#####aa#########aaa#aacdabbbaaaaaaaa#######bbbbccdcddbaabbaaa####aa###bhgea#######.##aaa#####aaaababbbcebababbabdeccbbbceffeecbaaaaaaaaabaaaaaaa#bcccbbbbaaaaaaababbbbbaaaabaaa#######a##a#aa#aaaaabddhg###########", +"#a#aaabcdddffdddeeedbbbbbcbbbbcbbbaabaaa#a##a##aacaaaaaaaaaa#a##aaaaacdaaaabaaaa#accdeaaaaabbbbccbbbbaaaaabbbababcdddcccbbaaaa#aaaabbbaaaaaabdeeeaaaaaababbbbbbaaaaaaaaaaaa###a####ba####a####aaaaaabecaa######aaa#####a#ababccccbcbabaaaaaaa###a####dijdb########a#a###aa##a#abbbbddbaaaaabbabdddcfeffffeccbbaaaaa#aaaaaaaaaa#abccbcabaaaaaaaabbaaababaaaaa#aaaa###aaa#aaaaaaaaabchga#####aaa##", +"#a#a###abccdddefdeeecbbbbbbaabbbbbbbbba#########abaa#aaaaaaa##a#aaaaaccbaaabbabbcbbccfbcaaaababbbbbaaaaaaaaaaaabbbabbabaabaaa#aaaaaabbabaaa#abcdfea#aaaabbbbaaaaaaaaaaaaaaaa#######bba##########aaaabcedbb#######aa#####a##abdcbbccbaaaaaa#aaaaa#aa###bgjjga#######aba#aadba##aabbbccbaaaaabbaaabedffeffffdcbbaaaaaaaaaaaaaaaa#aaaccbbbaaaaaaaaaaaababbbaaaa#aaa#####aaaaaaaaaaabbbghc#####aaaaa", +"a##a#aa#aabccbdfgeefeccababbbaabaabbbaa#a##.######aaaaaaabba##aa##abbbcbcbbccacbbdedgheccbbabbaaaaaaaaabbaaaaaaaaaaaaaaaaaacbbba#ababbbbaaaaaaabdeeca#aabcbaaaaaaaa#aaabaaaaa####.##ba###########aaabbceeba########a#########cbbbabbbaaa#aa#aaaaaaaaa###djkjb#b#..#abbcaaabcba##aaabbcaaa#aaaaabaacfffffedffccbaaaaaaaaaaaaaaaaaaaabcbbaaaaaa##aaaaabaaabaa#aaaaaaa#a#a#a#aaaabbbbccgc######aaa#", +"##aaaaaa##aaccbaeihfgggcbabbbaaaaacbbceceeca########aaaaaabaaaaaaaabbbdcccdebbcbbabacedecbbbabaa#aaaaaabbbbaaaaaaaaaa#aaaaa#abbbbacbbbbbbaaaaaaaccddbbbbbbbaaaaaaaaa##aaa#a##a#####aa#############aaabbceeea########a########aaaaaaaabbaa###a###aaa######agjkhgfb.#aabddaaaaaaa###aabdb##b###aaaaa#cffffeeeeeccbaaaaa#aaaaaaaaaaaaaabcbaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaabbbbbdfeba####aaa#", +"#a#aaaaa###aacca#cjjhhjebcbaa##a##acegebdcbdb#.#cbcaaaaaaaaaaaaaaaaaabbcdgiecbbaaabbbcbcdcbbbbbaaaa#aabaabcbaaaaa#aa#aa#aaa###aaaaaa####a###aaaabcddbcbbbaaaaaaa#aaaa#aaaaa##a#####baa#.#######a##aabbcdddffa##.####aa##.####aaaaaaaaaabaaa###########a####chhiihc..ceffbabaaabaaaaabccaacc###aaccbbegfffededdccbaa#a#aaaaaaaaaaaaaaaabcbbaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaabcccefeaaa###aa#a", +"aaa#abaaaa##aaba##eiiikhccbddefeeffgecccdccdeffefddc#aaaba#aaabaabbaaaabcdhfbbbbaaacdecbbaabbbcbbbbaaaabbbbbbaaaaaa#######a###aaa#aaaaa######aaaaaccbcbaaaaaaa####aa##aaaaa#####a##############a##aaabcccccdfb##.#####a######aaa#aaaaaaaaaaa##########aaa##.#aejjifb#cffacbbbaaa#acbbcc##ddda##cddeefgfffeedddcabbaa#aaaaaaaaaaaaaaaaaaacbbaaaaaaabbabbbcaabaaaabbabbbbabbbbbbbbbbbdfc####a##aa#", +"#aaa#a#a##a####b###dgkkjgccfiifdfdeeccddddcdcccccbca#aa##aa#aaaaabbbaababeggdbaaaaadfcbbbbbbcccbabcbaaaaabcabbbcbaaaaaa##########a#a########aa##a#accbbaaa#########aa###aaaa###aaa####.#########b##aabcbbcddfb###############aaaa###abbaaba#aaa#########aa#####djjjifbcebccdcba#bbacbcb##addccdcdeeefgfffeecbccbbbaaaaaaaa#aaaaaaaaaaaaaabbaaaaaaabaabbbbbaabababbbbbbbbbccccbbbbcced####a###aa#", +"a##aaaaaaaaa#a#ba..#agkgfecfikgddcccdcccbcccbcbcbbdba##bccaaa#bbccccbaabbefffcaaaabdfbbbbbbbbccaaabaaaaaaabcbbbabbbbaaaa#######aaa############aa###abbaaa####a############a####a#######.#####a##aaa####aaaacfa#######..######aaaa###a#cdcbbbabcbaa#aab#########.chiiihfcddeghhgdccdabdaa#addcddceefeeffeeeedbbcccbbaaaaa#aaaaaaaaaaaaaaaaabbbbaaaaaaabaabbaaaababbbbbbbcccdccdcbbceea####aa###aa", +"a####aaaabaaabbab#.#aaeecdhfijfcccddcccbbbbccbbbccaaa###.a#abccccbcbcbbbbbff#a###abcebabbbbccbcaabbaaaaabccbbbbbbbbbbbaaa#aa####aa##############aaaa#ababaa##############a#a######a####################aabbcacaaab#####.#.##abbaa###aaabcacbcaaaaaaa#aa#########.bgihiifcdgijjjiidaaabe#a#bdcbccccddddddecdecbbbccbbaaaaa##aabbaaaaaaaaaaabbbbbabbbaaaabbbbbaaabbbbbbbccdddedddefeffa####a#####a", +"#######aaaaaaaaaa#.#abcdaahkkjgbbcccbbbbbcbbcbbbbaaaa#a######abddedccccbbacffcbb##acccacdcabbdccdbabaaaa#abbbbbaabbbbcba###a############.##.###########ababaa##################a##a###.################aaabcbcdbbbaa##.#.#.#aabaa###abcdcaabaa####aa#aabbb###a###.#bgjhacegijjjjjjhedfgea##cbbbccbbbcccccdcccbbbccaabaaaaaaaaaaaaaaaaaaaaaabcbabaaabaaabbbbbaababbbbbbccddddedffceedb######aa###", +"aaa#a####a##aaa##a.##acda#cejjfdbbbbbabcbaabbcbbaa#aaa##a#a###baecbdfedddefhhgefea#cedbafecbbcbecbbccbbbbabbbbbbbccabbcdcaa####################.#######aaaaca##########################.########a######aaaaccccbbca#a########aaaa####bedcaabaa##aaaabaaabc########..#figefhikjihhhhiijiihd##bbcdbcccbcccddebcbbbbcdbaaaaaaaaaaaaaaaa#aaaaaabbcbbbbbbbabbbbbbbabbbbbccddedeedffa###a#####aaaaaaa#", +"###aa############a#.##bccbbbbehhaabbbaaabbabbcbaba#aaa#######becdda#fgecddeehghegdabdecaabedbcaacbbddbbbbbbcbbbbbbdbaaccccba#########a################aaaaabcaba###############################a#####.###aaaabccbcb##a######aab##a###accbca#b#####aaaaaaaaa###.####...diihiiihfgeffeffhijid##ddcdccccccddddccbbaabddcaaaaaaabaaaaaaaaaaaaaaabbcbbabbababbbbbbbabbcbccdddedefc.##########aa#aaaa#", +"#aaaaa#aaa##a######.#abbccaaaabgfb#ababa#aaaacbaaaaabbbab####edeefeccgedcddehhfacebadecaaaabcccbbbbcbabbbbbcbbcbccccccabccdb#######abb###a##############aaaacbccba##########a######.########a###a#########aabcceccb###a#####aaaa##aaaaacbb##ac######aaaaa##aaa#######..diihffffffdeddddefiigaaeddddbbcdddccdccbaaabcedbbbaababaaaaaaaaaaaaaaaabdcbaabbababbbbbbbbbbbbcceeegc.#############aaaaaa", +"aabcbbaaaaaaaa########bbcdbaaaaaffa#aaaaa#aaabbaaaabcdeddabaefcdddefcgfddddeghcccffddbaaabbbbbccbccdbcbabbbbbbcbbbbbdcabbbddb########bca#a#######a##a###aaaaaaabdbaa#aaa####aca##...###aa####a##a########aaabbbdecc##aaa############aa#abba##a#########aa#aaaaa########.bgiedcccdccccccccdhigdeeeeedcdddccbcebaaaaaaceebbbbbbbababaaaaaaaaaaaabcccccfedcbbbbbbbbbbbbabcfffe############a###aaaaa", +"a#aaedbbbbaaa#a#######abddca#aaaadcaa##aa####aabababbbccccfggcbcccccfgeccccdddffedfecddcbbbbccbbccdcddbbbbbbcbbbaabbcc#abaacba########aa##..#######aa####aaaaa###bbaaa#aaaaa#cc###a.####aa##aaa#########aaabbbbadcdaaabba##########a#aa#bbaa##a#######a#aa#aaaaaa#######.ageccbbbbbbbbbbbcbehigffeedddddccbcccbbaaa#accdcbbbbbbaaaaaaaaaaaaaabbcbccdbaadfdcbbbbbbbcbcefccba#################aaa#", +"#aaacbaabbcbbbaa#######abcca##aaabbcba########abbaaabaabccdcbabbbccbcedccccccccccccedbbcdbbbccbcbbcbcbbbbbbbbbbabbbbcccbbaaaaaa##a####a#aa####.#####aa##a#aaaaa##abbcaaaabbbabcaaa#.#.###aa#a##a########aaabccabbddbaabaa####.##.aaaaaa##bba##############aaaa##a########.#bddbbbbbbbbbaaaaabfhhgfeedddccbccbdabaaabbbccddcbbbbbbaaaaaaaaaaabacbbcceb#a#babcbbbbbbcbce##.####################aa#", +"aaaaaa#aaaababba#######abcccb#a#aaacddb######aaaaa#aaaaabbbbbbbcbbbbcdcbcbccbccccddbababcccccccccbbbbaaabbbbccbdcbbbbabcbbaa######aa#aaa############aa#####aaaaa#acbabaa#baabbcb#a##.#####baaa#########aaaabcdcccccbaaaa##########abaaa###aa##############a####aaa########.##dcbbbbbbbaaaaaaaabghgffedccccccbbcabbaaabbcbdedbbbbbbaaaaaaaaaabaaabccdecbcabbbcbbbbbcbeea###aa####################", +"aaaaaaaaaaaaaa##########acceeba###bbbcda#######a####aaaaabbbabbabbbbbcccccccccbcbbcdcbaabbcbcccccbbbbbcabbbbddegebbbbbbbcaaaaa#########a######aba#####aa#####abaaaabcbb#aa##abaaba#####a##aaaaa######aaaaaaacccccbccaa##a#######aa#aabaa##aaa####aa########a#aaaaaa###########addcbbbaaaaaaaaaa#fieeeddcccbbbbbaaabaabbaaabdedcccbaaaabaaaaabbaabbbcdebaaccbbdddcbbcdc#aaaa###########.########b", +"aaaaa#aaa#aa#############abcdfdaaaabcdf###aaaa##a#####aaaaabbccabbaaaabbbcccccbcbabbccbbbbbbbbbbbccbbcccbbbcdcdedecabbbbaaaaaaa########abb##aa#aaabaa#aba###a#aa#aabcccbabb###aa#aaa######aa##aa######aaaaaaaccccdaba###########aaa#aaba#aaaa#aa##a########aca##aaa######a######cffaaaaaaaaaaaaa#ehfeeedcbbbbbbcbaabbbbbbbaadeeefedcbaabbabbccbabbdcbcaabdcccccceedffb##aa####################a#", +"aaaaa###aaaaaa#####.####aabccfgbaabbcfeda##aaabaaaaaa#aaaaaaaccbccbaaabcccbbccbbbbbbcbbbbbbbcbbbbbcabcccbababccdeccbabbbbaaaaa#aa########aaaaaaaabedaa##a#aaabaaaaabaccbaaaca###aaaaaa#####a###aa###a##aaa#aaaccbbabaa############aaaaaaaaaaaaa#########a##acdaabaaaa############acecaaaaaaaaaaaaafhffeddcbbabbcbbabbbbbbbbaabbdeddfeddbabbbdcabbabbababbbcbcbccddffcdaaaa##a###################", +"aa#a#####aa#aaaa#########abcdcfeaaacbdccfcbbbdddbbbbbaaaaa#aaaabcbaabbbcccbbbcbbcccccccccbbcbcccbbbbbcccbbabbacddedcaabbabaaaaa##aa########cb##aa#cfdaa##aaababbbbaaaabbbbaabaaa#abaaa#####a#bbaaaa##a##aaaaaabbccdaaaaa#####bb#####aa##aaaaaaaa############aabbbbaaaa##aa##########deaaa###aaaaabcgiggddccccccccabbbbbabbaba#aabcaacccccbbcdbaacbbabbbbabcbcdddd####abaa#a##a#a#aa############a", +"aaa#####aa#a#aaaaaaa######abccdfa#bbcddbcccdcdaaccdecbbbbbbbaabccbaaabbcccbbbccbccccddccccccddccbbbbbbcccbbbbbcccdddbabbbabaaaa########.####bba##a#aca###aaaaaaaaaaaaaabbbaabaabaaabba#######ababba.##aaaaaaaaabcdcb#aaaa#####a##########aaaaaa#a####aaaa##.##abbba#aab#aba#aa#a#####cgeaa####aa#aabfiigdccccbccccbbbbaabbbbaaaaaabccbbccccdabcbccaaaaabbbccdebdbaaaaaaaaa#a######aaaaa#########", +"#aa#a###aaa####aa##a#####aabbbbeb#abbceeba#a####aaaba##cdbbbcccdccbbbbbbccbbabcbbbcbcddccccccddddddccdcabbbcbccbbbddcbbbbbbbaaaa#########.####aaa####a#a#aaaaaaaaaaaaaabbbbaaabaaaaaaba####a#.a##ab##.a##a##aaaabbddb##aa#####aa######.##aaaaaa#aa####a#aaa###abbb###acaacaaaa##a#####bff###a##aaa#aacghhfccbcbcbbcbbbbbbbcaaaabababbdccccddbbccccaaaaaabbccee##aaaabbacaaaa######aaa#aaaaaaa###", +"#aaa##########aaaaa########bbbbbea#babcea#a######aaa####bccddcddedcccccccccbcbccbbbcbcddddcccbbbcccdefedcbaacbbcbbbbbbbbababaaaa############.###aa#a##aaa#aaaaaacbba##abbcbaaa#aaa#aa#########a#######a##aa#a#abbcbcc#a############aa####aaaaaaaaaa#######aa###aabaa##bbaaaa#a##aa######dea#####aaaaaa#behhdccbccacbbbbbbbcbbbaabbabbbcdcccdddbbbba#aaaaabbddb#######bcaaaaaa######aaaabbbaaaaaa", +"aa#aa##########aaa########aabbbbbedbaabddcb#aaaa#aaaa####cccaacdeeggecccccccbbabbbbbbbbccddcccbbbbcbcddeedcbaaabbabbbbcbbbabaaaa###########.#####aba#######aaaaaabbba#aabbbbaa###aa##a#####.#a#.#.####aa##aa#aaabccbca#aa#..########a######aaa##aaa#########aaa#aaaaaabcaaaa##a##a###a#a#bdb#aaaaaaaaaaabcfhfccccabbcbbbbcbcbbbaabaabbabcddcdcccbba##a#a#abddb########aaaaa#aaa####aaaaaaaabbaaa", +"aaa#aa##########aa#a#a#######abbabgebaabacca#ba#aaabaa#########a##bdeddeedddcbbbbbbbcbabacdddcccccbbbcdcdcdcabbbbbbababbbccbabaa###############aaabb####aa##aaaaabbbaaaa#abbbaa###aaaa###a###a##....###a##aa##aaabbbca##aa#.#######aaa##aa######aaa#########abaabaaaaaacbaaaaaa##a###a##a#afb##a##aabbbaaaaeggecebcbbbabbbcbbabaabbbbbbabbdddccccccabaaaaaaccc#####a#aaaa#a#####aaaaaaabbbaaabaa", +"aaaaa############aa#a########.#abbcffcabbceccaaaaaaaaa###a###aa#######aaeebccccccbbbbcbbccbdddccccccbbbccbbbbbbbcbbabbbbbccbbbbaaa########.#aaa#a##aba#aa##aaabbbabbbaaa###abaaa#########aa##a############aa###aabcc#aa#aaa#######.##aaba#aaaaaa##aaaaa######baaaaaaa#aaaaaaaaaa###aaaaaa###ebaaaaaaaaaaaaabbfhgedbbbbbcbbbbbbabbbbbbbabbbbddecbcbbbbbbcbbbceaa#####aabca#a#a#a##a#aaaaaabbbbbaa", +"aaaaaaa####aaaa#aa###########..#aabdddbbcccccaaaaaaaaaa##a##aaa###aa#####eddedddcddccbccbccccbbcbbcedbbcccccbbbbbbbbababbbcbbcbaaaaa############a#a#aa#aaaaabbaabaabaaa#aaa#abaaa#######aaaa#a###########.#aab##aacc#aa####a######..##aa#aaabbaaa##aaaaaaabbaabaccbaa###aaaaaaaaaa##aaaaa##a#ccbaaaaaa###aaaadgggfeababbcbcbcbbaabbbbaaabbbccddbcbbbbbcdccccca#a#a###aaaaaaaaaaaa#aaaaaaababccba", +"aaabaaa#a#######a#aaa####aa###.###bcdcbcbabddbaacbbababaa#a##aaaa#aa#aacdccbddddddbbbbbaa#aaa######bfggfdcccbabbbbabaaabcbccabbaaaa#########a#aaaaa#######aabaaabbabbaa####aaaabaaa##aa##aaa#b####.#########abb#aaee##a###.##.##.###..####abccccbaaaaaaaaabcdaabbccba##a#aa#aaaaa#a#aa#aaaaaaaabebaaaaa#a##aabbfghhgedaaabbbccababcccbbbaabccbcccbbcbbcdcdcaaa########aaaaaaaaaaa#aaaaaaababbccb", +"abaaaaaaaaaa######aaa########aa####bbccbbaabceaa#cbbbbbba#a##aaaa#aa###debacb#aacabaa##aa###########.#afhgeecbccbbbabaacbcccbbbbbbaa#a#########aa#aaaa####aaaaaabbbbbbbaa###aaabbba###a##aaa###.#######ba##aaadbaabeaa##aa#..###.##########abaaabdbaaababababbaabddbaa##aaaaaaaaaaa#aaaaaaaaaaa#aecaaaaa#aa#aaabdghhhfecccbcbbabbacccccbbbbbcbbbbbcbabbdcbcba########aaabaaaa##a###aaaaaaaaaabbb", +"baaabbaaaaaaaaaaaa###########aaa####acccbaaaabcbcabbbbbbba#####aaaba#acbcaa#aaaa#abaa############.#####.dhihgeefccbbbbaabccbbbbbbaaaa##########a#aa#aa####aaa#aabaabcbbaa####a#aaaa###a#aaa################abbeebbbdd##a#######..####.######aaaaabcbbbbbbbbbbb#abcccbaaa#aaa#aaaaaa###aaabaaaaaaa#bcbaaaaaaaaaaaabehhhfedaaabaaabbccccbabbbbccbbabccbbbdcbbaaa#######a#aabaaaaa#aabaaaaaaaaaaabb", +"bbaaaaaaaaaaaaaaaaaaa#########a#a####bbcbaaaaabeecbbaaabbaba###a#aaa##cedb#aaabaaaaa##a#########.##.###a#bfgedeffdccccbaaacdccccbbaa###########aaa######aaba###aabaabbbaaaa#####aa#a##abbaa####.##.####aaa#acbddddfega#a#######.######.##a#aaaa#aaaaaaaabccddebaba#bcba##aaaaaaaaab#aaaaabbbcaabaaaaccaaaaaaaabaabbehhfgebaaaaaaacdcccaabbcbbcbbbbbcdcbbcaaa#a######aa#abbaaaaaa#abbaaaaa#aaaaab", +"bbbaaaaabbbaaabaa#aaaa###.#######a####abb#aa#a#cfecaabbaaaba#######aaa#bddcdaaabaaaa#a#aa######.########ba.a####bfddcccbbacdccccccaa############aaa######adb###aaaaaaabaaaaaa###aaaa##abaaa#####..#####aaaaabbcdeedfgd#aa########.#######a##aa#aaaa#a###a#abeedecc##aaba#aaaaaaaa#bbaaaaabbbbaaaaaaaaaccbaabaaababbadgggfdb#aaaaaabcbbbbbbccccdcaabbcdcccbaaa#######aaaaaaaa##aa###aaaaaaaaaaaba", +"bbbbaa#aaaabaaaaaaaaaba#a######.#######abbbca##acdedcaabca#a#.###a######bddcfcaabaaa##a##a#####...##aa####a####a#abbccddcbbddedccccbaa####a######aaa#####acb###aaaaaaaaaaaaaa###########aaa####.####a##aaaaacdeceeeedc##aa########..#########aaaaa##a###aaaaaabcdedcb##aa#aaaaaaaaacbaaaaabbbbaaaaaaaaadfdaabaaaabbbbcdggfebaaaaaaacccbbbbbbccdcccbbbdcecba#####a####abbaaa#######a#aaabbaabaabb", +"bbaacbabaabaaaabbaaabbaabb#.####.#######abbcba#aabecdbaccaa#a#.##aa##a###acacecbaaaaaa##########..######..abaa#aa####aceeddceggeddccbaa##########a#aaaa##aaa##a##aaaaaaaaaaaaa#########aaa####a#aaa####aaaabbdffffgebca#ab#######.#..#aa######aa###aa####aaaa#baabbdcc##b##aaaaaaaaabaaaaaabbbbaaaaaaaabcegcabaababbbbabgfgfdaaaaaabbabbbabbbcdddbcbccccdbaaa#a##a###aaaaaaa#########abbbbccbaab", +"baaabbaaababaabbaaaaaaaaaaa##############abbaa##aadd##abbaaaa#.##aaa##a####aabcbaaa#aaa###a######..####.#..cdcbbbaa###abdcdedfghffddcbba###########aaaaaaaaaaaaaaaaaaaaaaa#aaaa########a#aaa#####aaa#a#aabbccddghhhfcca#aa##########...##########aa#aa###aaa##aaaa#a#bb####aaaaba#a#aaaaaaaabbcbbaaabaaabbefdabaabbbbbbbbfgggfdcaaaaabbbbbbbccdbdbcbcccbcbba##aaaaaa###aa#aaaa########bbabbbbaaa", +"aa#a#aaaaaaaaaaaaaaaaaabbabaa#######.#.####aaaaaaabdeb#aababaa####aaa#abba#####aaaaa###a##bdba##a######....acdbabbaaaa#####cddaeggffedcba##########aaaa###aaa#abaaaababaaaaaaaaa##a###abaaaa###.#bbaaaaabdcddeefhhifdda#bb#aa##aa######..########ab##a###a##a#aaaa#abaabaaa#aaaaaaaaaaaa#aaaababbbbaaaaaaabcffbbbabaabbbaacefggdba#aabbbbcbacddccecbbbcccbba##aaaaaaaaaaa#a##a#a#######aaaabaa#a", +"ba###aaaaa#cbaaaaa#abababa#a################aabbbbbbbea#aaabbaa#####a##adc##aaaaaaba##a####a########.#####...aca###########.####cffdcdecaaa#######aaabaa##aaaaaaa#aaabbbaaaaaabaaaba##babba######accbbbbbfccdeegdgfggeb#dc#####aaa#####...#######aaaa#aa##a#aaabaaa#bbaaaaa##aaaaaaaaaaaaaaabaabbbbbaaaaababbegdbbaaababbaabffffecb#aabbbbcbbcdddecbaabcbaaba#aaaaaaaaaaaaa###a########a#abbaabc", +"a#######a###aa#abaaaabbccba###.##############abcbcbbcbea#aaaaaaa#######.##ba#a#aa#a#a#a##a####.###########..###ba##############a#aeedbadfcdddcbb##aaaaaaa#aa#aaaa#aaccbbbaabbbbbabcbbcdccb######abcdbddeeefddddb#afdcfebdca#####aaa######.#####aaca####abaa#aa#abcb#accaaaa##aa#aabbaaaaaaaaaaaabbbaaaaaaabbbbbgdbaaabbbbaaaccffgfdcaabbccccccddddfcbaaaaaaaaa#aaabbaaaaaa#a#aab####aa##aaa#bcc#", +"aa###########aa#aaaaabbabbaaaa##..###########abdcccccbcdcaaaaaa#a##########aabb#abaa##########...#.########.######################.bfdaaccefddddbaaaaaaaaaaaaaa#aaababcccbbbbbccbbcddcabca####aaacdcabeggfdda.##.#cc#aefdbaaa###aaa###.##.####aaaaa#a###abd##a###ababbdc#aa#aaaaaaaabaaaaaaaaaaabbcbbaaaaaaabbbbgfbaaabbbbaabbbcefffddbabbcdccccedcabaaaaaaaaaaaaaaaaaaaaaaaaaaa#####aaa#aaaaaaa", +"aaaa##########a######.#a#abbaa##########a####abdedcccccccba##########a######aaaa#abaaaaa#######..################aa#aa###############ddabedcgededbbbaabbabaaaaaaaaaaabbccccccbccdddba###abacbbcccba####aaaaaaaa##.###acfcaaa##aa#a############aa#####a#a##aea#aaa#aabbcda##aaa#aa#aaaaaaabaaaaaaababcbaaaaaaaabbbgfbabbbabaabcdcbdefffdbbcccccccdda#aaaaaaa##abaabbaaaaaaaabbbaaaa####a##aaaabaa", +"aaaaabaa#######a###a##.###abbaa###############acdeccbbccdga##########a######.#aabaaaaaaaaa#a############.###aa###aaaaa###############.cdbbdefhhhfdccccbbbaaabaaaabbbbbccccdddcdccdb#####bbcbcddba####aa####a#a#####.##aedaaaa###aaa#######..#########a###a#bbbbbaaabbbbaba#aaaaaaa#aa#aaaabbaaababbabccbaaaabaabbbggdabbbbcbbbddcbcbdffdcaccccacccd#aaaaaaaaaa#abbbaaaaaaaabbabbabaa#aa####aabaa", +"aaaa#aaa##########a###.##aaaaaaa####.##aa#####abccdcaabccffa##########a###aa####aabaaabaa#aaa####a######..###a#####aaa############aa###bdddeeddfgfeeeddcabaaabbbbbbbbbbcdddddeeeecaa####abbaaaa#######a#a########.###aaadaaaa#####aa########.#..##.##a######aaabbba#bbca##a###aaaaaaaaaaaabbaaaabbbaabddcaaaaaaaaabfgdaaabbbabdacdbcbdfffdbbdccbc#cbaa##aaaaaaa#aaaaaababaaaa#abbaaaaa#aaaaaaa#a", +"###a#aaaaaaa######accbaaab#####aaaa####a#######accccabacccfe##.############aa####aa###aaa#aa####.#########.##########a############abca##bfcfabbbcaafffffdbbbbbbbbbabbcccdeeedefcaaaaaa##aaaaaaaa################a#.###abbcaa#aa#aaaaa#######....########aa####a#abba#bbbbaaaaaaaaaaaaaaaaaaabcabbbbbbabeedaaaaaaaaacfgecaabbabbacdbabcffffccccdda##aaaaaaaaababaaaaaaabaaaaaaaaaabaabaa##abb####", +"a########aaa#######cddebba########aaaaaa#######abccccbabcdefea#.########aaaaabb##aaa#####aaa##.....#.##.##############a#####.#####aabcbaabfc######.afggggcbbbcbcccbbbccceeeeffhgccbaaa#aaabbaa#a######aaa########a#.##aacdba##ab#aabb##.#.####...########aa#####aaaaaaaabbaaaaaaaaaaaaaaaaaaccbabbbbbbabefdaaaaaaaaabeffabaaababdedabbcfffecccddaaaaaaaaababaaaa#aaaabbbaaaaaaaabbaaa#aa##ba###b", +"#####aa#####aaaabbaaaacdb.#a#########aaa########abcbbbbbcdeeeefc.######aaaabaacbaaaaa##########..#..#....##############a###########abbbba#bd#a######aabbcfedccdddccccdddeeeeefgiedeebaaaaaabaaaa#aaaaa#aaaa###########aabcca##aabaaabba#....#....##.###.#aaa#######a#abaabbaaaaaaaaaaaaaaaaaaddbbbabaabbbddaaaaaaaa##adfecbbbbacddedbbccdffdccddaaa#aaa#bbaabca##a#aaabbaaaaaaaaaaaabb#aaaa###a#", +"####aaba######aa#abbaaaba###aa#############.####aabcabcbbdegfebc.########abbbaaaaaaaaaa#########.....#.#.######.#######aa#####.#.##aaabbbbbc##a#######..##ehfeeeedddcedeffeeeeehf#abcecccbabbbbbaabaaaaaaaa########a###aacdba#aaaabaaaaa#..##..##.#..####aaa##a####aa#aaaabaaaaaaaaaaa#aaaaaabeeccbababbbbbaaaaaaaaaaaabcffbbbbcdccdcbbbcdfgfedcabaaaa##bbababa#####abbaaaaaaaaaaaaaaaa#aaaaaa##", +"#a###aabaaaa###ba###ab##ba###a#############..###aaabcaabbdedefgb####aaa###aaaaaaaaabaaaa###########...#.############################aabbbadcaaa#####.######bfhhgggffffffffeeeefhhcaa##acfffeedddbaabaaaabaa########a####abebaaaa#a#a#aa############.###..#aa##a###aba##aaaaba#aaaaaaaaaaaaaaaaccdcdcbbbbabbbaaaaaaaaaaaaacfeaabbbbccdabccbdfffed#aaaaabaaaaaa#aa###aaaaabaaaaaaaaaaaaaaaaaaaaa##", +"###aaa#aaaa#a##.a##a#aba#aa###########.#.#....####abcbbbbccdffegb...##aa###abaaaaaaaa#a#aa#######aaa###.####.#####################a##abbcfda#aaa###########.#acfhihhhijiiiihgfhhgcaaaa#..acccddccecccbaaabcb#######aa###abcdbaaaaa#aaa#aa##########.##########aa##aaa#aaaa########aaaaaabaaabbaaababaacbbabbbaaaaaabaaaaa#cefdabbbabbcbbbccdfggeb#aaaaaa###aaa#a###aabbaaaaaaaaa#aaaaaaaaaaaaaa#", +"#aaaaaaaaaa##aaaaaaaa#aaaaaa##.###aa###.###...####aabdbbabbcfeced.#########aaaba#aaaaaa##ca#######aaaa######.########.########a#####aaabdhgfeaaaa#############.#aaba#addfghiiiiheb###aaaa###.####bdbcdcdcbbca##a##a##a##aabbdbaa####aaaaaaa#############a#.##aaaaaaaaa##aaa##a#a#acbaabbabbbaaaaaaaabbbbbaabbbaaaabaaaaa#a#bfgebaaababbbbbbbcggfeaaaaaaaaaaaaaaaa####aabaaaba###aaaabaaaaaaaaaaa", +"a##ba#abaaaaaaaa####aa###bbaa##.#######b#####.#.###aacbbaabcdeccc##.########aabbba#a##aaa#bba######aaaaa#################.######aa##aabbfhhihdabaa##############aa######.##a#bgfb###aaaaaa########cbacccdfeecaa###aa##a#aaabcdbab##ababaaaaa##########aaa#####aaaaaaaa#a#aaba##aabfdaa#aaaaabbbabaaababdbbbbbbbbbbbbbaaaaaaa#dffcbaabbbbbbbbbcefgdba#abaaaaaaaaa#aa##abbbaaacba##a###aaaaaa##aaa", +"aaaaaaaaaaaaaaaaaa#####a##aaaa########ab##.####..###aadccbbacdcaa###.######aabaaabb#aaaa###############aa#####a#####.##############aabbbehhhfcaaaa#####.########aaaa##aaa##a#.#caa####aa##########cdbbbbbcedefdcbbaa##aaaababbdbaaaaaaaaa#aba#########aa######aaaaaa#a#aa##aaa##addbbaaaaa#aaaaabaaaaaaccccdcbbabbbcbaabaaaaa#cfgdbabbbbabbbbbcfgedda#aaaaaaaaaab#a##aabbbaaaba#aa###a#aaaaaa#aa", +"aaaaaabaaaaaaaa#accb#########babaa###aaa##.##a##.####abcbccabdeaaab#..######aaaaaaa#####################aaa####a#####.############aaaabdgihgcbaaa################aaaaaaaaa#aa###a######a##########dbaaaaaaaacbcefgfddcccddegdcbdbaabaaaaaaaaaaa######aaa####aaaaaaaaa#############aaaaaaaaaaaacaaaaaaaaabbbbdeccdccbbbbaabaaaaabefecbbbabbbbcbcegededcaabaaaabaaaaaa##aabbbaaaa#aa#aaa#bbaaaaa#a", +"a##a#aaaaaa###aa#bbcbaa##aaa#aaaca##abb########a#####aacbbccbdeaaaba#########aaa##a#a####.################ba#########.##..######.bbabaaehhhgbaaaa#################aab#aabaa#aa###a##########a.###.ab#aa#abababbbcbcdcaacecccdefdc##abaaaaa##aa########aaba#aaa#a#aaaaba#a#aa#a##.##abaaaaaaaaabbabbaaaaaaaaaaccbbbcdbbbbaaabbbabbdgfdbbbabcbcccdddeeedcaaaaaaaabaaaaa##aabbaaaaa##aa####aaaaaaa#", +"####aaaaaaa######abbcca##aaaaa##abbabba#a#####aaa######aabccedfaaaab#########aaa###.#######################b########.#ba#...##.#acbccccfgggebaaaa##a###############aababaaaa#a##a#a####a##a########c#aaaaaaaabbaaaaabccdebabbbdgeaaabbbaaaaa##a#######aaab##a##aaaaaabaaa###aaaa####ba#a##aaaaaabbaaaaabbaaaaacbbbcbbbcbbaaabbbbcbcfgecbcbbbccddccceddccaaaaaa#bbaaaaaaaaaaaa#aaa##a#aa#a#aa####", +"##a###aaaaa#######aaaaaaaaaaaaa#aabbcaaaaa#a###aa########aabeeea###aaa#######aabb#####a######.#######aa##.######aaaabedccbbb##bbbbaabbbbccdeaa##a##a########aaa#####aabbbba#a#aaa#a####a###########caba###ababbbaabbabcdcddcbabehcaaaaaaaaaa############ab##aaaaaaaaaaaaaa#baaaaa###bb#a##aaaabbbbbaaaaabbbaabbbbcccbabbbaaaabbccccbfffcccbccccbccccddeedaab#aaaabaaabaaabaaa###aaa###bb##a#####", +"aaaa##aaaaa#aa#######a#abbaaaab######aaaaa#aaaa#aa#######aabdefb#aaa#bc#######abcb#####a#################aa#a..###aabcdfffggfdcbbbbbaaaaaabdeaaa###########aaaa#####aabbbbbaaa#aaa#####aa#a##.#####aaaaaa##abaabcbbbaaabaabbbbcdefaaaabaaaaaa##a######aaa######aaaaa#aaaaaa##aaaa###aa#aaabbbabbaabbaaaaaaaabbbbbacccbaaaaaabbccdccdefegffdccecbccccdeeddcbaaaaaaabbbcbaaabaaaaaa#######aa######", +"#aaaa##aaaa#############abaaaaaba##aaaaaaaabaaaaaba#####a##abdgca#aaadeb########bba#####aa#aaaaaa###aaa#ab#aa#.###.#acfhfddgccbaa#aaaaaa#abcfaaaa#######aaabbaaa#####aaaaaaaaa#aaaaa#aaaa##########aaaa#aa##aaa#acccabaaba#a###acdbaaaaaaaaaaa###a##.##aaaa###a###aaaaaaaaa###aaaa#abb#aaaabbbbbbbabaaaaaaaaaacbbbccbbbbaabaaacccccdfdbdfgeefcddabccbcedddccbbaaaaaabbbababbaa#aaaa#a##ab##a####", +"##aaaa#############aa#####abaaabda##abaaaababbaaaaba####aa#abbdeaaaaaadf###############a#aaabbbbba#aa#aaaa#baba.#accbffffgddcbbaa#####aa##acfeabaaaaa###aabcdcbba######aaaaaaaaaaaaaaa#aaa##########dbaa########bbdcaab#abaaa##abceaaaa#a#aaaaaa#a###.######a#####aabaabb#aa#####a#bcbaaaaa#aaaabbbbbaaaaaaaaaaccccbccabacaaaabceeeeggdcdfffccccca#bbcbddeccccca#abbbbbbbaaabaaa#a#aaaaab#######", +"##aaaa####.##########baaa##aaaaabda#aaaabbaaccbaaaa#####aaaaabbcbbaaabdgfe###aaa#######a##aaabbabbb#a#a#aabdceeedcabcaeddcfhecdb#########aacdhcbccbbbbbbbbdehhedba##aaaabbbbbaaaaaabbaaaaaaa########cba#######a#abbda#aabcbaa##aabceaaa######aaa##aa########aaa##aaaaaa#aaa###.###aabaaa#aaa#aa##abbbaa#baaaaaaabbbbbbdbbabaaaacaddacbbbbddccccbbda#cbbcdcddeccccbaabbbbca#aabaaaaaaaaaaaaa#####", +"#aa###a####.##########aa#a##aaabaccaba#aabbaccbaaaaaaaaaaaaaabbccabaabeffeebbcb#.####.#aaabbaabbccccccccdddcec.#aaaaaaadccbbcccca.#######aabdhecdddeeeddeefecbbeedcaaaaabbbbbbabbbbcbbaaaaaaaaaba##aba####a####aacdccaa#ccbbaa##aabcdaa########a##aa########aaaa##aaaaa##aaa#########aaa##aa#aba#aabbbaaaaaa#aaaaaabaaaccbaaaaabccababbbb###bcbcbbecabbccdcddcdcccaaababbbbaaaaaaaa#aaaaaaaaa###", +"#aa#aa##########a######a#####aaaaabc#abaaaabbcbbaa#a##aa#baaabbbbbabbcfffgghebdcbbacacbbbbbbbcbccdccfdaaabdedcaaabaaaaacccbbbbbbcb########abcfgedeffeeeegfcbbcbadgdddaabbbbbbbbbbcccccbbaabababbbaacbaa#########abcccbabccbbbaa##aabcb#a#######aa######a#a##abbbbabaa###a#aa########.bbaaa#aaaaaa#aaabbbccbaaaaabbbbbbbaaaaaaaaabbbccccaaa###bcdbabcbbbabcdddcbddccbbaaaabcccabaaaa#aabaaaaaaba#", +"#aaaaa#######a####a###aa##.###aaaaabc#abaaabbcbba###aa####a#aaabbbaabcdcdeccdecccccba##aaabbaaaaaa##beaaabacfdeaabdecb#bdcbbbbbbaca#######abcdegeeeeffgfdabbccddeehhhfdbbbddeeccdcccdccbbbbbbcccbcca##a###a########aa#.aceccbbaa#aa#acb###.#####aa#####aba###abcdcbcbaaaaaaa#####a###bc#abaaaa#aaa#ababbbbccbaaaaabbcccbcbaaaaaabccdacccb#a###abddbbbbbbabbcebcbbdcccbbaabbabcabaaaaabcbaaaa#aaa", +"aaaaaaaaaaa####aa#####aaaaa.###a#aaaccaaabaabccaa##aa#######aaaaaaaaadc##abaaaaa###a#######a#########cb#aaaacdddb#bbdda#becbbbbbbac#######abceffhffffda##babcccdeeddbddeecdcdebdeeccdddeddcccdeba#b###aa##a#########a###bedbbbbaa#a##aca###.#####aa####aaa####bbcdddbaaaaaaaaa#######adbbabaaa##aaaaaaacbabbccbaabaabbccccaaabbcbdcbcecccaa#a#a#adcabbbbbcbbcbccaabccdcbbbbcacbaabbaabcbaaaabaab", +"bdbaaaabbaaaa#aa##a#aba#############abcaabababcba##aa#########aaaaaaabdb##aaaaaa###a##################b####aaccdeaabcbbaaeddbabbbabb#######bdfhghhgda###aabbcccecbbbdcccefdbbcbcb#eefgghggfeegdaa##a###aa#######aaa#####bedcabbaa#####acb##########a##aaaa####acbccccaaabaabbbba####a##dbba#aaaaa##aaaabdababbccbabaabbcddcbacbbccdacdbba#####aaaabcbbbbbbbccbbababbcddcbabbbabaaabcaaabaaacabaa", +"aacdbaa##.##a##aa#aa#aba###.#########abca##aabbbca#..###########aaa##aab######aaaa#########aaa#a###aa#######aaccdfbabbaaaeeddbbcbbbdbaa#abcdfhjigca######abccbadb###cfbcbbecabbba#begfhggddcggdbbaaa##############a#aa#.cddccbaaaa#####ab##########aaaaaba####accbbbbaaabaabbbabb#######aba###aaa#aa#aaabcaaaaabccbabbcccdedcbdbbacdcdccaa##a#aaaaabcbbbbbacccbaaaabaccccbaaaaaaaabbbbaaaaababba", +"aababbaa#####a##a##a###a####.##########aba###abbbbba####.#.#######a###aab######aa#a#########aaa#####aaaaa#####bbceebbbba#ceedccedcegdcbcddedbcbed#######aabccdbdda##adeeb##abbaaaaacbadeddfdghdcbbbaaa###########abbbcdbbdcbbca##aa#####bd###.#.###aaaaaaaba##abbbbbbbaaaaaaaabbaaa#######aa###aaa#aaaaaabcaabb##abcbbaabcedccdcbaaccccba####a#aaababcbaaaabbccbbaaababccbaa##aa##aaabaaaaaaabaa", +"aabaaaaa#a#####a###aa##########..######aaba####aaaabb#.###############aaab##.###a#a#######aaaaaaaaa#a#aa###a##aacdceddfgfcfffgdccdeeefggdbaabbbbdcaa###aaabbcddeb##a#adfeaaaaaaaaa#bbaaccbeedhecbabbaaa#########.adccbcdbdbbcbba#######a#cda########abbaaaba##abbacbbaabaaaaabaaaaaa########aba##aaaaaaaaabcaaa#a##abca#aaabdefecbaadbbbaa##aa#aaaaaabdcbaaaaabcbaa#aaaabbbaaaaaaaaaaaaaaaaaaaaa", +"aaabbaaa#########a##aaa###########.##.##aaaa#####aa#cba################abcb.####aaaaaa##aaaabbabaabbbaaa##aaaaaccgghggecdfihhg#a####a#a#abbccccacdcabbbbbacccdfeba#####aaaaaaa###a#ababbccadcgedccbaaa############ccbabccbcacabaa#####a#bacd###.####aaaaaaa###aaabbccaaaaaabbabbaaaa###.##..#bbb###aaaa#aaaaaaa########a#aabccceecbbdbbbbaa#aaaaaabbaadccbaabaabba#####aaaabaabaaa##aaba#aaa#aaa", +"aaaa#aa##############bba##########..#.############aaaaaa#####.##########abca..####abaaaaabbbcccbbccddbbabbbbbcdefebdfd##a#.bedaa#########aabbbcbcddddcbbbcdeffd#########aaaaaaaa#aa#baaabcbacegedbbaaa##########bcdbaabbcccbbbaaaaa#####abbcca####.##aaa####aaabbcccdbaaaaaaabaaaaaaaa####.###abba##aaaa#aa##a############aaaa##cfebdcabcb###a##aaaabbabacbaaaaaba#a####aaa#aaaaaaa####aaaaaaaaa", +"abbaaaa####a##########aa###################aaa####abaa#a################aabc#.#####aaaabbbcdddcdfffefgffeddfgdcdcb####aaaa###bb#######a##aabacdcddbdccacdefecc#a##a#####aaaaaaaaaa##aaaaabbbabfgdcbaa########aaacbbbbabbbbcdaba##a#####a#abccda####aaaaa#aaa#abaaaccbbbaaaababbaa##aaa#########bbba##abaa#####aa#a##aaa#a###aaa##defdcabbbaa##aa#aaaabbbaaccaaaaab######aaba#aaaaab####abaaaaaaa", +"aaabaaa#################abba###############aaaaa##aaaaa#a###############aacaca.#####aabbbbccddfda#adeca#####b###aa#aa#aaaa##aaba#a####aa#aabccdccedebaacccb####aaaa###a###abaaabaaaaa#aaaaaababdgdbb##########cabbdbbbaaaaaccaaaaaaa##aaa##acdc#.#aaaaa##a##aabaa#ccaaabaabbaaacbb##abaa######..abca##aaaa#####aa#aaaaaa######abaabdggcaaa#aaaaaaaaaaacba##bbaaaabba#aa#aaaaa##aaaba###aa#aaaaa#", +"#########.#################aaaa#.#.##aaa###aaa##aaa##a##aa###############abbbba#.##.#aabbbbcefc####...#####aa#####aa###aa####aa#######a#aaacbacbbdddbbccdfecbcc###aa####aa#aaaaaa###aaaaaaa##aaacfdaaa#####aaaabbabbbbaaabbabbaaa###aaaaaaa#abce..##ababc####aaaaabdaabbbbbbaaabbbaaa#a##.#######abaa#aaaba##aaaaa#a##aaa###aaa##ababehcaaaa##aaaaaaaadc####abaaaaaba###aaaaaaa###aaaaa#aaa#####", +"####a######################aab#....##aacaaa#aabbaaaaa#####a##############aabbbcb##.###abbcceca###################aaaaaa#a#aa##a#aaaaaabaabbbbbacaaabbabaafddcbcb###aaa#aab##aaaa######a#######a##cfeaaa#####abcbbbbaaaaaabbabba###aaaaa#aaaabaaee#.##ddaaa####aaaaacaaabdcbbbbaabaaba#aa##.#######aaaa#aaabaaaaaaa##aaa#a##a#aaaaaaabbcgebbba#aaaaabaabbaba###aaaaabbaaaaaaaa#aaa##aa#a##baa#a##", +"####a##aa##################aabda#.#####bcaa#abaabaaaaaa###################aaabcdb.####bbbdea##########.###########aaaaa##aaaaa##aaabbbbcbccbbaaaaaaaabbbaaaacdcbbbaaaaaaaabaa#aaa################abecaa####aadcabcaaaaaaabbaab#####aab#aaaaabaaade#..#ca.#a####abcbbb#abbccaaabbbabbbb#a############aa#aaaaaaaaaacaa##aaa##a#aaaaaacabccfebbbbaaaaabbbbaaba####ababacbaaabaaaa##a#aaaaaa##aaa###", +"#####aaaa###.#a######a#######aab##..####abbbbbbbbaaa#aaa####aaaaa##########aabddea.###abda#################a#########a#####aaa###aaabbcdcbdbbaaaaaaaaabbbaaaaacddcbaaaa###abaa######..############abeda###ababbbccbaa#aaaaaabaa##a###ab#aa#aaaaaacec##ab.########babbaaaabbababababbcda###############a#aa###aaabcbbaaaaa###aaaa#ababbcdcdecaabaaababbaaa#######aaabbbbaaaaaabaaaa######a#aaaaa#", +"a#######aa#a######aa#a#aaa###aaac#########abddccbbaaaaaaa####aa#aa########.abehghhc##abca##aaa##################################a#aabccb#aabaaaaaabbbaaaaaabaaabbbdba#aa###aaa##################aa#abefccaabbbcbabbaaaa#aaaaaaaa#aa###abaa##aaaabbcfdaba.#a######bacc##aaaabaababaabcbca##.#####a#####a#aaa#####aaaaab##aa##aaaa#aaaabccebbffbaaaaaabcaa###a#####bbbbbbbaaaaabaa#aa######aa#aa#a", +"#baa#aaaaa###a#a#aaaaaaa####b#aaba#########aacbdcccaaa##a###aaa#aa##########bbfikjicacc###aa#aaaa#############a###################aaabccca##aaaaaabbaaaaabbbbaa#aabcbbaa####a#################a#aabaabdfbdcccbbbbbbbbaaaaaaaabbaaaaa#a#aaa#aaaaaabbcfdbb#######a#aaac##a#ababaaaabbcdaaaa##########a#aaaa#a#aa##a#aaaaaa#aaaaaaaaaaabbccdcaaegcbaaaaacaa#####a####bbbbbbbaaaabba##a###aaaaaa####", +"####aa#aaaa##a#aaaaaaaaa##a#####aba##########aadcbbba####a####a#aa##########abcdfhiigc#a##aaaaaaaa#aa#####################a#######aadccccaba##aa#abaaaabbbcaabaaba#aaaaaa####a###a#a###.#####acbbcbaabcehfdccccbbbbbbbaaaaaaabaaaaaabaaaa###a#aaaabbcddca####.#####aa##aaacbabbbbaabcba#bc############aaa##aa##aaaaa#baaaaaa#aaaaaaaabccdeba#cgfbaaabca#a###aa#a###bcbbbbbbaabbba##b###aaaa#a###", +"###a#aaaaa#aa######aaaaaaaa######aaaa#######a##aaaa####.###aaaaa#a###########abacdhiiga##abbaaaaaaaa##############a########a##a##abbcabc#abbaaaaaaaaaaaaaacaaabaa###a###aa###a###aaa########bbbbcbbbbddceihebbcbbbbbabbaaaaaaaa#aaaaaab#a#####aaaabbcccfb#.########aa##abaaaaaaabbaaaabbcbc#####a######ba##aaa###aa###aa##abbaa#aaaabbbdcccbbabdhebcbaaaaa####a#####accbbbbcbaacba#aa###a#aaa###", +"#a####a#aaaaa#aaaaaaaaaaaaaa#######aba#######a####ab########aaaa##a#a##.#..#####aehhjihb#abacba#aaaaaa############a#a########aa#aabdcc####abaa##a##aaaaaa#ababa#a##aaaa#######a#aaaaaaaa##aacaabcccbcbabbcghgdbbabbbccba##aaaaaaaaaaaabaaa####aaaabcbcdccaa#########.##aaaaaaaaabababbabaa#######a#a##abbba#a######a###aa#aaaaaabbaabbcdbbbbabbadffbbaaaaaa#a##a####aabcbbbccabbabaaaba##baaaa##", +"##aa###a#aaa#a##aaabbaaaaaaaaa##aa###a#############bba#.###aa#aaaaaa#######.####adfehjif###aaaaaaaabbaaa#a########aaa###a######abbbbcca.###a###########a###aa###a#############aaabbbbbaaceb#aaabbbccbaaabbbdggdcbbabbbbaa###aaaaaaaaaaba#aa#a###aabbbbcdc#####aa#######aaaabbbaaabbbbbbba#aa#######a##aabbaa#######aa###aa#aaaaaabbbbbccaaccbbbccdfgedaaaaaaaaaaaa##aaaccbcccbbccba##aa##abaaa##", +"########a#aaaaa#aaaaaaaaaaaaa#aa#ba###########a####aaaaa#.##aaaaaaa##a#a########bbceeijfc####bbababaaaaaaa#########aa##a#aaaaabbadcccba####.############aaa#aa#############a##abbabbbaa##ceaaa#aaaabbbaaaaabbdgfbbbbbabba####aaaaaa#aaaaa#####a#aabbbccdccca#aaaa######aaaaababbaaabcabba##ba##a##a#aaaaaaaaa#######a#a##aaaaaaaabbbcccaabbddcaabbabdffdbbbaaa#aa####aabbccbbcbbddbaaa####acbaa#", +"#######aa#a#aabbaaaaabaaaaaaaaaa##aa#a#############abaaaa####abb###aaa#a########babcfhiiea###acbbabbaaaaaaaaa####aaba#aaaaa#aaabaccbcbaa###############aaaa###a##############aabaaaaaa####bbbabaaaabbbbaaaabbbcffbbbbbbbbaa##aa##a###aaaa####aa##aabccefcadda##aaaabb#aaaaaaaaaabbbbbbbba##abb######aaaabbba###############aa#aabbcccbabbaabdccccaabacfggccbaaaaaa##a#aabccbbcaabdbacba####bbaaa", +"aaa####aaaaaaaaaaaaababaaaaaaaaaaa#aa##############abbbbaaaaa##bbbaaaaaaa######ab#bccehiic###abcaabbbaaaa#aaaaaaaa#aaaaaaaaabcbccacba########.##########aa###############a#aaa#aa#a##a#####acbddcbaaabbbbbaaaabbefcbbbabaaaaaaaa######aaa###aa#####abcdghedcbbbbbcccdcbbaaaaaaaabbbbbbabaa#.acca#a###aaaaaaa########a##a###aaabbcdcaaaaaabbaccddaaaaacaadggfdbaaaaa#aaaaaabccbbaacbaababaaaabbaa", +"aaa#a#####aaaaaabaaaabbbaaa#aaaaaaa###aa#######.#a###abbbaabbbbaaaaaaaaaaaa####a##ababchie###aabbbaaaaaa#aaaaa#aaaaaaaaaaaabccccbccb####a#############aa######.###########aa###aa#aaaa#a###abcccdbbbbaaaabbaaaabbceebbaabbaaaaa#########aaa##aa#####acdfdefebcddcbbdffdcbaabbaabbbbbcdbbaaa##abca#####aaaa#a##a#aa####a#a##aabbdedaaaaaa#aaccbeda#aabbaaaacefgfdbaaaa#aaaaabcccbccabaaabbaaaacc#", +"##a##aa###aaabbbaaaaabcbaaa#aaaaaaa#a##########a#####aabbaaabaabaaaaaabcccca########aaacfhc##aaabccba#aaaaaabbaaa##abbababbcccbeecba#####a########a####a#a#####.##########b######a##a##aa###aababaaabbaaaaabaaaaaabdfcababbaaaa##############.#######bddcbdeffcbbba##dihdcbaaaaacaabbbdcaaabaa#aba#####aaa######aa##a###aa#abcdccdb#aa###aaaccdcbaaaaaaabbaaabehhebaaaaaaabaccbcbbbaaaaaaaaaaacb", +"a##aa#####aaaabbbaaaaaababaaa#abaaa#############.###aaaabcaabaaaabbbbacdedaaaa######a##bccdccaaaaaacdcaaababbbaababbbccbcbbcdcceedc####a##a###########a#aaa######..####.####.###aa######abbaaaabaaaaaaaaaaaaaaaaaaaacfeedbbaa############.######aaaa#abbaaaaccbabaaa###igdccbbbaaaaaaabcbabcbcb##a######a####a#aaaaa####aaaacb#abdcaaa#a###a#acddcbaabaaaaaaaaadfhhedaaabbabbcccbbaaaaaaaaaaaaaa", +"ba##a##a#aaaaa#aaabaaaaaaacaabcbaaaa#aa#########.#########aaaaaa##ababdefcab#aa########aabdfgbaaaaaacdcaaabaaaaabbbbabbcbbbcccddaaaa####aa#aa########a#aa#########..##.##..###.###aaba###aaaaa#abaaaaaaa#aa#aaaaaa#aaaegdcbbbaa###########.######aaa##aaaaab#abaaaaaa#.febaaabcccbcbbcbbaaadbcecbaa#####a#aaaaa###aaa#aaaaabaaaabccaaaaaa#aa###adbbbcbbaaaabaaaabbchifbabcccabbccaacbaaa##a#aaba", +"#ba########a###aaaaaaa#a#aaa#abaaaaabaa##a#aa###############aab####aaaaabccaaa##a#.#####abcdfb#aaaaaaaaabaabbbcbbbbbababbcdddfedcb#a##aaa#aaaaa###aaaa##aaa##.######.###.###########a#########aaaabbaaaaaaa###aaa##a###bfedcbbaaa############a####a######a#aaabcbbbaaa#gdaaa###bcddcecccca#addefgfddca###a##aaaaaaa##aabaacb####bbdcaaaaaa#aa###ccbbbccbaaaaaaaaabaadhieabaabbccdcbabbaa#####aaa", +"#aab####aa###aaaaaaaaaaaaaaaa#aaaaaaa#####aaa#a##.############aa#abaaaaaaabaaaaa########abccdfcaaaaaaabbbaa#abbcbbaacabbbbcddecdcc####aaa#aaaaa#aaaaaaa##aaaa###..######.#####a########aaa#a####aaaaa#aaaaa########aa####dedbbbaaa##############a###a#####ababccbaaaaa#gcaaaa####bdebbbbbca#bddcbaabccaa##a##aa#aaaaaaabbaca####abdbaaaaaaaaaa#a#ccbbbbbbbaaabbaabba#adhgcbaccccccdccba######aaa", +"a##aa#a###aaaaaaaaaaaaaaaaaaaaaaaaa#aa###aaaaa###.#############a##abababbaaaaaba######aaabbcddhcaaab##baaababaabaaabbabbbbcdddffeeb###aaabcaaaaaaaa###aaa#aa####.######a#######b#####aaacb#######ababaa#aaa##aa########a#aaeecbbbaa##################a##a##bbaabb#aaaa#cd#aaaaaaaace.aaa#bdccdcaaabcacbaba###aaaaaaaabaabccaa#aaabbd#aaaaaaaaaaa#bcccbbbcbbaaaaaaabbaabbhidbbcccbdeddaaa#aa#aa#a", +"aaaa#aaaa##aaaaaaaaaa#aaaaaaaaaaa######aa#aaa####..#########.###aaabbbcbbbaaaaaaba#####aabbcccegcbaaaaaaaacbaabbaaabaaaabcccdeeffddaaaaabcbbbcfffecdcba#abb#############aa#a##acbbcba#bbaa########aabba###a##########aa#aaa#eedccbaaa#####a#a###########aaa#aaa#bcaaaaaafaaaaaaaaacfa##a#aaaba#abaaccbcbbccbaaaaaaabbbbbbaaaa#a#abccc#aaaaabaaaaaadcbbbcbcabbbbaaaaabaaccfjgbccbcccccaa##aabaa#a", +"#a#aa#aabbaa#aaaaaa##abaaaaaaaaa##aaabaa##aa#a###.#.##############aabbbcacbaca#aaca#####aabbccdeedbaabbaaaabbabababaaaabbccdddffedffb###bbccefebccbdeda#aaabbaaa#######aaaaa###aabcca#adaaa#####aba#aaaa##aa################.cedcbbbbaaaaaaaaa##a######aa####aa#bbaaaaaadc#aaaaaabbee####abaaa#aa##abaaabbabdcccdcbbaccbcb##aaaaabbcdbaaaaababaaaacbccbbccbaaabbbbaabababadjiedccccbbbaaaa#aa#a#", +"aaaaa###aaaa##aaaaa####abaa#aaa#a###aaaa######aa#################a##abbbcccbbbaaabba##.#aabbbbddedd#aacb#aaaaaaaaaaaaabbbccdddggffghecbbaabbbddabaa#aaaabaaa#bbbaaaaa##a##aba###aaabb##bbaa####aaaa###########a########.#####aaeecbaabbaaaaaaaaaaaaaa###aaa##a##aa###aaabeabaaaaaabchca###a#aa#a###a##aa####bca#abdecbcdbaaba#aaabbdcaaaaaaaabbaaaaccbbbccdbabaaabbbabbbabacjkjgfdccbaaaabbaaa##", +"#a#aaaa###caa#####aaadb#aaa#aaaa#aaa##aaa###aaaa#a####a##a######a#a##aabbbbabba##aabaa##aaaabacdececaaaba#aaaabaaaa#aaaaccdeeefgeeefbcbbbcbbbcbaaaaaaabaaaaaa##abba##a#####aaa###aaaa##.#ba##.###aa############.##.#############dedcbaabbaaaaaaabaa###a###aa##aa#aaaaaaa#dbbbbbbbaacgg#b####a####a##aaabaaabbcaa#abacdcaaaabaaaaabbccaaaaaaaabbbbcbabcacccccbabbaabbbabcbbaaejklhfcbcbbaaaa#aaaa", +"####aaaaa##aaaaabaaaaabbaaa##aaaa###aabbaa###aa#aaaa###aa#######aa#a##bcccaaabbaa#acaa###aaaabbcdcdcbaabaaaaaabaa##aaaabbccdfffghffdaabbaabccddbabaaaaaaaaaaaaaaaaa##a#######a####aaa###.aba######a#################a############bfedbaabbbbbaaaaabaa##a#########abbbba##dcbabbbaaabcgdc#####aabaa###a#bbbbbbbbbbaaabbcbbabbbaaaabbbdebaabbbaabcbbbbacbabbabbbbabbbaababbbbbghillgcbbbbbaabbaaa#", +"###aaaaaaccdcaaaaaaba##aaaaa##aabaabaaab########aaaba####a###a##aaaaaabccbba##bbba#bca###aaaaabdcddcda#abaaabaaaaccaaabbbccefgfghffaaaabbaaabefbcbaaaaaaaaaaaabaaaa##aa#########a########aaa###a##############.##.#.############a#abdebabcdcbbcbaabba############acdea#abecbaabbbaabbdfc##aaaa#a#aaa##abbbcaba#adebaecabbaccdcbbabbcbdddbabbbabccccbbacbbbbbabccbbbbbaaaabcbcfijjkjfddcbabdebaaa", +"db#bdccbbcb##aabbbbaa###aaabbbbaccaaaabca####.#####baba##a#aaaaa#aba#accbbbbaaaaaaaacbaaaaaaaaacccdccc##abaabbaaabdbabbcccdffffhggbaaaaabdbaaaababbaaaaa#a#a#aaaaba#a#a################aabaaaaa###########.#####...#####.##.####aaaa#bedcccaaaaabbaaaaa##a#####aaaaddaabdebabbbbbabbbbgcaa#a#aaaa###aaabdaddabaadcfdfgdacbaabcbbbcccbdcdffdacdcedccbbbacbbbbcccccbbbbabacabbdgigbbgjjedcbbbccaaa", +"#bbbaaaaaabaaabbbea#aaa#abbbbabaaaaaaaaba#############b####aaaaaabaa###abbbbbaaaaaaaacbaaaaaaabbcccccdd##cbcbcaaaaaaabcdeffgggiigabbbbbaabcaaaaaaaaaaaaaa#aaa##aaaaaaa################aaba###baaaa#######.#####....#########.#a##aa##a#adfca###abbaaaaaaa#####a####bdbacfdaaaaaabbaacedfa#aa#########abefeddcccdebccfggfedaaccbacddecdccdeddccefddcccccccabaabbabaabbaabacbbhijgdbacfkjeedcba#a#", +"###aaaaa#abbaaaaaaa#a####bcaaaba###a#aaaa######a####aa######aaababaaaa##aabbaaaaaaaaabcaabbaaaaabcbccccbcbaaaaababbcccdefgfgghkgbaabbcbccbaaaaaabaaaaaaaa#aaaa#aaaaaaaaa####a########aaabba#aaaa#####a#.###.######.#####.####.##a#abaaa#aaddaaabbaaaaaaaa#########aabgggfbaaaaaabbbabbcfea#a#####aa##afghhfggghhgccddffhfffcccbccdfgeeeceec#aabcddcdddccebaaabaaabaaacbbbb#ejhjgbbceceikibbceba#", +"aaa##a#aabbabbaaaaaaab####bc#aaaa#aaaaaa#ab##aaaa##a#aa######aa#baaaaaaaaaaaaaaaa#aaaaacbaabaaaabbcccccdbaaaabbbbccddeeefeegjheb#a#aabaccdcaaaaaaabbabaa#aa##aaaaaaaaaaaa#######a###aaaabba#abaa####..###.###.####..#####.#######aa##ba#####bcbaaabbaaaaaa########abdfggebabaaaaaabbbbbchfaaa######abbfegggefgghgffeecefggfhheecdddeeefdcefcabaabccbaabcbcbaaaaaaabbabbbbbbfghggdbcbcbbgkjfbbecb", +"#aa#a###aababbbaaaaaaac###.acaaaba#aba####ac#aba###aaaaaaa#aa##a#a########aaaaa#aaaaabbbbbaabbaaabbbccccebaaaabbccddddedegggfhbaaa##aaabcccaaa#aaabbbbcbaaa#####aaaaaa#aaaaa#####a###aaaaaabbdaaa########...##.###..########.#####aa#aba###a#accbaaaaaaa#######aaaaabccdeeccbbaabaabbbbegfgeca#####adefffefgggfghggfeeccegihijigedbccfeceddfeaaabcacbbaaabbaaabaaaabbbbbcbchgghfgdabbaa#bgkjgcdd", +"d#a#a####aaaabbbabaaaaaa####abaabaaaaaaa###acdbaa#a###aaaaaaaa###########aa#a####aaa#abbbbbaabaaaaaabcbccdaaaaabccddeefefhgefgbaaaaaaabaabbaa##ababbaaabcca#aa#aaaaaa##aabaaa####a####aacba#bcb#aa#.####.#...##.##..################a########a#adbaaaabaa#aa##aaaaabbbcdeddddcbabebbcbbffeefdec##adeeefeffefghgghghhgfedfheabfghhfdcegecbbbbccaaaabcaaaaaabaaabaabbbbabbcdfffgffffabbbbbcabgkjec", +"cdaa##aa#aaababbbaabbaaaa####bbabcaaaaaaa##.acaaaaaaaa#aaaaa#ba###########aaa#a###aaaababbaabaaaaaaaabcccdgbbbccccddeffefgfeffbaa###a#aaaaaa#aaaaaaabbbccaaabaaaaa##a###aaabfd#####aaaabbaba#aa########.###.##.###############################bacedcbbbbabaaaaaaaaabcccccddedddbbdeecdefeededdeeffdegffeddefgfgggggcb##abbca###bbefeefeddcdcbeeaaaaab#a###babbbbbababcbccfgfeeefegcbaaabbca#afkh", +"gdcbaaaaaabbbaaabaaabbbbaaa###bbcbaa#aaaa#####a###aaaaaa#aaa#aaaaa##a#####a#aa#aa#a#aaaabbaaacaaabaaaabccdfgddddddccdfhhffddfbaaa####aaaaaaa##a#aaaaaabbdb#aaaaba#a#######aacegdbaa#aaabaabbb########.#.##.##..#...####.#######################babedededcbaaaaaaaaabccddeedefecfffeeffddddddeddeeeddeggfddeeffbaaaaaaaabdb#baa#a##cbdfeaaabbcdfbaaaaa####a##abbbbaabbbbdcgfgeeedeefabba#aaaaaabg", +"gjgccbaaaaabbbbbbbbaacbaaaaa###aaaaaaaaaaa####aaa#####aaa##aaa#a#a#######aaaaaa##aaaaaaaabba#acaacbaaa#acccfgdefefcdecfhhddbcaaa#a#####aaa#aa###aaaaaaabbeebaaaaaaa####.###aaacdcbaaaa#aaabba#############.#.#.#...###########..###############aacddeeededceeedccefggfgggfedggghfdfecdddccccddeeeeefddfffddddbabbbaaaaabefcdb#aa##aaabcaaaaa#bdgb#abaa#######ba#bbaabaaeegfgfeeeecfcaaa#aa#aaaa#", +"#bgifcbaaabbbcbbbbaabbbaba#a#aa##aaaaaaaa######aaaa##a#aabaaaaaaaaabaaaba##aaba###aaaaaaaaabbabbabaa#a#abcceffeecb#cddeeggcdb##a##aa##aa#########aaaaaaa#bedaaaaaa##########abaa#aaaaaa#aaabaa#####a####################..######.#a##.#########aabcccbcda##afgggffdbbbabdhheghifedddeecbccdcdefffeeffdfggfdbaaaaa#aababbacdddb#bb#aaa#a####ababbdebbbaaa####a#babbaaacddfgffeefeeddcbabbaaaa#aaa", +"a##ehiecbbbccdccbbbbaabbaaa#aaa##aabaaaaaaa####aaaa#####aaba#aabcbbbaabbba##abaaa######aa#abbacbaaaaaaaaabcccdfcaa##bbbbceabaa######aa##a##aa####aaaaaaaa#abaaaaaa###a######abbbaba##aaa#a####aaa###a############.########################a####aa#dcddcdb#a#dedeedcaa#baacgegiifedddddddcdddefeffggfgeedbba#aaaabbaabaaaaabceebbdaaaaa######aaaaabdddb#aaaaaabacbbbaabdfffgfgfeeeeddgcbaaaaa####", +"#b##adiifdbcefedccccbaabaaaa#aaaaaaaaaaaaaaaa##abaa######aabbaabbcbbaaaaaaa#abaaa#######aaaaabcca#aaa##aaaabbccc#########a###aa##a###aa########aaa##aaa#aaa#aa#aba##a#######aabbabcaa#ababbca##aa####a#####a.#########################a###a##acba.ddeecccba#cfeeedcaaaaabccbaigfeeeddddcbcdcddfeffggeedaabaaaabaaabbabaaaaa##cffedeaa#a#aaa#aaaaaa#abfebabaaaaaacadcaaffecffffgfffeeggaaabaa####", +"#caaa#.ahjgffefgggffecbbbabaaaaaaaa#aaaaaaaaababaa#aa#a#aaaabaaaacccaaaaaa#a#aaabaa######aaababaaaaaaaaa#aaaabccb####aaa##ab###aa#####a#a####.#aabaaaa########a##aba########acbbaaaaaaaaaabbbaaa################a###a####aa############aaccb#adcbbdddccbcdebdedccba#a#aabdcbaggeeddedcbbbccdeeffffhggfcbaaaabbbcaabaaaba####a#debceea#aaabaaaaaba#aaa#cfgcaa##aabcbcbdffedfeeeefefeedhcaaaa#a###", +"####aa##.behhgfeeeddefedbbbbaaabaaaaabaaaaaaaabaaaa#aaaa#a#abbaaabbcbbaaaaaaaaaaaba####aa#aaabaaaa##a#aa#a#aaabbcc.##ab##aabca##aaaa############aabaaaaa#a#a#####aaa#bb#.####bccbaa##aaaa###aaaaa######a#######bbabba####bb###a#a###a###bcccccdcdccddcbbabcdcddccba####bdddb#bdcecdedcbbbbbcceeeeehhcdaaaababcbcaaaaabaaa#####ab#aabb###bb##abcaa###a##adfeba###aabaaefefffedddeedefefhbaaa###.#", +"#####aaaa###chikjiigedcegcccbabbaaaaaabbaaaaabaa#aaa#a#a##aaaaaaaaabaa#aaaaaaabbbaa######aaaaabaaaaaa##aaba##aaabab.###aaaaaabaa#aa#a#############a###aaba########aa#cbb####abcbaaa##aaa#a######a#.####aa###bbccbbdccbaaabb###a#aaaaa###cbbbaccccbbcccaaaabbccccbbaaa#accdcb##bacgeeedccccbccdeeefggebdaaaaabbbbbbaaabaa#####a#a#aa#####aaaa##ca#####a####beeca#b#abadgefffedeedfdcffeff#a#a###.", +"..######a#aaadd#acdhihecdgecbcaa#aa####ba#aaa##aa##aaa###aaaaaaa##ababaaa#aaaaabbbaa######aaaaaaaabaaaa##baa##a#a#b######aaaaaaaaa#################a#aa#bcb#####aba##a######bbbcbaabcaa#################a#abcdbdefededcbcbaa##aaa#a###bcbababbccbbbbbcaaaaabcccbaabaaaabcdbba###bhhfhgeddccbccddfhhhfbbaaaaaabbbccaaaabaa####aa#a#####b####aa#aa#ab###a##aaabefd#a#abbfgfeeeeeedeeddefggbaaa####", +"##.######aaba#abaaaabeiiebceddcbaaaaa###aaba#########a##aaaaaaaa###aaaaaaaaabaabbbbaaa###aaaaabbbaaabbaaaaa###a###bb#####aa###########a######a#####aa#baaaba##abcedcbaa##a##bcccbaaaddccaa##############a##bbceffgfededdedcbaa#a#aaa#bcabaaabbbccbbbbbbaaaabbcbbbbaaaaabbcda#a##ehgfeeeeecddbcddfhhgcbbbbbbaaaabcbbbaaaaa###.#a#a#a####aaa###aa##a########aabbbedbacfegggfeeefeddccddgihdaaa####", +"##.###a####aaaa#bacbaa#chidccdfdbbabaaa#ababaaa###a###aa#aaaaaaaaaba#aaaabccccbcccccabb###aabaabbbcbaabaa########aaab.####aaa##################a####b##aaaabb#aacdddcbb#######bccaaaabdbba#####aa#a#########abccccccddcffhigcbaaa#aa#acaabaabbbbaaabbbbbaaaabbbbaaaaaabcccdda#a#higheddefedeecdffffeeaaabbbbaaabcbaabaaaa#########a####aaaa######a#######aaabdcbadgfdeddegfgfeedcccccehigaaa####", +"###########aa#####aacdb##ejgcbbfedcaaaaaacbabaa#####aaaa#aaaaaaaaaaa##abbbbbbaaabbcddddbccdcccbababaaaaaab#########aba..####aa###################aa########aa##aaaabbbba##a####ccaababdaa#aa#####aa##########aaaaabbccdfgjjihdcaa#aaaacbaabbababbaabbbabaabbbbbbbbbbbbbcccddebadhggfffeeffffeeeffdccddaaaabaaabbabbbbaaaa######..######aaaaaa#a###a#aaa###aaaccc#ceggedddcffffedcbabccdfgebaa###", +"#########aabaaa####a#aabbachjgbacdedcccbabaaaaaaa#####aa#######aaaaaa#aaaaaaabaaaabbccdccddcbbbabaaaaaabbaa########aabb.#######a##################aaa##########aa##abaaaaa######bbaaaaba#a#a#.##.#a#aa###aa###aaaaaabcddgijijjigeba#abdcbbcdcabbbbaabbabaaabbbbaaabbbbbcacddee#dfeeeffeccdghhfffebccccaaaaababbbbaaabba#a########.###a##aaaa##aa##aaaaa####aababbddceggfedcdffedcbaabcdeeffaaaa#", +"#######a#aaaaaa#a#####aaaabcdiibaaacecddcbaaaaaaaaaa##aaa########a#aa###aaaaaaaaaaaaabcccbbaaaaaaaaabaabbaaa######aaaaca.###.##a#a####a########aaaaaaa##...###a###a##a#aaaa#####bdaaaaaa########a########a##a##aaaaabbbbegfeedeghgeccddeeefgcbbaaaabbbbaaaabbbaababbbbcccbceeebegdddeffedbdeiihecbcbdbaabaaababcbbaaabaaa#a#.############aaaa##b#a##aaaaa##aabbbbccdceghgeddefedcaaaaccdedfaaaa#", +"########bcaaaaa##########aaaa#gidaaabedcccbbbaabdbaa####aba#a#############aaaa###aaaaaaacbbaaaaabbabbbbbcbbabaa######aabb..##.####aa#aaa######aaaaaaa####a#.####aa##ba#aaaba#####dbaaaaa######aaa#aa######aa###aaa#aaabccebabaabbdfhhhgfghggdbaaabbcaaabbaaabaaaaaaabccccccedchigdcdddcedccabghdbaaabcaaabaaaaabbbbcbbaa##a########a##.#aaaaaaaaa#aaaaaaaca#acbbbbbcccdefeddeecdcbaababcfdfeaa##", +"########baaaaba#aaaa#####a####aciib#aacdddbabbaabbb#aa#####aa#############aaaa##aaaabaaaabaa##aabababbbbccbbbcb#######aaaa#...##.#####aa########aaaaa######a############a#aaaab##abbaaaa#######cb############aa#aa#aaaaabaaa#######bfhigihhfbaabaaaaaabaaaabbaaaabaaaccbccdcchiihhdbcddcddccbbeeaaaabbbaaaababaabbbeeeaa#####.###.aaaa#aaaaaa#aaa#aaaaaa#bbadccbbbbccccbcddddcbcccbaaaaddddge###", +"########a##abbaaa#########a#aaabcfjhaaabcdecaabaaaaaaa#######a########a#aa#abaa#####aaabaabaa##ba#abbccbaccaaca########abcb..######################aa###ceb#######aaa#####a#aaa###acaa#aa#######b############a#a##aaaaaabaa########abacfhhfcbbaaaabaaabaaaaccaaaaaaaacbcbbcffgfgcegeddeddcdccbcd#aaababbbaaababcaabaaccba########a#abaa##aaaa##aaaaaaaaaababcbbbaccbbcbccdddcbbbcbbcbbadcdeehd##", +"########bb####aaba#########a####aabfjfbbcbcfdbabaaaaaaba######aa######aaaaaaaaa##a#####aaa######aaaabacbbaaabaa#########aadc...#######.##########aaaaaa#ddeb#a####aaaabeb######a###bbaaaa##b####aa#.##########a#a#a#aaaabaaa##b###.adbaabeecbaaaaaababaaaaabcabaaaabbbbbcdcfgeddgbbggeedddcccccc####aabaaaaabbaabaaa#acda############aaaaaa#aaabaaaaaaaaaabcbabbbabcbbbbcddccbcbbbabbbbccdfggf#a", +"aaaa####bc##a#aaaaaaa###.#####.####aciiecccbceebaabbabbb######a#a####a##aaaaaaa########aaa#######aaabcbbabbaaaaa#########acfc..####.#.###.###aa###a#a#aaabcaaaa###aaaa##########a##bdcaaaa#ba###baa##########aaa####aaa#bbababdcbaacbbbaaaabbaaa##aaaaaaa#aabbbaaabbbbbbcdcccddcdec#adfedddcccbe#####aaaaaaaaaabbbaaa#bdb##.#######.####aaaaa###aaaaa##aaabccbbbaababbbbbcdccccbcbbbcbbbdcefghc#", +"########a#####aa#bbaaaba######...####adhifegfddfdcabccbaa###aaaaaaa######aaaa##aa##a###b##########aa#aaaaaabaaa######a###abdfb..#######.##.#####aaa#a###baaa####aaa#########a####a#bddcbaaaa####aaaa####ad##aaaaaa#######abadddccccdcba##a#ababa###aaaaaaaaabaaabbbbbcbbcbbccdccbaba##afedddccbfa######a#aaaaaabbabaaaaab#####.##..#..a###aaaaa#aabbaaaaaabcccbbbabbbbbbbbddccbbcbbbcbbcfdeeffha", +"##############aababaaaa##########.##.#..chjjhjifffdeccdbaa#aaa###aa#####.##aa#######.#######a#########aaaaaaaaaac########acchc.....#..###########aa##aa#abaaa##aba##a######aaaa##a##bdcbaaaa#####a#aa###bd###aaaa#aa##a####adgdcbbcddbb###aaa#a#####aaa##aaa##abbaabbbbcbbbcccddeccc#a#bhggfedaec##########aa#aaababaaaaaa#####.##.##.####aaaaaaaaaaaaaaaabdcbbbababbabbbabddcbbbbbbccbbdifdefge", +"a###a##########abb#aaab#a#######...#####.##a#acgkigfeefdcaaa##aa#aaba####..######.#a###a#aa#aa##.#######aaaaaa##ba#####aaabbeha...###.###.#######a##aaa#aaa#a#aaaa###aa#a###aa###a###cdcaaa######a#####abb####aaaaa####a####deebbbccdbba##aaa#aa####aabaa#a#aabbbaaaaabcbcbbccbcedbba###cdffffeefba###########aaaaaabcaba#####.####.#######a#aaaaaaaaaaaaacdccabbababbabbaabcccbbbbbbbccdeeedefh", +"f#######aa##a##aaa#aa#bba#########..############afkjgfgfeeeba#aaa##a#######.####.#.#####abbbaa##########aaaa##a#a#######abbcdhe#...######.##a####aa#a###aa#a#aaaaa######aaa###########bdbbaaa####a######aa##.##aaab####aabdecdcbaabbbaba##aaa#########abaaa##abbbaaaaabbbcdbaccbcebaa####adghfedeeba#############aaaaabbcb##########.######aa#aaaaaaa###bcdccbbabbbacbaabbbbbbdcccbbbbbcccccddeh", +"hc#####aa######aa####aaaa#####a###.......##aa##a###gijhhhggeb##baaaa####...#####.#..a###acccaaa##########aa#####aaa####aacdddhf#..###.#..####aaaaaaaaaa###a#aa#aaaaa#####aabb##########cecaaa####a##############aabb##aabacddbcbbabbbaaaaaaaa##a#######baaaaa#abbaaa#abbbabcbbbcdgd####a##adcgfecdeb######a########aaaa#baaba########.######aaaaabbbbbbcbccbbbbbbbbbaaaaabbbbbbccbcbbbbcccccdeed", +"egb##baaaaa####a##aa#aaa#a#######.#..###.###########adfilkhfca#abaaa#####..##....#....###bbccaa##a##aa####aaaaa##a##a##abbcfhjfb#..#####.######aaaaaaa######aa##a#abbbba###aba#aa#######cecaaaa###a#.#######aa##aa#aa###aaabcbcbbcbbaaabb##aaaaa#######abaaaaaabbaaa#abbbbbabbabdfeaaaa##a#ca#eecccfcaaaaaaaaa#a#a######aaaaabca########a####aaaabababbbbbbbbbbbbbbbaaaaaaabababccccbcccdccbdffd", +"cfhd#acaaaa##a#######a#a##a###a##.....######.##########bddjkidca#########..###....######acaacbbb#a###ab##aaaaaaaaaaaaa#aabcfgejfa#.###a######a##aaaa#aaa#a###aa##a#abbcba#####aa####a###aeedbaaa##aa####...#aaaa#bcaccbaaaabcdccabcbbbaaca#aaaaa#########aaaaaaabaaaaabbbbbbbaaabbecbbcaaaaaa#adecccedcaaaaaaaaa##a###########abaa######a####aaaabdbbbbbbbaabbbbbabbaaaaaaaabbaabccbccbccdccdefg", +"fedfea#a####a##a#a#######a####a#.##..#.####...########aaaaaeikhea#####################aaacbabbdfdbbaa#aaabbcbbaabaaaaaaabcdfbbeica..#a########aabaaaaaba#a###aa#######aaa#####aaa#.aa###adffdbaaa##ca####.#########abbcdeeeefcdcbabbbbbaacbbaaaaaa##a##a##baa##aa###aaaabbabbaabaadfb#bbbbbaa###feccbeecbbabaabaaaaaaa#aa###a####a########a##aaaaabbbbbbcbabbaaaaaabbbaaaaaaabbbabccccccddddeeee", +"fggehdaaa######a##########aaaaa#.##.####..#..##.#######aabbaadjljgda.#################aaaccbccddcccccccccccccdcbbccbcbaabbcfdcbgf#...#aa######abcbaaaaabaaaaa############.##aa##a########dffedcbaa#cc##########a####bbbbcdffeedaaabbbbbcbabbaaaaaaa#######abaaaaaaaaaaaabbabbaa#a#bdcbbbaaaaa###cfeeehhecabbbbbbaaaaaa##aaa##a###a########aa#aaaa#bbcbbbabbbbaaaaabbbbbabaaaaaaaabbbbbcccddddeee", +"edehhg#aaa######a#a#####a##abbaa###.###################aaabbcaacjllkhbaa#######a######bbaefddddcbbbaaaababefeedddccffdccdfgeeeefec#...#ab#.####abccbbba#aaaaaa###########..###a##########bfdfdccaaacfb.######aababaaaccccbdffebbbbcbbaacccbabbabaaaa######aaaaaaaaab#aaabaaaabaaaabbeffcaaaa####aeeeefiihfcabbbbbbabaaaaaaaa##a######aaaa####abbabbabcbaaaaccbbbbbbbbcbcaaaaaaaaaaaacbbcdddddede", +"eefgghcaa#######a##aa######abbbcc#.############.###a#aaaaaaaaccbafjllkjecbaaaaaaaa##aabcccgefeecccbba#aaaa.acffffffcacdccbbbfffefda#.##########aabcedba##aa#a#####a#####..#####aa###.####bceecccbaabdfa##aabbbaabbbbdcbbccdcceebabbbaaabcdcbbbbbaaaa######a##aaaaaaacaaaaabbaba###acdeegcbbb#####aeffgfgijkgcbbbbbbbbabbaaaaa##a#aaa#abaaaa##aacdbabbccbaaa#bbbbaabaabccbaaaabbaaaaabbbccdeedddd", +"deeffdfd#####a######a#######aaaca#a############bdca###aca##aaaceddfijjnligdcbbcbaaaaabcddchgedddbccaaa#aaaaa##accfbbbaa####bdhfedhd#.###########bbcccdba###aaa#####a##a#.#####a####.####.#abedebdcbbcfe#####adcbcddbbdbaaacbcbccbbbaaa#bbcbbbbbbaba#a############aaaaaaaaaabaaaaaaabdfcccbbba#####aceffgiijihedccbbbbbabbaaaaaaaaaaaaaaaaa#####aabaaabbbaaaaaabbaabbbbbcabaaaaaaaaabbbbcccdddddd", +"ddddecbdca###a###a##baa#aa##abaaba#a###.#####.#aabaaa#aaa##aa#acdhilmklmlmkheegecbbbbccbcefgedcdcbbbbaaaaa#aba#a#cdabcbaaa#achihggfa############abdb#bcaa##aaa#########a###.######..########beddecbcdffc###.#acdfffdabcca#aabacbbbbbaa#abbbbbbbbbaa#############a#aaa#baaaaaba###aaadfd#babacababbbcegfhhiihgfdddcccbbbaabbaaaaaaaaaaba#aaa###a#aaaaaaaaaaaabbabbaabaaabcbbbaaaaaaababbccdddddcd", +"deddddcacaba###a####aaaaaa#aaaa#aaa###aa#########a##aa#aaa##aba#.cfehhjkjllmllihfedcccbbdefgdcccecbbbccbaaaaaaaaabdbbbcbaaaabhjjhggea#.####a##a#accaa#cdaa#aaa#.#############a##a##.###a####.cedccccefbbaa#####deffeaacdaaaa#aabbbbbaaaaaabbaaabbaba#####a.###a###a#a#aaaaaaa#a##aaacdecaaaabaa#aa#bdgfeeefhhfdccccddcbbaaababaaa##aaaaaaaaa###aaaaaaaaaaaaaaaabbaaababbbbabbbaaaaaabbbbcdcdccdd", +"dddcccdbbbcba#bb#aa###aa##a##a####a##.####aaa##a#aa##a#a#ba######.fffkjlhkkljmmmlieeddccefaeeeccdedbcdccbcbaaaaaabaccbccaaaabeijjigieba.#######aacbaa#accaaaaa##########a#a###aaa#############decabdeeeaba###..adeddcaabcbba##aabbbaaaaaaaaaaaaaaaaa#####a###########aa#abaaaa##a#abbcdeba#b#aa#####cefedcbbdeedcccdddcbbbaabbaaaaaaaaaaabaaa###aaaa#aaaaa###aaaaaaaaaabbbaabbcbaaaaaabcccccccdd", +"ddccbcccbcedaddaaaaaaaaaa#aa#a######...###########aaaaaaaaaa####..cfhjjkmlmklkklmnjfeedeefebdeddegheeedddccbbbaaabbccbcbbaabbbgjkjjhifda.#######aaaaa###abaaaa####aaa###########aa##########..adccaddcecbabbaa##dedddcbabcbca#aaaabbaaaaaaaaaaaaaaaaaa###############aabaa##a####aacbcddebaaa########cffecdcbceeefdddddcbbbaabbbaaaabaaaaaaaaaa###aaa#a#aaaaaaaaaaaaaaaabbbaaaacbbaaabbbbcdcdccb", +"cdcccccbbcdbaacbbbbbbaaa#aa#aaaa#####..#..##.#####a#aaa####aa######eigfcfgijjjlmmmmnlhfhiggdddeefgegfgffdeddcdcbaaccccbcbaaabbcfjkkkijgfb#######a#aa######a#############a###aaaaaba############abcc#ddcccbdecdcaddddddecbbbccaa###aabaaabaaaaaa#aaa#########.####a##a##a#aa#a######abccdgbb#ba#a######cffgfdefffehgdddeccccbaabbbaaabbabaaaaaaaaa###aa##aaaaaaaaaaaaaaaaaaaaaaaabbba#aabbacddccc", +"cddcccbbcccaabbabaacbaaaaa#aa#aa#.#...#...#..###a###a#########aa##adeaaa#abedefijlkmnnlkkjdddfdcebb#degfaefgfeddcbdcddbacbbbbbbdjjklkkihgc#aa#####aa################aaa##a#aaabaaaaa###########aabdbedcabdddeeddddedcccddccbbbca###aaaaabba#a#####a#a###aaa###.###a#######aaaaa###aabbbbcdaaabaa##a####aeghhhggghhhfedddcccccbbbbbbbbbbbbbbaaaaaa####aaba#aca#aaaaaaaaaaaaaaaaaaaaabaaaaabbbcddd", +"dddcccbbdedaabdaaaabbabbbbaaaaaa#.##.##.#.#####################aaaddbbaa#aa##a##aceejnllkkhfhfccfbbaaaabafabdeffgfcdddcabbbbabacgjkkllkhjhbaa#####aa############a##aaaa###aaa#aa#a#####.####a##aa#deedcabdeeeedeeddeedbccdcccdcb####aaabbbaaa#####a##a##a####################aa####aabbbcdea##a########aaabehiiiiiihfedfdccccccbacbbabbbcbbbbaaaaaaaa##ab##bbaaaaaaaaaabaaaaaaaabbbaaaaaabbbbbdd", +"ddccdbcbedcaabbbbaaaaaabbababbaa#################a##########a###a#ecbaababaaaa#####abkllllljgbaaccbababbabaaaa#cedfheedcabbbbbbbchkkkklkhggeba###aba####.####a####a##aa##aaaaaaa##aa####.####a####dfdcba#bdeeeeeefedddcbbcdbbadcba###abaaacaaa###a##a###aa#####.####a######.##a####abbbbccbbc#ab##a#aa#ca###cfggihhihffffedcccccbbabccccdccbbbaaaaaaa#aa#aa#aaababaaabbaaaaaaaaaaaaaa#aa#abbcccc", +"dedcccbcecaaacbababbbaabbbbbcbaaa#..###.#########a##############.cdabbbbbbbba###aabcddilmmljeaaabcbbbbbbbbbbbabaabcefgfecbbbbbbcdfjjkkkmkhfgecbaaabb########a######aaaaa####aaa###################befcbaabbadfeeeeffededcbbccabccccaa#aaa#abaa#######a########...###########.##..###abbbbcbbf#aa###abaa#a#####acfgffgfggefddcccccbbabcecbbbcbbaaaaaaaa##aa#aaaaababbbabbbbbcbbabaaaaa##aaaaabbcc", +"cddecccccdcaaaaaabbbbaaaabbbbaaaa########.####################..aaababaaacbba#abddbcdfeejmllf#aabbbaabbbbbbaaaaaaa#afffdedcbbbddffjfijjkkkhgfed####aba#######a####aaaa#aa#####a######a############adffddcaa#befefedeeddccccbcbaacbaabbaa###aba####a###############.###########.######aabcddcefbb###bbaaaaaabba#cffffghhgfffedccccccbcbbebbbbbbbaaaaaaaa####aaba#aaaabbbbbbcbaaaaabbcbaaaaaaaabcc", +"dddddfebdfeba##aaaaaaabbbbabaaaa####.#########################.abbaaaaaaaaabbaaabba##aceeilmme#aaaaaaaabbbbaaaaabbbbbefgeddcddddegiighiiggjggfdba##aaaa##############ba#b###aaaa#######a##a#aaa####dfgffgcaabefeeededccccdddcbbbbbaaacbab###aaaaaa########a#a########.#########..####aaabdcdecbdc#aa###aabbcccaacegggfgghggfeeeddddcccbccbbbbaaaaaaaaaaba#aaaabaaaaaaaaaaaaaaaaaaabbaaaaabbabbbc", +"bcdeeeeedeeda##aaaaaaaccbbaaaaaaa####..##.#########a##########aaaaaaaaaaaaababba#aa####abbdhkmgbbbaaaaabbabaaaaababbbaehfcdeeeegghkkjjigdeehfeccaaaabcba########a####aaa#####aa####a####aa###baba##adfgfffdeeffdcddddddbcccdccbbbbbbb##bdb###aadb#a##############.##.######.##########abcdcedecegdb#a#aaabbcddaa#adfghfghgffefeefeeddcccccbbcbaaaaaaaaaaa#aa###aaaaaa#aaaab##aaaabbbabaaaabaaabb", +"cbceeeefffffd#aaaaaaaaaddbaaaaaaaa#############.#############cbbaabaaaaaaabaaaaaaaaa###aaa#achlkigdaabbabbbbaabcaacaababccdbbdedcdfehkkjgeceheccda#aabbba###.######a#aaa#####aa######.#a#aa##aa#aa##adgggfeeggffdcccddcccbbcbccbbbaaa####ca##abcba#aa##########.#####a######.#.#######abbcbddbdfhgeaaa##abbcdcaaa##aaceghdfgffffffeeddddcccbbbaaaaaaaaaaaa##aa#aaaaaaaaaaab##a#baabbabbbaaaababb", +"ccddefgfefffd#a##aaaaaabccbabaabaaa##########...############acbaabaabaaaaaaa#aaa#aabaaaa#aaaabgkjiifbabbabbaaaabaaabbabaaaaaaabcc#####cgkmjgfhfcbcaaaabcbaa########a#aa###a###########.####a######aa##bghfefgeddeccbbbccccccbcdcaaa#a##a#aa#a#aaaacbaa##.############aa########.#######bbbccddddggfbaa###abbcbaaaa#aaabeeeeggghgggffeedcccbbbbbcbaaaaaaaaaa###aaaba#aaaabbaa#a#abbbbbbabdbbaaaab", +"bcceddefhgfcbaa#a#aaa###aaabbbaaaaa#######################aababaaaaa#aaaaaaaaaaa#aaaaaaaa#aa###cefllgabaaaaabbbaaaaabaaabbabaaa#ba######bfjljhghcac##aaacaa########a###############aa#.##a#############afgfgfedcccccbbccccccddcccaa##a####aa#aaaaaabaa#################a#a##.#########aaabccccddeegfbaa###abbaaa#aaaaaabdfceghhhhhhgfedddcbbbbbbbbaaaaaaaaaa###a##aaaaaaabbbaaacbbabbbbbcccdaaaa", +"bbcccdefhiea###a##aaa######aaaa#aacb##############a####aaabcbbabbaaaaabaaaaaaaaa##a#aaabaaaaaaaaabekljbaaabbaabaabaaaaaaaabbaaaa#a#aa#####aekkhhiba###aabbbb#####a.#########a#a#####a#######aa####.#aba##gggfeedccbbbbbbcbaabccbcbaa##a###aa##abaaa#aa###..###########.###a##.#######aaaabbbcdddcefgaaaaa##abaabaaaabbaabdeffghighhgfffeeccbababbbbbaaaaa#aaaa#a####aaaaaabbaabbbbbbbcccbcccdbaa", +"bcccccdefgeaaaaaaaaa#a#a#a##aaa#a#aba#######a#.###aa######bcaaaaaaaaaaabaaaaaaaa###aaaaaabbaa#aaabbchkkc#aaaaaaaaaaaaaaaaaaaaa#a#aaa#a#######dkklibca#aaabcdca#a#aa#################a######aaaa######aab#cghhgfddcbbbbaabaaaaabbca##a##abaaa##abaaba#a#aa############...##.###.#..####aaacbbcdccdcdedbaaa#a#acbaaa#aaaaaaabcffffghhhfggfeddbcbbbaaaabbaaaaaaaaaaa#aa#aa#aaabbbcccbbbbbbbbbbcdccb", +"bbbccccdfcec##aaaaaa####a####aa#aa#aca##a####baa#######a##bbbaaaaaaaabbbbbaaaa#aaaa##aaaaabbba#aaaaaadijgaabaabbaaaaaa###aaaaaaaaaaaaaa#######behlidcdbaaabbcecaa######a###aaa###########a####a#######aaacghihgfedcbaaaaaaaaaababbbaa###aaa####a#aba##a#a#####..######......#...#.#.####aaccbcccdcdehhdaa####bcba###aaaaaaabaaadfeeegihgecdedcbcbaaaabbaaabaaaaaaa##aaaa#aaabcbbbccbbbbbbbbbcbbb", +"babbcdddddde######aaa###########aaaabda##a####abaaa#####abbaaaaaaaaaaaaaaabbbaaa#aa##aaaaaaaaabaaaaaabcdkib#aaaabbaaaaaa####aaaaa#aaaaaa##a##a##acgjhfgefcbbacccbaa####a######aaaa########a#############bfffhjigedddbaaaaaabaabbbbccaa####aa###a##aa#################a##.....#..#########aabbbbcccddfheaaa####bba####abba#aaaa##bca.#bghfedecbccbbbaaaaaabaaaaaaaaa#a#aaaaabbbbbbbbbbbbbbbbbbaba", +"bbabbdcdddcec#####aaaa#a####a###abaaaaaa##bda##aaa######aaaaa#######aabbbaaaaaa##a##aa#a#aaaaaaaabaabacbdjjbaaaaaabaaaaaa##########a#aa##aaa##a#a##cfhhededabbdcbcca##########aaaaa############a######a##dffgjiiheedcbaa###bbaabbbddba#########aaa####################a###..###..##..###aaaabbbbcbcfffebaaaa#aabaa##a#aaaaaaa#####aa#.bdegfeccbbaabbaaaaaaaaaaaaaa#aaaaaaaababccbcbaabbbbbbcbbab", +"dbbbbcdcdcdcea###a####a#aab#aaaa##aaaaaaa##a####aaa###.##aa###########aaaabaa#aaaaaaaaaaaaa#aaaaaaabbaabbbhkfcaaaaabbaaaaa##########aaa###aaba######.ekjgddbabbaabccbba########aaa####.#######aa##aaa#####dgfgghgggedcbbaaa#aabbbcbedba#######aaa#a####################aa#.......##..####aabbbbcbcdefeebb#aaa#aaa##ab###aaa#######a###.##cgefdccbbabbbaaaaaaa#aaaa#a#aaaabbccbbcbbbaabbbbcbccbbb", +"bcabbcceffabbc########aaa#aaaaaaba#aaaaaaaa########.#####aa######aa####aabbbaaaaaaa##aaaaaa###aa#aa#aaaaabbfkjhdaaaabaaa#aa##aa#####aa#a#a#aaaa######aikjjhbaaabbaacbaaa###############.###################bfhggggggfedcabaaaaabbcdeccaa########aa##########aa######a#a##a##..#.#...#####aabbbbbcccecdgccb##a####a##a############aaa######agfedccccbbaaaababaaaaaaa####aabbaaaaabbababbbccccbbcb", +"ababbccdffdbbbba###aa#aaaaaaa#baaaaaaaaaaaa#########.####ab###########aaaaaaabcbbbaa###aaaa#ba###aaa###abbbbflljeaaaaaaaaa###########aa##aaaaa#######.afikkiba#abbaaba##########a############################ehffgggfeedcccbaabababcccbaa######aa##aa###.###aa####...#########...########abbbbcbbbcdecfgdaa#######################aa##a####bfeeddccbbbbbaaaaaabaaa#abaaaaaaaaabaaaabbbbbbccccccc", +"adbbbbcdddecbaba#a#######a#a##aaaaaaaaa#aa##########.###aac##########a##aa#aaaabcbbaaaa##aaa####aa#aaba#abbbbdillhcaaaaa####aa####aa#aaaa##aa#########.#chkli#aaaaabbaaa########a#aa###a###############.###aa#fggffgffedeecbbbaaabbbbcbaaa#####aa###a############################.######aababbcbbbccedcfccaaaaaaaa###############.####a#####bffeddccbbaaaaaaaabaaa###aabaaaaaaaaaaababbbbbbbcccc", +"ccbbccddeeeccaaca##a####aaaaaa##aaaaa#a#aaaa#########.###ab####.#a###aaa##aaa#aaaabbaaaaaaaaaaba#abaaaaaaaaaaachkklfbaaaa##########a##abaaa############..#bimiaaaaaabaaba##########aa#babaa##############.##a##aegfcbdeedfedbbbabbabbcbbbaa#####a#####aa######################.#########aabbbbbcbbacddddccaaa#aaaaaa###a#####################afgeecdccbaaaaaaa#abccbaaaaaaa#aaaaaaaaaaaabbbccbcc", +"ccedcdddeeeccbbbcba#a###aaa#a#a#aaa#####aa#a#############ab#####.#####aa#a#aabaaaabbbbabbba##aa###acb#aaaaaaaaacfihkida##a#a###.####aaaaaaaa##a###aa######.ahljc#abaaaaaaa###.####a######abaaa############.#####.bababeedegdcbccbcbabaaabba#a##aa####aba#aba#a###################.####a##ababbbcbbbcdddedea#aaa#a####aa#######.###.######a##a##fgfedddbbaaaa#bcdccbbba####aaaaaaaabbabbbbbbbcbbc", +"cddeddddeefddcbbcc#a#aa#aaaaaaa#aaaa####aaa######aa######ab#a########aa#a#aaaaaaaaaaabbaabba#aab###abb######aaabbcfheihc######a#####aa#aaaaaaa####aaaaaa###.aikjcaaaaaaaa#################aaccbaa#a################aaaaaaabdddcbccbaaaaaaaaaaa##b####abbcccb##.###a#############..###aaaaaabbbbbccbbccccddecaaa#aaaa###a########################effedccaabbaccbbaaaacc####a#aaaa#aabbbbbbbbbbbcc", +"dcdcdcdeddfecdcbcdaa#aaa##a###a###aa##############aaaa###aba#############aaaabaaabaaaabbabbaaa#aba####a##a###aaabccefadhhb##aaa#####aaaaa#aa#a##aaa#aaa#####.aflkcaaaabaa####################ddcbaaa#################a#aaa#bdddbbcbaaaabaaaaaaa#a####a#baa####a###a###aa#############aaaabccccbcccbbcdcdedefb##a###aa##aa###############a##aa####efddcbcecbccabbaa#aacc###a##aa#aaaabbababbbbccc", +"ccdddcbcfhfddcdcbbc#####a#aaa##a########a#a#aaa#####aaa##abaaa##.#######aabbaabbaaaaaaaababbaaa#aaaaa###a#a#a#aaabccdha#diga##aba#####ca##aa####aaaaa#a#######acildaababbaa###########a#######abccbaa#########.#########a###cdedbbdcbbabba#aaa###a####aaaa#aab###a##a#aa######aaa######aabbccccccccccddddeddfca#aa##aaa#aaa#####a####.###aa#a##a#cfeddedacaaabcaa###aacc###########aaaaaabbbbbcc", +"ccccddccdeffdcccdccb########aa##########a#aaabaa#####aa##ab#aa###########aaaaaaababaaaaaaaabaabcabba############aaabcffb.afjfa#aba####a#a########a#a########aa#abhjb#aaaba#a##########a#######aabcccbb####.#..###aba#########abddbcecbbcbba#aaa########aaaa#a#a###aaa########aaaaa#####aabccdcddccccccccddedcec###ba#a####a#a##########.######aa#adedcbbaabaaabbaa###aabca##aaa#a##aaaaaaabbbbbc", +"cccccdcedcddfebbdcbdb#######################abcbba#######bbaa######.######aaaaaabbabaaaa##aaabababaaaaa########aaaabbcfiea#bgjeaaa######aa#a#############a####a#acgigaaabb##########.##a#######aaa#adcba##########ba#a#a#####a#adfcddbcccbaa#aaa######aaaaaa##aa#aabbab#aa####aaaa#####aaabbccdddcdcbbbbcccddegd##baaaaa#########a################abbcccbbbbabbbba#####abca##aaa####aa#aaabbbbbb", +"bbbccddcdcddefdbcdadcaaa#####################aabbbba#a#aabba#aa##########aaaaaabbaaaaaaaaa#a#aaabbbbbaaaa###a#aaaaaaaabfifa##ejgbaaa########a##################acbcfigba#aa###########a#########a#aaabbbba#######.#a#a#######aaaaffddccbccba##aaa##########a######aabaaa#.####aa######aaabbbccdeeefggecdedcdfedcbaacbaaaa##a#a####a############a##aa#accdcbcbbbbbba#####aaca#aaaaaaa###a#aaabaab", +"bbbbcccccddddfecbccbdc#a############a###aaaa#aaa#aa##aabcccc###########aa#aaaaaabaaaaaaaaaa#aaa#aaabbbbbbaa###a#aabaaabbbhie#.bfhfbaaaa###aaaaaaaaa#######a####aaabdhifbaa########aabaa###a######aa#####bccaa#####.#####a########afgeddccdcba###aa########a#a#######aa######.##########aabcbcccdffghihgdcddcbacbbeabaaaaaa#a###################a##aaaa#bcddcdcbbbab##a##aaaba#aabcaa####a#aaaaba", +"bbbbbbcccccdefedbbcacdc####aa##a#.##a#.##abb######a##aabbccc###########aa#aaaabbbbaaabaaaaaaaaaaaaaaabbbccbaa##aaabaabba##diic##adhebaaaa#aaa#aa##aa##########aabaaagjjf#a######a#aaaaaaa#a#######aa#a###bdddaa#a###.#a###########adcdddddcba#aaaaa#a###a##a##ba#b###aa####.###aa#####a#abcdcbbcdghihhgdcaaaaaabcfdccaaaaa#aa###################a##a#a##acbcdcbbcba#a#####aaba##abaaaa###aaaaaaa", +"aaaaabbbbbcddeedccebaccb###a####a####a#..aba##########aaaaccb.############aaaabbaabbaabbaaaaaaaaaa#baaaccbbaaaa#aaaaaaaa####fjfb###egebaabcb##aaa##############aaa#achkjbaa######aaaaaba#a#aa###a###########abba###################abaceddcbaaaaaaaa#####a#####a####a##a######.###a##abaaccddedeeffdghfaaaaaaaabbdfcabbaaaaa###############.#########a###bccbedcbdaa######a#abaaaba########a#aaa", +"#a#aaaabbbbbbcdedcccbabbb##aa######.######ba#############abcc##############aaaaababaaaaabbaaaaaaaaaaaaabbcbbccba#aaaaaaaaaaa#beihb##afgdbbcba#aaaaa######a######aa#abcilheba#####aaaaabaaaaaa#########a####a##a#aaa###############a#aaadedbbaaaaaaaaa##aa##a#######a##aab######.##aaaababceefcddcb#.#gfaaa#aaaaabcfgcaaaaaba########.#####################aabddcbcabaa##a##aaabaaaa######a######", +"##a#aaaabbaabbccdcbcbbbacb###a###########.aba#######aa###aacf#######.#######aaaaaabcaaa#acaabbaaaaaaaaabababbbcdcbaabba#abaaaaabfje#a#aehdaaaaaaaaba#####ab#a####aabaabijiebaa##aaaaaabaaaba##aa#####a#a###########a###a###########aaaaaabbbaaaaaabaaa#aaaaa#####a##abaaaaaa########abbabcdgeba##.##.bdaaa#a#aaaacfgcaaaaaa########.a########.#######a#aa###abccbbbaaaa#aa#abbab#abaa####aa#####", +"#####aaabbaaaabcbccccbbbcca###a############a#########aa##aaacb###.#.########aaaaaaaaabcbaaabaaaaaaaabaaaaaaaaaabcaaaaabaaaaabaabaejhbaa#aggcaaaaaaaaa####abb#a###aa##aabhigddbababba#acbabaaa###aa####a#c#a#############a#a########aaaaaaaabbaaaaaaaaaa#aa##a#####aaaaaa###aaa######aabbabege##b#######aa#a##aaaaaceecbaaa############################aaaa##aaacbbbaaa##aaa#aaaaa##aa#####a#####", +"####aaaaaaaabbabbdcbcdccbbba#aa####a##a####a######..##aaaaabab###.###########aaaaaaabbbbbbaaaaa#aaaabcbaabaaabbaaaaaaabbaaabbabab#bghcaba#dhfaabaaaaaa#aa###aa##aaaaaaaabeegbccbaaabcbbbaababa######aa#aaaaa##aa#.######aaa#########b#aaaaaabaaaaaaaaaaa#a##aa#aaa#aaabbab##a####ab#aabbbbcfhaaca##############abbabddbbaa####################.###a##a#aaaaa#aabbbbbaaaaaa###aaaaaaaa#######a###", +"#####aaaaaabbbbbccdbccdcbcca##########a#####aa##a######a#aaaabc###############aaacaabbabbbbbaaaaaaabccbbaaaaaaababcaa#bbaaaaaaaa#ba#eiebabaafhb#aaa###a#a####aaabbaa#baabbbigcebaaabcbbcdbbbcca#a##a###acbbaa#ab##########aaaa########aababbbaaaaabaaaaa##a###a#aa###aaaca##a#aa.bc#abbdccbdga#####.###########abbbbcdebaa##a##a##########a####.###a#aa###aaa##aabbabbba#a#####aaaaaa########aa#", +"#####bbbabbbabbcddddcccbbbcca#a##aa###a#################aaaaabb#a####.########aaaacaaaaaacaaaaabcaaabbcdcbbbcbabbbabbaaaaaaaaa####aa#cijdbababhfa#aa###aa##a##a#aaaaa#aabbbflggfaabacbaabbbaacbba##aa#abccbbaa###aaa#####a#aaaba###a#aaaaabbacbaaaaaaaaaaaa###aaaaaaaaaacaaaa#bbab#abbcccccbdc#################aabdceedebaa#########################b#####aa#####bbbabbaa#a####a#aa##ba########a", +"aa##aaabbbbccbbcccddcdccabbdfa####a###########aa######a#a#aacc#######.#########aaabababbaaaabbaaaaaaaabbbbaaaaaaabaabbbaaabaaaaacba#a#beijbaaaaehfa###########aa#abaaaabbbbdhjghffedccaaabaabaabbaaaacbcbcccbaa#aaaaaaaa#aaaaaaaa####aaaabbaadebbaaaaaaaaaaa###aaabaa#a#aaaaabbbbbbbabcdcccefe####.##.#######.##a#aacccccaa#aa#####.###############aaa###.#a###a##bbbbbaa#a########aaaaa##a#####", +"###ab#ababbccbcbccdddccccbbbeda##aaa######aa###abaa####a###abdb#a###.######aaa#aaabbbaaaaaa#abbbaa#aaaaabdaabbcbabb#aaaaaaaabaaacbcba####ejdbbbacgjd##aa#aa#####aaabbaabaabbejiiiihhggfbaabbbaabcba#bcdcdddddcaabbbbcbaaaaabaaaaaaa##aaabbbbcdedbcbaaaaabbaa#aa#aabbaaaaaaabccbbbbbcdccddffebb####################aabccccca###########.#########a####aaa####a##aa#abbaaaaaa########aaa####a#####", +"#aaaaabbbabbcccccdedccccedccdebabaa#aa###########baa##.##aaa#aca#######.#####aaa#aaabaaaaaabaaaacbaaaaaaabaaaabcbaabaa##aaabaaaaabaaaa###.cjgcbbbadiib##aaaaa####aaabbaaaaabdhlijjiiihfefcbaabbbbbbababdedfddedccbccdccbccdccccbaa#aaaaababcccdddcccbaaabbaaba#aaaabbaabbaccdddcdefffedeeed..################.######abcbdfbab#a###########################a#a#####aaaaaaaa##aaaa######a##.#a####", +"###aaaaabcbabccccdcddcccccbbccebaaaa##############a#a####aaa##abb##############aabaaababaaabaaaabbaaaaaaaaaaaaaabbcbabbaabaaaaaaaaaaaa####.afhdbbaabfihb.#aa###aa###aaba#aaacclljjiijigddecbaabccbabbbdbadcbeffffeffgghhhighgfhgffcaaababdbbbbcfddddcbbbbbccabaaaaaaababddehggfegjiedaaaa#a####a##############.######bcdcddbaaa##a###################a#a#####aa####aaaa#aaa#a########a#######aaa", +"aa##aaaabaaabbbdddccdbcddcccccdd##a#aa##aa########a######aaba###ab##############abaaaaacbaaaabaaaaaaaaaaaaaabbaabbaccbaaaaaaaaaaaaaa#########bfgbaabbdije.######aa#abbaaaaaaabellkkkkllkiiigfdcdcbabbcbcdcbcgijkjhhhhijjic#dcbcbddghffeeeihiggfgddedcccbcdcdcbcbcbabadeeffghhhebegdddb#########a#a####################babbbcbbb##a##################aa##a####aa#a###aa#a#aaa##a#######aaaaa##aa#", +"a#aaaaabaaaaaabcdcceccefcadgeceebba###a#aaa########a#####aabaa#aabda########a####aaaaaaabbaaaabaaaaaabbaaaabbbbaaaaaabbcbaaaabaaaaaaa#aa######.eiebbbbcfihc#.###abaaa#aa##aaaabellkjlkjklmnnmlkgfccbbdddeefghjijkkllkhd#cfeabcbbcbbdgjjhgecccehieeededccceeedddddefcdffcedbacdec#bbaba#########aaaba#########.#######aaaacccdbbaa####################aa##a####aaaaa#aaaaa#a####aa######aa#aa##aa", +"a#aaaabaaaaaaaabcccdddggedbdfccecaaa###aaba#a#######aa#.##aabba#aabc###########aaaaabcbaaaabaabaabbbabaaaaaabbcccaaaabbbbbbaaabaaaaaa#aa#aba###.bigbbbccdilid.##aaaaaa####aabbbcekmljgdfiijikmlmnkgdeefeeegieeddgdcghgdbabcfdebcccceffggfcbbbbbcefgedddcceeefdedcbccefgb####babedcaa##aa#######aabcda##.#############aaaaabcdcdbaa#########a########a###a###aabbbbaa#aa#aaaaa##aa######aaa##aaa#", +"##aaaaabbaaaaaaabcdceeffedccfgedcaaa##aaaa###a#a#####aa..##abaaaabbd#########aaaaa#a#bbbbbbaaaaaaabbbbbaaaaaabccbbaaabaabbbbab#aaaaaaaaa#aaaaa###ahibbcdccgjkg####a#aa####aabbcddegkhddgihhghiibdilmljjjjiiihfaaa##aeeedcbbdghfdbbdfedfedccbbbbdbffhfededeefhhfc#####cea#####aaabdfda.a######.##abdfb##########.###a##aaaabadefecb#a##########aaa####a##aa####acbbbaa##aaaaaaaaaaa#####a######a#", +"a##aaaaaabaaaaaabacddeddfdccefffd#aaaaabbaa#a#####a#.aaa###aaaa#abbdb########aaaaba#aaaaababbaabbbbbbbbbaaaaaaa#abcbaaababbbbcb#aa#abaaa###########fhdcccdcehihb###aa######a#bccdefggiglkjjhiihba#cglkjhiihgebcaaaaaa#aacdbbdefhfdbbeedbccbbbabdcbgjifefedeggfgfa#aa#a.aa######aaaacffba####.###abdeca######a###########aabbegffgedaaa##########aa####a##aaa#####aaaab#aaa##aaa#aa######a#######", +"##aaaaa#aaaaaaaaabbcdddceddeeecdfbaaaaabbbaa#####ab#########aaaaaabbc########aababbaaaaaaaabbbaaaabcbbabbaaabaaaaaaabbbbaaabaabbbcaaaaaaa##########.bhfcccdddefigc#abaa#aaaaaacccdegeiihkihhjhbbaa#.#a##a#..##aaaaaaaaaaaacaabaacefedefbbedcbaccdbcfgiihhfdec.addb#ba###aa######aaaaadgeca#######aceaaa#################aaabdgeeghffb########a######aa####abaa#####a#aaaaaaa#aa###a#.######aaaa#", +"a##a####aa#aaaaaaabccbccdedefebbef#baaaaaabaa#####a#aaa####aaa##aaaada########aaabbbaaaaabbaaaaccbbcabbbbaaaabaaaaaaaabbbbabbbbaabcb#a##a#########a##bifdccdddefgjeaaabaaaa##accbbcddfhehijhdb#aaaaa#a####a#abaa#aa##aa#aaaaaabbbaabefigffefdbcccdcbaacbbdhhfeaacbabb##a##########aaaaadhgb#####aabecaa########a###########baegfefgfeca##a#######a##aaaaa#aaaaa####aa#aabbaa#aaa###a#.#####a#aaa", +"#aa#####a#a#aaaaaaacccbbccdcdedbcfcaaabbbaaaaa####a###a###abdb####aaeda######a#aa#aabbbabbaaaaacddbaaaaabaaaaaaabcbaabbbaabbbbbbababa####aa###aaa#####dihecccdedeejgaabcbaaaaabcbbbcdeheggeabaaa####aa########aa###aaaaaaaaaaaaaaccbaabdegedddddddccbbbba#abaabcbbaaaa##a##.#.#####a#a#abefb#####abdfaaa#####aaaa#a########aaadfeeffffc#######a######aa#aaaaaaa#aa##aa#aaabaaaaaa#######.###a#aa", +"aaaaaa#aaaaaabaaaaabbcbbabbbcceedffdbaabcaaaa##abaa##aa###acefa####abdaa###.####a##aabbbcbcbaaaaabba##aaabaaaabaabbbaabbbaabbbbabbcbba#a##aa###aaa#####bhjgccdddefdhheabbaaababcbbabcdehfcaaaaaaaaa#aaaa#######aa###a##aaaaaabcdaabbbbabbbefedeccddcbbbaababbbcccca#a####aa#############aaceda###aabfebaa####aaaaa##########aaadefedegca########aaa##aaa#aaaaaaa##aaa##aaaaaaa#bcba#########aa##", +"#aaa#aaa#aaaababcbbbbccbaaabbbbdgffgbaabbbaaaa#aaa####a##abbgea##aa##bca#########a#a#bcbabbbbaaaaaaaa##aabaababbbaabaabbbbbbbbbaaaabbaa##a#####aaa######adhidddddfhdfigbcba#aaaaaaaacbcfdabaaaaaa#aaaaaaa#######bb#####aaa##aabccaaabdcaaaeeefeddefcbbbbaaaabcbbbcdba#####a####..#######a##abdb#aabcefdaa####a#aaaaa#######aaaaaabacefc#########a###aaaaaa##aaaaaaaaaaaaabaaaa##aaaa###.#####aa#", +"#############aabaaaabcbbaaaabbcceeeeeaaabbaa##a###ab#####abddb#####a##cb#######aa#a##aabbbbbbbaaaaabaaa##bbabbbaaabaabbbacbcbbbcbbbbaaa###a######aa##a#baaagkecdeegfeehfcbba##aaaaaaaaccdcbaccbaaaa#aaa##aaa#########a##a###aaabcaaaadeddbbdcdeigfdbcccbaa##cbabcbcdaaa####aaa######.######aa#debaacfdcaa#####aaaabaa########a##aabccdd#############aaaaaaa###aaaaaaaaaaaaaa###aaaaaa#########aa", +"#############aabbbcbbccbaaaabbccddeedca#abaaa#aa###a##.##aaaa#######aaaca############aaaaaabaabaaaaaa##a#aaaaabbaaaaabbbabbbcbbccbccbaba##########a##aaabaabejfddddehddhgdbbba##aaaaabbbcccaabaaaaa#a#a##a#aaa###############aabcaaaaaegeddcecacdghfdccbaaa#cbabcbac#######bba#################bcdcbeebaaa###aaaa#aa#a###a####abaabdcdcba#a##a####aa###aaaaa##aaaa#aaaaaaaaaaa#aaa##aa#########a", +"aca##########a#aaabdbcccbaaaabbccddeedbaaaaaa#aa#########abca#######a#aca############aaaaaaaaaaaaaaaaaaaaaaaaabbabaabbbbbabbbcbbbbcabbbba##########aa###aabbbeidbbccehefhhcbbaaa#aaabbaaabbcaaa#abcaaaaaaaaaaaaa#####.########aaabaacbedfdbbbdccccfhebaabaaa##a#acaba######daa###.######a####aa##acfdfdaa####aaaaaaaa###aca#aaaabaabccdeaaa###aa#aaaa##a#aaaaaa#abaaaaaaaabaaa##############.aab", +"aa#bb#####.######aaabcccbbaaaabbbcddeebaaaa########.#####abca##########abaa####a#####aaaaaaaaaaaaaa#aaaaaaaaabcbbaaaaaaaabbbbbbbbbccabbaa#a#########a#####aaaachdbccdefehgiebbbaaaaabaaabccacbaaaacbaaaaaaa#aaaaaa#############a#baaaaceddbaabcbebbefdcaaaaa###ba#baa#####.aba##############a#a##aacfghdcaaaa#abaaaaaa######acbababbbdbaa###aaa#aaaa#a#aa#aa#aa##abaaaaaaabaaaaa##############ba", +"a#aa#a#####.###a#aaabbcccbbbaabbbccccge#aa#######.#######abbba#######aaabbaa####bba###aaaaaaaaaaaaa#######aaaaabbbbabaabbaabbbbcbbbcbabbbaaa#a##a##########aaaabeccccddfgefhgaccaa#abbabbbbabbbba#aa#aaaaaaaaaaaaa#######a#####aaaaaabacdccabbbcecaacdfecbbaaaa#aaabaaa#####aa########aaab####a###aabeggbaaaaaaaaaaaaa#a##a###aaaabcccccaa###aaaaaaa#aa#aaaaaaaa#abaaaabaaaaaaa#a###########a#aa", +"###aaaa###a######aaaacccbbbbbbbabccccehb#a########..#####abbca#######aaaacaa####cca###aaaaaaaaaaaaa#######aaaabaaaacdbaaabbbbbbbaabbbbcbccaa############a#aaaaabaccbdccegeccffbbaa######.#abaabbbaaaaaaaa#aaa#aaaaaaa#a##########aaaabbcc#abbabaabaddcbceebbba#aaaaaba######a############aba###a##aaaccggbaaaaaaabaaaaabaaaaa#a#bbabbccdb#aa###aa#aa#aaa#a#aaabaaaaab###abbabaaa###a#a########aa", +"###aa#a######.######aacccbbbbbabbbccccfheaaaa#############bbcaa#######aaabcaa#####aa####aaaaaabaaaaa#aaa##aaabaaaaaacdcbaabcbbcbbbabbaabbbbca#a######aaa##a##a#aaacabccdeggacge.#aa####a#baaaabbabaaaaababbaaaaaaaaaaaa#########aaaaaaabda#aaabbbacbcdbbcdeca#a#aaaaa#a#aa#aa#############aa#####a#aaabcfgcabaaaaabaaaa#aaa#####babbbcccc##aa#a#aa#aaaa###aa#aaaaaaaaaaa#aabbaaaa###a#a#####abba", +"###aa##aa##########a#acbcccbbbbbbbbbcceffebaa#############accbaaa######a#bdcaaa####aa##aaaaaaaaabaaaaaaaa#abbbaaaababcddccbcccccbaabaaabbbbbca####a######aaaaa##a##bbabcbdgefeed########a#a###ab#aabbbaaaaaaaaaaabaaabba#####a#.#a##aaaabca##abbbaccbbdcbcdedb#aaaaabaaa###aaa#########aa#aaaaaaaaaaaaabceecc##aaaaaa#a#aa########abbacccc##aaa#aa##aaaa###aabaaaaabaaaaaaabaaaa####aa#####a#a#a", +"b###aaaaa#######.##a##abbdcbaabbbbaabccdegea########a#####abcbba###aa####acccaa######a#####aaaacbbbabbccbbaaccaaaaabbbcccbcbccbbaaaababaaaaabc###a#aa#####a#aa#a#aabdaaacbbafhgbfa.#####aaaaaaaaa#aabaaaaaaaaaaaabbbaaba###a###########baba##aaaabacaabccbccdeeaaaa#aaab####.########.##aabbbaaaaaaaaaaabccaccba##abbaa###a##a###a#aabbccca#aaa#a#abaaaaaaaaacaaaa#aaaabbaaaaa#aaaa#a#######a##a", +"baabaa#######aaa#####aabbccbbaaabbaaabccdfeba#######aaa###abcabbaa##aaa####ddbaa######a###aaaaaaaaaabbcbbbbbccaaaaaabbbbbcccccbbbaaaaaaaaaa#abca##a#aaaaaa##aaaaaaabcaaaabaabgicce##.#a##aa#a#aaaaabaccbaabaaaaaaaaabbbaaa#aabb##########aa#aaaaaaaaaaabccccddfebaaaaabbaa################bbbbbbaaaaaaaabbbc##acbbaaaaaa####a#####aabbbcccb###aaaaaabbaaaa#a##aa####aba#bbaaaaaaabaaa#######a##a", +"baaaaa#######aa#######aabccbabaabbbaabbbcdgdb#a########a##abdbbaaaa##aaa##abdcbaa#############aaaabbbbbbbbbabccaaaaaaaacbbbcccbccccbbaaaaaaaabbca#aaa#a#aaaaaacbabaa#aaaaaccbbjgabc###bb######abaaabbcccbabbbaaaaaaaaaaaaa##aaaaaa#######aa###aabcbaaaabbbccdeeefebaccbbbbb#.####a####.###abaabbbbbcbaa#aaabca.##acccbaaaa########aaababbcba##abaaaaaaaaaaaaaaaa#aaa#baaababa#bbaaaaaaa#######aa", +"aa##aaa###############a#abcbabbaaaabaabbbcffcaa##aa##aaaa#abbbbaaaaaaa##a##abdbaa##############aaaaabbaacbabbbcaaaaaaaabbbaaabacbccbbbaaa#aaa#aabb#aaaaaaaaaaabbbbaaaa##aabbbadiabbc.##c#######aaaaaabbccbbabbaaababaaaaaaaaaa##aa#######a#####aabbaaaabcbbbcddcefhgceeaabba##############abbbbbbcbaa###.###aca####aacdba#a#a######aaaabbcbbaa##aaaaaaaaaaaa#aaaaaaaaaaaaaa#bababaaaabaaaaaaa#ab", +"cb####aa################abcbbbaaaaabbaabbbdgdb##a#aa#aaaaa#abaabaaa#bba####aaddba#######a#########a#abbaaccccccbaaaaabaabccbbabaabcbbbbaaa#aa###acda####aaaabaaabbcbbaaaaa#bcbcebbccd#.aba######aaa#a#acbaaabbbbbaaabbdbbca##ba###abc.#.####.##a#bbaaaaaaccccdecdefghgfccccb#.####.#...###aaaabbabddba###...##bb#####a#bcba##########aaabbccaa###aaaaaaaaaaaaa##a#aa#aaaaaaaa##ababbaabaaaaaaaab", +"ec##########a##aa#.#####abbcbbaaa#aa#ababccfffcaaa#aabaaaaaabbaaaaa#aba###aabbfdaa###.#############a#aaabbccbbccaabbaabbbbbbbbabaaabbbbbaaa#a###aacdba##aa#abbacbbcbbbaabaaabbceabccde.#c#aa######aaa#aaa#aaababbabaabbdefecd#aaaaaaec#.#########aaaaaa#aacdcbdbabdfegddffdba##.#.###.###aabbbbabbccbba###.#.##bc#######abbba########aaabbbddcaa##aaa##aaaaaaaaaa#aaa#aaaa#aaaaaababaabbaaaa##ab", +"bca######.#####aa#######abbbbac#a##aa##abcdcehfaaaabbbaa#abcbbbaaa#aaba#####acegdaa####.############aaaaabbbbccccbabababcbbbbbaabbcbbabaa##aaa###aacebba###bffcdbcbbcbbcaaaabbbhbabbcee.##aa##aaa#acaabbaaaaaaabccaaaaaabdefge##aaaacea###########a######abdfdabaaaaababaceeb###.#...#.##aaabbbabbbaabaaa###..##bea###a##a#aca#a#a#####aaababb####aaaa##aaaaaaaaaaaabaaaaa#aaaaaababaaaaaaa###ab", +".#a###########.b########aacaaaacaaaaaaa##acdffgbaaabaaa##aaehdbaaaa#aaaa#####acfgbaa#########.########aaaabbabcdecbaabbabbbbbbbaaababaaaa######a##aaddbaaaaab##a##abccccccbbaabfhaababgd.######aa#aaaaaaaaaaaaabacdddbaaaaaaddeda#aa#ba######..##a########abdcaaaaababcabbbcddb#a###..#.##aaabccbbaaaaa#########abed#########cb#a#a####a#aaaaacb###a#aaa##aaaaaaaaaaaabaa#aaaaabaaaababaaa######", +"#########aaa###a########abbaaaaaaa#a#aaaaaacdegeaabaaccbaa#acefcaa###aabba###aadfdbbaa####.#############ababaaabcccaaaaabbbbbbbabaaabbbbaaa#####aaaabdeaabbba########aabdedcbabbffaababhd########a#aaaaaaaaaaaaaaacedbabaaba#bfggcaaa#########..#.########aabcb#aaaaaabaababccddba#..##.####aaabbaaaaaa##...#####acecb########abba#aa#a#aaaaabbca##aa#aa#aabbaaaaaaaaaaaaaaaaaaabaaaaaabaaa#aa##", +"##########aa###a#####aaaaaaa##aaaacc#a###aabbcefbabbcfcddddbabgfa#a#aaaadbaa##abdedcaaaaaa#############a#aaaabbbbaacbbabbaabbaaababbaabababa##a##aaaaaccbbbb########.###abbacdcccgbabbbcida####aa#a#baaaaaaaa##aaabccaaaaaacbbabggb#a#####aa##..##aa######aabbcbaaaaaaaba#aabbcccca#.########aaaaaaaaa###...#######abdec########abb#aaaaaaaaaaabcbaaa#####aabbbb#aaaaaa#abba#aaaaaabaaaaaaaaabb#", +"###########aaaaba###aaaaaa####aaabdebca###aabbcfgfbacdccdeheaadgea###a##dcabaaaabdedcbaa##################aaaaabbbccbaabcbaabbbbabbabbbaaabaa#####aa#abddbcb##a########a##.##accdeedbcccejcbaa####aaaaaa#a#aaaa###aabbbbaa#bdbb#chfa####a########.###########babbaaaaaabaa#aaaaabbcdc#..######aa#aaaaaa###.#..#####a#abdeba#######bbbbaaa#aaaaaabcca#aaaa#aaaabbbaabaaaaaaaba#aa#bbaabbaaaa#####", +"######a##a###a#aaaaa#aabaaa##aaacddbbcaa##aaaabdifdadeeddfffaabdddbaaaaabd#aaaaaacfedcaa#################aa###aaaacccbbabbbbaaabbbbbbbbbaaaaa######a#aaacdddaaa#########a######aabbicceedghcbb##aa#aaaaaa#aaa#a####aaabbaa#adffbafgd####aa###################aaaaaaaaaaaaa#ababaaabbbcb#.####aaaa#a#a#a##..########a#aabbcdd#.###a##bbaaaaaaaaabbbbba######aaaacbb#abaaabaa#a#aaaabaabbbabaa####", +"######aaaaa####aaaaba#abaaa###a#bddccaaa######abcfgghhhfdfffcacbabdecca#bca#aba##aeffeba##############.########aaaaccbbbabcbbbaaaababbbbbbbaaaa######aaaabeeaa#aaa######a###a#aaaabfgdbbddhhccb###aaaaaabaaa###aa##aaaaaaaa#bffgd#cda##a#a######a#a###########aaaa#aaaaabb#abaaaa#aaaabbca####aa#aaaa####.#############aaabcdc#####a#abba###aaabababc#aaa##aaabcaaaaabaaaaaaacaaaabaabbbbbaaa###", +"a######aaaa##a#aabbaaaaacba##a##acccddbaa#a##aaaaacccdefefefdacaaaacgebcdb#a##aacbbegfdba#aba##############aa###aaabcdbccbbabcbbbbbbbaabbabaaa###a###aaaabcdb#baa#a###########aaabddgcdcbbcfidbcb#aaaaabaaa#a#a#abaa###a#aa##dfffeaa#####a#####aa##b.######.###aaaaaaaaaacbacaabaaaa#aaaacccaa####################a########abceca###aa#abaa#aaabaaaacda#aa###aacaaaaaabaaa#aaabaaaacbbbbacaaaaaa", +"aa##a###aaaa#a##aaaaabbbbbbba####bbbacbaaaa##aaaaaabccbdedcefaccaaa#accccaa##aaabcddfgefeeffea################aaaaaabbcbcbbcbabbbaabbaacaaaa#a#######a#aaaacfcaaa##a############aacdee#a####eifccc#aaa#ccaa###aaa#ba###a###a#befffd######aaab###aa############aaaaaaaaaabbcbcdbbaa###abbaaabccdca...#######aa#a####a######aaaabcdc######aaaaaaaaaaabbcdbaaa##aababaa##aabaaaaaabaa#abbbbaaba#aaa", +"#aaaaa##a#.###a#aaaaaceccbbbab##aaaaaaaaaba#aaaa#aaabccbcdddgfdaaaa######aa##a#aaaeggihgeefeddeca###############aaaaababcbbbbaabaaaaabacbaaa##a#####ba#aaabadgeaa#a##a####a##a##aabbeeaa#####bhibaca##aadbaaaaaca###########aadfddfda###abaabb#aaba#####a######baa#aaaa#abdc#bccbaaaa###ba#aaabdfeec#########aa#aaaa####aa#aaaaabde###a###aaaaba#aaaabbccbaaaaaaaaaa#a#aaabaaabbaaaababbbbaabaaa", +"##aa####a#####aaaaabcccbbbcbbaa##aaaaaaaaabb#baa##aaabbcccdefgiecbaaa##aabba###a#affghihfccdddddeca################aaabaaaabaaaaaaaaa#aaaabaa########aaaabaabcgcaaaadda#aa#######aacdde#######aegbbdbaa#adbbaabcaa#aa#########acfeeecaaaaaaaabbaaaba###########aaaaaaaaabddfbaaababaaaaaaa##aba#acefgca###aa#####abb######aaaaaaabcfa##a###aaaabdaaaabbbbdb###aa#aaaaaaaaaabcbbbbbbabaabbbbbbaa#", +"####aaaa#a#####aaabccccbaabcbcca##aaababbabbabaaaaaabcccbacddefffdccabccdedaaaabdeeffgggeccddccdcdca#a##############aaacaaaabaabaaaaaaaaaaaaaaaa###aa###aaaaacdgcaaabaaa#######a##abdchaa######.cfcbcb#a.bffcbbbab###aaaa###a###ceedddabcbaaaabbabbaaaa##..#####aa##aaaa#acecbbcbaaaaabaaaa##aba#aecbccdcabaaa##abbaa#a##aaaa##aaaabdd##aa##aaa#aaababbbbbdb#a##aabaaaaaaaaaaaaabbbbbbcbbbbcbbaa", +"aaabaaaa####aaaacccbbcbbbaaaabdaaaaabcaabcbbbbbaa##abcddcbcdefedffedbdccdeec#aafffdddeffcccbcdcccccccaa#############aaaab##aacaaaaaaaaaaaaaaaaaaa###aba#aaababdefaaaaaaa##a###aaaaabccgcaa#######bgcdeca##bhgbabaac##a#aaa##a###befddfdddbddbaacabbbbaa####.#######a#aaaaaacbaabbbaa##ababa##aa##acaaaabbcb#aa#a#aaa##aa#####a#a#aaaabeca#aaaaaaaaabaabbbbbdb#aaa#abaaaaaaaaaaaaaaaaaabcbaababaa", +"aaaaaa#aa#####abbbcbbabcccbbaaabbccccdbabccbbbbbaaabbcddcbceeeddeggddfbcdeec###dffedddeddcccedccccbbcdb#################aa#aaabaaaa#baabaaa#aaa######aaaaaaaabbcdfaaaaaaa#a####a#aaaabge##########bhcbccaabdeeaaaa###a###aaaaaabceedefeeedeeccabbabcbbaaaaa##.#.#######aaaabbb#aaaaaaaaaabaa##a##aaa#acbcabca###aa####aa#########a##aaaedb#abaaaaaaabbabababccb#aaaaba#aaaaaaaaaaaaaaaaabbbbbaaa", +"aaabaaaaaa###aaabbbbbaaaacbbbbbcccddefdaabbbbccbbbbabbccbcdddddeeeffefcedffedbabeeecddcbcccbdbbbabbbabba#aaaaa##a######aa#a##aaaaa#a##aaaaaaaaa###aa##aa###aaabbdedaaaaab#a####aaaaabbgha#a########becaccdfgddda#aa#aaaabaaa#a#addeecdcdfeeeddcacbbbcbbaaaaaa###########aabacbaaaaabaaba#baba#aa##bbbdbacaabcb##aaaaaaaaaa#########a#aaabddbaaaaababbbbbaaabcccbabaaaabaaaaaaaaaabaaabaaaabbbbaa", +"abbabbaaaaaaaaaaaabbabaaaaabbcbbcdedfggccbaaabbbbccccbccddeddccdddcddecddeffddecddccacbaacbbbbaabaabaaaaaaaaaaaaaba####a###ba#ba#aa#####aa#aaaaa############aabbcdebbbaaaa########ababdhf#a#########afecfffebceaa###aaa#aaaaa##abeeddddeegffdcfdbbabcccbaaaaba###########aaaabaaaabbaaabbbaabbaaaaacdcaacaaaabca##aaa#aa#aa#aa#######aaaaacee#bbaababbbbbbbbbccdcaaaabbaaaabbbaaaaaaaaaabaaaaaab", +"babbaaabaaa#aaa#aaaaaaaaaaaabbbbcdbadccdbbbaabbbbbcbbccdeeedeabcccccccccdeedfddcccdbcbaaaaaaabbbaaaaaaaaaccaaa#aa##aaaabbaab#a####aa####aa##aaa###############abcdedbcba#####aaaa#aabbdhie.#####a#####fgffececeda###aaa#aaaaaa#cddecddcddefeegefeccbccccbaa##aaa#.#####.##aaaabaa#aaaaa#aab#bcccbbccbbaab#aaaabcbbaa#aaaa#a#a######aaa##aaabdfdbbbbabbbbbbbbbbccccaaaaaaaaaaabbbbbaaaaaaaaaaba#b", +"bbaaabbaaaaaaaaaaabaabbbaaaabbabcedcbbabccaaaaabbbaabbceffcccbbcbbbbbbbbddcdddbbbabbbbaa####aaabaaaaa##aacfeaa######a##aaabbbaaa##aa#a#####bcca#a##aab##aaa#aaaacccgdbbb#######aaaaabbbdhhb###########aeifddbbceda#aaa##aaabaabefffcdddccdeeeedeffefeddccbaa##aaa###.###..aa##aba##aaa#aaabaaabccddcccaabaababaabcca###aa#aaaaa####aa#####aaacffbbbbbbbbbbbbbbbbcdcaaaabbaaaaaabbaacbaaaaaabbbab", +"babbbabbaaaaaaaaaaaaabbbaaaaabbbceddcbaaabbbbbaaaaaaabcdffdcabbccbbaaaabbbbbbbbaaaaaabaaa#a##aaaaaaa####aadd######a########abbaaaa##a#####a#aa########aaaaaa#aabbbbdgcaaa###aa##aaaaabadfgb######aa###aadidcdbaceca#aaaaaa#abcdeeeccdeddccddeadeefffffffecbaba#######.###.##aa#abaaaaaaaaabcaaabaabcbd#abaabbbbaaabdba#a#a##a###aaaa#########aacefdbbbbbbbbbbbbcbcccaaaabaaabbaabaaccaaabbaabbaa", +"baababbbbabaaaa#a##aaabbbaaaaabccehdbaaaaaaabbaaaa##aabdgieccccbcbaaaaabaaaaaaaaaabaaaaaaaaabaaaaa###a###aaa################aaaaaacba######a#a##########aaaa#abbbbbcdhb##a####aaaaaaaacbfe.##aaaaa#####aadhcbbaaefbdb##aaccddfgedbddccccbbcdedceceggfeefefdcbaaaa#####.###.###aaaaaaaaa##aba#aaaaababdb#aa#aaabaa###bcbaa#######aa#############abdffcabbbabbcbbcbcbcdcbbaaabbbbbbbaacabaaaaaaaaa", +"bbbbabbbbbbbaaaaabdcabdcaaaaaabbcdffcbaabaaabbbaaaaa##bcgjfbbbcdddcbbbbbbbbbaaabaabbbaaaaaaaaaaaba#########a#a###############aaaaaabaa#######a######aa#a##aaaabcbabbcceda#aaaaaaaaaaabbbec.a#aaaaaaa####aadhcabbbeecbaaadefggfeddcddcccccbccdccdddeghggeeeddcbaaaaa############abbaabaa#aaaaaaaaba#ba#aaaa#abaaaaa##aabbb###aa#a#a##a##########abbcffdcabbcbbbcccbbccccbaaaaaabbbbaabbabaaaaabba", +"bbbbbbbbbbbbbbaaabfdcccbcbaaaaacdceebaa####aaabbbbaa##bdghfcbaaacdddccccccccccbbababbbaaaaaaabbbaa#a##aa#a#b##a#aa###a#######abaa###aaaa##a################aaaaabbbcbbcffaaa#cbaaaaaaaacec.#####aadea##a#aabgdababdfda#adfggeddccccbbbaccbbcbcddddgghigffffbabbaaaa##########ab#aaaaaaaaaaaaa####aaaabaaaaaaaaaa####a##aaca##a######a#########acbbbbcdefdabbaabccbbbbccccbcbaaabbbaaaababaaaabcc", +"bcbbbbbbbbbcbbbbbcecccbaccedaaabddcaaa#######aabcbbbaabdfhfdcaa###acdcabdfeeedcccccbbcbbaaaaaaacbaa###aaaa#aaa#####a#aa##aa###ba###aaaaaaaba############aa#aaaaaaaaaabbbfgaa#adbaaa#aaaaehaa###aa#adea#a#aaabgbabacefdb#dfffedccbbaaaaaaccbbcdecdggihihhfdffcbbaaaa###aa###..#aa####baaabaaaaaa#####aaaaaaaa#aba#a###abaa#cbaa##.##aa####aa##aa#baaaacccefdbbabbcccbbbdccdbaabbbbbbbaaabbaaaaabc", +"cabaabbbbbbcbcccccddb##abaccbabbdbcaa#a##a####aabdcdbbcdddghcbaaa####bcacigggecbbbcbcbbabcaaaaaabaaa#a##abb#########a##aaaaaaaaaa###aaaaaaa########aa##aaaa#####aaaaa#acegfaaa#aac##aaaachfc###aa###aabb###a#bbabccddefdceffedbcaaaaa#aaabbbbcdegihhhhgggdcffecabaaaa##a##.###abca#aaa##aaaaaaaa######a###b###baa####aaaaaaaaabca###############aaaabbbbbbdfebbabcccbcdcbbdcbbaababbabaabaaaabbb", +"febaaaabbbbcdcccccb#####abbabbcccbbaaa####aa#a#abdeccbddeeehgcaa#a#aa#addhifdddbbccbcccbbbbaaaaaababaaa#aaba####a##a#a##aaaa#aaaaa#a##baaaaaaa#####b###aaaaaa##a##aaaabcefihefc##aaaaaabbdha####aaaa#ab######aaaabbccdefegffdcccaa#a##aaaaaabbehhhhffffcddbdcdbbba#ac######..###bb###a#abaaaaaabba#####aaa######a#aa#####a#####bbca###########a##aaabbbaaaabdfdbaccbccbcbbccdcbbbbaaaabaaaaaaabb", +"dedbbbbbbccbcdccddb#####bbbaacccacbaaaa###aaaaaaacfdcbcdegghigbaa#aaaaaadfhgedcccccbbbbbbbbbbbbbbbbaaaaaabbba########aa#aaaa#abaaa####aaaaaa############aaaaaaa###aaaabcfghgihfbcb#abaaabbge####aaaaab######a#aaaaaaccdeeddfdbcbaaa##a##aabaafhgggfedccccdccbaaabaaaaaa#########a#####a##aabaabcaa#aaa#a#####.####a###########a#aaaba##a####a#aba#aaaabbaaaaabdeecccbbcbbccccdcbabaaabbbaaaabbba", +"bccdcbbbcccccbcdfda#####acbabcbaabaaa#a###aa#aabbbefedcdffiihhcaaaaaaaabacfffefedcbbbbbaaaabbbbbbbbcaaaaaabaaa####a###a##aaaaaaaaba#####aabaa###########a#a####a###baabccghfhiieaa##aaaaabdga##a#a#aaaa######aabbaaabbbcddegdcbbaa##aaaaaaabbfedfddecbbbbbbaabbabbaaaaaaaaaa####aa####a#a#aaaabcbaaaaaaaa##############.######a#a#aabbba#a####a#aaaabaaabaaabbabcfedcbbbcbccccccbabbabaaaaabbccb", +"bbccccbbcccccdddeca####aabbccca##aaaa##a#####abbbbeeffeeccfjjifbaabaaabbbcdecdeffdbcbbbaabbbccccbbdcbaaaaa###########a#a#aaaaaba#a######aaabcaaabaa###aa#aaa######acedbcdfihfhifba####aaaadhc###aaa###########a#bbaaabbccccfecaaacca##aaaaaccffdfccedbbab#a#aaaabbaaabababaa###########aaa###bbaa#aaa#abaa##########.########aa####a#aabba#a###a###aaaaabaabaaabbbcdfedbcccbcccccabbbbbbabbbbbbc", +"bcdcbbcccccddddddba####abbbbdca#a###a###aa####aaabcededcbbgiijjhcabbaaaaaccddddcceedddddddeeefedbbcbcccbbbbaaa#a###aaaaa###aaaacaaa##a###a##acca############acaaaaa#abbccdghccggfcaba#aaaacggdaaa###############abbbaabbdeefedbaaaadda##aabbchedeefedbaaab#####aabbaabacbabaaaa########aa#a###aa####aaabba##a##.#############a#a####aaa##abdba#########aabbaabbabbaabdeddcbbbcccccbbbbaabbbccbba", +"bbddccbccdccdcebcbb#####abccbcd######aa##a######abcddcdddeggiihhhdaaaabcccceedccbbcbbccbccdeeeggfeddccdeccbbaaaaaaa#a##aaa###aaaba#a##aa######a#####a######aaaaaaabaaababcehb#adcbdbba#aaabdceaa#################abbbbbacgeeecca###bedcaa#adfhccdffbbbba###a####aaaaabbbbaaaba###aaaa##########aa#.##aaaaa#aa#b######a#######aaaa##aaaa###abcdb######a#aabcbaabaabbaaabcdedbbbcddcbbbbcabbbccbbb", +"bcdfdddcccdddcecbb####a#aabccabaa#####aaaaa#####abbccdedeedcijfggfabaabbbbccddccbbbabaaaaaaaaabbbgihihffedccbbbbbbbba#a#aa####aaaaaaa##aa#######a###aaaa########abaabbbbaccega#cdaaabaaaaabbfea#a#################abbbbbaeedddcbaaabacceccefihdccedcbaa##########aaaaaaabbbaaaa#####aaa##a############aa####aaaa######a#####aa##a##aaa###aaa#a#abc#aa###aabcaaaabbbbbbbbbbcddcbccddcbbbbabcccdcc", +"ccbcffhfdddddccadbaa#####aabbaaba##########a##aaabbaacdddfeehjifgha#aabcbacddccbbbbbabbaaa#aabcccefgdddeffeecdedbbbbcba###aa####a##aaaaa##a###aa###aba#aa######a#aaabbba#abbfcbcccccbaaa#abbfjg#aa###########aaabbaaabbcbdedcdbbaaabbbcceghhiiedcedbbaa######a###aaaa#abaaaaaaaa##aaa##a##############aa####aaaaa#####ab#####aa##a###aa#aa#a#####aaaa##aaaaabbbbabbbbbbbbbbbbdddccddccbcbbbcccdd", +"eecbdggfdddedcacda####a###abbaaca######aa##aaa#aabcababcdeeedgigdfgbbcbbbbbcccbbbbbaaaaaaaaaccddddefdecccbbcbbddcbccddedcaaa#a#aa##########a########adbaa#########aabbbcbcabbdcdcbbbcbaa##abbfiaaa##############baaabbbbccedcccbaa#abbbbbefgihfdcccbaaaa###a######aaba#abaaaaaabaa#aaaaaa######...#a#.#####aa#aaaa########a##aaa###a###aa#aa#aaaa#aabbabaaaaabcbbbbbbbbbbbbbbbccdeddcccbdccccdde", +"eedfhhfcba#abb##a#####a#aabcaaccbc#####a#aa#aa###ccbbbabcdfffhgifehfebbbabbcccbbbbbbbbaaaa#ccdcddfghfeccccbbbbabcddegcbccdcaaaaaa###a###a######a#a##accba#########aaaabbccbbcbcehb###cbba##bdehe###############aa##aabbbccdcbccba##aacccbcceffedcbbaaa#####a######aaba##aaaa#ababcbbbbcbaa########.#.##a####a####aa######aaa###aa####a###a##a#aaa####aaadbbaaacccbbbbbbccbcbcccbcceeeeededcdbccd", +"dgghigdb##a#a########baaa#abbcbdbbb#####aa#aaaaaaabaababcdegiihdggffdcbaabbbbabbbbbabaaaaa#ccdccdegedccbbbbbbcbbbbaadbabaacdb###aa###############aaaab#aa##a#######aaaaababbbabbfieaaaa#aaa#chke.#########..#aaaaaaaaababbccbbcbaa#aabbcbabcdeedcba###a#####a#a##.###baabbaaaaaaaabbaaba#########....#.#######ab#a#######a######a#########a##aabba###aaabbbbbbacdcbbbbcbcccccbdddeededegeddddcdc", +"dhghhfa##a######a######aabaacccedaaa#######aaaaaaaababbbccdghgfedgfgcabaaaaaaabababaabaaaaabdcceeeecdbbbababbbbccbbbbbabdbabcba#a############aa##aaaaab#aa###########aababcbbaabeggh######aaagj##############aa#####abbaabbbbbabbbabcabbaaaabcddccba#######.###########ccaaa###aa##aaaa###a###..##....#.aa##a############aaa#####a#####a###aaa#aaaa#aaacaabbbbbbeccccbbccddccdegghhgfeegd#bddccc", +"ffhhhe###########a#####b#bcadddcbaaaa#####abcca#aaaaaaaaabdhihgddfgfgcaaaaaaabbbabbbaabaaaabedcefecbbbbbbabbbaaabbacdca#aaa#bbdb#aaa#########aa####aa#a###a#####.###aaaaadbbaabaddcggbaaaa#bbdia#a##########aaa###aaabaaaabbbbbbaacefebaa#aaaabcccbaaaa###########.#.##ad#####.##aaa#aa#aa#####...#...###ab#ba######a###a##ab#####a###aaa##aa#aaaaaaaabbbbbbbbbbceddeeccbccccddfhijjhggghb#bba##", +"#afhgcaa###########a#a##aabcddca###aa######abbbabaaaaabaaaeiiihgbbgeddaaaaaaaaabbaabbbaaaaabdcccddddccabbbbacaaaaabbbaaabaa##acdd###a######..a#a#####a#aa##a########a##aaecb#abbbcccfgaaaaaaaeia#a#a##############aabbaaaababbababdgeca####aaaaabcbbba#####a####.#######da##############aaaa#######.##.#.#ba########.#a#aa##abba##aa#aa#aa###aaaaaaaaaabbbbbcbccccefgeeccbccbbbbdfiihgggeb#aaaa#", +"##bhgd###############ab#ababcdd###aaaa####aaaaaaaaababaaaadhhigebabfddcaaaaaaaaaaaabaaaaaaabcbbbcbbcecbbbabbbaaaabbaaaaaba###abadea#########.#a##########aa#a###a###a####aabbabbaadccghbbbaaabfi#a##a###aa####a##a#aaabaaaaaaaabbacfdba##a#aaa#aaaabbb######a######.##a#######aa#a##a#a####aa#####a#.#a####aa#########aaaaa##aaa###aa#aaaaa#aaaaabaaaabcbbbbccccceeceeeefedddcbbceeffhgfebaa####", +"##.dhdb#########ab###bdababaddc######a###.#a######aabacaaaadghfdbbabecdba###aaa#aaaaccabaaacababbbbbbbcbcbbcbaaaaababaaaba####abbcfbaa#aaa###.###ab#####aaaa##a######aa#ba#aabbbabdcabefbcaababhe#a##aa##aa###a#####aabba#aaaaabbbefcba###aaaa#aaaaaaaa#########a#.##############aa#bb#aaa##a####.###########aaaaa#######aaaa###a####a##aabaabaaaaaaaaaabbbcccddebbbbdedefdcccccbceeghgfdaaba#aa", +"aa#aeea##########c####ba###aca#####aba#############abcabaa#acdefccbacdbdc##aaaaa###aabdbaaabbcccbbbbbbbccbabcabaabbabbaaaaa###addbcdba#a################a####aaaa#aaaaaaaa#aaacbabdcbbbehca#abbeh#aa######aa######aa#aacfbaaaaaabbdgdbaa###aaaa#aaaa########.###aa#a.###########aaa#bbaaaaaa####a#.##.#######aba#####a#############a#aaaaabbba#bbbbaaaaabbcddddddbaabcedccbaadfdcceeggdbaaaaaaa#", +"aa##ada#a########aaaa###a###a######abaa#########aa#abbbaaaabbcddeeebcdbabb#aaaaaa####aaaabcccbccbaabbbabccbaaaaaaaabbaaaaaaa##aabcccfeb##############a####ab#aaa##aaabbaacababaaaabcdbccffc##abeh.##aa###a#########aaaaacbabaaaccddfgdbaaa##aaaaaaa#######.##.#######.#########aaabaab########a#a##.#########aaa#####aa##a#aa###bdaaba#aa#aabaaaabbbabbbbcddefecbcbaabbdcbaabcecccefgcaaaaaaaaa#", +"aaa#aaaa#aaaaa#####aaaaaa###########a#####a##ab#a##aacabaaabcccbdhedfdbbabc#aaaaaaaba##aaaeheaaaaaaabbbacddbbaaabbbaaaaaaabc#aa#a###cfgb#a#########aa###aaaccaaaaaaaacbabcdaacbaaabcddcccgfcaabeg.#a#aa#a###aaaa####aaaaabaaaaaaceefhfdbaa###aaaaaa########.####.###.####.####aa#abcbaaa####aaa#############aaaaaaaa#aaaa#ba#babffb#acb#aaaabaaabbccabbcccfgdaa##bcbbaaacbcbacebbbcddbbaaa#a####", +"accccedaa#aa#aaa##a#aabda#################a#a#a##aaaabbbabbcccdcccfcfecbaaceca#aacdbcccba#ahgabaaaaababbbccccbaabbbbbbbaaabcb###aca#aabcc##a##########a###a#abaaa#aaabbddddbbbcbaaaaabcdddhecccg######ba#a##.#a###aaceca#cbaaaaacdefhgfcaaa#aaaabba#########..#####...#.#######aaabccbaaa####aa########.####abb##aa#aaa#a#ba#abbefba##bbbaaaaaabbccc#ccddeffcaaaa#baaaaabebbbbcbbbbcbbbbbaa##a##", +"#abeeebaaa###aa###aa###aaa###################aa###a#aabbbbcddddccefegfcca#adhbaacccaaabcbcdecaaa##aaacabdabdcbaabbabbaaababbcb#aabb#aa##dea##aa#######aaa##a##aabaaaacacdfebbbbbbabccccfeddfgfed...#a##aa###########acdbabbb#aa#acddegfecbaaaaaaabaa#########...#####.#########a#abbbabba##aa#####.##....#####a##aaaaaaaa#baaaceeebaaaaeedbbbabbbccb#cedddcccbaaaaaaabaa#bebbbbbbbbbbbbbaaaa####", +"##aadba#aa##a#######abbda################a#######aaaa#ababccdeeddffhhgccbaabefdbbaaa#aabcbbabca#aaaababbbbcccbaaacaabaaabaaaabbaaaab#aaaaefaaaaaaa#.###a#a#a######bbbaabccabbdcbabbcbcdbbaaaefeiiffa####a#######a##aaaaabbcba#baabdddefffdcaaaaaaaaaa##########...##############aabbbbbdabaaa###.....########aaaaaaaaaaaaabcccbdfebaaaaaacfdccbcddc##baabcbabaaaaaaaaabaaaedbcbcccccbbccbaaaaaaa", +"a##aba#a####.######a##bgb#######a########aa#######aaa##aabbcceedddeghiebaaabccebaaaaaaaabaabaaabbaaabbaaabbbbbaaabbaaaaaaaaabbccbbcba#####cfebbabbbacaaaaaa#aaaa###acbbbbbbbbcbaabbbccbaaab#.aceffdfghfa#a####aa#aa##acbacbbbaaaaabcedcddedbaaabaaaaaa#######..#.################aabccccdbbb####.#..#..#.#..########aa#aaa#aaabdddbcababbbdeddedeeb####aaaaaa#ba#aababcbbbaeccbcbcbcbbbbaaaa###a", +"ba#a#####a#############cb#########aa##a###a####ab#aabaaaabbbbedcdccehihcbbbbbbccaaa#a#aaaaabbaaaabbbcbbaaabbbccaaabbaaaaaaaaaabbbbacda####aaedbaaabddba#aaab###aa####aaddcceebabbbcbcdca#aaba#aaabaabfmka##aabaaaaaa#abbabbbbaaa#acccdddccedbbbbaaaaaaaa##a####.#.###############aabddcbbcaaa####.#......aa###aa####aaaa#aa##aacccccbbbabbcdedddea####a##aa#a#bccbccbcbbaaaadddccbbbbbbaa#aa####", +"ab##aaaa######a##########aa###b##aaaaa##a#a#####ababbbaababbbccccdcdgjifbbabbcccca#aaaaaaaaacaaaaabcccbaaa#bbbcaaaaaaaaaaaaaaaaccbaabbaa#a#a#bcbbaa##a###aaba######aaaaaaddfhgccddddacacaaaaa#aaaaaaabhnk.aabbb##aa####aa#acaabb#aabccddeecccbbbabaa##aa###aa#######.######a###aaaabdddcdedda#########...#####aaaaaaaaa##a###aabcbbccbbbbcddeeefc##a####aaaaaacdccbbaababaaabccdccccbbbbaa#a####", +"#####a#aaaaa###aaa######ba###aa#bba#aa#abca##bb#abaabbbbbbaabbbbdccceihgecbcdccbcd#ababa##aaabaaaaaabccbaabbddbbaa#aaaaaaaaaaaaaccbaaa#a######aabdcb##aaa##a#a#####aaaa##aabffebccddcb#aa#######aaaaaadlnd#aabbabaaaaa##aaaa####aaaabccdeedbb#aa##a###############.##..#.#####aaaaabccdeecdaa#####.########.###aaa#aa###aaaa#aaabcbccccbbccddeef##aaaaa####aaaccbaabaaaaaaaaba#bcddcbbbbbb#aaa#a", +"abaa###aaaaa##a#a##a#############a#a#ababda#aaaaaaaabbaabbbbcbbbddbddgifhedbcccbbcc##aabbaa#aaaaaaabaabbbccccdebaa##aa#aaaaaaaaaabedaaaa##########becaaaaa#a#########aaa##abceffdccb##aa########a#abbabilk#a#a######ab#aa#aa#####aaabbcddedbaa#a######a#####################a#aaaaaabdddfgfc##########...a#a###aaa#a#aa##a###aaaabbbbbcbbbcceghfaaaaaaaabbabccbbbaaaaaaaa#abba#aacedcccbaaaaa#aa", +"bbaa##aa#aaaa#aaaaaaaaa#aaa##########abaaaa#baaaaabbbbbabbbbccccddbddggghhfdbbcaabbbbbaabbaaaa#aaabbaaabbb#bbbaaa#####a#aaaaaaaaaabb##aa##########aabdcbabaaaa####aa###aa#abbcdhhcaba#baaa#######aaaaabhlmc#a#####aaaaa#a##abba#aabaaabcdgfbb################################aabbaabbccdhigca#########.########aaa########aa#a##aaabbbbccbccdgfha#caaa.##fedbbcbaaaaaaaaa#aaa###aaadecccbbaaaaaa", +"#aa###aaa#a#aaabbbbbcbaa##a#######aaabaababaa#aaaaabbbbbaaababccdecdfhhiihgfdbccbbcbabaaaaaadca##abbaaaaaaa#bb##aaa####aa#aaa#aaaabbda.##########aaaabddcbbaa#a##aa#aaa##aaabbdecca#a#aa#a########aaaaaeili##a######abaa###aaaaaacfeaabddcdbaa##############################aaabbbbbbcdfgjieba####.#####aa#aa############aaaaa###aaabcbbcbbcefggcbbfeedbedbcbabbaaaaaaaaaaaaaaa#aaa#cdcddcbbaaaa", +"aa#a###aa#a##a#aaaabbccaa#aaa########bacbaaaaaaaaaaaabcbbbbbbcedcdccfhfhkhggfdbbccbbabaabaabdda###aaa#aaaaaaacb#########aaaaaa#aaaabec##########aaaaaaabddcbaaaaaaaaaaaa##aabacbaaaba#####a##a######aaabgklbaaa#####aaaaaaaaaaabbbfdaacddeddcbaaa#########aaab##########a##aaaabbcbbbbeffhjifdcb#####.##acbb#aaaa###########aaaa#aaacbcbbcbcegfaccgghgffdcbbaabbbaaa#aaaaaaaaaba#aaaabeecccbaaaa", +"aaaa########aaaabbabbbbcbbbaaaa#####.##aaaaaaaaaaaaabbbbaaaaadedcdccegijkifddebccbbccaabaaa##aa######aaaaaaba#aa#########aaaaaaaaa#bccda#######aaaaabbaaabddcba#aaaaaaaaaaaaabcdaaaaa##abaaa#a#a#a##aaaafhlg.aa#a#a###ba##b#acaabcdfaaaccdccedba##########adcbca#########a#aaabbcddccbdefggiigecb########aaaa#abba###########aaaaaa#bdbccbccef#abdeddeeddccba#bbbbbaaaaaaaaaaabcaaaaaa#eedccbbba", +"aa#aaaaa###aaaaaaaaabbbbbbbbaaaa#######aabaaaaaaaaaabbaaaaabbbfeccccdfiljigcdeccccbccbccbbaaaa#######a#aa##aaa#####..#..#aaabaaaaaaabacb######aaaaaaabbaaaacddcbaaa##cbabaaaaabcbaaaaa###a##a####a##aababchl#.###a#####aaaaaa#aabbdeaaacbbbbdfdccbabb####a#ddbbbba##########abbbccdcccddefghhfcaaa######aab#abaaddaa########ab###aaaacccccdefd#dbgebcccdcaabbbaaaaaaababbbaaabacaaaaaba#eeddcbba", +"aa#aaaaba#a#a##aaababbccbabbbbba########aa#a#aaaaaaaababbaaaaadcccaddfhkjigdcdecccbbcdcecbaaaa######aca####aa#####a#####.#aaaaa#aabababb######aaaaaabbabaaaaabcdcbaaaaaaaaaabbbcaaaa#a####aa####a#aaaaaababjh.####a#####aaa##aaaabdabaaaabbabdeeeddddcb#.##debaaabaaaba####aaabbccdcccddeffgfgcaa##aa###aaaaaccaddca########a#a###aaaccbbceffbaacgeaabbbbabaaaaaaaaaaabaaaabbcaaabaaaabbbccdedcb", +"ba#a#aaaaa####aaaaaaaaaaccbcbbaa#######aaaa###aa##aaaaaaaabbbabbcbbefffhjihfcbfcbcbbbcfhgcaaa#####a#deaa##aaaa###############a##a###aaaaa###aaaabbaaaababbbbbbbbedcbaa#abbbbbcccaa##a######aa##aaa##abaa#aabja##.#######a#a###aaabecaaaaaaacccbcaaaabbdddefedcbaa###aaaa#aaaabbbcccccccddfggghdba####aababababcbbddba###a###a#aaa##aabbcccegfbaabcaaaaaaabbaaaaabbaabaacaabbbabbadbaaaaabba#aefc", +"ba#a#aa#######aaaaaaabaabbebdbbb######aa####a###a####aaaabbaabcabcccddffjhfdbaefcdbbbbdjkjebaa#####bccb##baba#####aa######a###a#a####aaaaa##a##aabaaaaaaabbbbbbabefdbbcbbbcbbbcbaa####aa#######aaaaadaaaaabbdg###a#a####a#aa#aabccccaaaaaabcdbccaaaaabbdeeedcdcba###aa#aabaaabbbcbcccddddeffffdbaa####abccbb#bbccdbccaa###a#aaaa#a#aabbdcdfgdaaaccaaaaaa#aaaaababbaaabbbbbabbbbbcbcbaaaabaa###be", +"fcb#############aa#aaaaaaadegdacbaa###aa####aaa#a####aaaabbaaabaabddccehieabaabecccbbbbbikkgca####acbb###baba#####aa####aaaaaaaa######aa###aaaaaaabaaaaaaaacbbbbbbeffedccbcddddbaaa##aaaa###a##aaa#adba#aaabbie.#.#aa##aaaaaaacecaaaba###a##aabdb#a#aaccccccccbbba###aaa###aaabbbbcccdddedegcddcbbaaaabbabbabbaabbaaddbaa#####aa##aaabbddefgcabagbaaaaaaaaaaaabbaaacabaaaaabbbbabbaaaaaaaaaaaa#a", +"bdeba#########aaaaa###aaaaacfebbbbaa###aa#####aa########aaababaacbdeccehhbaaaaaddcbbbbbcgijhea####acb########a##aa#a##a#aaaaabaaaa####aaab###aaaaaaaaaababbccbbbbacbedffedcdeeaaaab#aaa#aa##a##aa#a###aa#aabackc.#.##aaaaaabdefb#a#aaaaa#a####abc####abcbbeecbbaaabb#aaaaaaaabbbbcbcdededdefdcaccbca##aaaa###aaaaabaaeccaaa###aaa#aaabcccdffbbacfc#a#a#aaaaaaabbaaaaeabcbbabbbbcbbabb#aaaaaaa#aa", +"##aba######aaaaaaaa##a#aaa#fdaabbccb###################a#aaaabbabccccdehibabbbbcfdcbbbabgihc#a####abbaa##a###aa##a#aaaa##aaa##aaaaba###daaa###abcaaabaaabbbbbccbcbcdcdddggfedbcbaaaaa##a#####aaaa#aa#####abbbbdjb.a##aaaaabeecabba##aabda######aa####aaabbdcdcbaa#bcbbaaaaaaaabbbcccddedefffdcbccbab####a#####a#aaabaabeeba######aaacbcddegebbacccba##a#aaaaaaaaaaaaccbbbbbabaaa#aaabbaaaaaaaaaa", +"aa##baa####aaabaaaaa#####aacaababbccbaa##################aaaaaaaabbccbegifaaaabbcecbbbbaadgb#####aeeabc#.######aa##aaaaa#aaaaa###abaa##edaaaa##aabbaaaabbbbbbbccbbdccccdddehhdabbaaaaaa##a###aaaabb######cebcbcgj#aa##abdfggcbbbaaaabdfea####aaaaa##aa###aaa#aaaa#aaabbaaaaaaaabbccddeeddeffeeeefcabaa#aa#####aa#aabbbacccbaaaaaaaabcccdegfbbbceaacb#####aaaaaaaaaaaacccabaaaaa#a#abbccaabbaaaa#", +"#aaa#daaaaaaaabbbaaaa####abbaabaabcbbbbb##aa################aaaaabbbddehecacbaaaabecbbbbabaa#####adcca#########a#a##daaaaacaaaaaa###aa#aca#aa##aaaabbbaabccbbbbcddaccdeddecfhgcabaaa#ab#a####a####aaa#aaaabbbcbcijdchihgighedbcbbcdfdabbbbccaaaaaa###caa#aaaa#a#a##aaaaaaaaaaaaabcccdddddeeedeeeffbaaaaaa##aa###aaabbbabcdeabaaaabbbbcdegibabbfaabca####a#acca#aaaaaaababbbaaaa##aaababbaaabaaaa", +"#####adcbbbaabbbaaaa#a#a#####aaaabbaaabcbaa#################aa#aaaaabddgeadbcaaaaabccbbbbba#####a#a##aaaaa###aa#aa#bccaabaac#aaa#####a#..#####aaaaaabcbaaabbbbcdccdcddedceefgfccbaaaaaa#aa###aa##accaaaaaaaabbbbdjkfdfgjjhgfeeeeeedcaabaabaaaaa#####ab#a#aaaa###a####aaaaaaaaaaabbccddccccdccdeeegfbcbcaaa#aaba#aaabdcbbbababbbaabbcccdghg#aadbaabbaa###a##acdaaa#a#aa#baaaaaaaaa#a#aaaccbaabaaa", +"a##a#aaedbbcbabaaaa##a##aa####aaaababbaabacaaa###a#######a####aaaaaaaccehbbbbcbaaaaacdbbbcb#a#a#a#.####aaa##a#aaaaaaabaaaaab##aaaaaaaa#####aaa##aa##abbaaabbbccbccbcdcdcddeffcaabaaaabba#aa####a##bcbaaaabababbbbejib#abccdcbbccba##a##aaaa##a######a##aaaaa#a###a#####aaaaaaaaabbccccccccccccdeegfcdabbaaaaaaa#aaaabccbbbaccbabbbcddefedea#cd##a#aaab#aaa##bcb###aaa##abaaaa#####aaaaabbcbaabbb", +"aa##aa#bhgccbbccbbaaaaa########aaaaabcbaaaabbaaaa###aa#####a#a#aaaabbbbcega##acbabababecccdabaa##########aaaaaaaaaaaaaabaaa####aaaaaaaa##.##abaaa#aaaaabbbbbbbbcdbbccddcdcegeaaaab#aaaaaaaaa####aabbabbcbbbcaaabbcegiaaaaaa##abbcbca##.###aaaaa####aaa##abbaa#aaaaa####aaaabbaaabbbbccccbcccdddedfddcaaaaaaaaaaaaabbccdbbbcecbbccdefged#a###fa######aaaaaaaabaa#######aab#aaaa#aa#aaaaaabcccabaa", +"aa##aadafhhfeccbbbaa#aaa##a####a#aaaaaaaaaaaaaaaaabaaaabaa#aa###aaaaaabbcfd#a#acbaaaaabeecdcc#############abbaaaaaaaababbba###aaaaaaa#a#####aa#aaaaaa#aaaabbbabcccehgeecdegebaaaaaaaaa#aaa#aa###aaaaababccbbaa#aabceggaaaaaa#aaaabcb####a###aaba######a#a#####aaaaba#####aabbaaaabcbbbbcbbacceeddeebabdbabbaaaaaababcdccdccdcbbccefecb#####cc#########aaaaaaaaaa##ba#aaaaabbbbaaa#aaaaaabcccdgdb", +"##aaacdggggghgdbbbbbaaaaa#aa###a###aa##aaaaaaaaaaaaabcbbaaaaaa#aaaaaaabbbdfd#aaacdaaaaaadgefc#######a#a###abb##a#aaabaaaaaa#######aaa#a########aaaaa##aabbbbbbbbccefhfeeegfbbba#aaaaaaaaaaaa####aa##abbcdacbaa##aabcehfaaaa###aaababa##.##a#aaaca#a#aaaaaa#aaaa#aabcc#####aaaabbbbbadcabbbbbbceedefcaabcecaaabaaababccdcdddccbbcceda#####baeaa#aaa#####ab##aaaaa##aaa##abbbbbbbbaaaaaaaaabbbagig", +"f#aaaehhfffeffhfbccbbaaaaaaa####a#aaaaa###aaa#a#abaabccabcbabbbbabbaabbbbcehdaaaaaaaaaab#dgeaa##a###########aa####aaaaaaa######a####aaaa###a###aaaaa###aabbbbbacccdedddfgebcbaaaaabbbaabaaba#########abcbdabaaa#aabcdeibaaa######aaaca######aabbb####aaaaaaaaaaa##bbdb####aabbbbaaaacdcaabbbbcceddeccccaba#aaabaaaabccddddddceddeec#aca#aabebaaa#######aaaba#######aaaaabbbabbbbbaaaaaaaaaba#dii", +"hd#aaejiedefeeddedccbaaaaaa########aaa#######a#a#aaaabbaacbbababccbbabbbbbceidbaaaaaaaacbcgeca#############aaaaaaaaaaaba######.a############a##aaaaaaaaaaaacbbbccccedbcfcbbbbaaabbbbaaaaaaababaaa#baaaabababbabaaaaabdfhaaaaa#aa##b#bbaa#####abb##a##aaaabbba#aaaaaacda#####abbbbaa####a#abaabccbdecdbbaaaaaaaaaaaabccceeedcdfgffeba#aa#aa#bcaaa##########aa##a####aaaaa#aaabbbbaaaaabbbcbbbeefh", +"ggecdhjkiefeeddcdefdababaaa########aa##a########abaabaabcdabbcdccbcbabbbbccchiecaa#abbbaaaadeca#####a#######aabaaaaaabba###a##.#############a##aaaaaaaaaaabbbccdddbbeccdbbcbbbabbbbbbcbbaaaabccaaaabaabcabbabaaaabaabcefeabaaaaa####aaccb####aaa###a###aabbab#a#aaa##aaa#####acbba#a######aaaabbbbfefdaaaacaaaaaaaabbbcefffeefbed########a##dbaaa#######a#############a########aaaaaaaaaccfgfhdf", +"efddegijmkfeeeddccdgdbcccbaaa####a#aaa#####a####a###aabbcbabacccdccbbbbbcbbdfijhbaaaaabb###cedbaa###aaa#####aabbccbaaaaa###accb###a##########aaaaaaaaaaaabcbbccddddcddaaaabbbabbbbbbcbaabbbbbaaaabbaaaaabbbbaaa#ccaabbddheabaaaaa####abca#####ba##a####abcaaaaaaaaaa#aaaa#####bbaaa##aaaa##aaabbaaadfdbaabcbaaaaaaabbacehhhhcaaaa#####a#ab##ccaa########aa#############ba#a#aaaa#aaabdaaeffghgff", +"eddcbcdefijgeedcccbbdeccccbaaaaaaaaaa#a#########aaa##a#abcaacccccccbcbbccccdefikibaaaaaaaabbdddca#a#a#aa####aaabbbaaaa##a##aaaba##aa##a######aaaaaaaaaaabbbbbccccddddaabbaabcdbbbccbacbabcbbccbaa#aaaa###baaaaa#a#aaabcdfjb#aaaaaa####abaa.####a##aa####bcbbaaaaaaaa#####aa##abaaa#a##aaaaaaaaaaaaabecbaababaaaaabbbcbcehhcaaa##aaa#######b#.cbabaa#####aa##a#####a#########aa#a#aaabdefffggfefe", +"ddcaaabdefhihecdbbbbacdecccbbaaaaaaaa############aa##aa#ababbcbcbbbababccdceeegijgaaaaaba###bfcdc##aaaaa######aaaaaaaaa#aaaaaacba#aaa#a#ba#aa#aaaaaaaababcbbbbbcedabbaabbaaabbbabbdccbbbaabbbbbaaa#aaaaa##aaaaaa#####abcehka##aaa#####aaaa###..a#aba#####abcaaaaaaa#a##a##a###ba########aaaa####aa#deaaa#aaaaaaabbbbbccefcbaba##abaaaa.#a#ba##dc#a#a####abaabb#a##aa##a###a###aaaaabaceecddhhedd", +"cccbabbcdfffhheccbbbbbcdfccbbbbaaaaaa###############a##aaaabacbbbbaaaacccddcdefhjjhbaaaabaa##dfbbc###aa#aa######aabaabaabbbbbabdb#aa#a###bba#a##aaaabbabbbbbcbbcedbaaaaaaaaabbbbbcbccbcebbbbaaaaaaaaaa#####aaa####aa#aabdegj.############a##a##a#aba####a##baaaaaa#a###aa#aa########a##a#aaaa####a#eeaa###aaaaaaaaabbcdgfdbaa####aabbcb#aabc###cda#aa##aababcbb#a#aa###a##aab#aaaaababdecbcdheed", +"cbbaccbcddeffeedcbbbbbbccffdbbcbabbaaa#aa########a###ca#abaabbbabaaaaabcccddcdgiikjgbaaaaba##afcacba###aa########abbbbaabbbbbbbcbbbb#aa#a###aa##aaaaababbbbcbccdca#a##aaaaabaaabcccbbcbcbaabba##aaaaaba#####aa####aabbbddcdjd.#########.#..#######aba######aaaaaba########aa#######aaa#aba#aaa###aacaaaa##aabaaaaaaabbcefcbbaaaaa##aaacabaaaa###bca#####aaaaacaa#a###a##a#aaa#a#aabbbbcddcccegdd", +"cbbabbbbccddeedddcbbbbbbbbdfheccccbaaaa###########aa#bd##baaaabaaaaaababcddcccggijjjbaaabbaa##bcbabba##aa#######aaaaaaabbbbbbbbbcccaaaa##a##aaa##aaaabbbdbcbbcdfbaaa#aaabbbbbbbbbcccbccdedaaa#aaaabbaaaa#a#aa####a#abcccdccfi###########....#######aa##aaaaaaaaaaa##########a###a##aa#aa#aaa#####aaa#aaaa##abbbaaaaabcdefbbaaaaabaa####aa####a#a#dba#####bb##b###########aaaaa#aaabbaabbbccddede", +"baabbbbbccccdeedcccbbccbcbbcdiheccbbbaaaaa#aab##aa###aa###aaaacbaaaaaababccccdfhjjjl#abbbaaba#abeaabb######a#####bbaa#aaaabbbcbbabbaa###aa####a###aaaabacdcccdceaaaaaaaaaababbbbbbbcbbbcbdba###aabbbaaa#aa##########aabbabccgb.###.#########.########a#aaaa#abaa#########a##aa#####bcaabaaba###aaaaaaaa#####aaaaaabbbdhidabaaaaaaaa###########a###ebbb###aaa####a###aa#aabcaabbaaababaaabbbbbdcb", +"abcbbbbbbbccbbcddbcbbbbbbbbbcfeghfccbbabaaaaabaaaa####a#b##aaaabbaa#aaaaabccbceefhegdedaaaaaaa#abdaaba#aa##a#####aaaabaaaaaaabbbaacc###aa#aa####a#aaaaaaabcccddfbba#aaaaaabbbbabbccccccbcbdaa#####ac#####a##########aa#aabcbdh..#########.#####.####aaa#aaa###abb###########accaa###a##aaabbbba#a##a#abba####aaaaaccegcbbaaaaaaa#aa###.##a########aeaaaa###a#a######aaa##aaaaaaaabbaabbaacaacced", +"cadbbbbbbcbccbbacbbbbbbbbabccdeehgffccbcbaaabaaaaaa###a####aaa#aaaaaaaaaaabccbdeeffeehgcaabaaa##adb#aca##aaa#####aaabaaaaaaaaaabaacdb##aaaaaaa#abbaaabbbabbdecffbaaaaaaaaaaaaaabbaccbcbcccdcaa#############aabb######aaaaabbbehd..###d#.#.######.####adbaaaa##abba########aaaaaaaaaaaaa#aaaaaaa#a#aa#abaaa####aaacdeheaaaaaaaaa##aa#aa#####a####a#.cdaa######a##a###########aa##aabb#aabaaabbadf", +"cabdabbbabcccdccbccbbbbbbaabdcdefdcfgccbbbbaabcbaaa###aa##aca####aaa##aabbbccccddffhihhfbaba#c###bdaaagaaa#a######aabaabaaaaaaaa#a#aa####aaaa#aabbaaaabbbbbcddfeca###aaaaabbaabbabbcbccbbbccdada###aa######aaba####a###abaabcafjlf..defe##...#########bbaaa###aab#a#######aaabcb#aaaaaca##aaaa####a##aab###a##aabdfiida###aaaaa##ca#aa#####a####a###ecaaa########a##a#####a####a###aaaaaaaaaabab", +"ccbbbbabbaaabccdcbbbbbbaaaabcdbbbeeadgeccbbbbabbbaaa##aa#abedbaa####a####bbbcbccddehhhfdaa###da#a#ddaabhaa###########a#abaabbaa######a####aaaaaaaaaabbbbbbcbdeefcb###aaaaaaaaaabbbbccccbbaabbcaaa############aacbaabaaaaaaabccbdejkbd..bgccdcba########aa######aaa#a#######aaaccaba#bcaaba#a##aaa#####abba#aa#aabdgkjkihgdb#.cedcbb#.###dc########b##ebaaaa#########################aaa#aaaaaaba", +"abeecbbaababbbabbdbabbbbbaaabcccbdcb#ehedccbbaabbbaaa#abaaaedba###########acbbbcceeeggdaaa#bacaa#aadabbdf#######.#######aaaaaa######bca###aaaaaaaaaabbbbbbbccfffbaaaa#aaaaa#aaaabbccabbcccbbbbaaaaa#######a#aa#acaaaaaaaaaaaabccceglh.#....#baacca..####ab########aaa####a##ababbbba#ceaaaaaa###a######aa##acbbbbchgcddfgjihddigefegfffba#affeecbbaaabda#aa######a#a################aaaa#aaaaaab", +"babfdcbcbabaabababbbaaaaaaaabcccdbaaaacifddcbbbbbbbabaabaacecabaaaaa######aaabbcdeeedifba#adcbaaba#bcabbfe#aa####aaa###a#abaaaa######aaaac#aaaaaaaabbbdbbbbcceebbba##aaaaaaa#aaabbbbbbcccdcabaaaaab##a#aaaaaaa######abaaaaa#abbbbddei#####a####.#ee######aa######aaaba######abaaaa#a##bc##aa#a####a###a#aaaabcbbbceecbbcbdeffgfdccccdefeefgffedcefeb##cdbcba########a###########a###aaaabaaaaaaa" +}; +SIMPLE = T BITPIX = 8 NAXIS = 2 NAXIS1 = 384 NAXIS2 = 384 HISTORY Written by XV 3.10a END 3"3wUD3D3"3""3"3"333""""""""3DDDU3""""DªwUUD3333333"3""3""DfD"3""""""""33DUfffUªw3""UD3""3"3D"33wf"""""""3""""""""D""""""""333U3333DDff333"""""""""""333333DDDUD"3"""""3"""""""""3""""""3333UUfª"ff"""""3""3"""""3D"""""""""3D333DffD33D3UfwwˆwUDDDDUfwffwˆwwfUDfwf3DU3D3"""""""3""""""""3ffD33""3"333"33U3"33333"""3DDD3UD3f™fUDD33""333""""3"""fU3""D333DDfffˆˆU"""3"D""""U"33Uw""""""3D"""""""""""3333333DDwww3"""""""""""""33DD"33DDD3333"""""""""D""""""""""""3DDDfˆÝ™3""DD""3"""""3"3333"Df""""""""""D3333D™ˆDUUwˆ»ª™UUªˆfwfˆwww3""wwffD33"""3U"""""""""""""""3DD3333"33"""3DDUD333333""""3DU333ff"UˆfDD3333"333""""""3fU3"""333D3DDUUf™™™wU""U""UU""3™""""3""33"""""""""""""333333D3UffwD3""""""""""3333DDDD33""33D"""""D3""3"""""""3DD3Uf»Ì3U3ˆDDUD3""""""""""DD"3"3D""3""""""33"""""3UˆÌ»Ìª™ˆU3DfUD33UD3f3"""""""""""""3"D"3U"333"3DDDUDD3DD333333""3UDUfwUDwˆDD3333""3D3""""""D""""""333DDDDUUww™ª™™w3"3"D3U"""ˆ""""""3""3"""""""""""""""""33""""33333DUUwfD""""""33""33"33D3DD333DDU"U"""""3"""3""3D"w»ÝwUfwf33"""""3""""3D3"""""D""""""""3"""3UwªªU""""""D"""""fD"""""""""""""""""3"3D"U333333D3DD33"D33333333"3DDUff™ˆwwDD3D3"""3"""""""""""""""""""""3DD3Uffwwff™ˆD""3""""U3"D"""""""3""""""""""3""DU3""""""""33"""333"33UfDww3""""""""""""""33"DD3D3DDDUD""""33"""""333f™UU"U3"""""33"""""""""""""""""""""""""3""""""DUf™f"""""""""""""""DU""""""""33""3"""33"Uw"3D3333333DD33DUU3D333333333Dwfˆ™wDD33"3"""""3"""""3""""33"""""""3DD3Dffw™fˆUfU""""""""3U""3""""""""3"""""""333""DD""""""""""""3DDDUUw33"""""""3333"33DDDDDD3D3U"""D"""""3D3U™"""""""33"DD""""""3333""""33""""""DDfˆD33"""""""""""f"""""""""""""""""33""33""D""DDfU3""33333DDDDUffUDDD33DD3D33DUª™fDD333"""""""3""""""""D3""""""3"3DDDDUw™»»»Ý"333""3""3f""33"33""""""333D33"33"""""""""3"DUDDDUDf""""""""""3"3333333D333D3U3"""333"""""""33"3DDˆ3""""""3"""""3D""3""3"""""""""""""""333U™ªU"3"""""""""f333""""""""3D""33"""3"3"""33333UD3D33"3333DDUUffUUUD33333333Uw™fDDDD3""""""3U3""""3""""""3"3DUUDDDˆˆª»»»3"""33""3D3"33""""""""""333333333DDD""""""""""""333U3D33DUw3""""""333333333DDD3DDUfU"""""""33"""""""""3DDDUDDwª""""""""""""""""""""""""""""""333"""""3DUfw33"""""3""""""U3"333""""""""33""333DDUUfUfD33"DD3DUUfwwffUD333333DDwwU33D3"33""""""D""3""333"3"""""3DDDUUDUˆªªÌ»ˆ3""""3""wD"D3""""3333""3333333D3333""""""""""3"3333D3DDUD"""""""3"""3DDD33D3D3""33""""""3"""""333UUDU»U"3""""""3"""""""3""""""D""""""3"""""""33DfwD33""""""""D"3""""3D""""""D"""""""""""3333DUUDDDfˆUUDDD3"33DUwww™™fDD33333DUwDD3333"""""""""""3"D3333""""DDDUUDUfw™»»™3""""3""Uw33D""""""3""3""33333"3U3"""33""""""33"33333D33DfU3"""""""""33333D3DD3Df3333"""""""""""""""""3Ufˆ»""""3""3""""""""""""""""""ff"""""""""""33DUˆwU3""""33D3""3DDU"""""3"3D33""""""3"""""3"3UfD3DU™ffUUUD"""3Ufw™ª™fDU3333"DUfDDD33"""""""""""""3"33D3D333"3"3DDUDfffˆª»ˆ"""""3"3wDUD""""""""""""""""""""D3"""""3"""""""""""3"3D33333DfU"33""33"""333"33UDD333""33333"""""""""""""""3Df™Ì""""""""""3""3D""""""""""3"""""""Uf""""""""""33333DDfwD3"3""3"""""3"UD"""3""33""""""""""3"DffDUU™™fUUfUUD3DUfwª»ˆffUDDD33UfDDDD3""""""""""""""""3D""DDDDDDD3D33DDDDUfwªÌª3""""""""33UUUD""""""""333""""""""3"""""""""""""""33333DDDDUUUU""33""3DU333DD3"D3"3D33DD3""""""3"""""""""3DUw»3"""""""3"""""3D33"""""""""""3"""""""""""""""""3fD3""3"3"""""333D3Df™™D""""""3D3"3""""""""""""3UfwwwˆˆwfwffwUUfˆª»îÌwfffUUDDUˆU3DDD3"""""""""""33D3"3"DDDUDD33333D33Uwª»™3"""""33DfU3"""""""33DD3""""""DD3"""""""""""""3D33DDUUUUDUU""""333"333333D3""33333""""33"""""3333"""DD""33UU™f"3""""""3D"3"""3D""""""""""""""33""""""""""33"""UwU3""3D3"""""""33"Df™™™™D""""""3DD""""3"""""""""3U""fwwˆ™ˆwwˆˆfDU™»ÌªfwffUUDUfwU"3"3"""""""3""3""3DU"33DUDD3D3"3333DDD™ªfD"""333""""UfD""""3""""""33""""""""""""""333DDUUU33fDDU33D333"333333D33""""3DD""""3""3D"33"3""""3""3Dfwf"3"""""""DD3""""""33"3""""""""D33""""""3333wfwU""""D""""""""333Dfwwwffw3fU"U3""""""""""""""DDwˆw™Uw™U""f»ªfUfwffUUfUDD3"""""""""""""""33""D33"3"3DD33"33333DfªU3""""""""D3DˆfD""""""""""""3"""""""""""""""D333DDDDfU3DwD3333"""3333"""""""3"3"""3""""3"3"33"3"""""3Uw™"""""""333"""33"""""333"""""""DU""3333""""3""3DD3UfDU33""""""""""""3DDDfffUDUwˆwwf3"""""3D""""""""""""""3333"""""333D333ffw™w"""f™™wwwfww™w3DD33""""""""""""""""""3""3DD"3D3"3333"33""3333Df™U""""""""""3Uˆf"""""""""""""""""""""""""33333"DDDUfUUUwˆf3D3"""""333""3""3""3D3U"3"""""3DUfª3""""""D"""333"""""""""""33U3""3333""""DUD""3333DDfUUfDDDD"3""""3""""3DDUUUUUUDfUUffD"D"""3f3""""""3""""""333"33333"""""""""3"Uªª"""DUˆˆˆˆˆ™ˆU33333"""""""""""""""""""""""3D33"""""""""""""333UwU"""DU""""""UˆfwD"""33""""3"""""""""""""""""33333333DDfw™wfffˆw333""""""""""""""""33DU"D3""""3Df™w"""""""3"3"""""D""""""""""""""3DD""""33333"UD"333333DffUfwD""3DfD"""3"""3"3DDUDUUUDD33DDfU"3"f""""""3"""""""""33333333"""""""""333"ˆªˆ""""U"w™™wfDD333""""""""""""""""""""""""3""""3""""""""""33DwU""D3"""""3ffDUDD"33""""""""3"333"""""""""""""""""""""333"3DDDf™ˆffDUfˆf3"""""""""""""""""""3"3DD33""""3Dfˆˆ""""""""""3D3"""3"""""""3"""33""""3D3333D33"DDffUUff3"3U3"33""""""3"3DUDDUDDUD33DDfwfD3DD""""""""""3""""""3333"""""""""3DDDUˆU3""""3™ˆDD33DD33""""""""""3D3""""33""""""""""""3333Dfˆ""D3"3"3"3fDDDU"3""""""""""""""""3""""""""""""3""""""""33333333DU33DDUUDUDfˆf""""3"""""""""""33"33D333D"""33Dfˆª"""""""33D3D""""""""""33"""""""""""33"""3333DDDD3DDDUUUfUwUUD"""""""""""""33DDU333DfD33DDUfwˆfU"w"""""""""3""""3""""""""""""3DDD"3""""""fU33D3"3"""""""""""3"33""3"D""""""""""""DDf™3333D3"""""DU333D3""""""""""""""3"""""3""""""""""""""33"""333DD3DD3DUDUDUUfwwD""3""""33""""3D3""""3"3"3333f»ª3"3DDUD33DD3""""""""""""""""""""""""33DDDDDDDDDDDDUffˆwDU"33"""""""""""3DD333"DD3"333DUUfwfUf"DU""""3"""3D3""""3"""""""""33D3""333"UD333""333""""""""""33"""3D3"""""""""3UUˆf"U3D"""""3DD33333""""""""""""3DD""3""D""""""""""3D3"""3333DUDDUDUUfUDffwˆwDD3"""""""""""DD""""""""3333U»ÌwUwˆ»»™ˆwffffffUD""3""3""""""3"""""""""""""""""33DDUUDDDDUDDUfffˆw3D3D"""""3""""3UD333"3"333""33DDDUˆ™ˆ""U3""33""""DU""""""3"""""""""""""DD3""3""""""U""""""""333"""""33""3""3D33333"""""""333UUf™fD"D3""""3fD3333"3"""UDD"""U"""""D"""""""""D"""""""333""3DD3333DUU"DDUfUUfDw™ˆD"3""""3"""""""""333D3Dª»UD™ª™ˆªˆ™fU3D33DUwU"3333DD""""""D"""""""""""""""""""""3DDDUUUUUfffUfffww3"""""""""""333"3DUf"3""""3333DUfˆª3"33w""3D"""DD""""""""3"333"""""""3"33"""3""""""3"""""3"""""""D""3"33DD3""""""""""33DD3fˆªw""""33DfD3333""Uˆ3"ff"3D"""""""""""""3""fU""""""33""""3333333DD33UDDDDUUUf™™U"33"""""""""""33Df3D3Dˆ»"""3UwˆˆD333""""3Uwf""""""""""""""""""33""""""""33DDUUffUUfwwffffwD"3""""""""333"DDD3""""""""3DDDUfˆw333Df""D3""""""""""""DDD"3"""""""33DD""33"""""3"""""""""""""wU""33DD3"""""33"3DDDDUf™ª3"3333DwUD333"3ˆª™D""33"""""""""""""""""3"U""""3D"""3"""33333DD3D3DUDUUUˆˆwfU3D3"""""""""""""3333U»3""""""3ffD"33"""3U""""""33UDUD3""3D33""""""""333DDDUUfUfwwwUD3DD3"3"""""3""3ff3""""D3DUUfˆf33"DDD3""""""""""""""DD33333"3""""""33""""""""""3Uf3"""""""""""Dwf3333"""""""""3"3""D3UfDDf™™3"""""UUD33333Dˆª»™f""D3""""""""""3"""""""3""""""""""3"33DD3333"D3fUwwfUDUff""""3"""""""""""""3"DÌD""""""3Ufw3""""""""3D"3D33ffD33"""33""""""""3333D3DUfUfUUfwUD"DD3D""""""""""3""fDD"""""""""3DDDUww33"DwD"""""""""33""""f"3D33"3333D33"33"""""""""wD3"""""""""UfˆU"D3""""""""""""33"""3""3UUDDf™ªf"3""3fDDD33333ªÌ̈D""D333"3""""""""""""""""""""3""""""""D333333fwwfUDD3DUUUU3""""""""""""U3""""33ªf"""""""""DfD"""3""""3U3"""DDDDDDDD333"""""""3333DDDUUUfUfˆDUUD33""""33"33"33""33""UU3"""""""33UUfwˆD"3"ˆ3""""""""""""33"""D"3"""""3333"33"""""""""""""3"""""""""""3""33f3U333""""""""33""3D"3DDDUUww»™wU3"fwDU3333U»Ì»f3""3DD33"3""""""""""""""3"""""""333333"3fwU33D333D333D3"""""""""U"""""33Uˆ"""""""3DDDD""""""3DU3DD"""""33UfffUDUD3"""""3"""333D3DDDUUUUfwwwwU3"""3DD3333DDU3DD""""""""""33UDUwˆU"""DD"""""""""""3"33"""33333"33333D3D3""""3""3f3"""""""""""""""""DD3D33""""""""""""""""333"33D33fwww™»ª™wD3wD3D333Dw™ˆD""""Uf"""""""""""""""""33""""3"33333333fUD3"""33333DDD"""""""""3""""3»""""""3fD"""""""DDD3D""""33UUUfwfUD3""""""""""333DDDDDDDUUwˆˆˆ™U3"""3"3"3"3D33UU3""""""""33DDDfˆw3""3D"""""""33"""""33""3""D""333"33"U3"""""33""fwD""""""3""""""3"33DD3"33333""""""""""""3"33"""""UDDD"UUw™Ì»ªˆUDUfDDD33DUDfD3"""""D"""""""""""3"3"33""""""33"3"""""3DUD3""""""""""333D""""""""""""""3"3»™""""""""3U"3""""33"3UfffUUUUD3Uf3"""3"""3""""33DDUDDDUUfwwˆwˆD"""""""""DD"UUD""""""DD33Dfww3""Dˆf""3333"3"""""""""""3""""33D"""3""""333DDUfUD3""""""""""""""""33333333""""""3""""""""""33"""""333wfDDDDUwªÝ»ªˆDUfDDDD3DD3DD33"""""""""""""3"""""""3"D3"""""""33""""DUUD3"""D3"3"""""3D3""""""""""3"3D™Ý"""""""""33Uf"""D3333UwUDD3"33"UU3333""333DDUDDDUUfwˆ™™wD"""""3"3""UU"""3""""DDDDDUfwUU3ˆf3DDDUD""333"""""""3"333"""3"D"""""3"ffUUD33"""""""""33"3333D333"""""""""""""""""3333"""""UfUDUDDfˆª»ÌªwUUf3DD33DD""3"""""""""""3""""""""""""3DDU""""""33"""3UUD3""""""""""""""3DU""""""3""""""""""w™Ýˆ""""3"3"D""3DUw"""DDUDDfU3""UD3D"""""33DUUDD3UfwˆˆªªˆfD3"""""33"""""""3U3DD3DDfw"3UfUUffUUDD3"33333"""""""""""3D""""""ffUDD333""""""""""""33DD"""""3"D3""""""""""""3D333333DfUDUDDw™w™Ì™ˆˆwU33DD33"3""3""3UU"""""""""""D3""""""""""3fD"""""""3UUD3""""""""""""""3"D3"""3""""""3ˆÌÝ3""""""""""""""333wU""DUUfUUD3""""""3"""""33D3333fww™»ªwUD3"D33"""""""""""D3D33D3Dfˆw"DDˆˆ™ˆwwUD33""333""""""""""""3"""""3ffDDD3"""""""""""""33333D3""""""3""3"3"""""""33333"""3"3DDUfDUw™™ªª™ˆwU3DD33D3"3""""""UD""33"""""""33""""""""""""33U"""""3UUD33"""""""""""33UfDD""""""""""fªÝª""3""""""""Dwf""3UUDU3"""""333333DUwˆ»ªf3"""""""""""""3D33D33DfwˆˆD33wffU3fU3D3"33""""""""""""""""""DUDUUD33""""33"""""""""""""""""""""3""""3"""""33333"3333DDDDUU3UUˆˆˆ™™wU33D""33333""33"""""""33"""333333""""""""""""""33""""3UD3"3"""""""""33DU™™D"3"3""""""""3™ÝîD""""""""33"""3"""3DUˆw33""33""33DDU™ªˆD""""""""""3333DD3DDUˆw™"D"""wfU33D3"""""""""""""""UfDDD33"""""""3"""""""""""""3"3U"""""""""33""3333D333UU3UUˆªw™fU3DDD33DD""33"""""""""3""333DDDDUf3""""""""""""""3fU""""3fD""""""""""3DfwwUDD3""""33"3ªÝÌ"""3"""""""33DUUfU3"""""""""""3UUUwˆwD"""""""""""""33333D333DDfˆ™w""""""""33"3DD333"""""""""33"""DfUDDD3""""""""""""""""3"""33""""3D"33"3""333333""3333UDDDfª™ˆfD3DUDD3DU"3"3""""3""""""3DD3""33UU33"""""""""""""""DD3""""""3UD3"""""""""""3wwf3DDUUD3""""""""UÝÿU""33"3"""""""""""""3DDUffU33""""""""3DDUffDU""""""""""""""3D3DDDD33DDUUffw""""""""DD3""3""""""""3"3DUUD333333"""""3"""""""3""""""""3"333""3"333DDDDUDUˆ»ªw33"33DDDD""""""""""D"""""3DDD3"""333D""""""""""""""""DD3""33""""3D33"""""3"""""""UUw™ˆDDUUUU"D"D""""""""""""3™ÿÌ""333"""""D""33""3DDUUffDDD333"3"""""""""""3UUUDUfUU"""""""""""""3D33DD3333DUUfffwD"""""""DUDD33""3"3"""3DDUDDDD3333"""3"""D3"""""3""3""""3333fUDUDDf™ª™D333333DD"""""""""33""""333D33"""333DD"""33""""""""""3333"DU"""fU3"""3UU3""""3""""UUDDff3"333D3DUD"""3""""3""3wîÌ"""3"""""""33"3333""""DDDUUUDDfU3333"""""""""""3UUD33D"""""""""""""""DDDDD333"33DUfUUUf"""""3DD3DD3D33""""UUUDD333333""""""3"""3ˆ3""""""""33DDffUUUfˆ™ªf3"""3DDf3""""""""3""3"""33"""33"""33333"""33"""""""""33DD33D3"Dwf33"333"D"""""""""""D33333333D3""333DD3"""3"DfwwUwˆ™w"""""""D3"D333"""""3DfUDUUfU3"""3""""""""3DDDDU333""""""""3UUU3D"3"333UfUUfUff3""""""3"""3"3D333"fDD3D3D3D3333"""""""U3"""""33U"""""""3"3DDUffUUww™™ˆDD3""3fwU33"""""3D33"3D"""""3"3333DDD3"""D""3"""3""""33""""3""""fw""""""""""333""3DD"33UD3"33D3DU33"""fwfªªww""""""""33D3"3""3UUUfwwwUD""""""""""""33333U"3""""""""""""""""3DDD3Uwf3""""""DwUDD3DUUD3""3D3"3"""""""""3"""fU3D3DDDDD33DD3""""""""3fff3"""""""""""""""3333DUUUUDDfwfˆwDD""U™3""DDD"""3D3DUfD""""""D"3U"3UD3""33"33"""3"33D3""33""Uf"""""""""3""""D"DUwf333333"3DDDDwfUUwˆwfU""""DU3"333"""DUUfˆwfD3"""""""3""""333"33""""""""""""3"""Dfff3""""ffU333"333DD3DfUUUDDD3"""""""3""3f3333333333333"""""DDDDfU""""""""""3U""""""""333"33DDDUDDDwDwfD3""DfD"""DU3DDD3""™ˆ"3"""""3"333DDDD3""3333333"""3D3"D"""3DD""""3""""""33UUUU333D3"""""3DUUU™fDDDˆ3"""""DfD"D3"""""DUfw™ˆwD"""""""33""""3DD3""""""33""""""3""33fw3"333""""""33DDDDDUUfwwD""""3"""""3f3333D3333D33333""""""""""""""""""""""""3"""D"3"""3DDD3U™fUwU33"3D"""""""3""""f™f"""""""333"DUU33"""333"""""""3D"""Dwˆ3""""""DD""""""""D3"3DU""D3"""3DUUDDDˆwD""3fˆ"""""""""""""3""""""Dffw™wU3"""""""""""3D3""""""""""""""""""3"3"3ww3"D3""""3"""33DD"33DDDwˆU""3D33"""D3D3"Df333DUU33"""""""U"""""""""3"""""333""""33DUUfff3DU3"33""""""""""3DDD3DD3""333"3DD3""""""""33"""""""""3DDDwf3""3""""""33""D"3"3""""3DU3DDwwD"3f™""""""""D3"3"""DDUUwˆU3"""""""""""""3""3""""""""""3U""3"""""3""""333"3333DUUfwfD3D3""33UD3""3DfDDDfwˆD""""""""""""ff"D3""D""3""3D"3"""DUfwDD3"DU3UD"""""""3U3"""33DDD3333333DD3"3D"3""33"33""""""UU3DU3""""""""""""""""""D3"3UD333f™D""33f™""""""""Dw3""""""33UˆU3""""""""""""""""33""""""""3""""""""333"3333"""""33DUUUUUU3""3DfUDD3""UwUDDffˆˆU3"""""""U™U3"33U"3"3"UUD""""3"D""""Uˆ™wU33"3fDU3""""""""DD"3"""D"3"3333333D3D33D3"""""3"3"""3""33Dw3""""""3"""""""3"""333"3UD"3fw3D""3"3™f""""""""33""""""333fwD3""""""""""""""""33"""""""""""""""""3""3""""""""""333DDDUUf3333UfUfwUDDDDD3Dffˆ™ˆwU""3"""3™ˆU"3"3"3DUU"""""""""""""3"3""""U™™ªˆf3"3wUUD""""""""""""3"""""""3D333D33DfD333"333""""33"""""3""3"Uf"""""""""33"33""UDDˆ™333"""3wª"""""""""3""""""""33"DwU3"""""""""333"""""""""""""""""""""""""""""""""3""""3D3333DDDDDffDffffwfUUUD33Dffww™ˆwf3"""w™ˆD""""""3DUUD""""333"3"""""3"""fªªª™ˆ33ˆfUU"""""""""33""333"""""3UDDDUUUUDD"3333"D"""""333"""3"""DUU""""""""""fD3"333DDDwˆ"""""""fª"""""33""""3"33"3"3UˆfD""""""3D333""U"""""3"""""33"""""""""""""""""33333D3DDDDfwˆffDD3DD3333Uwªª™ˆˆˆf3""""ww™™™f"33D"UUUD3"""""3DD""""""""""3U™ª™ˆUUwˆwˆD"""""""333"333""3""""3fUDfwfD333333"333"""33"DUD""""33U3""""""""""""""U33""3"UUDˆˆ3""""33Uª""""""""3""""333333""Dfwf3""""""3DDD3"""""U""""""""33""""3""""""""""""""3333333333DfUUffDD3DDDDUUw™ª»»™ˆˆˆ™333"U™ˆ™™w"""""3""DDDfU"""""""""""3"333DDUˆ™ˆwfUˆwˆD"3"""""""3"3"3""3"""""3UDDffffDU333"3"3333DD33333"3U3"3D3"""""""""3""""3"3D33""3fˆˆ™"""ˆ»"""33""33333"333"3D"33""""3DUUDD3"DD""""""""""""""""""""""""""""D""333333fDDDD33DDUUDDUfˆˆ™™ˆwffˆU3UUDDDUˆˆ™ªˆU3""3""""33D3U333"""""""""3""3"3DUfˆªª™UˆˆwwUD3""3333"33333"3"""""DDUDDUfˆfUDD333333D3333""U3"3""DU3""""""3""""""""3"333"33wªf"""""""D™Ìf"""""""""3"33DD33D3""""33D3"3DUffUD3""""3""33""""""""33""3""3""""""33""""333333"DUD3333D3DDDDD3UUUffUfUfˆfUUUUDUDffUw™™wD3""33""""3D""DD3D"""""DD333"3DUwww™ˆªwf™wf333"33DDD33333333""""DDUDUUwˆ™wfDDDD3333"3DUUfˆD3DDUD"""""""""""DD3"""""33DD33D3Df™3D33"3Uf™f""""333DDUD3DD3"""DDD3DDfwwfUD33""""""3""""""3"3D3333D3""""""""""""""""""""U33"""DDD333333DD3D3DDD3DDfffffUfUDU3DDUffD3UˆˆwUUUfUD"DU"""33""D""""""""3D"3"3DUfffUˆªˆUwˆ33D33333DDD33333"""""""""DDUUUUfwUfDDD33D33UUD3DDUUfUD""""""""U3""""333D3D"33UDUD333D3"""33wª"""3"""3333DDfUDDD3"""33333fwˆª™wUDDD3"""""""3""3""""""3""""""""""""""""""""""""""""""33"3"""""3D333333333333333DDUfUUDDD3UDDDDUUfDD3Dww™wUUUUUDD"U3""""33""3"""""33""DUUUwff™»ªwˆ™"""3D3"DUUDD33333"33"""""3DDDfwˆUUUfwwffDUfU3333D3"""""""""""""3"""""""333""33wD3DDDDD3""""33w»ˆ"""""33"""33D3UfUDU33"""333DDfˆ™™ªªfUDfU33""""""""3""""""""""""""""""""3"""""""""""""""""3333"333333333333UUUDDUUDD3D333DDDUU3DUwUUUDDDUUUDfD33"""3DD"3""""""""33DDUfUffUDª»wˆˆw"3""3333DDUUDD333"3"""""""""333ˆª™ª™wwfUDD33333333"""""""""""""""""""3""3333"DDfˆ"DU"""3"""""33wf"""33333"ffUUUD3"""3"DDfDDfwª™UDDfUD3"""""""""333""""""""""""""""""""""""""3D""""3D""""3333333333DUUD3DDUUD3333"3DDDUDD33UUDD3DDUDDUDf3D33"3DD3DU""""3DUUDUUUfˆˆªª™™™U""""3DDDDffUDD33D33DD3DDUfffˆˆwfUUDDUfDD33""""""""""""""3"""""""""""""3"""3"3Df™3"UD3U33""""3UDf"""33333"DˆfffDD"3fUD"""Uw™DDUww3333"""""""3333"""3""""""""""""""3""""""""""3DU3"""3D3""3""33"""3DUfU333DUUD3333D"333DD3333DUD33DDDDDUUUUUU3""3333UD""""""""3DfUfUD33ˆªª»»™D"33"""""DDUUUUDDffUUUUUUUfffwfU33D3DDD3333"""""""""""""D""""""DD""D""""""33DDUˆ™DDˆˆwD"3"""""DˆˆU""""333""33UffwfU3""""UU"""33D™fUffwfU3"""3""33""3"D3"3""""""""""""33""""""""3U3"""33""33"33""3UfUUD333DDDDD3333""333DD33"33DDDD33DDDDDUUUfD"""33DDD"""""""3333ffwwffDDw»»ªw3""3"""333DUfDUfwwU3D333""333DDDD33UD3""""""""""""3"""""3D"""3""""""""DfU3DUwª™w™ªw3"""""U™D""""33"""33DDDDwfD"""DD""""""DDwwUwDDfU33"3"""""33"""3"3"3"""""33""""""3"""""""33""""""""3""3"""333DUwfU3DDD3DDDDD"333333"333333D3DDUD333DDDDD3DUwU""D3"3D3""3""""""""333fwfUDUwwªª™™D""""""""3"DwwwfwfUD33333""""33333333D""""""3"""""""""""""3"""3"""""3""3DDˆ™w™ªªf"""""""3Uˆ"""""""""33"""333DUUfˆUD33"""""""""33wfUwUUfD333333""33"33""""""""""""""""""3D3""""""""""""333"""""""3"""3"""33"3DwfUD333D3DDDDDD3"33"3"""""33DD3UfU333333DD3DUDDUU3333""DDD"D3"""""""""""DwUD3DUfˆˆ™ªˆ3""""""""Uw™ˆfUDDDDD3333333333333333""""""333""""""""3""""""""""""""""""""3Dwˆ™ˆª™w3D3"3"""33ˆf"""""3"""""""DDUffUUwU3D3""""""3""w™ˆˆˆwfUDDDDUDD3"""3""""""""""3""3D"""""""""""3""""3"""""33"""""3UffDDD33D33DDDDUD3"3"""333""""333"wf3""""3333DUDDDDD3"33"33DDD33"""""""3UfDD3UUfff™ˆD""""""UU™ªwUUU33DD3DDD3333""""""3"3"""""3""""""""""""""3"""""""3"""""""""""3Dfwª™fwD""""""33U™""""""3""""33DDUfwfˆwwUDDD"""""""""33f™™™™wwwwDUU3UDU333""D33""3""""""33""""""""33D"""""333""""3UwU3"DD3DD3D33DDUD3333""""3"""""""33D"3""333333D3DDDDDUU3"3"DD3"33U3D""""""3UDU33DUUUˆ™D3"""3D"DªˆˆˆfD333D3D33"3D""""""3"""""33""""""""""""""""""""""""""""""Dfˆw"""""D""""D™wD""""33"33"3DDUUfwUDfwwfU3D""""""""3333DUfˆª™™™™ˆˆˆUDwwfD"3""""""3D"""""""""""""33"""""""""""3D"""""333333Uwf33"3DDD3DUD33UD33""3"33"3""3""""3333D333333333D33333DfDDD3"DDfU"""3UUD"""""3D333""3Uw™wUD"""DUD"3UwfffUDDDDD33D33"""""""D3""""""""""""""3""""""""3"""""""""""""333wˆ"""U3"""""""f™"""""Uf"""""3ˆ3"3"DfwU3UwwwfUDD33""""""DD33DUfDUˆˆª™ª™™wUwwD33""""""""3"""3"""""""""""""""3"""3""D3""""""""3""""DDDfwU33"33DDD333UDDU3""3333333"""33"""""3D33333333333333"""3wUDDD3D3"""""DUDff3"""""3333""3Uˆ™wD3"""DUUUDDDDDDDDDD33"3"333"""""""333""""""3"""""3""""""""""""333D33Dww"""D3""""""""DfD""Uf""""3ˆU"3"3UwU""UwˆˆfUUDDDD333"DD33D3DUUUUˆˆ™ªˆwwww3"33"""""3"""""""""""""""""3"""""""""""""D""""D3333DUfwU"33""3DD3333DDDD3D3"""333""""3"3""""3DD3333"3333333"""""3UD"3UD""""""33DUwwD3""3"""333"""""3Dˆ»w333DUUUD333333333"""3""333"""""""""""3"""""""""3""""""""""3D3"33DDfU""""""""""""333fD""""""""""U™D"333ffD3"""UfwˆˆwfUUDUUDDDDD3DDUDDUUUfˆ™ˆˆfffUUD3""""""33""3""""""""""3"3""""""3"""""""333""""""33DwwUD"33D333DDD33DDDD3""""""3333""33"3"""""33"3""3"3333"3""""""""333"""""3DDf™U3"""""""33""""""3UˆªfDDDD3D3"""""3""""""""""3"""""""""3"""""""""""""""D3""""""""33333DU™3"""""""""D3wf"""""""U™D33""fw3U3""DDUUwˆfU3UUDDDD33DUfUDfDfˆˆwffwfwUD3""""""""""""""3""""""3"3U3"""""3""3D3"""""3UwwD"333"33D33D3D3DUD33"""3333333""D"3"""""""""3"333"33"""""""""""""333"""""333DfUUD3"""33333"""""""3DUwwUD"33DD33""""33333333""""""3"""""""""""""UU""33""""""""""""""""3333UˆD""""""""""3"Uwˆ3""""UªUDU3"DfD""""""""3DUfffDDUfUUDDUUf"UffwwwwwwwfD3"3""""3"""""""""3D"""3""3D3U"3""3333"""3U3""""""""""DfwU333333333333D3DDD""""3"""33""3""DD"""33""33""33"""33"""""""""""3""333""""33"3DfUD33"3DD"""""333""33DfwwDDD33D33333333UUDUUU333"3333"""""3"""""""Dwf""""""333""""""3DD""""3"""""""DDDˆU333"""""333U™™3"fªwUU33DfU"""""""3""3fwwwDUUUDDUffffUfwwfwfUUDD3""""""""3"""""""3"""3DDUUDDD""3""3"3""3DD"""""""""""""Dww3333333333333333DUD""""33""""""33""D3""""""333"33"33"""3""""""""""""""""""3333DU3"UDDU333""33333D33DDUfffUf"3DDDDDDDDDUffUwUUDDDU3D3"""""""333"""""""""DD"""""""""33""3"""""""""3DUfU3D3"""""""33U™ªf"wˆwwfDfDfU""""""""""DUUfDUUDUUfwffˆfwfDD3DDDD3"""""""""3"""""""""33DDD33DD33""3""""3D33""""""""""""""3UwU3333"3333333333DDDD"""""""""""33333""""""""""3"3"33"33""""""""""""33"3"""""33D33DUfUwˆˆDD3"""3333DDDD3DDUUfUUDDUUUDUUfDUUfwwUUfDUUDD"D3""D3333""3""3"""""""""""""3""3"3""""""""""""33DUf333"""""3"3U™w""wfDwwwf3Df"""""""""""3ffUUUUffˆwwUDwU33"3DDD3""""3"""""3""""33"""333""33"""""DUD""D""""3D"""""""""""""""Dff33""3"333333333DDUD""""33""""333""""""""""3""""""3"""3"""""""""33333""""D33333DDDUUfwU""3333DD3333"33DD3DUUUUUfffwwfwDfUwwfU3"3fffDUUD3DDD3U333"333"33""""""""""""""""""""""""""""""""33UfU"""""3""""""33ˆ™""3fD"DDUwˆUUU"""""""3"""""UUffDUDUwfffUUD"D333D33""""""""3"D3"""""3""3"3"3"""333U3"D""3D3""""""""""""""3UU3"""""3"33333"""3DDD3"3""""3""""""""""3"""3""""3333"""""""""""333D33"3DDD33"""33DDDDU3"3DD33333"""33DUUD3DfffUUfˆˆUUw3DUffDUwwfUUUfUUDDDfUDDDD33DU3"""""3""""3""3""""""""""""""33DUw"""""""""""""3ˆf3™D3DD""3Uff"""""""""""3DffUfwfffUffDD"33"3D33"""""""""333""""""""""3"""""""D3D"3D"""""""""fU3"3"""""""33"3"3"3DD3""""3""""""""""""""""""33333""""""3""""""""DDD33D333""""3U"""""3D""3D33333"""3DUUD3DUfwfUwwfU3UDDUffD""wwwUUUfwwDDD3DUDDDDDDD""""""3""D""""""""""""""""""""3""""3"3Ufw"""""""""""""3DDˆD""3ˆDUfD"3™ˆ3"3""D"""""3fwUUwUUU3UU3""D"3333"""""""""D3""333"""3"3""""D""""33D3""""""""""""""3fD""""""""""3""33333U3""""3""""""""""""""""""3D3""3"3""""""""""3DDDD3""3D3DD""""3"33"33"3""""""3DDD3"DUUfwwwUDD"3DDUfU""""3UffwwˆˆˆfDDUUDDUDUD"""""D""""3""3"""""""""""""""""""""""DUˆD"""3"""""3UD™""DwD3D3"3wwD333"3"""""DffUUU"3D3""""33"33"""""""""""DfD33D3"""""3"""""3""fD3DDUD"3""""33"""""""""""3UU""""""""3"33333U3"""3"""""""""""""333333D3333D33""""""""""3DDD333D33"""""""""""333"""""33DDDUfwˆªfD3"""""33"""wwˆ™ª™wDDUUUUUfD""""3""""3"""""""""""""3""""""3""3DˆD""""UU"""""DUUf"fˆ33U3"""U33""3D"""""DwfffD""""""""33"""3""""""""""3UUw3"""3"3""""""""3""DfwˆD""""33"""""""3Dw""""""3U""""3333U3""""""""""""3D333333"3""333333""""""""""""""DfDD333"3"""""""""3""""""""3DD3DUUUˆwU""""""""""fˆˆª™ˆffwfUUfD""""""3"3D3333""3"""""3"D3""""3""""3"Uˆf""""""""33ff""3™ª3"D"""U3"""""D"""UwUUwU""3""33""3""3"""""""3UD3DD3""""3""""3UwffD"""""""""""""3Uf"""""3"""""33DD3""""""""""""""3"""33""""3"3333""3""""""""""""""""3333333"333"D3""""""""""3DD3UfUDfw"DD""""DDDD"""""3DUUwˆfwffwwf"""""""33D3D33D3"333""33""D""""""""""DwD""""""DUff"fªwDDD"""DD"""""3"""3fwwwU"""3""""""""""""33D3DU33"""33"""3DDUD"""""""""3DUD"""""""""""33DU3"""""3"3""""3""""""3"""3333""3""""""""""""33"""""D3"""DDDUU3""""""""DDDUfwfwfwU"D""""Dˆf3DU3"""D33fˆwU3""3""""""3DU3DD33"3D3333333""33"3""""""""3DU33""""""3UUˆDUD33DwªU3D3"""""3""""""3"""""Uwwwf"""""3""""""""""D3"D""3""""""""DDD""""3DfD""""3"""""3""""DU"""""D""""""3""""""3""""D3333"D"""""""""""""""3""3""""3UUDD""""3Dwˆˆ™™™wUwwwD"D3"3UfDD"3D""3""fwwf3"""""DD333"3D333""""3"3333333""""""""3ff"""""""""""3wˆU33UU™™DD3""""""3"""""""""""""3wwˆUDU""""""""""""""33"3""""""""33D""""""""""3DUD""33""""3"3"3D""""""3D"""""3"""""""D""""3""33333"""""""""""""3""""""DUU33D""""""3UªwU"UffUUwww""3UUU3"""""3U""""""DwfUD""""""""DDD33"3333"""333333333"""""""""DUUU""""""33ªDDffUˆ™D33"""""""""""""""33"""Uww3"wˆU""""""""""""""""3"3"""333D3""""""""""33DUU"33"""""""""33333"""""D33"3"""3"""""""3""333"3""""""3""""""""""3Uf3D"""33Dwˆw3"DUDDUf™f""Uˆf""UD"3""""3UfUD3"""""""333DD3""3D3""3333"33"333"""3"""""3UU3D3"""DDUffU3DDDf»D3"""""""""""""""3333""3U33D™w""3"33""""""3"""""""33DUD""""""""""3Uf3"3333"""""""""3DD"""""""""333""3"""""""3"""33""33""""""""""""""""""DD"""33Dfw3"33DwDUUUU3"3ˆw""""""U3"""3UfUD"""""""""""3333""D33"33""33"""3"33""3"3"3"""""""DD3333"33"DUDDDˆ3"333DªU""""3"""""""""""3DD""""""D33"3ˆˆ3"""""""33D3"""""""3"""33DDDD"""""""""""3UfD"33"""""""""""3D3"""""3333"""""""33"""""""3"""""""""33"""""33""""""""""""""DUfˆf""3""DD3"""DfwD""""33"""UwU33"""3"3"""3DDD"""""3333333"3"""3333"""""""3Uf""333"""3UfUD3"33ww""3"3™U""""""""""""""""DfU3"3""3"3wˆˆD"""""3D3""""""3""3"3DDUU3""""33"""""""DfD3"33"""""""""33D"""""""33"""""""""""""""""""3""""""3""""""3""D""""D""""""""DUwwˆ3"""3"""""f™U3"""""""""Dwˆ3""""""33"3DUfD3""33"3333333"""3"3"""""""UU3"""""3""3DDDDDD33""3w™""3"3ˆU"""""""""""""""3"DUUU3""""""UUfU"""3"""3UD"""""3"3D"333DUU3""""3DD33""""""3fUD3""""""""D3""""""""""""""""3"""""""3""""3"3"""3D""""3333"D""""3DUDf™w""""333"""3D333"""""3""DfˆU"""""""3333DDDD3"3"3"3D33333""33D33"3"""""""Df33"3wwDU3D33D33D""""333™3"33Dff""""""D""33"""""""3DD""""""3Ufwˆf""""Df"""3UwU"3"""""3"3"Dff3"""333"333""3"""3f""""D""""""3"33""""""""""""""""3"""""""""""3"3""""""""3fD""""33D33""""""3"3DDwwwD"""""3""""""33""""""3"""33wU""""""33DD33DD""33""33333333"3"""33333""""""DU3""""33"D33D333""3"""33Df"3DDUfD"""""""""""3"33"3""33UfwfDU""""""fD""""""""DUD3U3"3UwfˆUUwwU3"""3333"33DD33"3D"333""""333UUD""""""""""""""""""""""""""""3"3""33"""""3D3"""3D333"""""33""333UˆU3"""""""""3""3"""33"""UU3""""33""DDDDDD3"""""3""3DD33"3""3D3333""""""DU"""""3"""33D33"""""3D3Df33DDU"3""""""D3"""33333"""33U33D"3""3D"33""""""DDDDUfDUfwˆ™ˆwDDDD3""""33"3UU3"33"3D3""""33DD"""""""""""""""""""""""""""3"33""3""""""""3"""""""3D3"33""""3""333DwwD"""""""""3333"""""""""3U3"""""""33""D3"333D""""""""333"""3"D3DD333""""""""33"""""""""""3333""""""333"Uª"33DD""""""33DD33"33"""3"3"""""""""""""""33""""3D333DUUDfw™ˆDff""33""333333D3"""D"""DU3"""""""33D33""""""""""""""""""""""""""""3"3"3""""3""""""""33"""""""""3DD3"3""333""333DUˆU3"""3U33""""""""3UD3""""""333333333"3DD""""""""D333DDD3DDDD33""""""""33D"""""""""""D3"3"""""""DD33»ˆ"3D33"3"""33DDD3"333"""""""""""""""""""""""3D3""""333DDUfffwf3"DD33333""3""33333D3"""""3D""DDD3"""""""3"33D3""3"""""""""""""""""""3"""3"3"33"""""""""3""3"""""""33DD33"""33"""3DDUwf3"""""3D"33"""""UU3"""""""""""""33D33333DD""""""33333DDDDD333"""""""""""3D"""""""""""""""3D""""3""3ˆªDDf"""""""""3"DD3""3"""""""""333"""""33"""""""""""""3DDDDUUwf3"""""33""333333""""""""333D"D33"""""""""333DDD3""""""33""""""""3"33"""""""3"""""3"""""""33UD3""3333""3DDUfˆf"""3D33""""DDD"""""""D333"33DD33""DD"""""333DDD3D3DD33""""3"3"""""3D"""""""""3U"""D33"w™ˆ3w""""""""""""3""""""""""""333""3""3"3"""""3"D""3DD3DDUff"""""""3""333"""""""""""3DD"DD3""33"""""""33DDD""""""3"""""""""D""""""""33""""""""""""""""""D3DDD333333333DDfwwf3"""DD3""""3UD""""""""""""""3"""""""""333""""3"3DUUDD3DDDDD3""3"""33333D""""""""33"3D3UˆfwffU"""3""333"""""""""""3"""33"""""""3D""333"DD33UD3DUfU3"""""3"""""""""""""""""""""3DffDD""""""""""33"DDDD"""""""""""3"""""3"""""""3""""""""""""""DDD33333"333DDDDw™f""""33D"""""3D""""""""""3"""""""""""3""""""DUD3""3D33D333"33""3333D""""""""""D"3DDUfˆˆ"Dˆf"""3""""33"3"""""3"33"""""""""""""""""""3U""""333"D3DU33DUfD""""""""""""""""""3DwˆD"3"""""3"""""""3"333DDDD""""""""""""""""""""""""33"""""""33""""""""""DDD3333333"3DDDDf™3""33D"""""D""DD""""""""""""""""""3""""DU3"""3333333""3333D3DD""""""""3"DD3UDDfˆfDDww33"""3""333"""""""""""""""""""""""33DD"33"3""3"UUD3Dff333""""""3"""3"""""DDˆˆ3"""""""3"""""3""""""33"33DDU3"""""""""""""3"""""3"33"3"""""""""""""""33DDD333""333DDDDˆf"""333""""33""33"""""""""""""""""""3333"3""33""3333D333D3"333"""""""""3fDDDDUUwˆfw™ˆ"DD"""33"3333"3333"""""""""""""""""""""""3"DUDD"333DfD""DUwfD33"""""""3""""""""3"""3fˆˆ3"""""""""""""""""""3DDDDD""""""""""""""""""""3""""3"""""""""""""33"""3DDD33""""333DUUff3"""""3D""3""""""""""""""""""""""""""3D33""""""""333333333DD"33""""""""D™U3DDUfwf™ˆªf333"""""3"""3DD"D3""""D3""""""""""""""3""""DfUU3""3D3f33fwUD"""""3"3"""3"""""Dwˆ™UD"""""3"""""""D3"3"333U3"""""""""""""""""3"""""""3"""""3""D"""""3U3DDD3""""33DDUUffU3"""""""""3D"""D""""""""""""""""""""""""""33"3""33333"333D3333D"3333"""""333fªU33DDf™fw™™D33""""""33"""33D""""3D""""""""""""""""3""D3fUwU333UDDDDw™f3""3"""""D"3"U""""""DwUwU"""""""""""D"""""3""3DDUf"""""""""""""""""3""""""""3"""""3""333D33DD3""""33DDUUffUD""3"""""""""""""D"""""""3""3""""""""""""33"""""333"333D33DD3DD3"3"""""3""3f»wUUUUf™UU™ˆU333""""""333DDD""3"""""""""""""3D"""""fˆfUUDfD"DUˆ™wUDD3"""D3"3D3"D33"3DUD3ff3""""""""""""3""3UDUD3"""""""""""""""""""""""""""""""""3""""3D33""""33DDfffff"""33""""3"3UU3"D3"""""3333333"""""3"""33"333"""3""333"D3D333D3333"""""""3"""ˆÌfDUffˆwff™wD33"""""""""DDUD3"DD3"""""""""""""""3D""""UfUU33UDUfªˆwU3DDD3""D3"3D3DU""""""""Uf3""DwUD""""""3"""""3DDUU"""""""""""""""""""""""""""""""""""""""3"3D3333DD3"""3333Uˆwwˆ3""333"""""""""33ˆf"""3D"""3D3"3333""""""""""3""3"333""3""333333333""""33"""""""U™ªUUUUUw™Uwªˆ3D3"""""""""D3DwU"3"""""""""""""33"""""3DD"""3UD"""fffwfUUfwD3333""""3D333DU3""""3U3""3DfwU""""""""""""""3"DfwD""""""""""""""""""""3""""""""""""""""""""""3"""""33D33"333DDffUwwU3""3D"""""3"""""Dfw""3U"""""333D3D3"""""33""""3""""3""333""333""3333"33D33"""""""3™»ˆDDUUUfwU™™f"33"""3"3D33"3DUf™wD""""""""""""""""""""""3DU""3333"333fwfUfDDUUD333""3"333DDDD""""""DfU"""3wf3""""""""""UfwfUfˆD""""""""""""""""""""""""3D3""""""""""""""DDD33DDUDUfU3DwD"""333""""""""3U3""fU""""""333"33"""""DUU3"""""3"""""""3D3""333""333333"3"3""""""Uª™fDDDUfUff»ˆ""3D3"""""3D333DUf™fˆˆf"3"""""""""""""""""""""DD3""3UfˆfUUUUUUUDD3333""3""3D33""""""""3fw3"3Uw"""""""""""UwffwwwwD"""""""""""""""""3""""""""""""""""""""3DD3DDUfUfwf33fw3""""""3"""""""""""""U""""333"""""33""""DD33D"3333""""3""""""""3333"3333""3D3"""3ªwUDDUUUfwˆ»f"""3"""""DD33DUUw™f™ª»™U3""""""""3""""""""""""333""3fwªˆwwfwU3DDDUD3""D33U™™wf""D3"33""""""U™ˆ3""3fD"""3"fˆwfwˆwfD"""""""""""""""""33""""""""""""""""""""""""33DUUUDfUUfffDUw3"""""333"""3""""""33D""3"33""""""""333""""3D33"33"""3"""""""3333"""3""333D"""""""3™wDDDUUUfwªˆD"3""""""""DDDUfˆfªª™Ìª™™»™33""""""""""""""""D""3""DfwfUfw33fUD3"DDU3Dwˆªª™™wUfD"UU33""""""""UˆfD""Df""""""3Uˆffˆ™ww3""""3""""""""""""""""""""""""3""""""3"DUUfUUwUDDfwwwU"""""33""""""""""""33U3""""3""""""3"33""333333333""""""""3D3"""3"3333D3"""3"""w™UDDDUDf™ª™3"""3DDUfwˆˆªˆÝÌ»»™ªª™3"DˆÝÌ»™ªª™ˆf3D""""""""DU33Ufw™wU33ffU3DD333"3UD3ˆ»ªwfwfUfˆˆwˆw""""""""""Dww3""3UfD""""33fˆwwˆfU"""""""""""""3""""""""""""""33"""""""3DUDffwwfUDDwˆfUD""""""""""""3""""33U""""""333333"""""""33333""""""3DD33"""3""3333"3"""""""""""""""™ª33DUDDˆ»Ìˆ"""""33DUUfˆÌ™UUˆª™™ˆ™ªª3UªÝîÝ»»»»ªªª™w""""fffUD33Uˆ™wU33UwfUwfUDD3333U3ww™wfUfUffw™™wDDf""""3UwU"""3Uw3"""""3"UfwfD3""""""""D333""""""""""""""""""""3""""""""3DDDUUUˆˆfU3UwDDfD"""""3""""""33"""3D"""""3D3""""3""3""333"3""""""33DDD""""333333"""3"""""""""3"3ªˆ333DDUªÝªU""""""""333DfÌîÝ»ˆUwªª»ªÌîÝîÿ̈UffwfffˆªffUUˆUDˆ™ˆU3"3DwUf3DDDDfwwˆˆwD33333DfwˆfUUUDDfffwUfUD3DDfwˆ33"3fUD""""""3DU""""""3DUDU3"""""""3333"""""""""""""""""""""""3""""""3DUDDfDDfwD"UˆfDff33""""""""3""""3U"""""""""33""""3""""""33""""3333""""""33D3""""3"""""""""fªf3333Dwª™D"3"""""""""3fÝÝÌ»ÝÌ»ÌÝîÿÿîÝ̈wDD33UUUffwˆ™»ª»ÌÌÝÝ̙UDwf"3D33D33Uˆ»»™ˆfDDDf™ªfffUfUDDDfffUUUUUfwDUwwDfU3"DUfD33"3""""3"""""DDDU33""""""""""""""""""""""""""""""3"""333UUUDDU3DUUDDDDDUU""""""""3""3"3"""""D3""""3""""""""""""""33""33"DD3""""""""""""""3wˆ3""33Uª»f"""33"""""""3fÝÝÌÌÌÌÝÝ̪ªªˆwUDUD3"33D3DUD3Dˆª»Ì»™™™™ª»»ªDUD3D3UUˆ™wwfffª™ªˆˆwˆUUfUDDD3DUDUD3D3D3"3"Uffwwˆ™™™f3fˆUUU3""3"333D333""""""""""""""""""""""""""3D3"3DDDDUDUUDDDDD33DDf3""""""""""33""3"""3"3"""3""""33""""""""""""""33D3"33""3"""""""""""""w™U33""3wª™3""""""3""""DDÝÝ»»ªª»ªˆUUfD3""3DD3"333U3"UD3fwwwwfwwˆˆ™™™ªˆ™ˆw™ˆwwD"""3"3U3333DwUUUUD33333DD"3"""""""3"3UUf™ˆˆwfˆ»ªfU""""""3DUDUU3"""""""""""""""""""""""""333"33DDDDDUfUDDDDfUDDUf3"3""""3""""""D"""""""3""""""3""""D3"""""""3""""3D3""3"""""3"""""3""""D»ˆD333"Uªª3""""""""33"""""3U™Ýª»»ªªª™wfwD3""333333"3"3UfUwUUfUDD3DDUDD3DDUDDDD3"""""""3"3DDDUUUDDD3"""33""3"""""33""33"DDUUUDUfwwwfUfffU"3D3Uw3"3""""""""""""""""""3"3"33DD3D3DDUUUDDDD333fU"""""""3""""3U3"""""""333"""""""333"""""""3U""33D3"33""""""""3"""D3D3"f»U333"Dˆ»U"""""""33""3""33f»ªªªª™™ˆˆw3""333""3D3"3DUDUUUUUD""3333D3"""""3""""""""""3333DUfU3D3"""""33""""""33"""""""3DD33333DUDDUUwwf33""3DDDDD"""""""""33"""""""""""""""3333DD33DDDUUDUDD"33Uw""""""""DD"""3"3"33""""33""""""""3333"""""""3""333"""3"""""D3""3fª»3""""f™w""""3""""3333U™»ˆ™wwfUDD"""3""3""33""""D3D3DDD3""""""""""""""""""""""33""Uf33""""""""""""""3""""""""3333333"3DUDDDfwf"""DDDDD"""""""""33333"""""""""333"333"33DUUUUDDD333DD""""""""""33"""""D""""""D"""""3D"""33DUD333D3"333"33"""""""""""Dª»U3"3"3™w""""""""""""""333w݈ˆw""3"D3""333""D33""""3DD33"""""""""3"""""""33"D3""""""""""""""""""""""D""""33"3"33DDDDD3UD""3UDffUf3""3""333"33""""""3""""""""33333DDU3DDUD3DD""""""""""3D"""D""33"33333"""""""3DD33"""""""3"3D""33""""""""3"fªf3"3""w™3""""""""33""3""333ªˆDf3"""3D33DU333DD""""D33"""3""""""3"333"""""3""""""""""""D""""3D"33UDD3Uˆ""3333DUf3"""""""""""""33"333""""""""""""""""""33"33UD3DUDD333"""""""""""3"3"""""""333333"""""""""3D3""3"""33"""""""33"""33"3"33ˆ™D"3"U™w""3""""""""""""""""""3ffˆ3DD3"""3D333""3"3"""""""""""""3""""""3""""""""""""""""""""33"3""3""3333Dw™""D""33"3UU33"""""""""""33333""""""""""""""""""33""""3D3DDDD333DD""""""""D3"""""""""3D3"""3""""""""3""""""""""3D"""""3"""""3""3"f»™3"""ˆˆD""""""""""33"""""3™ªˆUU3"3"33""D3"3""""""D"""""""""""33""""""""""""""""""""""""33"3fˆf3""""""""DffD3""""""""""D333"""""""""""""""""""33""33DDUD3D333"D3""3"""""Dw""""""3D""""D""33"""""""""3"3"333DUD3""33""3"""""3w»f""f™U""""""""3""3"""3""3ª»ªf3""""""""3"""3"""""""""""""333""""""3""""""""""3"""""""33"3DUˆf3"3U""""""""DwˆD"""""""""""3DD333"""""""33"3"3"""""""""333333DUfUDDD3"333""3""3DD"""""3"3"""""33"""""""""""""33D33DD3""""""""""""3fª™3"wˆU33D3""""""""""3DªÝ™f3""""""3""""""""""""""""UfU33"""""""""""""""3""""3"3DffwDUUD3ˆw""""""""3DwˆD"""""3"""3UUD3D"3""""""3""""""""""33333DUUffUDDf3"DD3""""3"""""DD3""""33""33""33""""""""""3"""DD33""""""""""""w»w3fˆf3""3D3"""""""D™Ì»3"""""""3""""""33""3"DfUUD3""""""""""""""3""DDUUfUffwwUˆ™w""""""""33UwD"33""""""3DD3fUD3U""""3"""3"""""333333DDDDDUfwfU33D"DUD"""""33"""33DDD""""""3333"""3"""""""""""""""333DD3"""""3""33"UªªD"U™f3"""""""""""""3"""ˆ»»w"""""""""""""3UUU"""""UDUUUUUD3"""""""""3"3""""""3DUD33DUˆ™ª™™ˆUD""""""3DwUDD"""""""""""D3DUD33D3""""3""3"""""""""""3333DDDDDUUUUwfD3DD3UD"""""""""""""3DDDD""""""""3""""""""""""""""333333"""""3"""333™ªf3w™w3"""""""""""""""""3U™ªw3""""3"""""3DD""""wˆfUUDDUD3"""""""""3D3DDDUwwˆ™ª™ˆUDUUD3"D33f"3""""""""""""3DUUDUD333"3""""3"""3D"""""""3"333DDUUDUDUUfwU3DU"UD"""""3333""""33"""""""""33"""""""""""""33333"""""""""""""3wªw"f»ˆ3"""""D3Dwªˆ3""""""""3333"""""""wwUUDD3DD3"""""""3""""""""333DDUfffwˆˆfDUfUDUwfUD3""D3"""""""""""DDUD3D333333"""D""""""""""""3""3DDDDDUDfUDUUwf33UD3U3"3D33"33""""""""33"3"""""""3"3"3"""""""""33Dwªf"3ˆ»f"""""""""Dˆªˆ"""33"""""UD3"3"""""UwDUU3DDD3"""""""""""""""33"3"""""""""33DDUUUDUD3333DDDUUfˆU3"""""""33DDD3333"3333""3D"""""""""333333DDDDUUDDUfwwUDDDUDD3""""""3"""""3"""""""""3"3""""""""3""3D"33""""3Dww3"w»w""3""""""""3™»3"""3"""""3DDD33"3""3UU3DfD33D33""""""""""""""""""""3DDUDUUDDDDDDDDUUfUDfD3"""""""UfUD33""3"""33""""3D""""""""""""33333DDDUUUD3Dw™wUUDUD33D""""""""""""""3"""""33""33""""""""3"33""""""""""""""3DDU™"Uªˆ""3"D""""""""""DªÝU""3"33""""3DD3"""DUfU33UD33"33"""""""""""3"""""""""33DDDDDDDDDDUUUUfUUwD""""""""""""""DwfUUfU"D"""3D""""DD""""""33333DDUDUDUDUfUUwfDUD3DU""""""""""""""3"""""3"""3""""33"33""""3""""""3DDfw"U™™3""""""""""""""""""wÝÌD""""3""UUD3"""""""3UUU33D3""""3"""""""""3""""""""""3DDDD3DDD33DUDUfUfw3""""""""fwUUD3DfD3DD"33""""DD"""""""33"3"3333DDDDUUfUUUUffwUUD33DD""""""""""""""""""""3"""""""""""""""33""33"""3"33"""33Dw™fª™D"""""""""""""""""ªÌ»D""""""""""DD3""""""""""3UUUD3DD3"""""""""""3"33DDD3"""""""33333DD33DDDDUUfD""""""""fwwfUDD""33"DD33""""DD"""""""33333333333DDDDfUDUUUfffDD333D3""""""""""""""3"""""3""""3333"333""""D3"""""""""Dwª™ÌªU"""""""""""""""™Ý»D"3"""""""""3"""3"3"3ffUfˆUD3DD3D3"3"""33"""""3""3""""3"333D333DUUUfUf"""""""""wˆwfUUU33""""3DUDD333"""""""""33"3333333D33DDD33DDUUfffDD""D"""""""""""""""""""3"""""""""""33""""""""""3""3"""""""""""D™ÌÌÝw3""""""3"""3ªîª""""""3""3"""3"3""""fˆwD3UffUwfU333"33"33D333"""""""33333D33"DUUUUDD"""""""""""wˆffDUDD3""""""""3DD3"""""""""""""""""""333DD3DD"U3333DUUUfD3"3"""""""""""""""""D"""""""3D33"""""""""""3""3333UªÝݙD"""""""""""""""D™Ìݪ"""""33"""""""""wˆˆwwˆwwfUffD333"""3333D3""""""""3"33D333DDfUDwDD"""""""""3wwfUUDD33""""""""3"""""3"""""""""""3"3333333DDDD"3"33DDUwwU3333""""""""""3"""""""""""""3"""""""3D333""""""3"""""3333wÝÝ»f"""""""""""""""""wªÌ̪3""33""3""f™wwˆˆˆwffUDDD3""3"3"3DDD3"""""""""3333D333DUfDwˆU"""""3wffUUDD33333""""""3""""3"""""""""3""""333333DDDDDDD3D"33DDfww"33D"""""""""3"""""""""""""""333""""""""""""""""""""""33wÌ»™U""""3""""""""""""""""ªÌ»»™3"""33""D3"""3w™ˆˆˆˆˆˆwfUD"3"""""33DUfDD"""""""""""33333DDDfDUˆDD3"""""""ˆwfUDDDD33""""3"3"""""""""33"""""33"3"333DDDD33D3U3333DUDUDUDf"""""3"""""""""""""""""""""3""""""""""""""""""""""33""333™ÌwD"""""33""""""""""3"fÌ»ˆUU3"33""3DD33"""""""""Uˆwˆˆ™ˆˆˆfUD33"""""333D3fU3"""""""""3333D3DUfwff33"""""""3""""DˆfwUDD33"333""""""""""""""""33DD33D333""3333D3DD33333"33UDUUUDfD"""""""3""""""3U"""""""""""333""""""""""""""""""3""3"D3U»»3""""""3""""""""""""""Dw™™fUfU"33UD3DD""""""""Uwwˆ»ªª™ffUD3""33""333UU3"""""""""3333D3Dwwwf3""""""3""""""""""""3UfˆwfDD33""33""""""""""""""""""""""3"3DD3D3""333333D33"33"33DUUUUUUf"""""""3U"""3""""33"""""""""""""""333""""""""""""""3""""""3DU̪3""""33""""""""""""""""""""Dˆ»™wˆfwD33"DDD3""""""""3www™»ªˆfUUU3""""""3""3333DD""""""""""3333DDDUUw™f"""33""33"""""3D"3ˆ™wfUfD3DD333""""""3"""""""""""""""333333333333333333"3"333DDDDUwDfD""""""""""""D""3"""333""""""""33333"""""""""""""333"""""""Uª»ˆ""3""33""""""""""""""""""""3f™ÝªUDU3"""33DfD"""""""""""Dˆ™ª™ˆwfUD3""""""""""3"333"""""""3"""""DD3DDDUDUf™™U""3D3""""""""3"""Uwfffˆª™ˆfDUfUD3D3""""33"""3""""""""""""""3D333DD333333333D3333DDDDDUfwˆf"""""""""""""""""3""""3D"""""""""""3""""""""""""""33"""""33D™ÌÌD""""""""""""""""""""""""""UÌÌݪ3D""""3DUD"""""""""""3Dˆ™™ˆwUUD3333""3"""""33D"""3""""3""3"""""""D33DUDDUDUfU3"""""D3""""""""""3Dwwwwˆ™™™wˆˆwfUU3D333""""33""""""""""""""""""333DDD3333333333DUDD333DDDUfw™ªf"""""""""""D3""""3D33"33"""""3"""""""""""""3"""""""""3fÌÝ»3"""33""3""3""""""""33""""""""fÌ̙™ª3"""3333"""""""3"ˆˆˆwffUDD333333D3""3DD3D3""""""3""""""""""333DUUUDfwˆ""""""3""3""""33""3Ufwwˆ™ªˆ™™ˆwwwffDD3"3"33333""""""""""""""""33""3333333DDD3DDDU3""3DDfUUfw™ˆwD3"""""""""333"""""""3"3""""""""""""""""""""""""""DfwÝ݈"3"""""333"""""3"""33"3"""3"3w»Ý»™ˆ™D"D"""D"""""""wˆwˆwfUDDDDD33DDDDDDUUDDD"""""""""""3"""""""3DDDDUUffˆw3"""33"""""""""3UwDfˆ™™™™™™ˆwfUUUD33333333""""""""""""""""""333"""D33"33333DDDU""""DDUUfwˆwfwwwU"""""""3DD3"3""3""""D3""3""3""""""""""""3""""""""3ˆÌ»ªªw3"33"33""""3"""33"3"""""""3DDDˆÌw™wD3D""""3D3"""""""""3ˆ™wfwˆfUUfDD333DDDDDD3DUD""""""""""""D3""""333DDUUUUˆˆw3"""33D3"""""""3ffffˆˆˆ™ˆˆˆwwffUDDD33333D3"""""""""""""3"""""33""""333333"3U33""""3D3DffffwwwwwU"""""""""UU3""""""""D33""3"""""""3"""""""""""""D™Ý̪ˆU""33"3333""3D""D""3"3DDU33UfUDUwf™ÌÌ»ˆfDf™fDDU"""333"""""""""""""""UˆˆˆwffˆˆwwUDDDUUDDD33D3DD333"""D""3D3"""""33D3UU3Uw™ˆf""""33DUD"""""Dfˆ™UwˆwwwwwwffUUUUDDD333"""""""""""""""""""""""""3"3""33"333""""3"333DUfffffUffU""""""""DD33"""""""""""""""""""""3"33""""33U™Ìîˆ333"""""33"3"""""3"333"f™wDUffffˆˆ™ÌÌ»»ªˆUff™wfDD""""3D3""""""""""3"3""UwˆwwwUffwwUDUUUUUU3DDDUDD33333333U3""U3""3DUDfUfDfˆU3""""33DUU"""Uwˆ™wˆ™ˆwwfwffwffUUDDDDD33D3"""""""""""""""""""""""3""""333"3""""3"""33UUUUUwf3Uwf3""""""""3333"3"""""33"""""""""33"""33""DffªÝîîf""""""""3333"""""33333fwˆfUUDUUUUfˆªªˆ™ªªˆˆ»ˆˆwU3"""""3"3"""""""""UwˆwwˆD""3fwfffUfUDDDDUUUD33333"""D3"3"""""""""""3UDUfD3UD""""33DDD""Dfˆˆˆwˆˆ™ˆˆwfffUUUUDDD3DD3333""""""""""3"""""3"""""""""""""""""""33"""""33"333DDUUfDDDDDUD""""""3333""""3333"""""""3"3"""D33""3UU3DUwff»îÝÝw""333""333333""""""""wwwUfUD333UUww»wª»»ÌÌ̙ˆwfU"3"""""""""""UwwUUD""3fwfwfUffUUDDDD3D3""D3""33"""3""""3DUUDfw3333""""""33"Dwwwwˆ™™ˆwwwfUDDDDDD3D33f3333333""""""""""3"""""333333D3"""""33D3""""""""3DDUfUDDD3DfD"""D3"3"333""33333D3""""DU"33333333"""3DUUªÝîîÝ»f"""3D33333333333"3""3DfwˆwfD333333DUw»»ÌÌÌî̙wˆfD3"""33"""""""""3fwD3""33"UwffffwwfUfUD33DD"3DDDD""""""3""""3333D33w"""3""""DwˆwwˆwˆˆfwUUDDDDD33"3DfD333D33"""""""""""""""3"333"33333D33"3""""""""""33DDUUDDU3D3fUD""3333""""""33"3"33"""""fD3""3"3"""""3ÌÝÝÝÝÝ»ˆ3""DD3"3"33"3""""DfUw™ffUD"3333333D™ÌÌÌÌÝ̙ˆˆf3""3"""""""""""""""UwUD3"3UffffffwfUUUD33DU33"UD3""3"""D""""""""""3333DD33D"3"""D"Dwˆˆª™™ª™wwwwfUDDDDD33"3DDDDUDD333""""""""""""""3"3"""33"""""""""""""""""33DDDDUUUDDD33UfU""3U""""33"3333"""""""""UU33""""""Dff»ÿÝÝÌ̙w™wDDw33""""3"w"3UfwwˆwDUUUD"3333"3"Dˆ»ÌÌÝÝ̙»™3""""""""""""""""""UffUD"3UffffUffUUffU3DDUDDDUD3"""333""""""""""333DUf"""""3f™ªªªªªª™wfUwUDDDDDD3"D33"333D3333"""""""""333""""""""""3""""""""333""""""33333UUDUUDDD33DDD""33"3""D3""""""""""""""Uf""""3fUfwª»ÝÌîÿÿÝÌÌ»UUUwUDf33Ufˆw"fwˆwfUUD3UDUU3"D333333U»»ÌÝÌ̪™ˆD"""""""""""3"""""""3U3fUD"3UUUffUUUUfUDDDUUDD333D""""""33"""""""""""""""3333DU"""3""""fˆ™™™ˆˆˆ™™™wfUUUDDDDD33333333333333""""""""3""D""""""""""""""""""""""3"""""333DUUUDUDDDDD33DU3""D333333"""""""""""""""fªˆwDwˆª»»»Ýîîîîÿݙw™ªˆˆUUUffwˆfˆwˆwwUfUUDUD3""DDDD3D3"""33Dw»ÌÌ̪»ˆw3""""""""""3""3DDUUDDD3UfDUD"UUUUUUfD333DD""""3"""3""""""""""""""""3DDUˆ333""DwwˆwUfwwwf™ˆUUUfDDDD3""333"""33"3"""""""""""""""""""""""""""""""""""333"""33"DUUDDDUUDD3DDD3DfU"UU"""""""""""""""""""""""Dw™»»ÌîÝîÌÝÌÌÝîÿ»wffUffwf3UfUUfˆ™fffUUUDD333"""33DD3D33""333ˆ»Ì»»™ªwU"""""""3""""""""""UDD"UUDfD3"33""UfUUUD3"3D3D"""""33""""""""""""""""""""3"""""D3DUUf3"""DwwfDUD3DfffwUUUUUD333""333""""3""""""""""""""""""""""""""""""333""""D33"""3333DUDUDD3UUUDDDU333D3"33"""""""""""""""3"www̻ݙÌÌÝ»îîîݪffUUDDfw"fffDDUfU3DUDD3D3""""""3"DD3DD""""3fª»»ªˆªf3"""D3"""DD""""""""""UfD"3Ufff"3""UfUUD""3D33"""333"""""""""""""""""""""3""""""33DUf3"3""DfwfUD33UffUDDDUUUD333""33"""""""""""3""""""""""""""""""""""333""33D3""""""3DDDDDDDUUUfUUUUD"D"3""""""""""""""""""""""""3"Dwf™™»Ì»ÝÝîÝݪ™wfUDDD33UfwˆUDDDfD333DD3"""""""""3U333D3""""3™»»™ˆˆf""""DD""DU""""""""DfUDDDDfw33""Ufwwf""DU""""""33333""""""33"""33"3""""""""""""""""DUfD""""3""""3Uˆwfffw™™wUDDDDUUD33"""3"3""""""""""""""""""""""""""""33"""3"3333"333""""""3333DUDUDDUUUUUUfD3UD"""3"""""3""3""""3"""""""""DU™ªÝîÌÝîÝî̙ffˆfD3333DD3DfwˆfUDUD3333""""""3""DU"3D3""""D™ª™ˆˆw""3U33D""""""3fUUfD3DUwwD"DUwwwU"3DD"""3"D33333"""333333333""""""3"""""3""""UwU3"3"D"3"333Dfˆw™™ªª™ˆwUUUDDD333""33""""""""""3"""""""""""""""""33"33""3"""3D333"""""""3"33DDUUUUUDUUffwwUwU"""""D""3UD""D""""DfUUwª»»ÿݪˆUD33D3"""""3DUUD™ˆfUUU3DD"""""""""DDw333""3U™wfU™U33DDDU3""""""""3fUf3UD33Dwf"UD3DUU33U3"""D3D3DD333"""33D333333"3""""""""""""3"""""""3UwDDD333""Dfwwˆªª»ª™fUDD33333"33"""""""""""""""""""3"""333""""""33""33333D"3"""""""""3333DDDUUUUUUffwˆˆ™D""""""333DD"""""""""DD3"w»ÝÝÌ»fD3""""""""""3DDDˆfwffDDD33""""""DwwwwwwD"DUDD333wwwfwU"""3DfU3"""""""3DffDDD3""3Uw"""333""3333UD33DDUDDff3"333"""3DUD33333""""""""""""D"""""33"3""DUffˆD333"fwwˆwˆª»ÌˆD33333333"33""""""""""3""""""DU3"33DD3"""3333""3""3DD3""""33"""""333DDUffUUUUfUf™™ˆ"""""""33"""""33D""D»ÝÝ̙3"""33"fwUUUUD333""""3"3fwffUUUDDwwUDDUwˆffffwfD"3"3DD333""""""""3wUwUDD"""Dw3""3"3"""DDDD3Uwwf3333D33""DDD3"33"3"""""""""""""3"""3""""3""""33fwwD"""""ffffwªª™wD"333333"3""""""""""""""33"33"3D3""""DD33333333D3D""""""""""""D33DUUUUUfUfwˆˆf™U"""""""""""33""U»Ý»ˆU""""DD3DDUUDDDDDDDDDDDDDUD33DD3D3""33DwUD3ˆw"""3D3"""""3""""""""UwwfUD3""DD"3333DUwwffU"""33333D3"33""""""""3""""""""""""33"33"""3UD333"""""Dwfff™™fD"333333"""""""""""""""""33D333"3333"""""33333"3""""""""33333DDDUUUUfffwfUwf""""""""""""fªÌ™f""""D3"33UwU33"""""33D33""3"""""""3DUw33fªD""""3"""""3"""""""""""""UwwU3"""D""33DUffffwDUD3"33333""D33""""""""3""""""""33"33""3""Uw333333""wfDD3ffD33"3""3"""""""""""""""""333333D3"33""""""333"""""""333"3DDDDDDUUUUffffDw™U"D"""""""""3UU»ÌªUD""D""D333""3"""""""""""""""3Dwˆf»w"""""""""""""""33D3"""""ffU3"""""""""3D"DD3""""3DUDD"3D333""D"""""""""""""3"""""3333333"""33fD33D"""""""UfDDDfUD"""""""""""3"""""""3U3333333""33333"33""""""""33""3DD3DD3DDUDDUfwˆfˆ33"""""""""""""UwªÝ̙wD""3"""33DD"""""""""""""33Dw™»w3"""""""""""3333""3"""DfD""""""""""""""3D3D33D33"""33""""""3""""""33""""33333"33"3Uwf"""""D"ffDDDwD""""""""""""""""3D""""""3"3"333333333333333"""""""3"3"3DDDD3DDDUDD3UwwU™D""""""""""""ˆª»™™™ˆˆf33""""""DDD""""""""""DUUU™w""""""""""""""""""""33DfD""""""33""3"DUU3D33"333"""""""""3""""""33""""333"3D333DUˆU""UDˆwfDUf3"""""3""3""""""333333D3DD333333333"""""333333DD3D3333DDDDDUffUw""""""""33""wÌ»ˆwˆwfff3""""""333"""""""""33DU™f"""""""""""""""3U33"""""""""3""3UfDUD3""333"3"""""3""""333"""""333DU3"DD3Df3"""Uˆ™wfUff3""""""33D3"""""""""3DUDD33"333"D3""333333UDDD33333DDDDDUUf™"""33"""3"""DˆÌªˆwffwUD"""""""3"""""""""""""3""""33f™"""""""""""""""""""DUD"""""33""""""Uff333DDU33""""""""3"""""333"""""3D3D33DD3DfU33"DUwwwwffw3"""""""3D"3"""""""""""""""DUDD"33"3"33"33""3DDD3333333DDUfffUfw™""3"3""""D™»»™»ªwwwUfDDU3""""""""""""""""""""D"DD™D"""""3""""3"""""""3UD3"""""""3U""""""""UˆUD33DUU33"""""""""""33""3333D333DDDUUfDDD"3™ˆˆwfU"fD"""""3"3""""""""""""""""""""""3UD333"3"33"333"3UUD333333DD33UªwUfwˆf"""33"""3""U™ªwfˆwUUwUD"3DD3""""""""""""""""3""""""""3"""""3Uw3""""3""""""""3UUD3"""""""""U"""""""3"UUUDDDDUD3"""3"3""""""""""3"""33333D33D33DDUDD3"3""wfUUUDD3w""""""""33"3"""""3""""""""33""""""3DDD333"33333333UUDD33D333D33DwUffww™"""""3D"""""""""DªªfDDD3Dff3""33"333""""""""""""""""3D33"33""""""DwD"""""""3D"""""""""3UD""""3"3""""""""33"3"3UD3""D333""""33""""""""""""333"""333333DUDDDUUDUfD"UwfUUUDDD3f""""""""""333"""3U3"""""""""""""3DD333""3"33333DUDDDD3D333D333UDfwˆ™D33""3""""3w»w33D3DwU3"3""""""3""""""""""""""""""""3"D33"""3""""UD""""""UUf3"""""3f3"33""""3"""""""""3"""3"U3""3ffD3""""""3"3"""""3D"3""""33333DUDwˆfUUˆ33ˆˆffUUUDDDDDD""3"""""33""3""""DU""""""""""3""""""""""3D3"333"3D3333DUUDD3D333"3333DDUwˆˆw"""33"""""""3Dw»™"""3DUfD""3""""""""""""3"""""3""3""3""33DD3"DD""D""3D3""Df3""""""""D""""3""""""""3"""3"Dw™™wD33""""3"""3""""DD""""""""D3D33DwwˆwˆDfˆfUUfUUDUDD3DU"""3"333"""3"3D""3""DD3"""3""""""""""""""""3"3D333"DD33D3DDUUUD333D33D33"UDUff™U3""""3"""""""Dªª3""DUUU3"33""333""""""""""""3""""3""""3"3"3333DD333D3"""""""""""""""""3"33""""D3"""""""""3"""3w™ªˆª™™w3""3""""""3""""33""""3"""DD3DDUDD™ªª™™U3DUUDUUDD33ff""""333""""3"3""333fff"""""""""""""""""""""33"UDD3333DDDD3DUUUUD3DDD3""""UUUUˆf3D"""""""""ˆªU"""3fUDDD333""3U3"""3"""""""""""""D33"""""33"33333D33"3""""33"""""""""""""""3""""3"U3""""""""""""""""""3DDf3"3""33Uw™™™ˆwˆ™ˆˆU3"""33D"""33"""3"""""""3DDDDDDfUD™ªˆUDUUUDfUDD"3ˆ™U3"""3D"""3"""""3333D33""""""""""""""""""""D""D33333DDDUfwfUUffDUD3""3"3DwUwf""""""""""""""3DUªª3"""DfDUUD3"""""""""""""""""""""""""""""3DDD33"""""""""3""33"""""""D""""""""""""""""""3U""""""""""""""3333fˆwffUfˆ™ˆfDDUUfffwˆD33""""3333""""333""3"3333DDD3Dfff3fˆUUUfwwfU3Ufªª™fD3D3U3""3"""3"3D33"""3""""""""3""""""""3333DDUDfˆ™ˆfUUfwfUD""""DDUfUw""""""3""""""33"D™»ˆ3"DUfUDDD3"3""""""""""""""""""""""3""""33DDUDDUUD333"3""""""33""""33"""""""3"""""33""""3""""""""""""""3DUUˆª»ª»»ªˆf3""3UD33DUD"3333""33"3"""3333"""33333D"DUUffUwfffwwfDDUˆ™™wwwf3DDDD"""""3"3333"""33""""""""""""""""3"33UUDfˆˆwfUDUwwfUD3""3DUffww""""""""DU3f»ˆD33wfUD""""""D3"3""""""""""""""""""333333"""33DUUUU3DDUDDD3"3"3""""""3"3"""""""""""3333""DD""3"3U"""""""""""33DDUwˆ»»ª™UD""""""D3""33"3"33""333"3""3333333333333DDDUUf3"U™ˆˆwwwffwwwwfffwwUDDUU""""3"""33"3333""""""""""""""""""DDDDfˆˆfUUUDwwwwfUD3"3DDUwˆf3"""""""3"D3""D™ªUDDUwU33"3""""3"3"""""""""""""""3"""""3DDDD3DDDDD"33""3""333D3""3"""""3""""3""""33""DUUUD333DD""""3U33"""""3DDDDDDUUDww™ªˆD3""""""D""3""3333"""33333""""3333""""""3DDDUU""™ªˆ™fUUfwfUffDUwwwwff"""3333"""3D3""3"""""""""""""3UD3"UˆwUfUUfˆwˆwffUDDDDDf™ªˆ"""""3""3""""3fªªf3DfUUD3"""""""3"""""""""""""""""""3""3333""""""""333"""33""""""33""""""3"""3""3DfUD3"""3DDD3"""UUDD"""33DfwwˆwfUfUUfUD3""""""3D"3"""333DD333333""""33D3333"""""33DU""f™ˆwfffffDUU3DUUw™™ˆD333333""""3D333""""""""""""""""333fU3"DwfˆˆˆwfffwfUUDDUUˆª™U"""""""UU"DU™ª™fDUˆfD3D""""3"""""""""""""""""3"3""""""""333""""""""""3""""3""""3""""""""""""3D3"3""333D3""3D""""3DU3UfwfUfUD3D3""""""3D3"3"33DD33333D"""""3DDD3""3""""3DU33"3™™w™ˆfUUDD3DDUUw™™™w33""""""333DD""""3"""""3"""""3""""3fwU""33wˆwffffffUffUUfwˆˆ3"""""""D™ªÌ»ªªˆfUDfˆDDD3"33""""""33"""""3""""""""""""""""3"""""""""333"""""""3""""""""3""""3"3""""""3""""""""3"""D33"3D3""""""""""33DD33UDD3"""33""""""D333"DDDD33DDD""""33DDDD33""""DDUD33"DˆfffUDDDD3DDUfffwˆˆf3U"""""333333"""3""""""""""D""3ffD"3"3"UˆfwwwfUffUwUDwwfww""""3f™™ˆwfffUUfwfU3333"""3"""""3""""""""3""""""""""33"""33D33"""""""""""3""""""3"""""""""""33DD"3""3D"""""""3""""""""""333DD3""""""""""""33"33"33"""3DDDDDUDUDDUUD33"3DUDUUDD3"3UUU33UDfDUfUD33333DDfffff™™DU""""3"3D3D"""""3""""3""3333"3D""""Uwf3"""3""fwfwwwfUUUffUfwfw™3"""D""""™»ˆwwfwˆˆˆwwfD333"3"""""""""""""""""3"3"""""""""3""""DDD""""""""""3"""""3"3"""""""""""""3DD3""""3""""""3""""""3""D33""""""""""333"""""""""DD3"UD33UUUDD3DUf3UfUDD3""""3UD3"ˆˆffUUfUD333DDUffwwww™ˆˆwD3""""333D""3"""3""Uf3Dff""""3"""""3""""DwˆD""""3D3D3UwwfUwffffwfwffU™D"""""3"UªªwU3DfwfUDDDD3""3"""""""""""""""""""""3""""33""33D33""""""""3""""""""3DD""""""""33DDD""""""""""""""""""3""""33"3D"""3"33D""""""""D3"UUffDDD3"DwfffUD"""""3DD3"ªˆwfffUUUUD3DUDUUwfwwˆˆffU""3""""3"""33"3"""""DwwfUf"""""""""""""3wf3"3""""""D"UD""wwfDwwwwˆwwwffˆˆ"""3"""f™ªfD333DDUDD3333""33""""""""3"""""""""""""3"""3D333""333""3""""""33"D3"""""""""3DDDUwD""3333Df"3""""""""""""""""3""""""""333"3""""""""""""UDUUDU3"UfUffUD""3""DˆfˆªªwfUUUUUUUDUUUfwfwwˆˆwˆffU33"""""33""3"""""3Dff33U""""""""""3UUU3""""""3"D333""3UwwwˆwˆwffffUUˆD3"""""3ˆªwD3"""333D3333""333"3"""""""""""""""""""3"""""""""3"""3"""3""""""""""33"33"3""""3DDfwwffD3DUUffˆˆDU3""""""""""""3fU"""""""3"""""""""""3""""""3DDD3DU""wˆˆˆwwU333"3U™™fˆ™ªwfUUUffD3DDUDUfwwwffwwUwˆˆwU3"""""""3"33"DUUU333"""""3"33Uf333""""3"33"""DUUwˆwwffwffUUD3"33"""""""ˆ»ˆDD3"""""33333333""D3"""""""""""""""""""""""""""""""""""""""""33""D""D3""""DDDwˆUfwfwDUfDw™™UU3D""""""""""""""""33ff3""""""""""DUD3"""""""33"""DUUfffUfUDfffUDDfwˆˆwˆˆˆwfUˆˆˆ™wUwfDUUUDDDDUUfffffwUUwwwUUUU3"333"""""3fwDU3"""""3D"""""3Uˆ3"3""3"33""3""ffˆwˆwffffDwD"""""""""ˆUD3""""""333"""3"""3333"""33D3""""""""""""""""""""""""""""""""33"""D"""3""""3DDUwˆUUUUUUDDUw™™wwUUw3"""""""""""""""""33U3""""3""""DfˆU3"""""3""3333"3fUfUfUD3"""""""""3DDUUffUfwfDwwwffwwUUUUUUfUUfffUUfˆˆwUUffww3""""""""3U33"""D3Uwf"""33DUw3"""""""3333""3333UDˆwˆfffUffw"33"""""""3ˆDU"""""""3"333""33""""33"3D""""""""D"""""""""""""3"""""""""3"33""3""""""""3DDDUˆ333DDDDUUfwwfwˆwfww3""""""""""""""""333DD"""3"""""""""3wU""""33"3"""3"DfUD3333"3"""""""""3DDDDDUUfUUU33UffDUfwffUfUUffwwUfˆwwfUUfwˆwˆˆˆˆˆD3"33D"33fwffwfUUDUD3ff"""""3"3"33333"3"3D3DDwˆwfffwfˆD3"""33D""w̙U""""""333"3"""""""3""3""""""""DU3""""""""""""""""""33333""3""""""3D3DDU"""""3DDUUffwfw™ˆfwˆ3"""""""3""33"""3"33"""3DD"""""""""""3""""""D3"3D3"""""U3""""3"""""""""333DUfUUUUD3"3f33D33wwffwUfD"Ufffwfwwfwˆ™ˆˆ™ˆ™™ˆwfUw™f"3wˆ™™wUDfˆfD3333DD""""3D""""""3"""3""3333"33DUwwwˆwwww"33333D"3ˆÌ»fD"""""3"333"""""""D"D"""3""3""D"3""""""""""""""""""""""33333""33"""333DDDDf3""""33DDUUUUfUfˆˆˆw™3""""""3DDD""""""3333D3"""""""""""""""""""""33U""""""3"""DD3""""""""""""3DDUffDD33""3""3333fˆwˆfD""Ufwwwfwˆˆˆwˆ™ˆˆwffDDfˆª™ª»ªˆfU3DDwfDfUUwf"""3D"D33"""33"""3""""33333D3D™ˆˆ™wˆU"33""3ˆÌ»ˆDUU""""""33"33"""""""33D"""""""""""3"""""""""3"""""""""""""""""""""D3""3""""33DDDDDU3""""3333DDUUfffwffˆ»™f3"""3"DDUD"""""""33"3"""""""""""""""""""""33""3""""3"3D3"""33"""""""3Uwˆˆf3"3""""""33333D™w""""33wfˆˆˆfwˆˆ™ˆwwffDfwˆˆw™™ffDUUUfffwUDfwD"3""3DD3""3D3D3"""""""33"333333wˆ™ˆˆU3D3D33ˆÌ»w33fD3""""""33""""""""3D"""3""""""""""""3"3""""""33"""""""""3D""33"""""3D3DDDD3D3"""""3"33DDDUfwˆwˆˆ™Ìˆ3""33D3DD3""""""3"""""""""""""""""""""""""33""""""""3"""""UU"""33""""""""""3ˆˆˆw3""""""333"33Dwf"""""wˆ™™wˆˆˆ™™ˆDDUUww™wwwDDD3DDUwˆfffDffD""3DUUDUUUDDf3"""3"""3"""D3333f»™»ˆ33DfDfªÌª33Df3"333""""""3"""333f"""""3333"3""""""""3"3""""""3"""33333""""""""D3"""""""33DDDDDUUD3D3D"""""""3DUfwwˆˆˆªªˆ"33333""3D""""""""""""""""""""""""""3"3"""""""""UwD""33""""""""3U3"DwU""""""33""DfUw""""3fwfUUDDDUf3DDwˆˆwfU""DD3"DUUfDUDDUfUUDDfwUUDDDDDDD"3""33"3""33""3"D33™ª»ˆU3"DwÌ»ffUD3""U33UDD33D3""3333"""""3333"DD""""3D"3"3""""""""3""DD3333""""""""D3"""""""""DDDUDDD"3""33"""3U3"33DDDUwwww™ˆˆ3"""""3U3""""3"33"""""""""""3"""""3"""""""""3fUDDD"""""33""""""""""UU""3Uf3"33333"3333ˆD""""""""""3U"UU"3""UDwUwˆU"D3""3D333DDD3UDUwwU"DUDfUDD333"D3333DDDDD3333"3"D"33Uˆªˆ33ˆ»»fUD333DD"""""""""DDUD""""""3""""""""3""3"""3"""3"""""""""3DD33"333"3D""""""3UDUUDU""3"""3""""DD"""333DDfwˆwˆ™ww""""33"""3fw3D3""""""""""""3"""""""""""""3Uf3"3DUD33D3""33""DUf""3fD3""333""33UwD"""""""""333D"3""Uf3"fD"33"DDUD33"33D3UUU3"333"3DDDD33"D33333"3DD33333""""3D3Dwª»»Ì»wUUD3"3Uf3"""""""""""""3"""""33"""""""""33"""""""""""""3DDD"""33"""D""""""33DUDUD3""3""""""3""""""33DDUwwwˆ™wwU""33""3DDUU3"3"""""""""""""""""""""""3"""3wfU3""33333"""""3""""3333"UD3"333"""3DˆUD""3"""3333333333"""33D33"333""""333Uf3""333""3D3333"D3"33"3333"333""3"33333ˆ™ªÝ݈D33333""33""""""""D"""""U3""""""""""""""""""""""""3333"33"""3""""""3"DUfDfD"""3"""""3""""""""DDUfffwˆfffw3D333D333D3"""""""3"""""""33"""""""""3"""UfUD3""33"""""""3""""""""""""""U3333333""Dˆˆ3"""""3"""33D"""3"DUD""""3"""""33DD""""""""3333D3"3D"DDDDD3"33""333"3D33""f»ÌݙwD3D33"""""""""""""""""""""""3""""""""""""""333DDD333"""33"""3333UUfUU""D3"""""""""""""333DDUUUˆˆwwˆ™fD33""333UU"3""""""3"""333"""""""3""""3333"""""""""ffD3""33"""""""""""""""""""""""3f"3""""""3D™D""""""""3D""3UfD3DU3""3""""33UD""""""""33""""DD333DDU3"3"""333"333"3"D»Ì»ˆwUDD3""""33""""""""33"""""""""3""""""""""""3"""""""333D"D3"D"""D"""33DDUffU3""33""""33"3"3"3""""33DDUUUwwfUww333DDfwf3DD3UfU""""33""""""""""3DD""U""""3"""""""DfUD3333""""""""""""""33""""""UD""""""33ff"3""""""3"""33"3UDDDUD33"DD3D3"""""33DU3"""""3"3""""D3DD33DD3"""3333""3"3"3"U»ªfUDDDD333""""""""""""""""""""""""""""""""""""""""""""333D333""""""3"""33DDDfˆD3""""""""D3""33"""3""""3DDDUffwwUU"""""3D333DwwwfDUD3""33""""D33D3"33""""33"""""""ffUDD3"""""""""""3D""""""w"""""""""Dw"""""3""3""DD3D33DD3"""""""333333""""""3DDD"""""3""""""UD333D3D"3333"""""3""DDw»ˆ3DD3DDDDD""""3"""""""""""""""""""""""""""""""""""""""""3"3"33"""""3""""33DUU™D"""33"""3"3""3"""33"3333DUUUwwff3"""3D""""""""""""""3"""D3"3"3""""""""""ffD333""""33""33""""DU""""""""Df"""3UDDUD"""3D"D3"3"""""""""3""3DD"""""33U"""""""""""3DDD333D33"""""""33""33™ªU33DDD3UfUU""""""""""3""""""""""""""""""""""""""""""""3"""""""3""""""3DDUwD"""""""333"""33D33""D"3333DUUfDUDD""""""""""""""""""""""""""""""""""""UfU333""""""3"3DD3"""""ˆD""""3Uf33333D"3UUD3""3DD""""""""""""33"D""3U3"""""""""""DD3333333"""33""33""U™ˆD3"DDDDDDUDD3""""3""""""""""""""3"""""3"""""""3"""""3DD"""""3DUw3"""""""""3""333D33333"3"33DUUUwfUD3"""""""""""""""""""""33"""""""""""3wfUD33"""""""""3D333"""ˆU"""3DUUDfDDDD""UUfwˆwUUD"""""""""""3""D333UD""""""""DD333DD3"""""""""3""U™ªf"3""33DDUD3"33"""""3"""""""""""3"""""""D""3D3"""""""""""""3"3UfwD"3""""3Uwˆ3""""""DUD"""3"""""3333"33D333DDDUU"""""""""""""3"""""""3""""""""""""""""""fˆUD333""""""""""3"3""""""wf3"""3DDD3D33D33"""U3DfD3""""""""""""""""3""""3DD"""""""""U333D33""""3""""33D™ªw3"3DDD"33DD""D3""""""3""""""""333""""""3"3""""3"""""""3D""3""""3333"DUfU"""""3DDUDD""""""DUD"""3"333""3"333DD3D33DUDDffUD"""""""""33""""3""""""""""""""""""""DwffU33"""""""33""""DD3"3"""ªˆUDD333"""""""3D3"3D3D3""""""""""""D3"3UD""""""DUUD3""3"""""""""Uw™™fU"""33"33DDD33""""""""""""""""""""333"""""3D3""""""""""""""33"""3""3""""""3DDDD""""Dw™D"""3DD3"""""""33""""33"3"33DDD3ffD3"""""3""""""3"3"""33"""""3""""""3UwD"3"33""""3UUD3UfwwD333"Uª™UD3"""""D""333UD"""3"""3""""""""""3DUDDU3"""""DDUD3"""""""33"""3f™™f3"""""""3"DD3D333"""""""""""D3""""""""""3""""333""""""""""""""333""3333""""""""""""""3"3D™ªf""333"""""""""""""""""""""""3DDDD3DD3"""""""""""""3DDDU3333""""33""""33Dff33""33"""""""""""DUwUfwf3DUUD33UwwUD3""33""33333DU33""""3D"""""""""""""33UfU""""""""DD3fU"""33""""DfwˆwU3"""""""""3DDD3DD"3"""33""""DD""""""""""""""""3"3""""""""""""""3333"""""333""""""""33DDf™ªªD"3D""333"""""""""""""""""""""3D3DD"D3""""""""""""D3UUD3"""33333""""33fwD333"3""""""""""""""3DUˆ™fUD33333DDDUD33""""""""333333"3"""DD""""""""""""""33DUD""""""33"DDUU"""""D""UˆˆwU3"""""""""""3DD33""D3""3"3""""33"""""""33"""""3""""""""""""""3"""""33""""3"3Dw™ªªf""D33"33"""""""""""3"""""""""3"DD3D3"""""""""3""""""333"3""""3333""""333Dww33333333"""""""""""""3DDfwD"UU"""""33""""""""""33333333""33""""333"""""33DDD3"33""3UDDDD""3"DwˆˆDD3"""""""""3DD33D""3U3"D3"33""""""""""""""""""""""""3""""""""""""""""33Dffª»wD33"3"3"""""""""""""""33"UDDD3""""""""33"333""Df"""""""333"""""33Uˆw33333"33"""""""""""""""333DDUDDD""""""""""3"33"""3D"33"3""""""""""""""""""""""333DDD""33UUD""33"3UwwU333"""""""33DD33D33UU3""""D3""""""""""""33""""""""""""33""""""""""Uwf™»ªw""""""""33"""""""""3333DD"""""""""33333""Df3"""333DD3"""333UˆˆUD33"3333""""""""""""3""""""3333DUD""""""333"""3333333""""""33""""""""""""33333DD""DD333DDUwˆfU"""""""""""""""DD3DDD33DD3""""3"""""""""""""""""""""""""3"""3"""""""f™™»ª™3"3"D3"""""""""""""3UDD"3""""""""""3"3"""""""""""""""""D""3DDD3D3"33Dˆ™ˆU33"333DD3"""""""""""""3"""""""3D3DUDD"""""""""""3"3"33"3"""""333"""""""""""33""33DU3333"33"Uww33""""""""""3D333DD"33"3"""3"3""""""""""""""""""""""""""""""""""""3"DU™ªªˆ""33""""""""""""33D"3D"33""""""""""""""D"""3"""""""""3333D3333UUDfª™f33D33333"33""""""""""""""3"""""33DDDw3"""3"""""""33""""33D3D"3"""""""""33""""""333UDDD33"3U™f3D3"""""""DD3333D3""D3"""""""""""""""""""""""""3"""UD333""""""3DUw™ªªˆD""""""""""""""UDDDD"3""""3""""333D""3""3"""""""""""D33D3""3Df™wUDDDD3333333"""""""3""""""3"""""""""33DUUD""""""D3"3333""3D3"3D""""""""""3""""""""""""""3DDUf3"Dˆw3"""3D"""""3D333333""333"3"""""3""""""""""""""""3""3"""D3UDDD"""""""""33wªÌ»ªD"DD""""""""""3DDD"""""""33"""""3333""""3D33""""""3""3Uw3UDDD33333333""""""""33"""""""""""""""33DwU33""""D""3"3""""33DU""""""""""""""""""""""""""""""33DDUD""fˆD3"""""D"""3333333""""33"""""""""""""""""""""D"3UUDD33""""""""""""3f™ˆ™™D"3D"""""""3DD3""3""""""333""""""3"""333U3"""""""""3fwDD""333D3"33"""""""""""""""3""""""33DwU"3""3"DD""""3""3"3""3D3D"""""""""""3""""""""""3DDf33ww3""""""3D"""3333333"""""3"""""""""""""""""3"33333333"""""""""""""3UUf""3U"""""""""33DUD3U33"""""""""333"""""DUUD3"""""3"""3fU""3"333DD3""""""""3""""3""""""""DfD"33"33""""33"3"3"3"33DU"""""""3D33""""""""""3"33DUDUfD""3"""3"33""""""3333""""""3"""""""""""""""3U"3D"""3""3"""""""""3DU3333Uf""""""""""""""3333D3DD33""""""""333""""DUD333""""""""3""""""3fD""""UD"3D"""""""33""3""3"""""3"""UfD"""3D333"33DD"""333"3333"""""""""""""D""""""""""""D"3DDwf3333"""""3333""3""3"3"D3"""3"""""""""""""""""3""D"""""33""""""""333D3"33DDfD"""""""""""""""""3""33333"D"""33"3""wUUD3D3"""""3""""""Dwf""""3D3333""""""33"33""""""""""3""ffUU""""""""D"""3UD3333""3""3""""""""""3"""""""""""""""""""33Dˆf333""""""3""33"3""""""33""""""""""""""3""""""""""""""""""""3333"""3333DfwD""""""""""""D3"D33UUU33DDUwfD3DD""""""""""""""""""""DwU"""""""33"3333"""33"33"""""""""""3Df"3"3D"""""3U""333333"""333"""""3"""""3""""""""""""""3"3f™D""""""""""""UD"3"""""3"""""""""""""""""""3""""33""""""""""""""D"D"""3333DDUUwU""UfD"3""""""""""3""""""3DDUDDfUf3""DDD3""""""3"""3"""""""""""3"3UˆU33D"33U333"""""DD"""""""""""DUD""""""""3""DD"""3""33"""D33"3"""3D""""""""""""""3""3UˆˆD""""""""""""""D3"33""""33"""""""""""3"""""""""33"""""""""""3"""""3D""""333DUUUDUwwwfwˆwwfUUwˆUDUD3""""33"""3"DUDUU3UDD"DUfwfDD"""""""""""""""""333"3wˆUD3"""""D3333"3333DU"3""""3DDU""""""""""3"""DD333""""3"33"""""333""3""""""""""""UfwUD"333""""""""333""DD"""""3""3""""""3"3"""""""""""""33""""""""3D""3"""""333DDD33DDUU33"33333DUfwf3UwU"3fU""""333D3DUUUUD333DUfwwU""""""""""3"""3D3"DfˆfU33"""3DU3""33DDD333""""""33DD"""""""33DDDU3"""""""3"""""""""33""""""""""""Dwf3UD"3D3"""""33"3"D3"""""3""""""""""""""""""""""""33"""""""""""""D3""3D3""""""""""33"3""333""""""""DDˆˆ™ˆˆfDUwª™™ˆ""""33DDDD"DUD"33333"DDDUwf3""""""""""3"33DD"UDˆfUDD3"""DD3"3DD3D"D"3"""3"DU""""""""""33DD""""""33"33""""333""""""""""""""3DDDffD33U3333""""""""33""UDD3""3""33"""""3""3"""""3"""""""""3"""""""""""3"""""33"""3"""""""""""""""""DUDfUUwˆwDwwwˆUDDUfffwˆˆU3""3333UD"""""33DUUf3""Uwf"""""""""33""DD3ffU™fD3"33""""UDD3DU3U33D33""DU""33"""3""33"D33""3"""""3"""""""3""""""""""3D"""""3D""""3UfwfD3""U333""""""""""3UD3"""""3D3""""""333"""""""""""""""""""""""3"33"""""""3""33333""""3"""""""""""33Dff3333"DffUDDfUDfˆUD3DUUfU3D3fU""3DDU3UU""Uff3"33"""""D3"UfUUwUˆ™UD333""""333DU33UD33D"""3U"""""""3""3333333""""""""33""""""""""""""3D""33"3D33""3DfUDDUD3""DDDD3"""""3"3D3""""33DD33"""3"3DD3"""""""3"""""""3""""DU3""""""""3""3D"""333D""""""3""""""""""""DDUw3"33"""ffUU33D333U3"""3DUw™»ªˆD""3DD3"U3Dw3D33fD"333"3fˆw™ˆˆUUDˆˆU33""""""DUUDD3"""""3"""""3""DD3333"""3""333"33"3"""""""""3D"""""3DD3"33DDDUfUD3U33"DUDUDD""""""""3D33333"DDD3""""3"DDDD3""""""""3333"""""3"33"3U3""""33""""""""3""3D""3"3"3D3""""""""""3U3"""""""3""DDUf""3D33""fUU3"333"333Uw™ˆ™™ˆU"""33DDDfD333UDDDfwU33D3D3ffwˆˆ™ˆˆwffˆU""""""""3fUD"33"""D3""""""D3DDDD"""3""3333""U33""""""""""3U"3"33DD3"3""33DUUD3"D33DDU"DU33"""""3D3333333DD33"3"33DUUD3"333"3"""3D"""3"""D"3""""""""""""""""""""""""DD"""3""3DD"""""""""""""UD"3"""""""D3""""DUUU333UU"3fD333333"D"3Dfww™wwwwU"3"3DDDUffUU3UUffDUDUf3UffDDUUUfUUDDDUf3"3""""3fU3333""""D""""""33DUUU3""""""""""U33"3""""""""""D3"33DD3""3""33DDDD"""33D3UD3DfDDD"""""UD"33333D33D3DD""3DDUD3333D"D3""33""3D3""""3""3""""""""""""""3D"3"""33D33"""""""333""3DUDUfDDUfDDDDD3""""33""""""3f"""3"DwUf""3UfD33UD333333"D""3DUfˆffffwwˆwU"33DDUUff™™™wU333UUffDDUDDDUDD333333DDD3DD""""""DfDD33"""""D3"""3""3DUD3D3""""""""3D"3""""""""3"3333DD3"""""33DDD3D3""""""3DDU"DDD3""3UU333333"33Df3D33UDDD33""33"3D"3"""""3D3""""""""""""""""""3D"3""""33D33"""""3"""33333"33Dwwwˆˆ™f3UD33"D"D3333333D3DDUDDwU"""3UfUD"""3"""""DDD333333D3"3DwˆfUfwwffffˆwD33D3"UˆUUU""3333333333DDDDD33""3"3"333""D3"""3DDD3"3DD333""""3D3""""""3333"3"""""33""""""""""""333DD3"""""3333333"""""""""333DDDD"""3DU3"3D333"3DUUUD3UUDD33""""3DDD"3""""""3""""""3""""""""""3"DD"3"""33"DD3""""""""""""""33DD"3""3fwwff33D3"""33""33DDDDDDDDUUUDfD"""""""UDD33DDDD"""3U™fDUUUfffUUffwfD33ffUD"""""333333"3333D33"""""""""3""3""""DUDD""DD33""""3DU"""""""""""""""""""""""3"""333""""""""""""3"""DD3"""""3DD"3"33333D3D33fD"33DDUDUUDUDDD"""3"3333"""""""""""""""""""""3""""""""3U"""""33""DD3"""""""""33D33"""3Uˆwf"""""""33"333""""3UDfffUD"3D"fUUDw™fDU3""DU™D3DD33333333Uf™™fU3"""""33333""""""33"""""""D3"""33U"""3D3""""3Df""""""""""""""""""""""3"""""""""333""3"""""""333333U33"3""""D"UU"D3333UUDDDD33U"D33DUDUUfDDDD3""3333D"""3""""""""""""""""""""3"""3U""3""""3"33""""3""""33Uf""""""Uw""""33333"""""""3"3""DD3wwwwˆUUD33"""""Dwf"3"""""""3DUD33"""""""""""""""""""U3""33UD""3"3""""3Df"""""""""""""""3""33"""3D3"""""""""33333""""""""""DDDD3DD"3"D""""3DffffˆˆUDUwwwDDDDD"33D3UUfDDDDD""3333333"""3"""""""""3"""""""""3"""""3"""""""""3"""""3"""3UˆD""""Uf333"""""""""""""3"""Dw™wUUˆDD3"""""""""3Dw"""""""33"""""""""""""""""""""""""""""""DDD"3""3"""DU3"""""""""""""""""""""""""""""""33""""3333333"3""""""""""D333DD3333""3"""DDDDDUwU3UwˆffwDUU"3DD3DfUUUDD33""""""333"3"33""""""""3""""""""""""""33""""3"""""""""""""3Ufw3"""3D"3D3""""""3DUwwwˆˆwUD33333""""""3Uf"""""""""33333""""""""""""""""3""3D333"""3""3333DUfw""""3""""""""""""""""""""""""""""""333"33""33""""""""33333"DDD3""""""33DDUDDUfwfˆwwUDDfD3DDDDUffUUD3"""""""333D3"""3"""""""""""""""""""""""""""""33D""""""""""3fff""""""33"""""""3fUDD3333333""3333DDUf"""""""""3333"""""""D"3""3"333""33"3DUDUUD3"3f™D"""""""""""3""""""""""""""3"""""33"""""33333"""""333""3333DDD3"333""""33DDDD3wwwDDD3DDDD3DDDDUUffU""3""""3"""3"""3""""""33"""""""""33DD"""""""33"33"""""""3DDfUw""""3"""33""D3DDDDwˆˆˆf3"""""""3"3"""""""""D""""""""33"""""3DDUf3"333Uˆf"""333"""""""""3"""""""3"""""""3""""""""33"""""33"""""D333D333D33"""3333D3DwˆfD3D333DDUUDDDfUUDD""""""33"""""""""""""""""""""""""""""""33D3""""""""D""33"""D33DD3Uf"""3""""""3"33"3""f™™™ˆ3""""""3""3"""""""3"""3"3"333D3DUD""DfDDDUfwUD"3"""""""""3"""""""""3""""""3"""""""""33"33""""""""""DD333DU3333"""333"33UˆwU333"3D3DDDUUUfffUD""""""""3"""""""33""""""""""""""""""""3"""""""""DD33"3"""""""3D3DD"3Uf"""3"""""""""""""""3Uˆª™ˆD3""""""""""""""""U3""""""""D3DfwˆwUUDDDUUfˆUD3U3""3"""""""""""""""""""""""""""""""""""D"""""""""3333UfDDUDD3333""3"""""3fwfD333"3333D3DfˆfUfUD""3""""3""""""""333"""""""""33""""""""""""""""""""""""""""""3""UDD33"DUD""""3"""33"""""""""333f™™™wD""""""""""""D""""DU33333DfUfwUD33""""""3"33U3""""""""""3""""""""""""""""UU33""""""""""3""""""DDDDUD33"333D3""3"""""DwˆU3"3333"33333DwˆfUU"""""""""""3"""333"""3"""""""""""""3""3""""""""""33""3""D33""3DUfDDD""333"""""33""""""""""33w™™ª™U"3"""""3ˆw3""""""D3"DDDUwffD""""""""3DU3"3"3"3"""""""""""""""""""3"""3wU"""""""333"3"""3"3U3333333333333"""""""UwwD3""333333333DfwˆU3""3""""""""""""333"""D3"""""""""""""""""""""""""""""""""""""""3U33"33DwfDfU"""3"""""""D"""""""""3U™ˆwf""""""3""UUwˆ™ªªªª™f3""""3U3DUDUD33D""""""33U3"""""""""""""""""""""""""D3""33"333""""""""33333""333""""3""""""3wˆf3"""3"3333333Dˆˆwf""""""""""""""""""3"""3"""""3""""""""""""""""""""""3""""3D3333DDUwwfˆ3"""3""""""""""""""""33DwU"""""Dw™ª™™™ª»ªªªª™ˆw™™ˆD"""""DDDUUDDfDDD3"""3D3"""3DU3"""""""""""""""""""""""""3"""33"""3"3""D33"333""""""3"""""DfwU"333"33D333DDUwˆˆf3""""""""""""33""""""""""""""""""""""""""3""""3""33"""""3D""33UfUfwˆ3""""""""""""3""""""333"UD"""3w™™ˆˆˆwwwwwwwwffffw™™D"""DwwwffUUU3""3""""3""""3f3""""""""""""3"""""3"""""""""""""""""DDUDUD3333"333"""""""""""""Dwf""3333DDU"3DD3UwwwfU"""""3"""""""""""""3"""""""""""""""""""""""3""""33"""3"""""3D"3D33Ufˆwf3D"333"""""""""""""""33333D"f™wffffUUUDfUfwwfffff™w"3DfDDD3"33333""3"""""""""""DU3"""""3"""""""""""""""3"""""""""""""""""3ffDD3"3"33333""""""""""""3Dww3333DUDDUD333DUwˆwfUD"3""""33"3"3""33""""""""""""""""""""""""""""33""""DU3"""""3D33333DUffffwD""""3""D3"""""""3333"3U"""33DwfUDDUUUDDDDUUUfffffwˆªfUff3""""""3"""""""""""""""3DD"""3"""33""""""3""33""""""""""""""""""UU333"3""333UU"""""""""UwfD3333"DUUfU33DDUwwUDDUU""""""33""3D"""""33""""""""""""33"""""""""DUUf33""""""""3DDDD3"3DUfwf""""""33"""""""""3D3""3wD"wˆˆˆˆD333D3DDD333DDDffffww™ˆDD3""""""33"""""""""DU3""3""33""""""""""33""""""""""""""""""DD3"333333"3fwU"""""""""3fww"3"""3"3UfU"33DwwwfDDDUU"""""""""3"3""""""""333""""""""33"""""3"3"""""""""DD3"""3""""""DDDD"3"DDDwf"""""""""""3D"3wDw"333D""wwwwwU333333333"33DDDUfffUfwD""""""""""""""""33D"""""""""""""33"3333"""""""""""""""""""3D"333333"3ffU"""""""""DwˆfD""33"33"DU3"3DwwwwDDDDUU""""""""""3"3"""""""3""""""""""3""3"""33""""""""""""""""""3DDUD""3DDww""""""3"""3""""""""""""3UUUffUUwˆwfffUUD"3"""3333333333DUUUUUffffD"""33"""""""""U""""""""""333"33D""""""""""""""33""""333""3UUD"""""""""3wˆU"""333"3U"DU3D3UwwwU33UDD3DD3"""""""""""""""3"3"""""33""""""""""""""""""3"""""33"""DUfDD33DDUˆ""""3"""""""""""""""""DU33Ufw™™™wUDDDD333"""3""""33333DDDDUUUDUDDU333D3DUU3""""""fU"""""""""33333"""3333"3""""""""""""""33"""3"33"3DD3""""3""333ˆˆU"3333D333UUD3D3UwwUD"DDDD"DDDU"""""""""""333""""""""33"33"3""""""3"""""""""33""""3UfUDDDDDDD3"""""""3"""""""""UU"3fUDˆfUfU333""33"3"""""""""""33DDDDDD3DDUUU3""3"D33DDD3""""""""""DwD"""""""""""f""""""33DU"""""""""""""3"""""""3"3D3""""""""333ˆw3"333"3""3DUD3UfwwwU33DDDDDDDUU"""""""""3""33""""""""333"""""""""3"""""""""""33"33"""""3UDDDDD3DUD"""""""""33"3""3wU""DDfwUUUU3"""""""""""""""""3"3DDD33333DD33DUUD"3D""""DUD"3fˆˆwUU"DD"fwU3"""""""""""""3U""3"33UD""""""""""3"""""""""""33D33"""""""3333ˆw3"""3333""333DfwwwUU3"33DUDDDDfUD"3""""""""""""""""""""""""""""""""""""""""""3""""33DD3""3D3D33D3f""""""""3""""""""3"""ffU3"UwDUUUD33"""""""""""""""DD333""33333"3D33DUDD3"3DU3UUfffwUUUU3"wUDwf3UD""""""D""3"""""3D3"DD""""""""33""""""""""""333"""""""33333ˆU3"""3333"""DDwwˆwUD""33DDDDDDUUUUwD3""""""""""""33"""""""""3"""""3DD3""""""D3""""""3"3"3""""3333333f""""33""""UD""""""3""""D"DwwUDUfD""""""3""""""""""""333""""""3"""3"3"33""DD33333wDDUffˆUˆwˆˆf3UD"""""""""""""3"""33""""""""""""""""""""3""33333"""""3"33fˆU33"""3"33""3wwwwfD3""3333D33DUUUfD3""3D3""3"""""""""""""""""33""3D"""""""""""""""""""""33"3"""""""""3Uf3""3"3""""""33"""""""3U3"""DU3"33""""DUU"fˆˆwwfUD3"""""""""3""""3"3"""""""""""3""""33"""""3UDUUffw™™ªwUU"33"""""3""""""""3""3"""""""""""""""""""3"3333"""""""3Dww333"3""333""DfwˆˆU3"""3333D3"DUUDDfD333DDD33"""""""""""""""""""3"""3"""33"""3"3""33""""""""""""33""""UU"33""""""""""3D3"""""""DUD333"""3UDUfUwˆ™wwUUD33""""""""""""""""""""""""""""""""""""""33DDUUˆ™™™wDD"""""""""""""""33""""3""""""""""33D33"""3"""33fwU"3""33333333wˆˆˆwUD"""""3333333DDU3U3D3DDD3D33"""""""""""""33"3333"""33""D3"3""3""""33"""33""33"33D3"""3fDU3"DD"""""""D"DfD3"""""""3"""""DffUUDfˆˆfUUDD3"""""""""""""""""""""""""""""""""""33Uwwwwˆf3D""3""""""""""3""33UDD3"""""""""3""""""3333""""""""3DfˆD"3""3"3333"3ˆwˆwU""""""33"333"333DUUU3D3DDDDU3"""""""""""""3333DD3""33333""""""3"""""""""3"""333D""DUfUD""3D"""3UUDwD""3""""""""""33DDUUD33UUfUDDDD3"""""""D3"""""""""""""""""""""""DUfDffffUD""""""""""""""3DUfUD3"""""""""""D3"""""3333"""""""""UwU""3""""3333DUˆˆwf3"""""""DDD333333DDUDDD333UDfD3"""33"""""""33""3""33333"""""333"""3""""""""33"""DwfD""33"""3""""3UUDU"""3"""""""3""3wUUDDD33"DUDDDDDD""""""U3"""""""3"""""""""""3""""""""33DUffUwˆU""""""""""""3ffUfDD""3"""""""""33"""""3333"""""""""DD3""3"""3"33"UˆˆˆwU3""""""3D333333DDDDUD""33DUDDD3""""""""""""""""""""""""3"33"""""""""""""""""""""33D3"""""3ffD33"""33"3"""""DfU3"""3"""""""3wˆfUfwwUDDDD3"""DUDDDD33"""""""3"""3""333""""""""33""""""D3UUUUwfˆ"""""""""""""""3DDUUf3"3"3D3""""""""""3"""""333D""3""""DD""""""""3""33f™™wˆf3"""""""DUDDD""33D33D33333DUD33D"""""""33"""""""33""""""""""33"""33""""""""""""""""DDD3""""3D3D"3333333""""3""D3D"""""""3""U™ª™ˆffwDD3333""3DD333333""""""""""""""3""3D33""""""""""""33ff333UU""""""3D33333333333"3DDD3"""""""""""""""3"""""""3D3""""""""""""3f™™™wfU"""3"""33DDDD3"3333DD33"3DD333UD33""""""3"""""""3"""""""""""33"3"""""""""""""""33DD33""3Df""D333333""""""""Uf3"D3""D"3"""""w™ˆffD3DD333"3""D3DDD333333"""""""""""""""3333333"""""333"""""3""""U3""3f"""""3"""3U3"""3"3"3"33""3UU3"""""""""""""""""""""""""fD""""""""""3Uˆ™™™wfDDD3D33"33"DDDDD33333D33333D3"33UD3D3""""3"""""""""""""""333"""3""""""""""3DUD3D3"3UU3""D33"3"3"""""""""""DUDD3UUUUUU33333"""""3wˆˆwUDDD3"3333"3"""3D3DD"33""""""""""""3"""33"33""""""3""""""""3"33""ff""3DDDD3"""""""""3DU""33DD3""""""""""""""""""""3f3""""""""33wˆ™™ˆfU"""333DD"3"3DDD333""3DD3DDD33D33DUDUD"""""""""""""""""""""3"33DD3"""""""""""""""3UUU33DDDDD""""""""""""""""fUUfUUUDUUDD3DD3DDDD33D33DfU33DDDDD33333333"3"333D33D3""""""""""""""33""3""3"""""""3""""""""""3""DD""""""""33""""""""""33""3"DD3""""""""""""""""""DD3""""""""""Uˆˆˆwf"3"33D3D3D33""3333"""333DDUU3D33333DUDDDDD""""""""""""""""""""""3"3DD3""""""""""33DwwD"33DfDD""""""""""""""ff3DDDDDD3333D33DD3UUUDDDDDD333DD3333333D33"33333DD3333""""""""3""""""333"333""""3""""""""""3DD"""""""3""""""""""""3"""""""""""""""""""""""f3"""""""""""""33w™ˆfU33333D333333"3333333"3333UUfD3D333333D333Df""""3D"""""""""""33333""""""""""""33"3ˆf3""3"DD"3""""3"""3UfUUffUUUD3333333D3"3"DUUUDDDDD333DUDUDUD"333333"3"333DD3"3"""""33"""""""333"""""333""""""""""""""333D""""""""""""3""3""""""D3""""""""""w3"""333""""fˆˆfDf3D333"333D33"3""333333"33UUUDDDDDD"3""""""DDD"""""""""""""333"""3"""""""""""33333fU3""3UUD3""""""""DDD""DUffˆˆfDDDDDDD33"33333333DDUUDDD3333D3DUUffUD3"""33"3333D333"3"""""3"""""""333"""3333"""""""""""""3DD3D"""""""""""""""""""3D""""""""3U3"""""""""""3Dw™wDDDD"33D3333D3D333""3""33"3DUUDUDDD33""""3UU3""""""""""""""""33"""""""""""33333f"3"3Df"""""3DDUUDUUfUDDDDDDDDD3D3DD333D3DUUUUDDD333DDDUfwfUD3""D33D33333333"3"3""""""""""""""""D33""33D3""""""""""""""33D3DD"""""""""""""""""3""33"""""""Uf"""""""3f™™UDD3DD"D3333333D333""33"333DUDDDUUU3333""""""33UU33D""""""""""333"""""""""""""""""3333f3"33Dff3"""""3"DU333DDDUDD333333DD33"3D333D3DUUDDDDDDUUUUUUDDUD"333D3DD333UUD3333333"""""""""""""""""""""""3333"""3""""""3""""3""""""33UU3"""""""""""""""""333"D""D"""""3ww""""""Dˆ™™wDD3D3D33D3333333D""""3"3"33UDDDDUU33DDDD""""""33DDff""""33"D""""""""""""""""""""""""""""3DDUw"33DUU3DDDUDU""DDUfD3333333""3DD3"""33DDD333DD3DDDDUUDDDDDDUUDD333333DDD33333DDDUUU3"333"3""""33"""D"""""""""""""""333""3""3"""33""3"33""""""""""3DUD3"""""""""""""""""333"""3"3""""Dˆf""""""3wªªˆUDDDD3DDDD3333""3333""""""3DD33DDDDU"3D3DD"""""333DDUf3U3"""""""""""""""""""""""""3DUDwf"""D3UDDwD333UUU33333"""""""""3D3""333DDD333D33DDDDDDDDD33D3DDD33333DDD33"33"DUUfUD""33"3"""""""D3""DwU"""""3"3333""""3333""3""""3""""33"""""""""""33DDU"""""33""""""""""""3333""""""Uf""""""""3DˆªˆˆUUDDDDDDDD"33333"33"3"""3D""DDDDD33DU3""D33"3333"3D3DUUUU"3"""""""""""""""""""""3DDwˆ3""33DwfU""""3"""""""""""""DD3DD3"""3DDD33DD333333D3333333D33333D"3DDD3"3"3DDUfDD3"3333"""""""""""""""3fU""""""3"""""3"DD3"""D"""""""""""""""""DD33"3"""""""""""""""""DU""3"""""DfD"""""""""""""w™wwfUUD33"33D33"33333333""33UfUUwfUU3"333UD"33"33"3"333D3D3DDUUwwDU""""""""""""""""3DUwU""""3DUw""""""""""33DD"33""""333DDDDD3D3"33DD33333333333DD33DDD333DUDUfUfD"3333""""""""33"""""3"""3""""""3DDD3"33""""""""""""""""DDDDU"3""""""3"""""""""D"""""Dww"""""""""""""f™wfffUD333333D3""3333333""UfffwfUD3""33"33DD3"33UD3D""3UDDDDDDffUww3""""""""""""""""""DDff3"333DU"""""""333"33"33333DDDDDDDDD3D33DUD3""33D3DDDDD33333D"3333UUfˆf3333333D"""""""3""""3""""3D33"""3""3""""""""""""""DDDDD3DD"""""""3"""""""""""""""UUD333""""""""""wªfffUUDDD33333"""3""33"""3UfUDDD3""""3"""""33""333DUf3""DD33UUUD33DUD""""3""""""""""3"33""3DDD3""""DUU3""""""""""3333333D3333DUD3D3DD3DDDDUU3"3"3DDDDDDDDD3333"""3333DD3UD3333"3D33"""""""""""""""D3"3""3""33D3"3"""""""3DUDDDDD3"""""3"""""""""UD3333333""""""""3ˆ™ˆwwfUDDDDDD33D"33"""33D3UfU333333""""""""""3"""3DDUfD3D"333D33333D3ff""""""D3""33D333"""3DD""""33D3""33"""3""3DDUD3"333DD3DfUDDDDDDDDDDDDfU33DU333DD3D33D3D3333333333"3333DDD33"""""""""""""""""""33D""""333"3D""""""""""3DD"33UU3""3""""""""33""""""3UU333333333"""""3w™™ˆwffUUUDD3DD3U"3"""333DDUUD333333"""""""""""3"D33DDf3"3"3D333333D3Df"""""fU3333"""""3UUD"""""UD""""""3"3"333DDDDwˆˆD3DDDDDwˆfDDDDUUUwwfUwfDUUD3333DD33DDUDUU333333D333""33DD"3""D3""""""""""33""""""""DD"""""""""3333"UDU"""33""""33"""""""""""""ˆfDD33333333333D3f™ªˆwwffUUUUUDD3DDD33""""DDUD333333""""""""""""""33D3DDU3""UwUD3333333D3DfwDD3""""""3D33""""""""33DU3"""""ww"""""""""33""""3DUfUU"3"fwDUUUfwDˆwUUUUfˆ™DDDwwUU3"""33333DD3DDU3D3"333333D33333UD"333UU33D"""""""""""3U3""""""D""""""""333UfDD""""""33"""""""""3ˆªfUDDDUDDDDDDDDU™ªˆUfffffUDUUUDD3Df3""""""Dff3333333"3"3""""""""""""3DDDDDwfUD333333333333"3Dwwwf""""""""""""""""33DD""""3ˆw3"3"3"""""D3"""""333"3fUffwfDDˆfUDUUf™™w"Df3"UfD""""3DDD3333D3"33333D33D3DDDDDD"3DDU3"33"""""D3DD3""""""3DDfDD3""""""""""D33"D""""""""Uªª™wwwwwwUfUUUUfwªªˆ""fUUUU33DUUUDDUDD3"""3DfU333""3"3""""""""""""""""3UD3""33"3"333333333333DDfffˆD"""""""""3DD3333f™™""333"""33"33D3"3""""3fDUU"wˆfDUUff™ˆ™fˆU"3UfD""3fU3D""D33UU333333D333333U3""DDDD3"""""""3D"3""""""3DD3D3"""3""DD3D"3"""""""""Uªª™ªªª™wˆfwwfww™ª»ªUUUDUDDDDDDUUUUDD33""3UUD"""""""3"""""""""""""""33D33"33"3"3333333"33D3DDUUUfUfwD""""""""""""""""DU"Df»»wU33333"3D3""33D33"""""""3"fD3UwfUUUfw™™ˆfwf"DfU3"wfD33D3fD33DD3333"3333333DD"33DUD""""""D""""""DDDD33D""""""3fUD""3""""""3"""3Dwªˆfw™ªÌ»ª™™™™ªª»ªª™U33DU3DDD3DDDUUf3D3333DU3""""""""""""""""""""""33D3333333"3333333"33333DDUUfUffUww""""""""""""""""""""3DU""™ÌÌ»ˆ33DDD33333D33D3333""""""3UUfUDDDD33"DwwD33"DDD"DUD"33UDDU3"3"""""33333""3333D3"""3"3"""""""3D3DU333""""3"""3DUD""3""""""333"3ˆ»™"Dfˆª»»»»»»™fUwˆf"D333DD333DDDDDUDDD333DD""3""""""""""""""""""""""3D3"3"""3"""33333""3"333333DDUUUUfUwwDffU3"""""""3"""33"3""ffDU™wª»wDDDUUDDD3333DD333DD"""""3DDDD3D3D33333ww""3Df3"3333DD3D""33"""""3DD33333333333""""""""""""3"3"""""""33D"D"""3"33"""""3D"D3D"""""""""3ˆª™ªªwDUˆª»»»ªªU"""3f"3UD3DDDDUUUUUUfDUfD333DD33"""""""33"""""""""""33333"333""""33333"""3333333DDUUUfUUUfwfww""""""""""""""3""ˆÌˆwfDwªÌˆUUDDDUDDD3DDD3D3D33U3"3DD"""33DDDD3""33fwwwD""""3Uw33333333DD"""3"""""""3D333"3333""""""""""33""""""""""""""Dw""""""DUD333"3D3""""3D™ªªª™wDUUfˆ™™ˆUDDU"3U"""UUDUUDffwffwwffffU33DDD33""""""""""""""""""""""3333"""""""3""33""""3"3333333DDDUDDUD33Dff"""""""""""3UˆÌÌ»ˆDDwªªwUwUffDDUUUUDUDDDDD3D""""""""""333""3"3fˆˆU3"""""UwD333333DDD3"3D3"""""3D"333D3""""""""""""DD33""""""""""""3""3D33DUUw3"""""33""3""""""U»»»ªw3Df3DDUD3"33"D3D3"UUDDUDUfffwˆwwwffD3DD333""""""""""""""""""""""33"""""""3""33333""3"3"333333333DDDD3333DDfU"""""""3""""""3"fªªªÌ™DD3UUfwffwwˆfDDDUDDUfwwfwUUD"""3""""3""33""""3DU™w3333"""DUfD33""333D3333""""333333""""""""""""""""""""DD3D3"""""""""""""""""""3DDDDDUw3"""""""""""""""""""f»»ªw3Dww"D333""""D33DDUUU"DUUffwˆwwwffUUUD"33"""""""""""""""""""""D33"""""""33"333D""3""""33"3333"33333333333UwD"""""""""""DD"D»»™™»f3D3""""Dfˆf3UD3U3D3D""""""""""""""""""33DUˆªfD33"""333D3DUD33333""""""3""3D3"""""""""""""""""""""""3DUU3D333"""""""""""""""""3"""""33DUUUww"""""""""""""3""""D™™ªª™DDfww3"3"""3"""""3DD""DD""DD33fˆwwwfUfUUDD3"""""""""""""""""""3D33"""""""""""""3"""""""""""""""""""""""3DDDfwf""""""""""""""DD3"fª™wˆˆˆD3"333"""""D33DfDffD"""""""3""""""""333UDDDUf33D33"3"DfUfD333"3""""""""3333""""""""""""""""3333"D333333"""""""DDUU3333333"""""""""""""""""""33Dfff""""""""""33"""""""ˆ»Ì™ˆw3""3UU"""""""""3U33"""""DwwwwfffffDD3"""""""""""""""""""3D3"""""""""""""""3"""""""""""""""""""""""33333Uwf3""""""""""3DD3UwˆffwfDD"3"333""3""333""""""""""33""""333D3D33DD"D33UfUˆ™fDD33"33"""""""""33""""""""""""""""""D333""3"3333"""""""3UffD"""3D3"""""""""""3"""""3""""33Dff3""D333"333""""""""""""""U»Ì»33"33D"""3D3""""33D""""""""3""DwwwwwfUwwDD3""""""""""""""""""""3D33"""""""""""3"""3""""""""""""""""3333DDˆD""""""3DDUUUfwUfffD333333""333333333""3"""""""""""""""DD3"""33"33D33DDw3D""""3"33333""""""""""""333"33"3""3"""""""""33"3""""3DUwf"""""3333""""""""""""""""33"""""3DfU33""""3UD33DD3"""""""""""""3ˆ»»ˆ""3"""U3"""333DD3"""""33"""3fUwwfwwwwUD33"""""""""""""""""""DD333""""""""""""3"333""""""""""""""""""333ˆ™D"""""""""3DUUUwwUUUfffU33333D3333D333""3"""""""D""""""""""""""""DU""""3"""""DDUf"""""3333DD3333"""""333"3"3DUUUDDD33""""""""333""""""3Ufff""""""3"333333"""""""""""""3""""""""3fD"""""""3"3DDDD3D3"3""""""""Uª»U3""""""3333UU3"""""33"3UUUDwfwwwwfDD33""""""""""""""""3DD3D"3""""""""33"""3"3"""""""""""""""""""""3D™ˆ""""""3333DUwwfUUff3UD33333D33D3D3""""""""""3333""""""""""""""33"""""DUUw3D3"33DD3DD333""33""3""3"UwU33""""3D"""""""""333"3"33DffU""""33"3333333333""""""""""""""""DU"333""""""""3333DDUDUU3""33"""""3™ˆf""""""""3"333Df3"3"33"3UfDD333DfwwffD3"""""""""3"""""""3DDD3333"""""""3"33333""""3""""""""""""3UU™ˆ"""3""3DDDffUUffUD"333D33D333333"""""""""""33D3""""""""""""""""""""33DUUD3333333333333"333333""33Uˆw3""""""33"""""""""333DDffU"""""33"333"333333""""""33""3"""33D""3D3""333"""33""3UUD"""""""U»™"""""""""""33DDDwU"33333UUDDD33DD"DwwDD3"""""""""3"3"""3DDDD3"3"""""""""""3UD""33""""""""""3DUU™ˆ"""3"""33DUfUUUUUUUU33DDD3D3333"""""""3"33""""""""""""""33""33UfD3DDDDDD333DDDD3D333D33UUffD"""""3DD"""""""3333DUfU33"33"""""33333333"""""""33"""""""333"""33""3"""""""""3Uw3""Dˆ™™Df3""""3"""""3DUDff33333UUD3DD3DUD"3DfU33""""""""3""""""DUU333""""""""""""""""DD3"""""3"""""""""""DDUffU"""3333DUfUUUUDDDDD3DD3DD333"""""""""""""""""""""""3333333DDUUDUD33333DU333"UfDDDDD3D3"""""3"""""DD33DDw™D"D333"33"33333333"""333""333""""""3D3""""33"""""""3"Dw3U™™DUU3"33D""""3DUDDfD33DDfU33DDDfU3"33UD3""""""""3"""3""""DDD""3""""""""""""3"""33D"""""""""""""3"333DffU""""""333DUfUUDDD3DDDDDUD33"3"""""""""""""""""""""""33""33333wwUDD333"33""""33333"3D333""""""""""""""3D33DUwU""Df33333"""333333333"""""33"3"""""""3DUD""""33""""""333UD"Uˆ™wDU""""""33"""""3DUfDfU33DUfD333DDf3""3"DU"""""3333333"""""3UD3"""3""""""""""3"""3D"""""""""""""""""""3"3DDUDffD3""3DDDUUfUUU3"DDD3DDUD3333""""""""""""""""""""""""""33333"3Dˆ»wUDD333""""""""""""33"DDD3""""""""3""""333UwU3""3UfD333"3""333333333333"3"33""""""""DU3""""""""""33DD3"""wªªw"3D"""""3D33"""""3DUffwD3DfUDDDDDfww"""""DU3"""333""33"3"""3D33""""""""""""33""""3"""""""""""""""DD333DDDUfww"""""33UffUffUUU"DD333D3DDD3""""""33"DD""""""""""""""""3"33333D33DwUDDDD33""3"""""3""333DD33""""""""""3"""""""""DwD"""3D33"""3"33D""333"33333"""D3"3""""""3U3"""""""""33"U3"""fªª33D"""3"UD3"""3DDUˆˆ™ˆwfUUUUffUfˆU"""3UfU33"""33"33"""""D3""""""""""""""3333"""""""""""""""3""3333DD333DUfDfw"D""""3DUUUUUUU333DD"3DUDD3""""""33"""""""""""""""""D333"""""DDUUU3"""""""""""333D3"""""""""3"""""33"3U"""""3ffD33D3D3DD3333"3333333"3333""""""""""D""3""3"""""3333""""""""fˆw3""UD""""3UU3"""""""3DUwˆwwˆªˆˆwwwfUfwf"""3wwDD3"""33"""3"""""D3""""""""""""""33"3""""""""""""3D3""33DDDD33UUfUff"""""3""""3D33DDUfUD333"3UUUD3"33333"""""""3"""""""""""""""""""""""3D33"""""""""3D""""3""""""3D3D3"""""33""""""""33D""""""33ˆfD3333DD33333"3D"33D3333""""""""3""""""3""3"""""""""3wwD""""""3f3DUD3"""""""33DDUfwwfffˆª™wUUUUwwD""""3fwfDD""3333333""""3U3""""""""""""DDD333""""""""""3333333DDDDDDDDUUˆw""""""""DD3DUUD33"3D3DUUD333D3""""""""""""3""""""""""""""""""""""""""""""33DD""""""""""33""""""""""""3DDDD3"""""""3""""""""""""""3333""33"DD3UUfUD33333"333D3D33D"""""""D3D3""""""""""""""""""UªU"""""fD""UUD33""""33DUUfwUUfwUUˆªfUDDDDww3"""""fwfDD333333333""3"DU333"""""""""""DD33"""""3"""""""""33"3D3DD3D3DDDfˆD3""3"D33DUUD3333"DUUDD3"33"""""""""""""""33"""""""3"""""3"""""""""33DDD33"3""""""""""""""""""""""33DD333""""""""""333""""""""33""33D3""33DDDDD33333"333"3333"""""33DfU3"""""""""""""""""U™»D"""""""DU33UUD3333""33DDfwˆfDDfwwˆwD3DfDDfU"33"""DwwUDD333333333""3DD33""""""""""""33""3""""""""""""3"""333D3D333Dfwf3"""3"333DDD333""DU3DD333""""""""""""""3333"3"""33"""""""""""""333UDDD3"""""""""""""""""3D3"33"3""""""""3"DD3""""""""""""3DUU3"""""333DDDD3""3333""3333"""""""""3Dfff"""""""3"""""""""Dˆ»ˆ3""""""""wD""DUDUD3D33D33DDUffwffˆ™wfDDDD3DUUD""3"""fwwfDDDD33333"""DUD""3""""""""""""""3""""""""""""""3333D"3"3333DUUUf3""""33D3333""""33DD3333"""""""""3D""""""""3333""3""DD33"3""""""""""""33"3UD3"""""""""""""""""""333""333"3"""""""""""D33""""""""""3D3"""""3"D3DDDD"3""3""D3D3""""""""""""3UDDU3""33"""""""""3"UÝ»w""""""""UU""UD3DD3333DDDDUDDf™ª™wUUDDDDDD33Uw""""333DffwfUUUD3333"""fD""""""""""""""""3""""""""""""3333"D33333"""DDDUU""""3fD"33"""""3"3DUDDD333DU3""""33""""""""3D333""3"""33""3"""""""""""3fD3""""""""""""""""""""""""""33D3"""""""3"""""""""""""3""""""333333UD33"333D33"""""""""""""3DDDDD3""333""""""""3""""""™ÝÌw""""""""w33fD""""3DD3DUUUDfˆ™fD33DDDD333DDUU33"3""DDfUUUUUDD33"""Dw3"""""""""""""""D""""""""""""3""""D"33"""3333UUf"""""3D33"33""""""33D3DD3"33"""""""""""""33"333""""""33"3"""""""""""UD3""""""""""""""""33"""3""""333D3""""""""""""""""""""""""""""""""3333333D3"3"333D3333""""""""""""DDUUDUU3""3"""""""""""33"""U»ÝÝ»D"""""""""wUwf3""""3DDDDUUfˆwU3""333333"3UU333333333"UDffUDUDDD33"3Uf3""""""""""""""3"3"""""""""""""""""""""""""""3DUwf333"333DD333"""3"3""33DDD3"""""""""""""3""""3D33DD3"""""""""""""""""""""3DD3"""""""3""3"""""3UD""D"""""3""33"3""""""""33""""""""""""""""3333333DD333"D3D3"33333""""""""""""D3DDDDU333""""""""3"""""wÌÝÝ»™wD""""""""UDˆwD33"""3DDDDUˆˆD3"""""""""DU""33333333D3UUffUUDDDD33DfD3"""""""""""""""3""""""""""""""""""3""""""3""33Uˆˆˆ™™w3Uf333""""""33DDDDD33"""""""3""""3DDD"""3DDff3""""""""""""""""""UU33"""3"""""""""""""33"33"""""""3D33""""""""""""""""""""""333DD3""3DD3D33333""""""""""""3""""DD3fU""""""""DfÌÝ»ª™™™U3"""""""3UffU3""""""3DfwwU""""""3UU"3333DDDD3DfUwfUU3333UUU33"""3"3"""""""""3""""""""""3"""""3"""""3"33"333Uw™»ªwffD3"3"""""3"3DDDD33""""""""""DUU3""3333""""""""""""""""""3"UfUD""33""""""""""""""""""3"3D3D"""""""""""""""""""D3""333D3"3DDD3333D3"33"""""""""33"""""33"U3""""""3"D3ˆÌ̪™™ˆˆwfU"""""""DffD3"""""3wwˆfD""""""""DUD""""D33DD3D3fffwwwU"3UwfD"3"""3"33""""""""""3""""""""""""""""""""3"""3""33333DUfˆˆ™wwU"33"""""33"D333"3"""""""""""D3""""3""""""3"3"""""""""""""""""""3"33DDD""3"""""""""""""""3""""DDD3""""""""""""""""3"3U333"3D3"333333333D33""""""""""3"""""D3DU""""""""""33DDwÌ»ˆw™™ªwUwU"""3"33wwD33333"DˆU""""""""""""""UUD3"""3DDDDU33UffwfUUwUwfD33"D""""33"""""""""""""""""""3"""""""3""""3"333DDDUUUUˆª™D"33""""3"333DD33D3"""""""""33""""""3"""""3"33333""""""""33D"""333333333D3""""""3"""""""""""""""33333"""""""""""""D33D3"33"3D"333DUU3"""33""""""""33""""""""33DU3"""""""""333Dwª™ˆ™™™ª™™™U"333333ffDDDD3Uf™w""""""""""""3fUDD3""""3DUDUUD3wfwwUUffUDD333333"33""""""""3"3"""""""""""""""""3"""""333333333333DUww"3"""""""3DDD333""3"""""""""""""""""""""""3"""3"""333DUwwfwˆwwUDDDUUUDDDDD3""3"""D3"3"""""33"""""""""333D"""""""""""""""3""""""DDD3""""3D3""DD33UDD333"3"33""3DD3""""""""""3Uf"3""""""""33Dfˆ™ˆ™™ª™ªª™™ˆD333333fˆUDUfU™™UU"""""""""""""3UDDDDDD"""3333DUUUUwfwwU33"3D333333333""""""""""D3"""""""""""""""""""""""""""3333""33DDUU3333"""""33"3"""""3""""""""""3"""""3"""""""""3"3333DDUUUfffwUwwwfUDD3333DDDDD"""""D3"3""3""3"""""""""3DD3""""""""3"""""""""""DD""3"""U3"3UUUUwfUfUD33D"""3DUUD""""""""333DUD"""""""""33D܈™™™™™ˆªªˆfD"333DDwwfUˆªªU""""""""""""""3wfD3DDDD333"333UUUUUUDD3"""DUD33D3333333"""""""""3"""""""""""""""""3333"""""33""""3"33UUD3333"""""""""""""""""""""""""3"""""""""""3D33""333"3333DDUUUUUUfwU3DUDDUfDUUD""""33"""""3""""333DDD33""""""""""""""""""""DU3""3""UD"3DDUUUDDDDDUffUUUUUU3"""""""""""333D"""""""3Dfˆfwˆw™™ˆˆªªª™UU33DD33wfˆª™w3""""""""""UˆwfwfD3UUDDDDUUDfUDDfwUD3"3DUD""3333333""""""""""""""""""""3"""""""""""""""""3"""3D3""""""""""3333UUU333"""""""""""""""""""333"33D33"3DUffUD333"""""""333DDUUUDDDD33DD3UD3DD"""""""""""33DDUDD333""""""3""""""""""3D"""3""UwDDD3DDD3DDDDDUDDDDU33"""""""""""""333D3"""""""33Dw™ffwwˆ™™ˆ™™ª»ªwD33333f™»™D333"""""""""wˆU33DfwfDUDUDDUUUUUUffUD3"33D33"33D333""""""""3""""""""""""3""""""""""""""""""""""3D"""""3"""""33DDD3D"333"""""3"""""""""""33UDDDD333Dffwf3D""""""""""""333DDD""3""""""""""3""""""""""""3DDDDDD333"""""""""3"""""""""D3"3"3"fffU3333DUU3D3DD3DDDD"""""""""""""""""3333D3"""""333ˆ™Ufffˆˆˆˆˆˆ™ˆˆwfU333DUªÌˆ33333""""""""""""3™f""3DDUUfˆUDDDDUUUDDwwwUU33"333D33333333333"""""""""""""""3"""""""""""33"3""""""""DD""""""""""3DDD3"D"""3""""""""""""""""""33"""3DD333DUU33UD3""""""3""""""3333"""""3""""""""""""""""""""33DDDDUD333""""""""3""""""""333"3""Dwwww333333333333DDDD3"""""""""""""""""""33DDD"""""""3DˆwDUfffwˆˆˆˆˆˆˆfwwD33f™Ì»f33D33""""""""""U™f"333DUUUDfˆw3DDUwwwˆˆˆfUDDDD33333"333"""""""""3"""""""""""""""""3""""""""""""""""""""D3"""3"3"33DDDUfD3"""""""""""""3""""""3U333DfDUD3"""""""""""""""""""""3DD33""""""""""""3D""""33DDDDDDUDDD3333D3D"3333"""""""3""""33fwwUUf"3D3333DDDDDUDD333""""""3""""""""""3"33333D33"""""""3fwD3UffUUfwwwwwwfUUw3D™»ªfDDDD333""""""""""""DwD"3333DUUUDUf™ˆˆwwffUUˆwfD33DD333DD3D33"""""""""3""""""""""""""33"""""""""""""""33""""333333DDDDUU3""""""3""""""3UUDD3DUUU3""""""""3"""333""""33"33"3"""""D3D33""3"33DDDDUUUUUfffwˆwffUDDU3""""""""""""UfwfUfD3"33333DUUUU3DUUD""3""""""33333""33DDUDDD333D3""""""333wU33DDUUUUfwwwwfwˆˆffU»™fUDUDDD33"""""""""""33D"""""33DUDDDUffwˆUDDDUfwfDD3333333DD3333"""""""333""""""""""333D"3""""""""""""3""""3""333333UDDD""""3U3""""DDUU33UD3"33""""""""333333"""3""""3"""""""""""""333"""3""33333DDUUUffwfwwUUfwUDD""""""""""""3"ffwUfUfDD3"333UUU33DDDD"33333333DUDDD3DDDDDDDDD3"""""""""3"DˆD"33DDDUUUfwwwfUˆª»wf™UDDDDDDD333"""""""""3D3""""""33DDUDUUUfwˆfDUUffwfUDD333"3DD3333""""""3333"""""""""3D3"33"""""""""""""""3""3D333D33""""33D3""DDDDD3DD""D3D"""""""""""""""3DD"3333"""333""3"""""""""""D"333"DUD3DUUwwwwUˆffwfwfUUD3""""""3""""""UUwUDwUDDDDDDUD3D3DDDfD33"3DDUUUUUD3333DDDDDD333Df3""""""33wˆ3"DDD3DDDUDUUUffUˆ»Ìª™DDUUDDDDD33""""3""3""UD"""33DDD3DUUDDfwUDUffffUUUD"D3DDDDDD3"3"""3333333""""""""3"D33"""""""""""33"33D3D3DU3"""""DUU3"3D33DDD"3DUUD""33"""""""""333D""""33"""""3""""""""""""3""""""D333DUwwfUUfDDUwwwwfUU3"""""33""""3""3fˆf3UwfUUfwwfUUUUDUUUD"33"D3D3DD3""33"DDD3DU333DU3""""33333ww33DDDD3DDDDDDUUUfUwÌ̪UUUUUUUDDD33"""""33"3U3""3DDDU3DDDDUUwDDDUwˆffUDD333D3DDDD33"33DDD333333"""""""""D"D3"""""""""""""3""333333Uw"""""""DwwU"3D3DUD33"Uw3D33"""""""""""""3""""3"3""""""""""""""""""""3UfUUDDUUUUUUwwffffD""""333"""333DˆˆUDwfffffˆwUDD3"3DD33"""333D"""""333DU3333DD333U3""""33DDf3"33DDDD3DDDDDUUDUw™»™fUUUUUUUUUDD33""""""3UU""""33UUDD33UUUfUDDUˆfffUDD33DDUDD3DD3D3DDDD333""""""""33""333D3""""""""""""""""""33"DDUUf3""""""""3UUfwDDD3"3UDDDD3""""""""""""3""333""""""""""""""""""""""""3DUUUUDUfffUfwˆwfwfDU""33"""""33333"Uwf3DwUwˆwwfffD"""""""3"""D"3U3"""333DUD33333333DD3""33"fˆD"3DDDDUDDDDDUUUDwª™wUDDUUUUUUUUUDDD3"""""UU3"""""3DDDD3D3DDUUU™wDwˆfDDD3333D3DD3DD3DD3DDD3333"""""""""""3DD3D3"""""""""""""""""""33"UUfU""""""3""""DDDfwDDD3DUDD3D33""""""3D3""""""""""""""""""""""""""""""""DDUUDDDUUUUUDDffwwUDDUDD3"""""3333DwˆˆUUUwwwˆˆwf3""""""""""3"""3DD3333333"3DD33333D3U3""3333ˆ™3"DDDDDDDDDDDUUUwªˆU3DUUUUUUfUUUUDDD333"33wf"3""""""3DDDDD3D3UUUfDfˆwwwDDD"33DDDD33DDUDDDDD3333"""""""""3"3"""""""""""""""""""""""33DDD33U3""""3""""""3UwU33DDD33Uf33""""3""""""""""3"""""3""""3""""""""""3DDD""33333D333UwwwˆfDDf3"""3333D33fwwfUDDwˆ™™f3""""""33""""""""3""33"33333"D3333D3UU""33"3ˆ™"333DDDD33DDUUUUˆ™U""3DUUUUffUUUUUDDD33"3UwU"""""""""""3DDDDDD33DDUUD3fwUwwUD333DUDD33DDUUDDDDD333""""33DD3""3""""""""""33""""""""33DD3D"3"""""D3""3""33UD33DUD33fwD3"3D33""""""""""""""3""""33"""D3""""""""""""3UD3"""""""""3"Dffwffwwww3"""33"3DDf™ªˆwffUUfwU3"3"""""333"3""3"""""333333"3DD3"3UfUU""""33"D™™33D3DDDD33DDDUfˆ™f333"DDUUUUUUUUUUDDDD3"DfD3"3"""""""""""333DD3333DDDUDUˆwUwf33333DDD3D3DUUDDDDDD33"""""""33""""""""3""""""333UU33"3"""""D3"""""3333DDD3UDUU33D3D"""D"""3""3D"""""""""""""""33"""""""""""3D33""""""33DffUUUf™ˆwU"""3"DD3w™ªª™wwD""""DD3"""""""D"3"""33""3D3333333D3UfwwfUwU3"D""3"w»ˆ33D3DDD3DDDDUfwªªD3333"DDDUUUUUUUUDDDD33Dw33333"3""""""""""333D3333DDDDUfˆwfDwU3""3U"3333DDDUDDD3333""""""""""""""""""""""33333""3""""""""3""""""""""33DDDD3DDD""333""""""333""""3""""""3"33""""""""3"""""""""3""""""D3"""""""""3DUfUUfwfw™™f"33333UwˆwˆfUDw"""333333""""""D"3""3"""33"3""33UfffDD"3UDD333D""D™ªw333DDDDD3DDDUUf»Ìf"3333DDDDUUUUUUUUUUDDDff3"33""3"""""""""""333D33DDDUUfwˆfUwfUUUDDD3""3DUDDD3D3D""3"""""""""""""""""""""""3"3DD""3""""""""""""""""""3DDD33DUf33""3""33"""33""""""""""3""""""""3""""""333""""""""""""3"3"""""""""""3DUUUUfwfU™™ˆ3333Dfw3DUfUDfU"333"3"333D333333"""33""33333D3DUU333DUDf3333UD"3f™™f3333DDDDDDDDfUU™wUU33333DDDDUUUUUUUUUUDUwU""""""3"33"""""""""""3333DDUUDUwfUfUwwUUUUD3D"3DUUDD33D33"""""""""""""""""""""""""""33DD""3"""""""""""""""33333DUfDD33"""""33"""33""3"""""""""3"""""""""33"""""""""""3"""""33"""""3DUffUUfwˆ™™™f333wf33UUUDD33333"""3UD3D3D3"D3"""33"3D33DDDUU33DfwfDUD333DUUf™ˆˆˆD33D3DDDDDDDUUUww33U33333DDDDUUUUUUUUUUfˆD33""3"""333""""""333DUfwUfD"UUfUDUUU3"D"UfUDD33333"3""""""""""""""""3""3"""""""""""""3DU3"""""""""""""""""3DUD33DDUDUDD3D"3"""""333""""""""3"""3""""""""333""""""333"""""""""33DfUfUUUUUfˆ™ˆˆDUwfUwwUUD333"""33333DD"33333D"""""3DD333333fDDfwU3DU3D3Dfwfw™ˆˆ™U33D3DDDDDDDUDfwfU3"UDD33DDDDDUUUUUUUUfˆˆD333""D""333"""""""3UDUffUfw3""UfUUDUD33DUfUDD333D3""""""""""""""3"""""""""""""""""""3""33"DU3"D3""3"""""""""""3UDD3DDUffwf33"DD3"""3D3""""""3"3U333D"333333""3""3""3"3"""""""""33DUUfUUUfffw™ˆ™wUUDDU™fD333""""3"333"33"3D3""""""33DD333333ffwU333UU3UUwwUˆˆª™ªf333D33DDDDDfUfªD3D33DUDDDDDDDDUUUUUUDwªwDD3333"33"333"""""""3DfUUUfwf33UDUfDD3DDDUUUD3"3333"""""""""3"""""""""""""""""""3""""""""33"33DfwˆfD3DD"""""""3DUD3DUDwfUffD33"3""""""3""3""""""3"""DUD""DU""D3D""""""""3D""""3"""""""""""333UUUfUUw™™™™™™wDDDwwwwU3""3D3U3"3333333333"""""33DDD3333DwUfU33"UfUUffwUfw™wwfD33D3DDDDDDfUUˆª333333UfDDD33DDDDUUUU™ªUDDDD33""D"""33"""3DDfUUUfU"DUDfD3DDDDUUUUD33333"33""""""3"""""""""""""""""""3"""""""""3DDUUwˆwUUfwˆf""""33DD33DDUDDD33333"""""""3""""""3"3""""3DDU"3U3"33333DDD3"""""""""""""""""33"3DDUwff™ª™wˆˆwU3DffUUUfUUwUDD33D3333333333"""3"DDDD33DDUUUfD"3"3fUfwwwww™ˆU"""3DD3DDDDDUUU3w™w333D33"DÌUffDDUUUDDw™ˆ3DDDD333""3"""33""""333UfUUfU""fUUD3""DDDDDDDD33333"3"""""""""""3""33""""""""""3"""""""333"""""333fwwwwUDUDUfwwU""""""3"3DD333UDDDDD"333"""""""""""""""""""""""DD33UD33DDU3DDU""""""""""3""""""""""333DUffw™ˆfDDfU33DUfUffUˆf33333333DUD333""3"""3"DDDUUDDDD3UD""33"UUUffwwwˆw3"3333DDDDDDDDUUU3ˆˆ3""3333"3™fwDDDUUUUª™UDDDDDDDD333"3"3"""""""333DUffww""3DwfU"3DD3DDD"3D333333"3"""""""""""""3""""""""""""3""""3"""3""""333"DfwwfD3DDUUDDUfD""""""""""DDDDUUDUDDD33""""""""""""""3"""33DD"DU""UDDUUUDD3"""33"""3"""3""""""""""""3"333Ufwwªªf3DDDUUUffUDDDUDw3D3333""3D333333""""3DUffwffUUfU3"""3D3UDDfwwwww"333333333DUDUUUUUfw3""3333"3"fªUDDUUDf»ˆ33DDDDDDDD3333"""3"""""3"""3DDDDUwwf3""33""UUDDDUDD"3DDDDD33333""""""""""""""""""""3"""3"3"""""""33"33""3333UUfD33UDDDUUffˆ""""3"""3D333DUUDD333D"""""""""3"""""3"33333DD""3DDDUUff3""""""""3"""3"""""""""3D3Ufˆˆª™wDDDDUUUwwUD3DDDUwD3D333333DD3333"3""3DUwf3D33D"""3333DUDUwwwff""333DD33DDDUffUUffU"""3"""""D™ˆDDDwª»f33DDDDDDDDD33"""""333""33""33D33DwfD""""""UDUU33UDDD"33DDD333"33""""""""""""""""""""""""3""""333333"33D333UUD"3DUUUUfwˆw"""DfUDD"""""""DD33DUDDD3333""""""""""""3""""""""3"3"3D3"3"DD3DDUfU"""""""""3DD"D3"""""D3DDDUww™ªˆfDDDDUffUUUDD3DUUwwUfwD3"333DUfD3"3333DUUfDUU33"""33"333DDDUUffww"33"3333DDDDDUfDUfU3""""33"""""™ªwˆªÌwD3DDDDDDDDDDD33"""33D333DD3333DDDU™f"""fUwf3DDDD33D3DDDDDDD3""""""3"""""""""""3"3"""3""""333"3"""33333DUfD33DUfUfwˆ™D"3DfUD3"""""""3"33DDDD3333D3"""3"3""""3"""""""""33""""33""33UD33DU3333""""""3DUU3D33"""""3DUDDDffw™ˆ33UDDffffDDDDDDUUffwfffDDD"DDD3D3"33DDUfwU3Df3""""3""3"333DUDUwwwU"33333DDDDDDDfD"Uf""""3""""3""D̪»ÌªU333D3DDDDDDDD3D3333""33DDDDDDDDUUfˆwU""DffUD33D""DDDDD3DDDDD3""""""""""3""""""""""""3""""""3"""""""33333DDUD33DUUfUwˆw3"33""""3"""""""""33"33"33"DD"""3"""""""""""""33""""3"""D3UUD3DD"""""""""""DUf"3D33""""""3DDDDUffˆwD3DUUUffUDUDDUUDDDDwfUUUD33DD333333DDUUfUfDDDUD""""""""3"DfUDUUD3"3""3DDDDDDDDDfDDU""""""3""DUˆ™™wfDDDDD33DDDDDDDD3D333""333DDDDDUUDUUDf"D"DUDDUDD333333333DD3DUD""""""""""""""3""""""""""""""""""""333333DD3U333DUfwwwˆ"""""3""""""""""""3""33""DDUD""D33""3""""""""""""3"""""""3D"""3UUD"DU""""3"D3333UUUUD3"""""""""33UDDDUfˆw33DUDUfwDDUUDDDD3D33wUDDfD"3DD3D333DUUUD3wwUDDD3""D3""3D33ffD""""""3DfUUUDDDDUUwf3""""""33f™™wDDD3DDDDD33DDDDDD3D3D33"""333DUDDfUUD33"33"3D33DUD33333333""DDDDD""""""""""""3D3""3""""""""""""""""""""""""3""33D3333333Uwwwwfff""""3D""""33"""333"""3"3DDDU""DU33"3"""""""""""D"""""""""""""""3DUDDD"""""""""U3D3333"DD""""""""D33DDUDUwˆˆ333DDDUfDDDUUD333"DUwU3DUf333DDDUDDDDDUD3fwDD3"""""3D33DD"3UwD"""""""33UUUDDDDDDfwf"""""""""Uwˆ™™™U33DDDDD3D33DDUDD333D""""3333UDDUUff3"33U""D"33UUDD"3D3333333UUDD"""""""""""3UD""""""""""""""""""""""""3333DD33U33DDfwwwfDDU""3""""""3"""""""3""3U33D3"33"DDDDfU"""""""""""""""U3"""""""""""""""333D3DDDU3"""""3UD3"D3DUD""""""""3""DD33DDUUU™ˆD"3DDDUfD3D33D33"3"UfU33DUfUDUUffDDUUUfffUD33D3""333"33DUUUUfD""""""33DDDDD3DDUwwD""""""""w™fww™ˆfDDfwD33D3DDDDDDD3333"""3333DD33UUfU3"33DD""3DDUDDD3D333"333"UUDD"3"333"""3"UU3"""""""""""""""""""""""3333DD3D3333UfwffDDfD"""""""3"""""""""""3333333""33"DD3Dfff33""33""3"""3333""""""3"""3"""""3"33DDˆˆD3""3DD333DD3D"""""3U33"33"33DUUUˆ™3"33DDUUD333D33333DDˆwD3DDDfUUUUfUUfUUUD3"3"3"""""""DDUfwwfU3""""""""DDDDD333DDww3""""""3w™ˆˆ™™™™ˆˆ™fD3DD3DDDDDDDD3333"""3333D333DUD33"33D3"3D""3DDDDDD"333333333UUU3"""""3"3DU3"""3""""""""""""""""""""3333DD333"33UfUUD33f""33D3"""""""""33"""""3"3333"3333Uf3DDDDD333"3"""""""""""""""33"""33"33U3D333"""UD3D3U3"33""""3D3"""3DUDw™ˆU"333DDUD3D333333"3DˆUD3U33UfUfff™wˆU33333""""""""3UUUUˆffUD""""""333UDDDDDD3Dff"""""""Dwˆ™™ˆfUDDˆˆfw3DDDDDDDDDD333333""33DDDDDDDU""3""DD3"""""UfUDD3D3"""3333D33DUU3"""3333""U33""33""""3""""""""""""""3"""33"UDD"""333DDDDD33UD3D333"""""""""33""""33D333DDD3UU3DUDD3333D"33""""""""""""""""3"""3"33DD33U3"3DD"3UU3333"""""3U33""3333DUf™ª™3""3333DUD3333""3"33fUD33"DDUUUfffwfU"33"3""""""""3ffffwwD""""333D333333DDfU""""""3wwˆwfUDDDw™D3Uf3D3DDUDDDD33""""""33DDDDDUU3""3UD3""""""3UUUD333"""3"33333D3U3"333333"3"333"""""""""""""3"3""""""3D333"333333DDD333f"3D33"""""""""""3"3"""33333D3DUDDDUD333D333333""""""""""""""""3"33Uf""""D33333UUD3""""3""""3333DDDˆ™™™fUfD"3"3D3""""""3"3D33333DD3UUDfˆˆwwfDDD333"""3D"""""UUUfUD3"""""333"3333DDDUU""""""3DfwfUUDUUDDfwUUUwUDDDDDDDDD33""""""3DDDDUUU""33U""3333UUD33""""""3D333DUUUDD""""""3""""""""""""""""3""""""""""""3""D3"333333D3333Uw33""""3""3""3""3""""""""3333333DUUD3"3DD"""33""""""""""""""3"""""D333wwf""""3"33"33333""33""""3333DDDˆ™ˆ™ˆfww3"""33""""""33"3DD333333DUUUfwˆˆfDDD3"3"""333"D3"33UUUfD3""""3""3"33DDDUD"3""""""3DffUD"""""3333DDUUfwUDDUDD3D33"""""33DDUDDU3"33U"""DUUDDD"""""""""3DD3333Uffw33"""3"""""""""""""""""""""""""""""""3"D3"33333D3333Dwˆ3""""""33"3""""33"""""""""3D3"D33UUD"""3333333""""""""""""""""3U3D33fUfwD"""3"""""3"""""3"""""3"333Dwˆˆˆwffwf""""""""""""3D33333333DUDUUUfwˆf"3333""3DD""3""DfUUff"""""""""333"33DUfU3"333""""""""DwfD"""""3""333333DUwU3DD33333""""""333DU3""""3U3""DUDDD3"""3""3DD333333"333DffUDD3D33""""3"""""""""""3""""""""""""33"""3D33333"33Uwf"""""3"33D33""3""""""""""""3""33DDD3"3333333D3""""""""""""""D333"3fff3"3UU3"""3"""""""3"33333Df™™ˆffwwUD"""""""""""3333"333333DUDUUUwˆw™D33D333D3"""""3DDDU33"3""""3D33""3DUffD"""333333""3UUfD""""""""3333333DDwD3D3333333"""""333DD"""3"DD""DUD333333""""33DD""3333333"33DffD"33""""""""""""""""33""""""""""""333""3DD33D3"""DˆU""""""3"333"3333""""""""33"3DUUDDU3DUD3D333"""""""""""3"""3"""""""33""D""3UU"3DfwD""3"""""""333333UUˆª™™wwwˆf"""""""""""""333D333333333DUUfffUDfDDUDDDDD"""""3D3UU3""""3"""D333333UUf3333DD333"333fU3""""""""""""33"33DDfD3333DD3333""3333DD"""33DD"3DD"33"D3"3"3""3UD"333"33"333D3UfD"3""""""""""3""""""3"""3"3""""""33333333D3333"D3fU3"""33""""3D3333""""""""""3333DDDD3DUUUU3"""""""""""3""33""""""""333"3D3""3DD3UUwf3""3"3"""""33333DUUwªªªˆˆˆfU3""""""""""3D3"3DD3333333DDDUUUUDDDffDDDDD33""""3DDUU333""""""""""3D333DDDUDD3D3"3D3"3DffD3"333333""""3""333DUU33333333""333D3333"""3D3UDDDDD3""33""""3UU3"333D"3333DDDDffD"""""""""""""""""""""""""""""""3D3333333DD3333DUU"""""D3""""3UU33"""""""""""""33DD33DUDDUUD"3""""""""""""""3D"""33"""3""333333"3DDDUwfUD"""""""""3333DUUUˆ™™ˆwfUD3"""""""""3D333DD3333333D3DDUDDDDD3ff3DD333"""""DDDDDD3""""""""3"""333UU3333DDD3DDD3"Dff"D333D3DD3"""33"3333DfDD33333"3333333"3""3333DD"3D3D3"""""3fUDD3333333""3DDUUfU"""""3ffU""""""""""""""""""""""33"3"33"3333D333DDDD33"""""33"3""3UUD333"""""""33D3D33DfDDD333"3"""""""""""33""3""D"""3"3333333DUDwˆU333"""3"""""333DDUwfw™wˆfUfD""""3"""""D3"3f33333333DDD3D3333UU3fU3UUD""""""3UDD""3"""""""33333"UUDD"""3D33UD33D3UU"3333333DD"""""""""3DUUD33333333333333""""33""3f"33""""""""3DDU3333"33D333DDDDUDD3""fwwU3D"""""""""""""""""3""""""""3""33DD33DDf33D""""""""3333DUD333""""""""33333333UUUDD333"""""""""33"""""""3""333"33ffUfffwU""""33"""33"3DUUf™ˆªwwwUD3"""""""""""DDUfUUD"333D333DD3"33DDUDfffDUD""""33DDD""""""""""""""3"DUUU3""3""3333DDDDDwU3""33""33D"""""""3"33DDDDD3333333DD3DD""D33333U""""""3""""""""3"DD3"""""333333DDDfwwDUffUD3333""""""""""""""""3""""""""""333D33D3""""""""333DDDUUD33""""""""""""333333DUfU3333"3""""333""""""""33""333UwffU3"""""""3333DDUfw3wfD333"""""U3"DUfDUwD3""3D3333D333333DUfww3DDD"33DU333"""""3"""""DDDD3"""""3333""3UwfU""""3"33333"""""""3"33DfUDDD3333"DDDD3"""DD33"3f3""""""""""""""""3"D3D"""""""3333DDUfˆwfDDDDDD3D3"""""""""""""""""333DDD3""""""""""""33UfUUD3"3""""""""33"3D33333UUUD3"""""""3"""""""""""""""33"33UfwwwDD33"""""""""3DUDffDˆˆUD33""""""D333DUUUUU"33333"333"3333333DDwffU333333D33""""D"3"333UD3D3"33"3""3""3ffUD""""""""3D33"""""""33DUwUUUDD3333D3DD3"333"""3DU""""""""""""""3"""""""D3""""""3"33DUfwUU33D3DD3""""""""""3""""33DDD3"""""""""""3""3DD333""""""""""3"""33"33333UUfDDD""""""33""""""""""""""""""3DD3DDDf3"DwU3"""""""3DUUUDwˆwDD3""""3D33D33UDDDDD"33"3""3"3333333333DUDDUU3"333333""""3"333"DUDDDD""3D33D"3UUUU33"""33"333"""""""""333UUDUUfD3DD333UD3"333""33DU""3"""""33""""""3DwwUDDD33333333"""""""""3""""33D3""""""""""""""33DD33""""""333""""""""""3333"3"DUUUDD""""""""""""""""""""""3D"33D3333"3"3"3"""""""3DDUfff™ªw3"3""""33D33D"DD3D333""3333"3"""33333333DDDDDUU3DD33333""""333""33DDD3UD33U33UUDUDDD3"3""3""""""""""""""""33DDDUUfDDD33"DDD333""333DfD""""""""""""3DDUUD333"3333333"""""""""3"3""33D3""""333""33D3333""""""""33"""""""DD"33"3""3UfD33"""""""""3"""""""""33UD""3UD3D""D3"33"3""3DDUfwwˆ™wU"3"""""D3333D3"3D"3D3""""333"3""""33333DDD333DDUwfUDD333""""3"33"DDD3D333UU3UDDDDD3333""""33""33"""""3""3333DDUDDffUDDDD"D3""""3333UU3""""33""""""""""""33UUfDDUUDD333"3333Df3"""""""""""""""33333DD"DDD3"""DD33333"""3"33"3"""""""""""""33D3"""""3UDD33"""""""""""""""3"3D33"""""3Uf333"""""""""""3DDUUffwˆˆªf""""""""D"3""333"3333""""33"""""""333"33DD3""333Uwˆˆ™f333"""33"""333D3DDUD333DUUDDD333"33"333"33"3"""""""D33"3D33DDDDUUUUDD3DDD""""""33UD3D"""D33""""""""""""33DfUUfUDDD3""""DDDUD"""333"3""""3"""333"""333333DD3333"""DDD33D33"""333333"3"""3""""""3D3"""""33DD3D3"""""""""""""""3Uˆf3"""333DD"D3"""""333"""3DDUUDUffwwˆªˆ3""""""3""3D"""3"3333""33"D3"""33""""3"3DD3"33"33Uwwfw™UD""""""33"""3"3D3UffDDDfDDDD3"3"3333"33"33""""""33""33D3DDDDDUDUUUUDDDDUD""""3"3DUf"3""""3""33""""3"""""3fUUUDDDDD""""33D"3f""""33DD3""""33"""333""""333"""D3D3D33UDD3""33"D33333"""""""""33""""3"""""333D333D"""""""""3"""""""33UDD3""3DDUUUfD""""3DDU33"DDDUUDUfwUwˆªªwD3"33"""33""""3"3333333"33""3""""D333D33"""""""Dffffwww3"""""""""33D333UUDUUUUD3D33"""3333"3"33"3"""3"3"3333DDDUDDUUDUUDDDDUfD"""""3DDw33"""""33""D"3f""""""""""DwffDUDDDDD"333"3"DˆˆD"33"""33""""""33""""33"3"333333DDD33333DDD333""""""""""3"33"""""""3""""3DU3"3""""""""""3""3"""3"33333"3333D3DUUU33"""3DffD"3DDDDDDUUUwfUˆ»ˆU3"""3"""333""3"""3""3"DD""""""""33DD333"""3"""3DUUfwˆwf3333""""""33DDDDD33wfDD333"""3"3333333DD3""333"33DUDDUD3UUDUUDDDUDUUD3""""""3Dw3"U""""33"D33DD""""""3UD"3DD33"3"3""""DUwfUfU33""""""3""""""33"3""3"3D33D3D333"33"""""""""""3"""D3""""""""""""DU""""""""""""""""""""3333""""DD333D3333"""""""ffD"3DDD3DDUfUDUwˆªˆf""""D3"""3""D3"""""""3D333"""""""""3DD""""""""""DDDDfwwww3"33"""""3DDDDDUUDUfU3333""3D"333DD3DD3D3D333333333DfD3DDDDDfDDDDUDD33"""""""3Df33"""""""3"3D"DU""33""3wUD""3D3""3""3DwwUU3"3UD""""""""""""""33"3333333D333D3""""""""""""""""3""3"""""""""33""3""""3"""""""""""3"D"""3DD333D333D33"3Uw33DDDDDDUfwfDUˆªªUU""33""""3"Dwf""""""3DDD3"""""""3"""D"""""""""3DDUUDwˆwˆ3"3""""""33DDD3DD3DUU33"D"33333333"""D3""""3D3"33333D33D3DD3DDUDDUDDUD3""333""3"""Uf""3"""3"""33D3"DU3"33DDD""""""ff"""""""33"3UUwˆw3"""3DU"""""""""""""3"33""33333"3DD3"3"3""""""""""""33"""""""""""""""3D3""""""""3"""""""33"3"""""DD"""3U3DD3DD3""D""DDUUDDDDDDDUUfffwªÌ»f"3DD"""3wªw3"""33333"""""""""333"3D"""""""DD3DDDDfwwfDD"""""333D"33"D3UU33""3U3"""""""""""""""333""333333333D33DDDDUDUDDD"33333""3"UD""""33"""3""3D3DD""U3""""""""""""DˆU3""""DwwwU""""""33U3""""""""""""""33"333"""333""""""3"""""""""""""3""""""""""""""3""""DD"""""""3""""""3"""3"""33"3"3"DD3D33DDD""3"""""33DDUDDDDDDUffˆˆˆwªˆ""33"""wwwD3""33""""""""""""33""""""333D3333DUffˆwf3""3""3"D333D3DD""33"3""""""""""""""3"33"33D3DU33DDD3UUDUDDD"3D33"3"33""w3"""33""D"""3333"UU3""""33""""3wwD"""""""3D"33"""""""333D"""""""""3"33333""""33D3"""""""""""""""""3"""3"3""""""""""""DD"33"""""""33""""3D333"33"ff33DD3D3"DU""""""3333DD33D3DUfˆªwUwˆªw3"""""ˆªˆ™""""""33"""""""""3""""D"""""333333"3DUUUfwf3""33""3DDDD333D3"UD3D3""33"""""""""""3"3"DDD3""U3"33DDfUDDD33DD33"3""""""Uf"33""""333"Df33"""""""""""DwD"""""""3""3""""""""33""""""""""""""""""""3"3U"""33333"3"3""""""""""""33"""3""""""""""""D3333333""""""""""""""D333333"3UD"333DU3"DDU3"""""""3"33D33UUUfUDDUUfwª™"""""™ªªªwwU"""""3"""""""D"""3D""""333D""""3DDUUUfD"3"""""D333"33DDDDDD33U3UwU""33""""""""""""3333333"""3UDUUDD3333"333DD""333""3wU"""3""""""33333UU3""""""""""""3DU33"""""""""33""""""33"""""""""""""""""""3""""""""3333"""3""""""""""333""""""""""""""""33D3333"3D3""D3"""""3"""3DDDDDD3""3fD"333DUU3"DUf3""""""3"""33UwˆfUD3"DDUDˆªD"""Uˆ™U3UUU""""""""""3"""""""333333""""3DDDffD3UU3""33DD"3D33333"DDDU33U"33"""""""""""""3333DDDUD3D33DDDDDD3D""3"33U3"333"33ˆ""3""""""DDDUDUU3ffU3""""3"""""UfD3""3"""""""33"33"""3"""""""""""""""""333"""33""33""33"""""""33""333"""""""""3"""DD33"333333"""""33D33333333D3"""3U333333UUDD3333""""33"3333DfwfwUD3""U3DUU»fUf3ˆw3"3fDUD""""""""""""33D"33""""33DDffU3D3""""3UDDD3"3"""3333"33DD33""""""""""""""33333D3DD"3DDDDDUDDD3333"33"3"333""3wf""""""""3DD33"""fUUUD"UD""""UwD"""""""""""""""""3D"""33"""""3""""""""""""""""""""""""3"""3"""3D"3"""""""3D3""3""""""""""""""DD3"""333""""""3"3UD"""3333DDD333U3"333"DUDDˆfD"U333DUDDUUfUUDDDDD3""3D33Dˆ»™™»ˆf3""DUDDD"""""""""""""""""""33""33""""3DDUUfDD333""3D333D333""D33"U3"3DDDUU3""""""""3333"3333DU333"33DUUD333DD""333DD33""""Uª"3333333""333"DUffU3U""3DfU"""33"3""""""""3""""""""3""""D"""""""""""""""""""""""""3"3"""""3D"""""""33D3"""""""""""""""""3""3DD3""3333""""""33"fwU""3333DD333"UU"""3"Uffww™™™wwUfUUUffD3333DDD33"3D3"33Dw»»ÝÌf"""""DU"UD""""""""""33""""33"3D""""3"3DUUDfU3""D3"""""""3"333"D333DDDUwww3""""""D3""3D3"3DD33D333333D33DDfU333DDUDD3""3Dˆ33DD333"3"333DDDUfUfUD3""UUD3"""33333333"""""33"""""33""33""""""""""""3"""""""""3"3"33DU3D33""""""""""""""""""""""""""""""""3DD3"33"""""""""""""3w"""33D33333"3Uf3""3UwwUUfUfwfUDDfDDDUD33333DD3DD333333DDfÌÝU""3"""3DD3w"""""""""""3"""""""""3""""""33DDwˆw""3"333"""""""33""3""DD""3DDD3D3""""""""3""333DD333""333333UUUˆ™U333DDD3"3DUf3DDD3""333"33D3"fDUUUU3"""DUfD"""""""""""""""""33""33"""D3"""""""""""""""3""3"""""""3""""333333D3"33""33"""""3""""""""DD3"""3""""""DD3333"""3"""""""""""UD3""33"333"33UD""DˆwUUUUDUUUD"UwD""""3D33"3""""""3D"333U»Ýª"D3"3"3D3UwDUff""""""33""""""3""""3UUfˆˆD"3D3""""""""""""33333D33333""""""""""""3D3DD33""""3""3wˆwªfDDDDD33"""DDªD333D3"""3"""33DfDDDDUD"""DU3""""""3""""""""3D""33""3D""""""""""""""""""3"""""""3""""D3D3"DU3"""3""""""3"""""33DUUDD3""3D""""""3D3"""""""3DDD"""""""3"""3333333""D3"3ffUUUUDD3D33DDD3"3""""3""3"""""""""3333ˆÝîU3D3""3f3UˆU3DfD33""3U3""""33""""""""""33UDfffUDDUD33""""""""33D333"3"""33"3"33""""""""""""3DUDD333"3D333Dwª»w3DUD"33"3D3ªw"33"""3""""wDDD33D""U3""""3""""""""3""""""3U33""""33""""3"""""3""""""""""""""33"3333""333""""3333333DfwwfDDD3""33"""""3""""""""UDD""3"""3333"33"333"3DD3DDwU3DD33333D""3D""3"""33""""""""""""333DˆÝݪ"DD333UUˆ"3DUU33""Df""""""""""""""3DUUfffwwwˆU33""""3""333333DU"3UD3D"""3"""""""""""""3D3333"Uw333"f»™™f33DD"""""DDwª"3""3"""3"fD33DD3"wD33""""""""""""""""""3DU""""""3""""""""3"""333""3""""3"3D33D33333D3"""33DDDDUUˆˆˆf3""UD"""""3DDDD""""""""""""""33""333"""""333D33Dw™™ˆwDDD3333DD3""33"""""""3""""""3""""33Df™ÌÝ»»U"3"DDD3ˆ3""DDU3"Uf""""3""""""D3""DDUfUUUfwwwf"3"""""""DDDDDDD333DDD""3""""""""""""""3D33"""3333""fwDDU3""""""DUfª""""333""""DUDDDDD3Df"33"""""""""""3""3D3"""3""333""""""""""""""33"""""""""""3"3D33D33""333UUUfˆ™™f3""3"3"""""3""3DfD3""3D""""""""3"33"3"""33"33""33D™™wUDDDD3D3fD"""3"""""""""""""""""3Uˆ»Ì̪»ª»U"33UD"3w""3DfD33fD"""""3"""33""""UUUfUUUfffwfDD"""""3DDDUD3D3333DD3333"""""""33""""333333"""""""33333""""Dfˆ™""""333""UDDUfU3DD"""""""""""3U3""33"333"""""""""""""""D3"""3"33U3"33"3D33D3D3DD33Ufˆ»Ìˆ3"""""""""""""""""D3DD3D"333""""""3D"""""333333"333D3""3wwDD3DD3DD33D3""""3""""""""""""""33ªÌÌ»™ª»ªD"333DDw"""DUf3D3U""""""""""""D"DDD"3DDDUDDDDUUUwUD3""""333"3DD33D333DDDD""""33""3"""33333""""""""""DD""D"""3DwªD"""3UUffUU3"""""""""""""""3U3333D"333"""""""""""""3"""333""3333U33"""3DDDDDDUDfw™™Ì™U""""""""""""""3DDDDDDU3"3D3""""""""""""""33"33333DD"3fwUDD"3D33"3"DDD3"""3""""""3Dfªªªª™ª»f33"33""f""3DfUD""3""""""3""""3""3D"3"33DDDDDDUffffDD""""""""""""3333333DDD333UD33DU"""""33""""""D3""3DD"""3Dwªˆ"DUUˆfwUU"""""""""""""""""DUD3"33"""333D"""""""""333"""33""333D3D3"33"3DUffwˆ™»Ì»ˆD"""""""""""""""DfUDD33D3""""""33""333""""3D""333333"w™wDD333333"3"D3"D3"""""""33DUfˆ™™™D"ˆ3"3"3""DD3"DUwD"""""""""3""""D"""3""3"33DDDDDDD3DUwU"""""""""""""""333333DDDDDD33D3D""""""""3"""""3U"DDDff3""""3f™»"""ffD33"""33"""D"""""""""3UU3333333333DD33"3333"33"33"3D3D3Dfw™wfUUDDfw™™ª»™ffD3"""""""""3"""""""DwfU33D33"""""""""3""3"""""3D3D333"33D™wUDDD33"333"""3""3D3"""""""""3DUUffw™fDUˆ3"33"""U"33Dw3"""""33"""""""""""3333D333DDUfU""""""""""""3"""33"333fUU33"""""D"""""3"""""UD"3"33"3Uf™U"DˆUD33""""""3D3""""D""""""3"333DwDD333DUDDDDfD333D333DUDDUUD3DUwffD3™™»ª™™ˆwwD"""""""""""33""""" \ No newline at end of file diff --git a/gtk/parent b/gtk/parent new file mode 100644 index 000000000..94fee6123 --- /dev/null +++ b/gtk/parent @@ -0,0 +1,10 @@ + gdk_window_show (widget->window); + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + gdk_window_hide (widget->window); + if (GTK_WIDGET_VISIBLE (widget->parent)) + if (GTK_WIDGET_REALIZED (widget->parent) && + if (GTK_WIDGET_MAPPED (widget->parent) && diff --git a/gtk/runelisp b/gtk/runelisp new file mode 100644 index 000000000..115080cf0 --- /dev/null +++ b/gtk/runelisp @@ -0,0 +1,6 @@ +#! /bin/sh +if test $# -lt 1; then + echo >&2 "usage: $0 file.el" + exit 1 +fi +exec emacs --no-init-file --no-site-file --batch --load $* diff --git a/gtk/simple.c b/gtk/simple.c new file mode 100644 index 000000000..47893772f --- /dev/null +++ b/gtk/simple.c @@ -0,0 +1,39 @@ +#include +#include + + +void +hello () +{ + g_print ("hello world\n"); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *button; + + gdk_progclass = g_strdup ("XTerm"); + gtk_init (&argc, &argv); + + window = gtk_widget_new (gtk_window_get_type (), + "GtkObject::user_data", NULL, + "GtkWindow::type", GTK_WINDOW_TOPLEVEL, + "GtkWindow::title", "hello world", + "GtkWindow::allow_grow", FALSE, + "GtkWindow::allow_shrink", FALSE, + "GtkContainer::border_width", 10, + NULL); + button = gtk_widget_new (gtk_button_get_type (), + "GtkButton::label", "hello world", + "GtkObject::signal::clicked", hello, NULL, + "GtkWidget::parent", window, + "GtkWidget::visible", TRUE, + NULL); + gtk_widget_show (window); + + gtk_main (); + + return 0; +} diff --git a/gtk/test.xpm b/gtk/test.xpm new file mode 100644 index 000000000..9b0d2efdb --- /dev/null +++ b/gtk/test.xpm @@ -0,0 +1,92 @@ +/* XPM */ +static char *openfile[] = { +/* width height num_colors chars_per_pixel */ +" 20 19 66 2", +/* colors */ +".. c None", +".# c #000000", +".a c #dfdfdf", +".b c #7f7f7f", +".c c #006f6f", +".d c #00efef", +".e c #009f9f", +".f c #004040", +".g c #00bfbf", +".h c #ff0000", +".i c #ffffff", +".j c #7f0000", +".k c #007070", +".l c #00ffff", +".m c #00a0a0", +".n c #004f4f", +".o c #00cfcf", +".p c #8f8f8f", +".q c #6f6f6f", +".r c #a0a0a0", +".s c #7f7f00", +".t c #007f7f", +".u c #5f5f5f", +".v c #707070", +".w c #00f0f0", +".x c #009090", +".y c #ffff00", +".z c #0000ff", +".A c #00afaf", +".B c #00d0d0", +".C c #00dfdf", +".D c #005f5f", +".E c #00b0b0", +".F c #001010", +".G c #00c0c0", +".H c #000f0f", +".I c #00007f", +".J c #005050", +".K c #002f2f", +".L c #dfcfcf", +".M c #dfd0d0", +".N c #006060", +".O c #00e0e0", +".P c #00ff00", +".Q c #002020", +".R c #dfc0c0", +".S c #008080", +".T c #001f1f", +".U c #003f3f", +".V c #007f00", +".W c #00000f", +".X c #000010", +".Y c #00001f", +".Z c #000020", +".0 c #00002f", +".1 c #000030", +".2 c #00003f", +".3 c #000040", +".4 c #00004f", +".5 c #000050", +".6 c #00005f", +".7 c #000060", +".8 c #00006f", +".9 c #000070", +"#. c #7f7f80", +"## c #9f9f9f", +/* pixels */ +"........................................", +"........................................", +"........................................", +".......................#.#.#............", +".....................#.......#...#......", +"...............................#.#......", +".......#.#.#.................#.#.#......", +".....#.y.i.y.#.#.#.#.#.#.#..............", +".....#.i.y.i.y.i.y.i.y.i.#..............", +".....#.y.i.y.i.y.i.y.i.y.#..............", +".....#.i.y.i.y.#.#.#.#.#.#.#.#.#.#.#....", +".....#.y.i.y.#.s.s.s.s.s.s.s.s.s.#......", +".....#.i.y.#.s.s.s.s.s.s.s.s.s.#........", +".....#.y.#.s.s.s.s.s.s.s.s.s.#..........", +".....#.#.s.s.s.s.s.s.s.s.s.#............", +".....#.#.#.#.#.#.#.#.#.#.#..............", +"........................................", +"........................................", +"........................................" +}; diff --git a/gtk/testgtk.c b/gtk/testgtk.c new file mode 100644 index 000000000..b1d698a08 --- /dev/null +++ b/gtk/testgtk.c @@ -0,0 +1,3110 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "gtk.h" +#include "../gdk/gdk.h" +#include "../gdk/gdkx.h" + + +void +destroy_window (GtkWidget *widget, + GtkWidget **window) +{ + *window = NULL; +} + +void +button_window (GtkWidget *widget, + GtkWidget *button) +{ + if (!GTK_WIDGET_VISIBLE (button)) + gtk_widget_show (button); + else + gtk_widget_hide (button); +} + +void +create_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *table; + GtkWidget *button[10]; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + table = gtk_table_new (3, 3, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_border_width (GTK_CONTAINER (table), 10); + gtk_box_pack_start (GTK_BOX (box1), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + + button[0] = gtk_button_new_with_label ("button1"); + button[1] = gtk_button_new_with_label ("button2"); + button[2] = gtk_button_new_with_label ("button3"); + button[3] = gtk_button_new_with_label ("button4"); + button[4] = gtk_button_new_with_label ("button5"); + button[5] = gtk_button_new_with_label ("button6"); + button[6] = gtk_button_new_with_label ("button7"); + button[7] = gtk_button_new_with_label ("button8"); + button[8] = gtk_button_new_with_label ("button9"); + + gtk_signal_connect (GTK_OBJECT (button[0]), "clicked", + (GtkSignalFunc) button_window, + button[1]); + + gtk_table_attach (GTK_TABLE (table), button[0], 0, 1, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[0]); + + gtk_signal_connect (GTK_OBJECT (button[1]), "clicked", + (GtkSignalFunc) button_window, + button[2]); + + gtk_table_attach (GTK_TABLE (table), button[1], 1, 2, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[1]); + + gtk_signal_connect (GTK_OBJECT (button[2]), "clicked", + (GtkSignalFunc) button_window, + button[3]); + gtk_table_attach (GTK_TABLE (table), button[2], 2, 3, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[2]); + + gtk_signal_connect (GTK_OBJECT (button[3]), "clicked", + (GtkSignalFunc) button_window, + button[4]); + gtk_table_attach (GTK_TABLE (table), button[3], 0, 1, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[3]); + + gtk_signal_connect (GTK_OBJECT (button[4]), "clicked", + (GtkSignalFunc) button_window, + button[5]); + gtk_table_attach (GTK_TABLE (table), button[4], 2, 3, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[4]); + + gtk_signal_connect (GTK_OBJECT (button[5]), "clicked", + (GtkSignalFunc) button_window, + button[6]); + gtk_table_attach (GTK_TABLE (table), button[5], 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[5]); + + gtk_signal_connect (GTK_OBJECT (button[6]), "clicked", + (GtkSignalFunc) button_window, + button[7]); + gtk_table_attach (GTK_TABLE (table), button[6], 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[6]); + + gtk_signal_connect (GTK_OBJECT (button[7]), "clicked", + (GtkSignalFunc) button_window, + button[8]); + gtk_table_attach (GTK_TABLE (table), button[7], 2, 3, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[7]); + + gtk_signal_connect (GTK_OBJECT (button[8]), "clicked", + (GtkSignalFunc) button_window, + button[0]); + gtk_table_attach (GTK_TABLE (table), button[8], 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (button[8]); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button[9] = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button[9]), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button[9], TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button[9], GTK_CAN_DEFAULT); + gtk_widget_grab_default (button[9]); + gtk_widget_show (button[9]); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_toggle_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "toggle buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_toggle_button_new_with_label ("button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_toggle_button_new_with_label ("button2"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_toggle_button_new_with_label ("button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_check_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "check buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_check_button_new_with_label ("button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_check_button_new_with_label ("button2"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_check_button_new_with_label ("button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_radio_buttons () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "radio buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_radio_button_new_with_label (NULL, "button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_radio_button_new_with_label ( + gtk_radio_button_group (GTK_RADIO_BUTTON (button)), + "button2"); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_radio_button_new_with_label ( + gtk_radio_button_group (GTK_RADIO_BUTTON (button)), + "button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +bbox_widget_destroy (GtkWidget* widget, GtkWidget* todestroy) +{ +} + +void +create_bbox_window (gint horizontal, + char* title, + gint pos, + gint spacing, + gint child_w, + gint child_h, + gint layout) +{ + GtkWidget* window; + GtkWidget* box1; + GtkWidget* bbox; + GtkWidget* button; + + /* create a new window */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), title); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) bbox_widget_destroy, window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) bbox_widget_destroy, window); + + if (horizontal) + { + gtk_widget_set_usize (window, 550, 60); + gtk_widget_set_uposition (window, 150, pos); + box1 = gtk_vbox_new (FALSE, 0); + } + else + { + gtk_widget_set_usize (window, 150, 400); + gtk_widget_set_uposition (window, pos, 200); + box1 = gtk_vbox_new (FALSE, 0); + } + + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + if (horizontal) + bbox = gtk_hbutton_box_new(); + else + bbox = gtk_vbutton_box_new(); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout); + gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing); + gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h); + gtk_widget_show (bbox); + + gtk_container_border_width (GTK_CONTAINER(box1), 25); + gtk_box_pack_start (GTK_BOX (box1), bbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_container_add (GTK_CONTAINER(bbox), button); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) bbox_widget_destroy, window); + + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Cancel"); + gtk_container_add (GTK_CONTAINER(bbox), button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Help"); + gtk_container_add (GTK_CONTAINER(bbox), button); + gtk_widget_show (button); + + gtk_widget_show (window); +} + +void +test_hbbox () +{ + create_bbox_window (TRUE, "Spread", 50, 40, 85, 28, GTK_BUTTONBOX_SPREAD); + create_bbox_window (TRUE, "Edge", 200, 40, 85, 25, GTK_BUTTONBOX_EDGE); + create_bbox_window (TRUE, "Start", 350, 40, 85, 25, GTK_BUTTONBOX_START); + create_bbox_window (TRUE, "End", 500, 15, 30, 25, GTK_BUTTONBOX_END); +} + +void +test_vbbox () +{ + create_bbox_window (FALSE, "Spread", 50, 40, 85, 25, GTK_BUTTONBOX_SPREAD); + create_bbox_window (FALSE, "Edge", 250, 40, 85, 28, GTK_BUTTONBOX_EDGE); + create_bbox_window (FALSE, "Start", 450, 40, 85, 25, GTK_BUTTONBOX_START); + create_bbox_window (FALSE, "End", 650, 15, 30, 25, GTK_BUTTONBOX_END); +} + +void +create_button_box () +{ + static GtkWidget* window = NULL; + GtkWidget* bbox; + GtkWidget* button; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), + "Button Box Test"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, &window); + + gtk_container_border_width (GTK_CONTAINER (window), 20); + + /* + *these 15 lines are a nice and easy example for GtkHButtonBox + */ + bbox = gtk_hbutton_box_new (); + gtk_container_add (GTK_CONTAINER (window), bbox); + gtk_widget_show (bbox); + + button = gtk_button_new_with_label ("Horizontal"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) test_hbbox, 0); + gtk_container_add (GTK_CONTAINER (bbox), button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Vertical"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) test_vbbox, 0); + gtk_container_add (GTK_CONTAINER (bbox), button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +void +reparent_label (GtkWidget *widget, + GtkWidget *new_parent) +{ + GtkWidget *label; + + label = gtk_object_get_user_data (GTK_OBJECT (widget)); + + gtk_widget_reparent (label, new_parent); +} + +void +create_reparent () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *box3; + GtkWidget *frame; + GtkWidget *button; + GtkWidget *label; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "buttons"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + label = gtk_label_new ("Hello World"); + + frame = gtk_frame_new ("Frame 1"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + button = gtk_button_new_with_label ("switch"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) reparent_label, + box3); + gtk_object_set_user_data (GTK_OBJECT (button), label); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + gtk_box_pack_start (GTK_BOX (box3), label, FALSE, TRUE, 0); + gtk_widget_show (label); + + + frame = gtk_frame_new ("Frame 2"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + button = gtk_button_new_with_label ("switch"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) reparent_label, + box3); + gtk_object_set_user_data (GTK_OBJECT (button), label); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_pixmap () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *box3; + GtkWidget *button; + GtkWidget *label; + GtkWidget *separator; + GtkWidget *pixmapwid; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "pixmap"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + gtk_widget_realize(window); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new (); + gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 0); + gtk_widget_show (button); + + style=gtk_widget_get_style(button); + + pixmap = gdk_pixmap_create_from_xpm (window->window, &mask, + &style->bg[GTK_STATE_NORMAL], + "test.xpm"); + pixmapwid = gtk_pixmap_new (pixmap, mask); + + label = gtk_label_new ("Pixmap\ntest"); + box3 = gtk_hbox_new (FALSE, 0); + gtk_container_border_width (GTK_CONTAINER (box3), 2); + gtk_container_add (GTK_CONTAINER (box3), pixmapwid); + gtk_container_add (GTK_CONTAINER (box3), label); + gtk_container_add (GTK_CONTAINER (button), box3); + gtk_widget_show (pixmapwid); + gtk_widget_show (label); + gtk_widget_show (box3); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_tooltips () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + GtkTooltips *tooltips; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "tooltips"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + tooltips=gtk_tooltips_new(); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_toggle_button_new_with_label ("button1"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_tooltips_set_tips(tooltips,button,"This is button 1"); + + button = gtk_toggle_button_new_with_label ("button2"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_tooltips_set_tips(tooltips,button,"This is button 2"); + + button = gtk_toggle_button_new_with_label ("button3"); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + gtk_tooltips_set_tips (tooltips, button, "This is button 3. This is also a really long tooltip which probably won't fit on a single line and will therefore need to be wrapped. Hopefully the wrapping will work correctly."); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_tooltips_set_tips (tooltips, button, "Push this button to close window"); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +GtkWidget* +create_menu (int depth) +{ + GtkWidget *menu; + GtkWidget *submenu; + GtkWidget *menuitem; + GSList *group; + char buf[32]; + int i, j; + + if (depth < 1) + return NULL; + + menu = gtk_menu_new (); + submenu = NULL; + group = NULL; + + for (i = 0, j = 1; i < 5; i++, j++) + { + sprintf (buf, "item %2d - %d", depth, j); + menuitem = gtk_radio_menu_item_new_with_label (group, buf); + group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem)); + gtk_menu_append (GTK_MENU (menu), menuitem); + gtk_widget_show (menuitem); + + if (depth > 0) + { + if (!submenu) + submenu = create_menu (depth - 1); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), submenu); + } + } + + return menu; +} + +void +create_menus () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *menu; + GtkWidget *menubar; + GtkWidget *menuitem; + GtkWidget *optionmenu; + GtkWidget *separator; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "menus"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + menubar = gtk_menu_bar_new (); + gtk_box_pack_start (GTK_BOX (box1), menubar, FALSE, TRUE, 0); + gtk_widget_show (menubar); + + menu = create_menu (2); + + menuitem = gtk_menu_item_new_with_label ("test\nline2"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_menu_item_new_with_label ("foo"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); + gtk_widget_show (menuitem); + + menuitem = gtk_menu_item_new_with_label ("bar"); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); + gtk_menu_item_right_justify (GTK_MENU_ITEM (menuitem)); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), menuitem); + gtk_widget_show (menuitem); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + optionmenu = gtk_option_menu_new (); + gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), create_menu (1)); + gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), 4); + gtk_box_pack_start (GTK_BOX (box2), optionmenu, TRUE, TRUE, 0); + gtk_widget_show (optionmenu); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_scrolled_windows () +{ + static GtkWidget *window; + GtkWidget *scrolled_window; + GtkWidget *table; + GtkWidget *button; + char buffer[32]; + int i, j; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "dialog"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + scrolled_window, TRUE, TRUE, 0); + gtk_widget_show (scrolled_window); + + table = gtk_table_new (20, 20, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 10); + gtk_table_set_col_spacings (GTK_TABLE (table), 10); + gtk_container_add (GTK_CONTAINER (scrolled_window), table); + gtk_widget_show (table); + + for (i = 0; i < 20; i++) + for (j = 0; j < 20; j++) + { + sprintf (buffer, "button (%d,%d)\n", i, j); + button = gtk_toggle_button_new_with_label (buffer); + gtk_table_attach_defaults (GTK_TABLE (table), button, + i, i+1, j, j+1); + gtk_widget_show (button); + } + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +create_entry () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *entry; + GtkWidget *button; + GtkWidget *separator; + + /* if (!window) */ + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "entry"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + entry = gtk_entry_new (); + /* gtk_widget_set_usize (entry, 0, 25); */ + gtk_entry_set_text (GTK_ENTRY (entry), "hello world"); + gtk_box_pack_start (GTK_BOX (box2), entry, TRUE, TRUE, 0); + gtk_widget_show (entry); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + /* else + gtk_widget_destroy (window); */ +} + +void +list_add (GtkWidget *widget, + GtkWidget *list) +{ + static int i = 1; + gchar buffer[64]; + GtkWidget *list_item; + + sprintf (buffer, "added item %d", i++); + list_item = gtk_list_item_new_with_label (buffer); + gtk_widget_show (list_item); + gtk_container_add (GTK_CONTAINER (list), list_item); +} + +void +list_remove (GtkWidget *widget, + GtkWidget *list) +{ + GList *tmp_list; + GList *clear_list; + + tmp_list = GTK_LIST (list)->selection; + clear_list = NULL; + + while (tmp_list) + { + clear_list = g_list_prepend (clear_list, tmp_list->data); + tmp_list = tmp_list->next; + } + + clear_list = g_list_reverse (clear_list); + + gtk_list_remove_items (GTK_LIST (list), clear_list); + + tmp_list = clear_list; + + while (tmp_list) + { + gtk_widget_destroy (GTK_WIDGET (tmp_list->data)); + tmp_list = tmp_list->next; + } + + g_list_free (clear_list); +} + +void +create_list () +{ + static GtkWidget *window = NULL; + static char *list_items[] = + { + "hello", + "world", + "blah", + "foo", + "bar", + "argh", + "spencer", + "is a", + "wussy", + "programmer", + }; + static int nlist_items = sizeof (list_items) / sizeof (list_items[0]); + + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *scrolled_win; + GtkWidget *list; + GtkWidget *list_item; + GtkWidget *button; + GtkWidget *separator; + int i; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "list"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (box2), scrolled_win, TRUE, TRUE, 0); + gtk_widget_show (scrolled_win); + + list = gtk_list_new (); + gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_MULTIPLE); + gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE); + gtk_container_add (GTK_CONTAINER (scrolled_win), list); + gtk_widget_show (list); + + for (i = 0; i < nlist_items; i++) + { + list_item = gtk_list_item_new_with_label (list_items[i]); + gtk_container_add (GTK_CONTAINER (list), list_item); + gtk_widget_show (list_item); + } + + button = gtk_button_new_with_label ("add"); + GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) list_add, + list); + gtk_box_pack_start (GTK_BOX (box2), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("remove"); + GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) list_remove, + list); + gtk_box_pack_start (GTK_BOX (box2), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +color_selection_ok (GtkWidget *w, + GtkColorSelectionDialog *cs) +{ + GtkColorSelection *colorsel; + gdouble color[4]; + + colorsel=GTK_COLOR_SELECTION(cs->colorsel); + + gtk_color_selection_get_color(colorsel,color); + gtk_color_selection_set_color(colorsel,color); +} + +void +color_selection_changed (GtkWidget *w, + GtkColorSelectionDialog *cs) +{ + GtkColorSelection *colorsel; + gdouble color[4]; + + colorsel=GTK_COLOR_SELECTION(cs->colorsel); + gtk_color_selection_get_color(colorsel,color); +} + +void +create_color_selection () +{ + static GtkWidget *window = NULL; + + if (!window) + { + gtk_preview_set_install_cmap (TRUE); + gtk_widget_push_visual (gtk_preview_get_visual ()); + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + window = gtk_color_selection_dialog_new ("color selection dialog"); + + gtk_color_selection_set_opacity ( + GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), + TRUE); + + gtk_color_selection_set_update_policy( + GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), + GTK_UPDATE_CONTINUOUS); + + gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_signal_connect ( + GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->colorsel), + "color_changed", + (GtkSignalFunc) color_selection_changed, + window); + + gtk_signal_connect ( + GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->ok_button), + "clicked", + (GtkSignalFunc) color_selection_ok, + window); + + gtk_signal_connect_object ( + GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (window)->cancel_button), + "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +void +file_selection_ok (GtkWidget *w, + GtkFileSelection *fs) +{ + g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs))); +} + +void +create_file_selection () +{ + static GtkWidget *window = NULL; + + if (!window) + { + window = gtk_file_selection_new ("file selection dialog"); + gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->ok_button), + "clicked", (GtkSignalFunc) file_selection_ok, + window); + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (window)->cancel_button), + "clicked", (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkDialog + */ +static GtkWidget *dialog_window = NULL; + +void +label_toggle (GtkWidget *widget, + GtkWidget **label) +{ + if (!(*label)) + { + *label = gtk_label_new ("Dialog Test"); + gtk_misc_set_padding (GTK_MISC (*label), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->vbox), + *label, TRUE, TRUE, 0); + gtk_widget_show (*label); + } + else + { + gtk_widget_destroy (*label); + *label = NULL; + } +} + +void +create_dialog () +{ + static GtkWidget *label; + GtkWidget *button; + + if (!dialog_window) + { + dialog_window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (dialog_window), "destroy", + (GtkSignalFunc) destroy_window, + &dialog_window); + gtk_signal_connect (GTK_OBJECT (dialog_window), "delete_event", + (GtkSignalFunc) destroy_window, + &dialog_window); + + gtk_window_set_title (GTK_WINDOW (dialog_window), "dialog"); + gtk_container_border_width (GTK_CONTAINER (dialog_window), 0); + + button = gtk_button_new_with_label ("OK"); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Toggle"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) label_toggle, + &label); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + label = NULL; + } + + if (!GTK_WIDGET_VISIBLE (dialog_window)) + gtk_widget_show (dialog_window); + else + gtk_widget_destroy (dialog_window); +} + + +/* + * GtkRange + */ +void +create_range_controls () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *scrollbar; + GtkWidget *scale; + GtkWidget *separator; + GtkObject *adjustment; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "range controls"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + adjustment = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0); + + scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment)); + gtk_widget_set_usize (GTK_WIDGET (scale), 150, 30); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_scale_set_digits (GTK_SCALE (scale), 1); + gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE); + gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + + scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adjustment)); + gtk_range_set_update_policy (GTK_RANGE (scrollbar), + GTK_UPDATE_CONTINUOUS); + gtk_box_pack_start (GTK_BOX (box2), scrollbar, TRUE, TRUE, 0); + gtk_widget_show (scrollbar); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkRulers + */ +void +create_rulers () +{ + static GtkWidget *window = NULL; + GtkWidget *table; + GtkWidget *ruler; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "rulers"); + gtk_widget_set_usize (window, 300, 300); + gtk_widget_set_events (window, + GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + table = gtk_table_new (2, 2, FALSE); + gtk_container_add (GTK_CONTAINER (window), table); + gtk_widget_show (table); + + ruler = gtk_hruler_new (); + gtk_ruler_set_range (GTK_RULER (ruler), 5, 15, 0, 20); + + gtk_signal_connect_object ( + GTK_OBJECT (window), + "motion_notify_event", + (GtkSignalFunc) + GTK_WIDGET_CLASS (GTK_OBJECT (ruler)->klass)->motion_notify_event, + GTK_OBJECT (ruler)); + + gtk_table_attach (GTK_TABLE (table), ruler, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (ruler); + + + ruler = gtk_vruler_new (); + gtk_ruler_set_range (GTK_RULER (ruler), 5, 15, 0, 20); + + gtk_signal_connect_object ( + GTK_OBJECT (window), + "motion_notify_event", + (GtkSignalFunc) + GTK_WIDGET_CLASS (GTK_OBJECT (ruler)->klass)->motion_notify_event, + GTK_OBJECT (ruler)); + + gtk_table_attach (GTK_TABLE (table), ruler, 0, 1, 1, 2, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (ruler); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkText + */ +void +create_text () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + GtkWidget *table; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + GtkWidget *text; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "text window"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + table = gtk_table_new (2, 2, FALSE); + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); + gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + text = gtk_text_new (NULL, NULL); + gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1); + gtk_widget_show (text); + + hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj); + gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (hscrollbar); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + gtk_text_freeze (GTK_TEXT (text)); + + gtk_widget_realize (text); + + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "spencer blah blah blah\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "kimball\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "is\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "a\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "wuss.\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "but\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "josephine\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "(his\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "girlfriend\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "is\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "not).\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "why?\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "because\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "spencer\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "puked\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "last\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "night\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "but\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "josephine\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "did\n", -1); + gtk_text_insert (GTK_TEXT (text), NULL, &text->style->white, NULL, + "not", -1); + + gtk_text_thaw (GTK_TEXT (text)); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkNotebook + */ +void +rotate_notebook (GtkButton *button, + GtkNotebook *notebook) +{ + gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos + 1) % 4); +} + +void +create_notebook () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *button; + GtkWidget *separator; + GtkWidget *notebook; + GtkWidget *frame; + GtkWidget *label; + char buffer[32]; + int i; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "notebook"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + notebook = gtk_notebook_new (); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); + gtk_box_pack_start (GTK_BOX (box2), notebook, TRUE, TRUE, 0); + gtk_widget_show (notebook); + + + for (i = 0; i < 5; i++) + { + sprintf (buffer, "Page %d", i+1); + + frame = gtk_frame_new (buffer); + gtk_container_border_width (GTK_CONTAINER (frame), 10); + gtk_widget_set_usize (frame, 200, 150); + gtk_widget_show (frame); + + label = gtk_label_new (buffer); + gtk_container_add (GTK_CONTAINER (frame), label); + gtk_widget_show (label); + + label = gtk_label_new (buffer); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label); + } + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("next"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_notebook_next_page, + GTK_OBJECT (notebook)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("prev"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_notebook_prev_page, + GTK_OBJECT (notebook)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("rotate"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) rotate_notebook, + notebook); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * GtkPanes + */ +void +create_panes () +{ + static GtkWidget *window = NULL; + GtkWidget *frame; + GtkWidget *hpaned; + GtkWidget *vpaned; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Panes"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + vpaned = gtk_vpaned_new (); + gtk_container_add (GTK_CONTAINER (window), vpaned); + gtk_container_border_width (GTK_CONTAINER(vpaned), 5); + gtk_widget_show (vpaned); + + hpaned = gtk_hpaned_new (); + gtk_paned_add1 (GTK_PANED (vpaned), hpaned); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_set_usize (frame, 60, 60); + gtk_paned_add1 (GTK_PANED (hpaned), frame); + gtk_widget_show (frame); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_set_usize (frame, 80, 60); + gtk_paned_add2 (GTK_PANED (hpaned), frame); + gtk_widget_show (frame); + + gtk_widget_show (hpaned); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_widget_set_usize (frame, 60, 80); + gtk_paned_add2 (GTK_PANED (vpaned), frame); + gtk_widget_show (frame); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Drag -N- Drop + */ +void +dnd_drop (GtkWidget *button, GdkEvent *event) +{ + g_print ("Got drop of type |%s| with data of:\n%s\n", + event->dropdataavailable.data_type, + event->dropdataavailable.data); + g_free (event->dropdataavailable.data); + g_free (event->dropdataavailable.data_type); +} + +void +dnd_drag_request (GtkWidget *button, GdkEvent *event) +{ + g_print ("Button |%s| got drag request %d\n", + gtk_widget_get_name (button), event->type); + + gtk_widget_dnd_data_set (button, event, "Hello world!!!", + strlen("Hello world!!!") + 1); +} + +void +create_dnd () +{ + static GtkWidget *window = NULL; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *box3; + GtkWidget *entry; + GtkWidget *frame; + GtkWidget *button; + GtkWidget *separator; + char *foo = "testing"; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Drag -N- Drop"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + box2 = gtk_hbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + frame = gtk_frame_new ("Drag"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + /* + * FROM Button + */ + button = gtk_button_new_with_label ("From"); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + /* + * currently, the widget has to be realized to + * set dnd on it, this needs to change + */ + gtk_widget_realize (button); + gtk_signal_connect (GTK_OBJECT (button), + "drag_request_event", + (GtkSignalFunc) dnd_drag_request, + button); + + gtk_widget_dnd_drag_set (button, TRUE, &foo, 1); + + + frame = gtk_frame_new ("Drop"); + gtk_box_pack_start (GTK_BOX (box2), frame, TRUE, TRUE, 0); + gtk_widget_show (frame); + + box3 = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (box3), 5); + gtk_container_add (GTK_CONTAINER (frame), box3); + gtk_widget_show (box3); + + + /* + * TO Button + */ + button = gtk_button_new_with_label ("To"); + gtk_box_pack_start (GTK_BOX (box3), button, FALSE, TRUE, 0); + gtk_widget_show (button); + + gtk_widget_realize (button); + gtk_signal_connect (GTK_OBJECT (button), + "drop_data_available_event", + (GtkSignalFunc) dnd_drop, + button); + + gtk_widget_dnd_drop_set (button, TRUE, &foo, 1, FALSE); + + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +/* + * Shaped Windows + */ +static GdkWindow *root_win = NULL; +static GtkWidget *modeller = NULL; +static GtkWidget *sheets = NULL; +static GtkWidget *rings = NULL; + +typedef struct _cursoroffset {gint x,y;} CursorOffset; + +static void +shape_pressed (GtkWidget *widget) +{ + CursorOffset *p; + + p = gtk_object_get_user_data (GTK_OBJECT(widget)); + gtk_widget_get_pointer (widget, &(p->x), &(p->y)); + + gtk_grab_add (widget); + gdk_pointer_grab (widget->window, TRUE, + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK, + NULL, NULL, 0); +} + + +static void +shape_released (GtkWidget *widget) +{ + gtk_grab_remove (widget); + gdk_pointer_ungrab (0); +} + +static void +shape_motion (GtkWidget *widget, + GdkEventMotion *event) +{ + gint xp, yp; + CursorOffset * p; + GdkModifierType mask; + + p = gtk_object_get_user_data (GTK_OBJECT (widget)); + + gdk_window_get_pointer (root_win, &xp, &yp, &mask); + gtk_widget_set_uposition (widget, xp - p->x, yp - p->y); +} + +GtkWidget * +shape_create_icon (char *xpm_file, + gint x, + gint y, + gint px, + gint py, + gint window_type) +{ + GtkWidget *window; + GtkWidget *pixmap; + GtkWidget *fixed; + CursorOffset* icon_pos; + GdkGC* gc; + GdkBitmap *gdk_pixmap_mask; + GdkPixmap *gdk_pixmap; + GtkStyle *style; + + style = gtk_widget_get_default_style (); + gc = style->black_gc; + + /* + * GDK_WINDOW_TOPLEVEL works also, giving you a title border + */ + window = gtk_window_new (window_type); + + fixed = gtk_fixed_new (); + gtk_widget_set_usize (fixed, 100,100); + gtk_container_add (GTK_CONTAINER (window), fixed); + gtk_widget_show (fixed); + + gdk_pixmap = gdk_pixmap_create_from_xpm (window->window, &gdk_pixmap_mask, + &style->bg[GTK_STATE_NORMAL], + xpm_file); + + pixmap = gtk_pixmap_new (gdk_pixmap, gdk_pixmap_mask); + gtk_fixed_put (GTK_FIXED (fixed), pixmap, px,py); + gtk_widget_show (pixmap); + + gtk_widget_shape_combine_mask (window, gdk_pixmap_mask, px,py); + + gtk_widget_set_events (window, + gtk_widget_get_events (window) | + GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_PRESS_MASK); + + gtk_signal_connect (GTK_OBJECT (window), "button_press_event", + GTK_SIGNAL_FUNC (shape_pressed),NULL); + gtk_signal_connect (GTK_OBJECT (window), "button_release_event", + GTK_SIGNAL_FUNC (shape_released),NULL); + gtk_signal_connect (GTK_OBJECT (window), "motion_notify_event", + GTK_SIGNAL_FUNC (shape_motion),NULL); + + icon_pos = g_new (CursorOffset, 1); + gtk_object_set_user_data(GTK_OBJECT(window), icon_pos); + + gtk_widget_set_uposition (window, x, y); + gtk_widget_show (window); + + return window; +} + +void +create_shapes () +{ + root_win = gdk_window_foreign_new (GDK_ROOT_WINDOW ()); + + if (!modeller) + { + modeller = shape_create_icon ("Modeller.xpm", + 440, 140, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (modeller), "destroy", + (GtkSignalFunc) destroy_window, + &modeller); + gtk_signal_connect (GTK_OBJECT (modeller), "delete_event", + (GtkSignalFunc) destroy_window, + &modeller); + } + else + gtk_widget_destroy (modeller); + + if (!sheets) + { + sheets = shape_create_icon ("FilesQueue.xpm", + 580, 170, 0,0, GTK_WINDOW_POPUP); + + gtk_signal_connect (GTK_OBJECT (sheets), "destroy", + (GtkSignalFunc) destroy_window, + &sheets); + gtk_signal_connect (GTK_OBJECT (sheets), "delete_event", + (GtkSignalFunc) destroy_window, + &sheets); + + } + else + gtk_widget_destroy (sheets); + + if (!rings) + { + rings = shape_create_icon ("3DRings.xpm", + 460, 270, 25,25, GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (rings), "destroy", + (GtkSignalFunc) destroy_window, + &rings); + gtk_signal_connect (GTK_OBJECT (rings), "delete_event", + (GtkSignalFunc) destroy_window, + &rings); + } + else + gtk_widget_destroy (rings); +} + + +/* + * Progress Bar + */ +static int progress_timer = 0; + +gint +progress_timeout (gpointer data) +{ + gfloat new_val; + + new_val = GTK_PROGRESS_BAR (data)->percentage; + if (new_val >= 1.0) + new_val = 0.0; + new_val += 0.02; + + gtk_progress_bar_update (GTK_PROGRESS_BAR (data), new_val); + + return TRUE; +} + +void +destroy_progress (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + gtk_timeout_remove (progress_timer); + progress_timer = 0; +} + +void +create_progress_bar () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *pbar; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_progress, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_progress, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "dialog"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + + vbox = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (vbox), 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); + + label = gtk_label_new ("progress..."); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + gtk_widget_show (label); + + pbar = gtk_progress_bar_new (); + gtk_widget_set_usize (pbar, 200, 20); + gtk_box_pack_start (GTK_BOX (vbox), pbar, TRUE, TRUE, 0); + gtk_widget_show (pbar); + + progress_timer = gtk_timeout_add (100, progress_timeout, pbar); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Color Preview + */ +static int color_idle = 0; + +gint +color_idle_func (GtkWidget *preview) +{ + static int count = 1; + guchar buf[768]; + int i, j, k; + + for (i = 0; i < 256; i++) + { + for (j = 0, k = 0; j < 256; j++) + { + buf[k+0] = i + count; + buf[k+1] = 0; + buf[k+2] = j + count; + k += 3; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + count += 1; + + gtk_widget_draw (preview, NULL); + + return TRUE; +} + +void +color_preview_destroy (GtkWidget *widget, + GtkWidget **window) +{ + gtk_idle_remove (color_idle); + color_idle = 0; + + destroy_window (widget, window); +} + +void +create_color_preview () +{ + static GtkWidget *window = NULL; + GtkWidget *preview; + guchar buf[768]; + int i, j, k; + + if (!window) + { + gtk_widget_push_visual (gtk_preview_get_visual ()); + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) color_preview_destroy, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) color_preview_destroy, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + preview = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_size (GTK_PREVIEW (preview), 256, 256); + gtk_container_add (GTK_CONTAINER (window), preview); + gtk_widget_show (preview); + + for (i = 0; i < 256; i++) + { + for (j = 0, k = 0; j < 256; j++) + { + buf[k+0] = i; + buf[k+1] = 0; + buf[k+2] = j; + k += 3; + } + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + color_idle = gtk_idle_add ((GtkFunction) color_idle_func, preview); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Gray Preview + */ +static int gray_idle = 0; + +gint +gray_idle_func (GtkWidget *preview) +{ + static int count = 1; + guchar buf[256]; + int i, j; + + for (i = 0; i < 256; i++) + { + for (j = 0; j < 256; j++) + buf[j] = i + j + count; + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + count += 1; + + gtk_widget_draw (preview, NULL); + + return TRUE; +} + +void +gray_preview_destroy (GtkWidget *widget, + GtkWidget **window) +{ + gtk_idle_remove (gray_idle); + gray_idle = 0; + + destroy_window (widget, window); +} + +void +create_gray_preview () +{ + static GtkWidget *window = NULL; + GtkWidget *preview; + guchar buf[256]; + int i, j; + + if (!window) + { + gtk_widget_push_visual (gtk_preview_get_visual ()); + gtk_widget_push_colormap (gtk_preview_get_cmap ()); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) gray_preview_destroy, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) gray_preview_destroy, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + preview = gtk_preview_new (GTK_PREVIEW_GRAYSCALE); + gtk_preview_size (GTK_PREVIEW (preview), 256, 256); + gtk_container_add (GTK_CONTAINER (window), preview); + gtk_widget_show (preview); + + for (i = 0; i < 256; i++) + { + for (j = 0; j < 256; j++) + buf[j] = i + j; + + gtk_preview_draw_row (GTK_PREVIEW (preview), buf, 0, i, 256); + } + + gray_idle = gtk_idle_add ((GtkFunction) gray_idle_func, preview); + + gtk_widget_pop_colormap (); + gtk_widget_pop_visual (); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Selection Test + */ +void +selection_test_received (GtkWidget *list, GtkSelectionData *data) +{ + GdkAtom *atoms; + GtkWidget *list_item; + GList *item_list; + int i, l; + + if (data->length < 0) + { + g_print ("Selection retrieval failed\n"); + return; + } + if (data->type != GDK_SELECTION_TYPE_ATOM) + { + g_print ("Selection \"TARGETS\" was not returned as atoms!\n"); + return; + } + + /* Clear out any current list items */ + + gtk_list_clear_items (GTK_LIST(list), 0, -1); + + /* Add new items to list */ + + atoms = (GdkAtom *)data->data; + + item_list = NULL; + l = data->length / sizeof (GdkAtom); + for (i = 0; i < l; i++) + { + char *name; + name = gdk_atom_name (atoms[i]); + if (name != NULL) + { + list_item = gtk_list_item_new_with_label (name); + g_free (name); + } + else + list_item = gtk_list_item_new_with_label ("(bad atom)"); + + gtk_widget_show (list_item); + item_list = g_list_append (item_list, list_item); + } + + gtk_list_append_items (GTK_LIST (list), item_list); + + return; +} + +void +selection_test_get_targets (GtkWidget *widget, GtkWidget *list) +{ + static GdkAtom targets_atom = GDK_NONE; + + if (targets_atom == GDK_NONE) + targets_atom = gdk_atom_intern ("TARGETS", FALSE); + + gtk_selection_convert (list, GDK_SELECTION_PRIMARY, targets_atom, + GDK_CURRENT_TIME); +} + +void +create_selection_test () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *scrolled_win; + GtkWidget *list; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Selection Test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + /* Create the list */ + + vbox = gtk_vbox_new (FALSE, 5); + gtk_container_border_width (GTK_CONTAINER (vbox), 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, + TRUE, TRUE, 0); + gtk_widget_show (vbox); + + label = gtk_label_new ("Gets available targets for current selection"); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0); + gtk_widget_set_usize (scrolled_win, 100, 200); + gtk_widget_show (scrolled_win); + + list = gtk_list_new (); + gtk_container_add (GTK_CONTAINER (scrolled_win), list); + + gtk_signal_connect (GTK_OBJECT(list), "selection_received", + GTK_SIGNAL_FUNC (selection_test_received), NULL); + gtk_widget_show (list); + + /* .. And create some buttons */ + button = gtk_button_new_with_label ("Get Targets"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (selection_test_get_targets), list); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Gamma Curve + */ +void +create_gamma_curve () +{ + static GtkWidget *window = NULL, *curve; + static int count = 0; + gfloat vec[256]; + gint max; + gint i; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_window, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_window, + &window); + + curve = gtk_gamma_curve_new (); + gtk_container_add (GTK_CONTAINER (window), curve); + gtk_widget_show (curve); + } + + max = 127 + (count % 2)*128; + gtk_curve_set_range (GTK_CURVE (GTK_GAMMA_CURVE (curve)->curve), + 0, max, 0, max); + for (i = 0; i < max; ++i) + vec[i] = (127 / sqrt (max)) * sqrt (i); + gtk_curve_set_vector (GTK_CURVE (GTK_GAMMA_CURVE (curve)->curve), + max, vec); + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else if (count % 4 == 3) + { + gtk_widget_destroy (window); + window = NULL; + } + + ++count; +} + + +/* + * Timeout Test + */ +static int timer = 0; + +void +timeout_test (GtkWidget *label) +{ + static int count = 0; + static char buffer[32]; + + sprintf (buffer, "count: %d", ++count); + gtk_label_set (GTK_LABEL (label), buffer); +} + +void +start_timeout_test (GtkWidget *widget, + GtkWidget *label) +{ + if (!timer) + { + timer = gtk_timeout_add (100, (GtkFunction) timeout_test, label); + } +} + +void +stop_timeout_test (GtkWidget *widget, + gpointer data) +{ + if (timer) + { + gtk_timeout_remove (timer); + timer = 0; + } +} + +void +destroy_timeout_test (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + stop_timeout_test (NULL, NULL); +} + +void +create_timeout_test () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_timeout_test, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_timeout_test, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Timeout Test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + label = gtk_label_new ("count: 0"); + gtk_misc_set_padding (GTK_MISC (label), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + label, TRUE, TRUE, 0); + gtk_widget_show (label); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("start"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) start_timeout_test, + label); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("stop"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) stop_timeout_test, + NULL); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + + +/* + * Idle Test + */ +static int idle = 0; + +gint +idle_test (GtkWidget *label) +{ + static int count = 0; + static char buffer[32]; + + sprintf (buffer, "count: %d", ++count); + gtk_label_set (GTK_LABEL (label), buffer); + + return TRUE; +} + +void +start_idle_test (GtkWidget *widget, + GtkWidget *label) +{ + if (!idle) + { + idle = gtk_idle_add ((GtkFunction) idle_test, label); + } +} + +void +stop_idle_test (GtkWidget *widget, + gpointer data) +{ + if (idle) + { + gtk_idle_remove (idle); + idle = 0; + } +} + +void +destroy_idle_test (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + stop_idle_test (NULL, NULL); +} + +void +create_idle_test () +{ + static GtkWidget *window = NULL; + GtkWidget *button; + GtkWidget *label; + + if (!window) + { + window = gtk_dialog_new (); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy_idle_test, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) destroy_idle_test, + &window); + + gtk_window_set_title (GTK_WINDOW (window), "Idle Test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + label = gtk_label_new ("count: 0"); + gtk_misc_set_padding (GTK_MISC (label), 10, 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), + label, TRUE, TRUE, 0); + gtk_widget_show (label); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("start"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) start_idle_test, + label); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + + button = gtk_button_new_with_label ("stop"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) stop_idle_test, + NULL); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), + button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); + else + gtk_widget_destroy (window); +} + +void +test_destroy (GtkWidget *widget, + GtkWidget **window) +{ + destroy_window (widget, window); + gtk_main_quit (); +} + +/* + * Basic Test + */ +void +create_test () +{ + static GtkWidget *window = NULL; + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) test_destroy, + &window); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) test_destroy, + &window); + + + gtk_window_set_title (GTK_WINDOW (window), "test"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + } + + if (!GTK_WIDGET_VISIBLE (window)) + { + gtk_widget_show (window); + + g_print ("create_test: start\n"); + gtk_main (); + g_print ("create_test: done\n"); + } + else + gtk_widget_destroy (window); +} + + +/* + * Main Window and Exit + */ +void +do_exit () +{ + gtk_exit (0); +} + +void +create_main_window () +{ + struct { + char *label; + void (*func) (); + } buttons[] = + { + { "buttons", create_buttons }, + { "toggle buttons", create_toggle_buttons }, + { "check buttons", create_check_buttons }, + { "radio buttons", create_radio_buttons }, + { "button box", create_button_box }, + { "reparent", create_reparent }, + { "pixmap", create_pixmap }, + { "tooltips", create_tooltips }, + { "menus", create_menus }, + { "scrolled windows", create_scrolled_windows }, + { "drawing areas", NULL }, + { "entry", create_entry }, + { "list", create_list }, + { "color selection", create_color_selection }, + { "file selection", create_file_selection }, + { "dialog", create_dialog }, + { "miscellaneous", NULL }, + { "range controls", create_range_controls }, + { "rulers", create_rulers }, + { "text", create_text }, + { "notebook", create_notebook }, + { "panes", create_panes }, + { "shapes", create_shapes }, + { "dnd", create_dnd }, + { "progress bar", create_progress_bar }, + { "preview color", create_color_preview }, + { "preview gray", create_gray_preview }, + { "gamma curve", create_gamma_curve }, + { "test selection", create_selection_test }, + { "test timeout", create_timeout_test }, + { "test idle", create_idle_test }, + { "test", create_test }, + }; + int nbuttons = sizeof (buttons) / sizeof (buttons[0]); + GtkWidget *window; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *scrolled_window; + GtkWidget *button; + GtkWidget *separator; + int i; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "main window"); + gtk_widget_set_usize (window, 200, 400); + gtk_widget_set_uposition (window, 20, 20); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) gtk_exit, + NULL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + (GtkSignalFunc) gtk_exit, + NULL); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (box1), scrolled_window, TRUE, TRUE, 0); + gtk_widget_show (scrolled_window); + + box2 = gtk_vbox_new (FALSE, 0); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_container_add (GTK_CONTAINER (scrolled_window), box2); + gtk_widget_show (box2); + + for (i = 0; i < nbuttons; i++) + { + button = gtk_button_new_with_label (buttons[i].label); + if (buttons[i].func) + gtk_signal_connect (GTK_OBJECT (button), + "clicked", + (GtkSignalFunc) + buttons[i].func, NULL); + else + gtk_widget_set_sensitive (button, FALSE); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + gtk_widget_show (button); + } + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) do_exit, NULL); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_widget_show (window); +} + +int +main (int argc, char *argv[]) +{ + gtk_set_locale (); + + gtk_init (&argc, &argv); + gtk_rc_parse ("testgtkrc"); + + create_main_window (); + + gtk_main (); + + return 0; +} diff --git a/gtk/testgtkrc b/gtk/testgtkrc new file mode 100644 index 000000000..e909e314b --- /dev/null +++ b/gtk/testgtkrc @@ -0,0 +1,69 @@ +# pixmap_path ":::..." +# +# style [= ] +# { +#