summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'gtk')
-rw-r--r--gtk/.cvsignore9
-rw-r--r--gtk/3DRings.xpm116
-rw-r--r--gtk/FilesQueue.xpm98
-rw-r--r--gtk/Makefile.am248
-rw-r--r--gtk/Modeller.xpm117
-rw-r--r--gtk/fnmatch.c200
-rw-r--r--gtk/fnmatch.h67
-rw-r--r--gtk/gentypeinfo.el137
-rw-r--r--gtk/gtk.defs810
-rw-r--r--gtk/gtk.h106
-rw-r--r--gtk/gtkaccelerator.c352
-rw-r--r--gtk/gtkaccelerator.h73
-rw-r--r--gtk/gtkadjustment.c118
-rw-r--r--gtk/gtkadjustment.h74
-rw-r--r--gtk/gtkalignment.c193
-rw-r--r--gtk/gtkalignment.h72
-rw-r--r--gtk/gtkarrow.c165
-rw-r--r--gtk/gtkarrow.h66
-rw-r--r--gtk/gtkaspectframe.c336
-rw-r--r--gtk/gtkaspectframe.h75
-rw-r--r--gtk/gtkbbox.c228
-rw-r--r--gtk/gtkbbox.h93
-rw-r--r--gtk/gtkbin.c286
-rw-r--r--gtk/gtkbin.h60
-rw-r--r--gtk/gtkbox.c453
-rw-r--r--gtk/gtkbox.h90
-rw-r--r--gtk/gtkbutton.c915
-rw-r--r--gtk/gtkbutton.h76
-rw-r--r--gtk/gtkcheckbutton.c362
-rw-r--r--gtk/gtkcheckbutton.h66
-rw-r--r--gtk/gtkcheckmenuitem.c250
-rw-r--r--gtk/gtkcheckmenuitem.h69
-rw-r--r--gtk/gtkcolorsel.c1463
-rw-r--r--gtk/gtkcolorsel.h152
-rw-r--r--gtk/gtkcontainer.c844
-rw-r--r--gtk/gtkcontainer.h95
-rw-r--r--gtk/gtkcurve.c860
-rw-r--r--gtk/gtkcurve.h96
-rw-r--r--gtk/gtkdata.c73
-rw-r--r--gtk/gtkdata.h60
-rw-r--r--gtk/gtkdialog.c80
-rw-r--r--gtk/gtkdialog.h64
-rw-r--r--gtk/gtkdrawingarea.c146
-rw-r--r--gtk/gtkdrawingarea.h62
-rw-r--r--gtk/gtkentry.c1678
-rw-r--r--gtk/gtkentry.h94
-rw-r--r--gtk/gtkenums.h191
-rw-r--r--gtk/gtkeventbox.c226
-rw-r--r--gtk/gtkeventbox.h57
-rw-r--r--gtk/gtkfilesel.c2161
-rw-r--r--gtk/gtkfilesel.h73
-rw-r--r--gtk/gtkfixed.c525
-rw-r--r--gtk/gtkfixed.h76
-rw-r--r--gtk/gtkframe.c419
-rw-r--r--gtk/gtkframe.h73
-rw-r--r--gtk/gtkgamma.c464
-rw-r--r--gtk/gtkgamma.h71
-rw-r--r--gtk/gtkgc.c382
-rw-r--r--gtk/gtkgc.h42
-rw-r--r--gtk/gtkhbbox.c269
-rw-r--r--gtk/gtkhbbox.h66
-rw-r--r--gtk/gtkhbox.c306
-rw-r--r--gtk/gtkhbox.h60
-rw-r--r--gtk/gtkhpaned.c355
-rw-r--r--gtk/gtkhpaned.h59
-rw-r--r--gtk/gtkhruler.c277
-rw-r--r--gtk/gtkhruler.h59
-rw-r--r--gtk/gtkhscale.c436
-rw-r--r--gtk/gtkhscale.h59
-rw-r--r--gtk/gtkhscrollbar.c383
-rw-r--r--gtk/gtkhscrollbar.h59
-rw-r--r--gtk/gtkhseparator.c90
-rw-r--r--gtk/gtkhseparator.h59
-rw-r--r--gtk/gtkimage.c181
-rw-r--r--gtk/gtkimage.h69
-rw-r--r--gtk/gtkinputdialog.c546
-rw-r--r--gtk/gtkinputdialog.h76
-rw-r--r--gtk/gtkitem.c191
-rw-r--r--gtk/gtkitem.h65
-rw-r--r--gtk/gtklabel.c329
-rw-r--r--gtk/gtklabel.h69
-rw-r--r--gtk/gtklist.c1007
-rw-r--r--gtk/gtklist.h107
-rw-r--r--gtk/gtklistitem.c394
-rw-r--r--gtk/gtklistitem.h62
-rw-r--r--gtk/gtkmain.c1129
-rw-r--r--gtk/gtkmain.h76
-rw-r--r--gtk/gtkmenu.c732
-rw-r--r--gtk/gtkmenu.h94
-rw-r--r--gtk/gtkmenubar.c310
-rw-r--r--gtk/gtkmenubar.h66
-rw-r--r--gtk/gtkmenufactory.c541
-rw-r--r--gtk/gtkmenufactory.h88
-rw-r--r--gtk/gtkmenuitem.c746
-rw-r--r--gtk/gtkmenuitem.h98
-rw-r--r--gtk/gtkmenushell.c633
-rw-r--r--gtk/gtkmenushell.h83
-rw-r--r--gtk/gtkmisc.c181
-rw-r--r--gtk/gtkmisc.h70
-rw-r--r--gtk/gtknotebook.c1303
-rw-r--r--gtk/gtknotebook.h98
-rw-r--r--gtk/gtkobject.c994
-rw-r--r--gtk/gtkobject.h250
-rw-r--r--gtk/gtkoptionmenu.c584
-rw-r--r--gtk/gtkoptionmenu.h71
-rw-r--r--gtk/gtkpaned.c452
-rw-r--r--gtk/gtkpaned.h78
-rw-r--r--gtk/gtkpixmap.c176
-rw-r--r--gtk/gtkpixmap.h69
-rw-r--r--gtk/gtkpreview.c1571
-rw-r--r--gtk/gtkpreview.h144
-rw-r--r--gtk/gtkprogressbar.c259
-rw-r--r--gtk/gtkprogressbar.h64
-rw-r--r--gtk/gtkradiobutton.c321
-rw-r--r--gtk/gtkradiobutton.h69
-rw-r--r--gtk/gtkradiomenuitem.c240
-rw-r--r--gtk/gtkradiomenuitem.h64
-rw-r--r--gtk/gtkrange.c1369
-rw-r--r--gtk/gtkrange.h144
-rw-r--r--gtk/gtkrc.c1489
-rw-r--r--gtk/gtkrc.h45
-rw-r--r--gtk/gtkruler.c305
-rw-r--r--gtk/gtkruler.h91
-rw-r--r--gtk/gtkscale.c229
-rw-r--r--gtk/gtkscale.h75
-rw-r--r--gtk/gtkscrollbar.c54
-rw-r--r--gtk/gtkscrollbar.h58
-rw-r--r--gtk/gtkscrolledwindow.c510
-rw-r--r--gtk/gtkscrolledwindow.h74
-rw-r--r--gtk/gtkselection.c1388
-rw-r--r--gtk/gtkselection.h91
-rw-r--r--gtk/gtkseparator.c57
-rw-r--r--gtk/gtkseparator.h58
-rw-r--r--gtk/gtksignal.c1322
-rw-r--r--gtk/gtksignal.h124
-rw-r--r--gtk/gtkstyle.c1795
-rw-r--r--gtk/gtkstyle.h217
-rw-r--r--gtk/gtktable.c1178
-rw-r--r--gtk/gtktable.h126
-rw-r--r--gtk/gtktext.c3522
-rw-r--r--gtk/gtktext.h204
-rw-r--r--gtk/gtktogglebutton.c372
-rw-r--r--gtk/gtktogglebutton.h70
-rw-r--r--gtk/gtktooltips.c632
-rw-r--r--gtk/gtktooltips.h88
-rw-r--r--gtk/gtktree.c81
-rw-r--r--gtk/gtktree.h68
-rw-r--r--gtk/gtktreeitem.c108
-rw-r--r--gtk/gtktreeitem.h72
-rw-r--r--gtk/gtktypebuiltins.c53
-rw-r--r--gtk/gtktypebuiltins.h54
-rw-r--r--gtk/gtktypeutils.c459
-rw-r--r--gtk/gtktypeutils.h196
-rw-r--r--gtk/gtkvbbox.c272
-rw-r--r--gtk/gtkvbbox.h66
-rw-r--r--gtk/gtkvbox.c306
-rw-r--r--gtk/gtkvbox.h60
-rw-r--r--gtk/gtkviewport.c616
-rw-r--r--gtk/gtkviewport.h75
-rw-r--r--gtk/gtkvpaned.c356
-rw-r--r--gtk/gtkvpaned.h59
-rw-r--r--gtk/gtkvruler.c282
-rw-r--r--gtk/gtkvruler.h59
-rw-r--r--gtk/gtkvscale.c441
-rw-r--r--gtk/gtkvscale.h59
-rw-r--r--gtk/gtkvscrollbar.c387
-rw-r--r--gtk/gtkvscrollbar.h59
-rw-r--r--gtk/gtkvseparator.c90
-rw-r--r--gtk/gtkvseparator.h59
-rw-r--r--gtk/gtkwidget.c3390
-rw-r--r--gtk/gtkwidget.h505
-rw-r--r--gtk/gtkwindow.c1195
-rw-r--r--gtk/gtkwindow.h105
-rw-r--r--gtk/line-arrow.xbm4
-rw-r--r--gtk/line-wrap.xbm4
-rw-r--r--gtk/marble.xpm408
-rw-r--r--gtk/parent10
-rw-r--r--gtk/runelisp6
-rw-r--r--gtk/simple.c39
-rw-r--r--gtk/test.xpm92
-rw-r--r--gtk/testgtk.c3110
-rw-r--r--gtk/testgtkrc69
-rw-r--r--gtk/testinput.c379
-rw-r--r--gtk/testselection.c466
184 files changed, 64000 insertions, 0 deletions
diff --git a/gtk/.cvsignore b/gtk/.cvsignore
new file mode 100644
index 0000000000..e5ac5d91d3
--- /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 0000000000..1ca75da752
--- /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 ",
+" O<e7pbryq5am9ay6XMpM>3& ",
+" 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&= ",
+" &<kvX&4 +O*&<X0e:%$pAti%:edugn0= ",
+" +X@&+, V,O&>+Xt>tktktv0%@k;Cls+ ",
+" =+O*4*X:p;9cy3&&8ve0FMtt$ee0>z7cZ6k ",
+" D=D4,=.k$sBs$ee=+X0Fk%-#t%0X&O0nu9bG ",
+" ,,434*&ze@F<eeeeee><tdhdSMe<&&XAaawx ",
+" 4,4,=+><peeeeee&=<%M%$hSF0X&O&kw5r%Z ",
+" D&vSFMF<>&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 0000000000..586d27ec43
--- /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 0000000000..60d43b1d25
--- /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 0000000000..62e27f9853
--- /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:ffp<gha:t979;06 ",
+" =OO@=@zieeee7ex:::fffff0,v72444h6 ",
+" =OOo&Osst7iee7wkf:f:ff;t721444ham ",
+" =#&&&&OO@di7eu:ff:fferiv114444hmMX ",
+" =O&&&..o.sdp33fff:errrii7cc1hhh6mmNX= ",
+" =O&&&@.o.@sberrrrrriiuxuxnB;44aMmVCO#OX ",
+" =O&&o@..o.zrrrie777nnxtuxx:x;n:>mV##&&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<m6p7wmmOo...O$GZ####$$CZVVDAAA----++X ",
+" qBcaM <gxgmXmo.@.o&$$##$$$CZZZDADA-A-++-NX ",
+" M6> 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 0000000000..0a45770a40
--- /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 <config.h>
+#endif
+
+#include <errno.h>
+#include "fnmatch.h"
+#include <ctype.h>
+
+
+/* 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 0000000000..d9d73b3d86
--- /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 <unistd.h>. */
+#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 0000000000..2de6a92d2b
--- /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 0000000000..0228e7a8bf
--- /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 0000000000..acd1b10468
--- /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 <gdk/gdk.h>
+#include <gtk/gtkaccelerator.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkalignment.h>
+#include <gtk/gtkaspectframe.h>
+#include <gtk/gtkarrow.h>
+#include <gtk/gtkbin.h>
+#include <gtk/gtkbox.h>
+#include <gtk/gtkbbox.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkcheckbutton.h>
+#include <gtk/gtkcheckmenuitem.h>
+#include <gtk/gtkcolorsel.h>
+#include <gtk/gtkcontainer.h>
+#include <gtk/gtkcurve.h>
+#include <gtk/gtkdata.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkdrawingarea.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkenums.h>
+#include <gtk/gtkeventbox.h>
+#include <gtk/gtkfilesel.h>
+#include <gtk/gtkfixed.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtkgamma.h>
+#include <gtk/gtkgc.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtkhpaned.h>
+#include <gtk/gtkhruler.h>
+#include <gtk/gtkhscale.h>
+#include <gtk/gtkhscrollbar.h>
+#include <gtk/gtkhseparator.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkinputdialog.h>
+#include <gtk/gtkitem.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtklist.h>
+#include <gtk/gtklistitem.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkmenu.h>
+#include <gtk/gtkmenubar.h>
+#include <gtk/gtkmenufactory.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkmenushell.h>
+#include <gtk/gtkmisc.h>
+#include <gtk/gtknotebook.h>
+#include <gtk/gtkobject.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtkpaned.h>
+#include <gtk/gtkpixmap.h>
+#include <gtk/gtkpreview.h>
+#include <gtk/gtkprogressbar.h>
+#include <gtk/gtkradiobutton.h>
+#include <gtk/gtkradiomenuitem.h>
+#include <gtk/gtkrange.h>
+#include <gtk/gtkrc.h>
+#include <gtk/gtkruler.h>
+#include <gtk/gtkscale.h>
+#include <gtk/gtkscrollbar.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkselection.h>
+#include <gtk/gtkseparator.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkstyle.h>
+#include <gtk/gtktable.h>
+#include <gtk/gtktext.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtktooltips.h>
+#include <gtk/gtktree.h>
+#include <gtk/gtktreeitem.h>
+#include <gtk/gtktypeutils.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkvbbox.h>
+#include <gtk/gtkviewport.h>
+#include <gtk/gtkvpaned.h>
+#include <gtk/gtkvruler.h>
+#include <gtk/gtkvscale.h>
+#include <gtk/gtkvscrollbar.h>
+#include <gtk/gtkvseparator.h>
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkwindow.h>
+
+
+#endif /* __GTK_H__ */
diff --git a/gtk/gtkaccelerator.c b/gtk/gtkaccelerator.c
new file mode 100644
index 0000000000..a06a06a995
--- /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 <ctype.h>
+#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 0000000000..ac6323209c
--- /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 <gdk/gdk.h>
+#include <gtk/gtkobject.h>
+
+
+#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 0000000000..ab6e63d216
--- /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 0000000000..7832d1dd1f
--- /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 <gdk/gdk.h>
+#include <gtk/gtkdata.h>
+
+
+#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 0000000000..b562cff770
--- /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 0000000000..c80ad7f14b
--- /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 <gdk/gdk.h>
+#include <gtk/gtkbin.h>
+
+
+#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 0000000000..b8bc2143ed
--- /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 0000000000..5a2edb0f5d
--- /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 <gdk/gdk.h>
+#include <gtk/gtkmisc.h>
+
+
+#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 0000000000..2e4795bcae
--- /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 = &GTK_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 0000000000..07f08a4cce
--- /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 <gdk/gdk.h>
+#include <gtk/gtkbin.h>
+#include <gtk/gtkframe.h>
+
+#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 0000000000..818493f9a2
--- /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 0000000000..816f1f0c24
--- /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 0000000000..4cb7efcc19
--- /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 0000000000..c8676ab849
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..dfb2fed087
--- /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 0000000000..5ff0dd22af
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..18afb177ac
--- /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 0000000000..ec72c99f78
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..d7f72ce1c2
--- /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 0000000000..8994db563e
--- /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 <gdk/gdk.h>
+#include <gtk/gtktogglebutton.h>
+
+
+#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 0000000000..a36dfa75a0
--- /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 0000000000..1dc816c7c7
--- /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 <gdk/gdk.h>
+#include <gtk/gtkmenuitem.h>
+
+
+#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 0000000000..78780b2ff4
--- /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 <math.h>
+#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 0000000000..c29ea64f45
--- /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 <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <gdk/gdk.h>
+
+#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 0000000000..977fabc29e
--- /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 <string.h>
+#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 0000000000..80c1ce0335
--- /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 <gdk/gdk.h>
+#include <gtk/gtkenums.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..d2b6e08c84
--- /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 <string.h>
+#include <math.h>
+
+#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 0000000000..0e1568bc74
--- /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 <gdk/gdk.h>
+#include <gtk/gtkdrawingarea.h>
+
+#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 0000000000..63add29f33
--- /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 0000000000..2e9d30b315
--- /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 <gdk/gdk.h>
+#include <gtk/gtkobject.h>
+
+
+#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 0000000000..55da2d1371
--- /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 0000000000..139699682b
--- /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 <gdk/gdk.h>
+#include <gtk/gtkwindow.h>
+
+
+#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 0000000000..3220446a5c
--- /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 0000000000..d11445b030
--- /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 <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..b9c25f63ac
--- /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 <ctype.h>
+#include <string.h>
+#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 0000000000..c24bee6c87
--- /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 <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..b82d5e4974
--- /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 0000000000..44a0d7a9a7
--- /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 0000000000..d90213dee3
--- /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 <gdk/gdk.h>
+#include <gtk/gtkbin.h>
+
+
+#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 0000000000..77f83a87a3
--- /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 <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <pwd.h>
+#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 0000000000..1248ac6a9a
--- /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 <gdk/gdk.h>
+#include <gtk/gtkwindow.h>
+
+
+#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 0000000000..59eba1f46f
--- /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 0000000000..ee9c131a00
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..fe78897432
--- /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 0000000000..3fe17a3cbd
--- /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 <gdk/gdk.h>
+#include <gtk/gtkbin.h>
+
+
+#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 0000000000..1d7abc6fba
--- /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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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 0000000000..872a7bd438
--- /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 <gdk/gdk.h>
+#include <gtk/gtkvbox.h>
+
+
+#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 0000000000..c9da069844
--- /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 0000000000..ff4ecc466c
--- /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 <gdk/gdk.h>
+
+
+#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 0000000000..9d86c010e0
--- /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 0000000000..c61c138b9d
--- /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 0000000000..4cdc926cd9
--- /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 0000000000..7dfbb3dffb
--- /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 <gdk/gdk.h>
+#include <gtk/gtkbox.h>
+
+
+#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 0000000000..23c50961e8
--- /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 0000000000..0a352e7999
--- /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 <gdk/gdk.h>
+#include <gtk/gtkpaned.h>
+
+
+#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 0000000000..ab6e69199e
--- /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 <math.h>
+#include <stdio.h>
+#include <string.h>
+#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 0000000000..c4bc744364
--- /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 <gdk/gdk.h>
+#include <gtk/gtkruler.h>
+
+
+#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 0000000000..3bebd30fca
--- /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 <stdio.h>
+#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 0000000000..61ae4fdb31
--- /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 <gdk/gdk.h>
+#include <gtk/gtkscale.h>
+
+
+#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 0000000000..9b757d406f
--- /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 0000000000..7d69512592
--- /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 <gdk/gdk.h>
+#include <gtk/gtkscrollbar.h>
+
+
+#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 0000000000..5f3a38c209
--- /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 0000000000..9902631516
--- /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 <gdk/gdk.h>
+#include <gtk/gtkseparator.h>
+
+
+#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 0000000000..fddd06a5dc
--- /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 0000000000..d3481d51dd
--- /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 <gdk/gdk.h>
+#include <gtk/gtkmisc.h>
+
+
+#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 0000000000..1d412a32ea
--- /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 <owt1@cornell.edu>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#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;i<info->num_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;i<GDK_AXIS_LAST;i++)
+ {
+ list_item = gtk_list_item_new();
+
+ gtk_box_pack_start(GTK_BOX(inputd->axis_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 0000000000..93c667f440
--- /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 <gdk/gdk.h>
+#include <gtk/gtkdialog.h>
+
+
+#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 0000000000..6dd0ec8dd8
--- /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 0000000000..36cf1ab451
--- /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 <gdk/gdk.h>
+#include <gtk/gtkbin.h>
+
+
+#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 0000000000..5cd1f804fc
--- /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 <string.h>
+#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 0000000000..81eca4afe7
--- /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 <gdk/gdk.h>
+#include <gtk/gtkmisc.h>
+
+
+#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 0000000000..7d7d4a66d7
--- /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 0000000000..3eff261b54
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..6420270259
--- /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 0000000000..4220ae73f8
--- /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 <gdk/gdk.h>
+#include <gtk/gtkitem.h>
+
+
+#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 0000000000..50d262430b
--- /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 <stdio.h>
+#include <stdlib.h>
+#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 (&current_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 (&current_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 0000000000..9d014e47c9
--- /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 <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..13fff9023a
--- /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 <ctype.h>
+#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),
+ &GTK_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 0000000000..5cd5d28fa9
--- /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 <gdk/gdk.h>
+#include <gtk/gtkaccelerator.h>
+#include <gtk/gtkmenushell.h>
+
+
+#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 0000000000..19f0aa3e76
--- /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 0000000000..691e8f36f3
--- /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 <gdk/gdk.h>
+#include <gtk/gtkmenushell.h>
+
+
+#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 0000000000..d6e9ea6841
--- /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 <string.h>
+#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, "<separator>") == 0)
+ {
+ entry->widget = gtk_menu_item_new ();
+ gtk_container_add (GTK_CONTAINER (parent), entry->widget);
+ gtk_widget_show (entry->widget);
+ }
+ else
+ {
+ if (strncmp (path, "<check>", 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, "<nothing>") == 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, "<shift>", 7) == 0)
+ {
+ accelerator += 7;
+ *accelerator_mods |= GDK_SHIFT_MASK;
+ }
+ else if (strncmp (accelerator, "<alt>", 5) == 0)
+ {
+ accelerator += 5;
+ *accelerator_mods |= GDK_MOD1_MASK;
+ }
+ else if (strncmp (accelerator, "<control>", 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 0000000000..d95fdb7751
--- /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 <gtk/gtkwidget.h>
+
+
+#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 0000000000..f7715fb25e
--- /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 <string.h>
+#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 0000000000..da51681090
--- /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 <gdk/gdk.h>
+#include <gtk/gtkitem.h>
+
+
+#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 0000000000..6d3de5a7f8
--- /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 0000000000..a468631ed2
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..0ef8f0731c
--- /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 0000000000..1bc9cbb93e
--- /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 <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..0b3115034e
--- /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 (), &notebook_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, &GTK_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 0000000000..402823b2e3
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..ffe487e891
--- /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 <stdarg.h>
+#include <string.h>
+#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 0000000000..023bbbf0c3
--- /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 <gtk/gtkenums.h>
+#include <gtk/gtktypeutils.h>
+
+
+#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 0000000000..919aa26692
--- /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 0000000000..bbddf23097
--- /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 <gdk/gdk.h>
+#include <gtk/gtkbutton.h>
+
+
+#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 0000000000..d6b53db3d4
--- /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 0000000000..1b25263b0a
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..ae640f81f1
--- /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 0000000000..970d4f40fc
--- /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 <gdk/gdk.h>
+#include <gtk/gtkmisc.h>
+
+
+#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 0000000000..4246a321ab
--- /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 <math.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#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 0000000000..2fe6ad5e08
--- /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 <gtk/gtkwidget.h>
+
+
+#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 0000000000..8db560ba0c
--- /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 0000000000..e831dfb97a
--- /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 <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..0c52836e96
--- /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 0000000000..bf346c27eb
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcheckbutton.h>
+
+
+#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 0000000000..edfcff6733
--- /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 0000000000..28abafc6b5
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcheckmenuitem.h>
+
+
+#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 0000000000..f00bbf6838
--- /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 <stdio.h>
+#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 0000000000..47ff50a36c
--- /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 <gdk/gdk.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..86bc20121b
--- /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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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], "<parent>") == 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, "<parent>"))
+ 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 0000000000..8c761bb9e6
--- /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 <gtk/gtkstyle.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..dad0e11f64
--- /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 0000000000..c74b203212
--- /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 <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..ba2f186168
--- /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 <math.h>
+#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 0000000000..6fe2e4925e
--- /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 <gdk/gdk.h>
+#include <gtk/gtkrange.h>
+
+
+#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 0000000000..3f5088b446
--- /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 0000000000..14aadad1ae
--- /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 <gdk/gdk.h>
+#include <gtk/gtkrange.h>
+
+
+#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 0000000000..79cc67aaf6
--- /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 0000000000..34a01ef6cf
--- /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 <gdk/gdk.h>
+#include <gtk/gtkhscrollbar.h>
+#include <gtk/gtkvscrollbar.h>
+#include <gtk/gtkviewport.h>
+
+
+#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 0000000000..ca6f5742f4
--- /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 <owt1@cornell.edu> 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 <stdarg.h>
+#include <gdk/gdkx.h>
+/* 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; i<info->num_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; i<info->num_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; i<info->num_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 0000000000..18f3dc4b54
--- /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 <gdk/gdk.h>
+#include <gtk/gtkenums.h>
+#include <gtk/gtkwidget.h>
+
+#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 0000000000..6ad41ad5b0
--- /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 0000000000..bfccd337a9
--- /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 <gdk/gdk.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..65efdb991f
--- /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 <stdarg.h>
+#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 (&current_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 (&current_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 0000000000..68ff999025
--- /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 <gdk/gdk.h>
+#include <gtk/gtkenums.h>
+#include <gtk/gtkobject.h>
+
+
+#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 0000000000..ae8c1a5d9f
--- /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 <math.h>
+#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 0000000000..c0ec33736c
--- /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 <gdk/gdk.h>
+#include <gtk/gtkenums.h>
+
+
+#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 0000000000..7711524dea
--- /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 0000000000..f144e78d26
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..ae3dd4b5cf
--- /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 <ctype.h>
+#include <string.h>
+#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 0000000000..012d679a3b
--- /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 <gdk/gdk.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..eabcb1b266
--- /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 0000000000..e48d1cf5a2
--- /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 <gdk/gdk.h>
+#include <gtk/gtkbutton.h>
+
+
+#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 0000000000..953d425923
--- /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 <stdlib.h>
+#include <string.h>
+
+#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 0000000000..e3ac596967
--- /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 <gdk/gdk.h>
+
+
+#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 0000000000..f3981ea0a0
--- /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 0000000000..1486a82ab8
--- /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 <gdk/gdk.h>
+#include <gtk/gtkcontainer.h>
+
+
+#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 0000000000..8f0d9f078d
--- /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 0000000000..921f681bc3
--- /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 <gdk/gdk.h>
+#include <gtk/gtkitem.h>
+
+
+#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 0000000000..e43573119d
--- /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 0000000000..ba9131f0f1
--- /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 0000000000..46e035fd9a
--- /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 <string.h>
+#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 ("<unnamed type>\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 ("<unnamed type>");
+
+ 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 0000000000..911885be95
--- /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 <gdk/gdk.h>
+
+
+#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 <gtk/gtktypebuiltins.h>
+
+/* 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 0000000000..4fc867fdf3
--- /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 0000000000..310553d2ad
--- /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 0000000000..585e99b87b
--- /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 0000000000..aad32c914d
--- /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 <gdk/gdk.h>
+#include <gtk/gtkbox.h>
+
+
+#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 0000000000..dfa00c4b08
--- /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 = &GTK_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 0000000000..9af4e8720a
--- /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 <gdk/gdk.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkbin.h>
+
+
+#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 0000000000..2dae03209e
--- /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 0000000000..9e66c1255a
--- /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 <gdk/gdk.h>
+#include <gtk/gtkpaned.h>
+
+
+#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 0000000000..43fe16bb7b
--- /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 <math.h>
+#include <stdio.h>
+#include <string.h>
+#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 0000000000..22bef7164e
--- /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 <gdk/gdk.h>
+#include <gtk/gtkruler.h>
+
+
+#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 0000000000..9c2e3058fb
--- /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 <stdio.h>
+#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 0000000000..75862d389d
--- /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 <gdk/gdk.h>
+#include <gtk/gtkscale.h>
+
+
+#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 0000000000..87421c7bfb
--- /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 0000000000..3160fc0758
--- /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 <gdk/gdk.h>
+#include <gtk/gtkscrollbar.h>
+
+
+#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 0000000000..fbbba19ffe
--- /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 0000000000..74d07dd687
--- /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 <gdk/gdk.h>
+#include <gtk/gtkseparator.h>
+
+
+#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 0000000000..26e0c9bbc2
--- /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 <stdarg.h>
+#include <string.h>
+#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 0000000000..51ea9940c8
--- /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 <gdk/gdk.h>
+#include <gtk/gtkaccelerator.h>
+#include <gtk/gtkobject.h>
+#include <gtk/gtkstyle.h>
+
+
+#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 0000000000..e97708a96c
--- /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 <string.h>
+#include <limits.h>
+#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 0000000000..ff22527312
--- /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 <gdk/gdk.h>
+#include <gtk/gtkaccelerator.h>
+#include <gtk/gtkbin.h>
+#include <gtk/gtkenums.h>
+#include <gtk/gtkwidget.h>
+
+
+#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 0000000000..493ecf325d
--- /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 0000000000..82428037d9
--- /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 0000000000..1ef2607610
--- /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ª"
diff --git a/gtk/parent b/gtk/parent
new file mode 100644
index 0000000000..94fee61231
--- /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 0000000000..115080cf08
--- /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 0000000000..47893772f7
--- /dev/null
+++ b/gtk/simple.c
@@ -0,0 +1,39 @@
+#include <gtk/gtk.h>
+#include <gdk/gdkprivate.h>
+
+
+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 0000000000..9b0d2efdb2
--- /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 0000000000..b1d698a083
--- /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 <stdio.h>
+#include <stdlib.h>
+#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 0000000000..e909e314b0
--- /dev/null
+++ b/gtk/testgtkrc
@@ -0,0 +1,69 @@
+# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
+#
+# style <name> [= <name>]
+# {
+# <option>
+# }
+#
+# widget <widget_set> style <style_name>
+# widget_class <widget_class_set> style <style_name>
+
+pixmap_path "."
+
+style "window"
+{
+# bg_pixmap[NORMAL] = "warning.xpm"
+}
+
+style "scale"
+{
+ fg[NORMAL] = { 1.0, 0, 0 }
+ bg_pixmap[NORMAL] = "<parent>"
+}
+
+style "button"
+{
+ fg[PRELIGHT] = { 1.0, 1.0, 1.0 }
+ bg[PRELIGHT] = { 0, 0, 0.75 }
+}
+
+style "main_button" = "button"
+{
+ font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+ bg[PRELIGHT] = { 0.75, 0, 0 }
+}
+
+style "toggle_button" = "button"
+{
+ fg[NORMAL] = { 1.0, 0, 0 }
+ fg[ACTIVE] = { 1.0, 0, 0 }
+ bg_pixmap[NORMAL] = "<parent>"
+}
+
+style "text"
+{
+ bg_pixmap[NORMAL] = "marble.xpm"
+ fg[NORMAL] = { 1.0, 1.0, 1.0 }
+}
+
+style "ruler"
+{
+ font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
+}
+
+style "curve"
+{
+ fg[NORMAL] = { 58000, 0, 0 } # red
+}
+
+widget_class "GtkWindow" style "window"
+widget_class "GtkDialog" style "window"
+widget_class "GtkFileSelection" style "window"
+widget_class "*Gtk*Scale" style "scale"
+widget_class "*GtkCheckButton*" style "toggle_button"
+widget_class "*GtkRadioButton*" style "toggle_button"
+widget_class "*GtkButton*" style "button"
+widget_class "*Ruler" style "ruler"
+widget_class "*GtkText" style "text"
+widget "main window.*GtkButton*" style "main_button"
+widget "*GtkCurve" style "curve"
diff --git a/gtk/testinput.c b/gtk/testinput.c
new file mode 100644
index 0000000000..1c6dae0e1d
--- /dev/null
+++ b/gtk/testinput.c
@@ -0,0 +1,379 @@
+/* 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 "gtk.h"
+
+/* Backing pixmap for drawing area */
+
+static GdkPixmap *pixmap = NULL;
+
+/* Information about cursor */
+
+static gint need_cursor = FALSE;
+static gint cursor_proximity = TRUE;
+static gdouble cursor_x;
+static gdouble cursor_y;
+
+/* Unique ID of current device */
+static guint32 current_device = GDK_CORE_POINTER;
+
+/* Check to see if we need to draw a cursor for current device */
+static void
+check_cursor ()
+{
+ GList *tmp_list;
+
+ /* gdk_input_list_devices returns an internal list, so we shouldn't
+ free it afterwards */
+ tmp_list = gdk_input_list_devices();
+
+ while (tmp_list)
+ {
+ GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
+
+ if (info->deviceid == current_device)
+ {
+ need_cursor = !info->has_cursor;
+ break;
+ }
+
+ tmp_list = tmp_list->next;
+ }
+}
+
+/* Erase the old cursor, and/or draw a new one, if necessary */
+static void
+update_cursor (GtkWidget *widget, gdouble x, gdouble y)
+{
+ static gint cursor_present = 0;
+ gint state = need_cursor && cursor_proximity;
+
+ if (pixmap != NULL)
+ {
+ if (cursor_present && (cursor_present != state ||
+ x != cursor_x || y != cursor_y))
+ {
+ gdk_draw_pixmap(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+ pixmap,
+ cursor_x - 5, cursor_y - 5,
+ cursor_x - 5, cursor_y - 5,
+ 10, 10);
+ }
+
+ cursor_present = state;
+ cursor_x = x;
+ cursor_y = y;
+
+ if (cursor_present)
+ {
+ gdk_draw_rectangle (widget->window,
+ widget->style->black_gc,
+ TRUE,
+ cursor_x - 5, cursor_y -5,
+ 10, 10);
+ }
+ }
+}
+
+/* Create a new backing pixmap of the appropriate size */
+static gint
+configure_event (GtkWidget *widget, GdkEventConfigure *event)
+{
+ if (pixmap)
+ {
+ gdk_pixmap_destroy(pixmap);
+ }
+ pixmap = gdk_pixmap_new(widget->window,
+ widget->allocation.width,
+ widget->allocation.height,
+ -1);
+ gdk_draw_rectangle (pixmap,
+ widget->style->white_gc,
+ TRUE,
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+
+ return TRUE;
+}
+
+/* Refill the screen from the backing pixmap */
+static gint
+expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+ gdk_draw_pixmap(widget->window,
+ widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+ pixmap,
+ event->area.x, event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ return FALSE;
+}
+
+/* Draw a rectangle on the screen, size depending on pressure,
+ and color on the type of device */
+static void
+draw_brush (GtkWidget *widget, GdkInputSource source,
+ gdouble x, gdouble y, gdouble pressure)
+{
+ GdkGC *gc;
+ GdkRectangle update_rect;
+
+ switch (source)
+ {
+ case GDK_SOURCE_MOUSE:
+ gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
+ break;
+ case GDK_SOURCE_PEN:
+ gc = widget->style->black_gc;
+ break;
+ case GDK_SOURCE_ERASER:
+ gc = widget->style->white_gc;
+ break;
+ default:
+ gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
+ }
+
+ update_rect.x = x - 10 * pressure;
+ update_rect.y = y - 10 * pressure;
+ update_rect.width = 20 * pressure;
+ update_rect.height = 20 * pressure;
+ gdk_draw_rectangle (pixmap, gc, TRUE,
+ update_rect.x, update_rect.y,
+ update_rect.width, update_rect.height);
+ gtk_widget_draw (widget, &update_rect);
+}
+
+static guint32 motion_time;
+
+static gint
+button_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+ if (event->deviceid != current_device)
+ {
+ current_device = event->deviceid;
+ check_cursor ();
+ }
+
+ cursor_proximity = TRUE;
+
+ if (event->button == 1 && pixmap != NULL)
+ {
+ draw_brush (widget, event->source, event->x, event->y,
+ event->pressure);
+ motion_time = event->time;
+ }
+
+ update_cursor (widget, event->x, event->y);
+
+ return TRUE;
+}
+
+static gint
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
+{
+ GdkTimeCoord *coords;
+ int nevents;
+ int i;
+
+ if (event->deviceid != current_device)
+ {
+ current_device = event->deviceid;
+ check_cursor ();
+ }
+
+ cursor_proximity = TRUE;
+
+ if (event->state & GDK_BUTTON1_MASK && pixmap != NULL)
+ {
+ coords = gdk_input_motion_events (event->window, event->deviceid,
+ motion_time, event->time,
+ &nevents);
+ motion_time = event->time;
+ if (coords)
+ {
+ for (i=0; i<nevents; i++)
+ draw_brush (widget, event->source, coords[i].x, coords[i].y,
+ coords[i].pressure);
+ g_free (coords);
+ }
+ else
+ {
+ if (event->is_hint)
+ gdk_input_window_get_pointer (event->window, event->deviceid,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ draw_brush (widget, event->source, event->x, event->y,
+ event->pressure);
+ }
+ }
+ else
+ {
+ gdk_input_window_get_pointer (event->window, event->deviceid,
+ &event->x, &event->y,
+ NULL, NULL, NULL, NULL);
+ }
+
+ update_cursor (widget, event->x, event->y);
+
+ return TRUE;
+}
+
+/* We track the next two events to know when we need to draw a
+ cursor */
+
+static gint
+proximity_out_event (GtkWidget *widget, GdkEventProximity *event)
+{
+ cursor_proximity = FALSE;
+ update_cursor (widget, cursor_x, cursor_y);
+ return TRUE;
+}
+
+static gint
+leave_notify_event (GtkWidget *widget, GdkEventCrossing *event)
+{
+ cursor_proximity = FALSE;
+ update_cursor (widget, cursor_x, cursor_y);
+ return TRUE;
+}
+
+void
+input_dialog_destroy (GtkWidget *w, gpointer data)
+{
+ *((GtkWidget **)data) = NULL;
+}
+
+void
+create_input_dialog ()
+{
+ static GtkWidget *inputd = NULL;
+
+ if (!inputd)
+ {
+ inputd = gtk_input_dialog_new();
+
+ gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
+ (GtkSignalFunc)input_dialog_destroy, &inputd);
+ gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
+ "clicked",
+ (GtkSignalFunc)gtk_widget_hide,
+ GTK_OBJECT(inputd));
+ gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
+
+ gtk_signal_connect (GTK_OBJECT(inputd), "enable_device",
+ (GtkSignalFunc)check_cursor, NULL);
+ gtk_widget_show (inputd);
+ }
+ else
+ {
+ if (!GTK_WIDGET_MAPPED(inputd))
+ gtk_widget_show(inputd);
+ else
+ gdk_window_raise(inputd->window);
+ }
+}
+
+void
+quit ()
+{
+ gtk_exit (0);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *drawing_area;
+ GtkWidget *vbox;
+
+ GtkWidget *button;
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name (window, "Test Input");
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+ gtk_widget_show (vbox);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (quit), NULL);
+
+ /* Create the drawing area */
+
+ drawing_area = gtk_drawing_area_new ();
+ gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
+ gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
+
+ gtk_widget_show (drawing_area);
+
+ /* Signals used to handle backing pixmap */
+
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+ (GtkSignalFunc) expose_event, NULL);
+ gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
+ (GtkSignalFunc) configure_event, NULL);
+
+ /* Event signals */
+
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
+ (GtkSignalFunc) motion_notify_event, NULL);
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
+ (GtkSignalFunc) button_press_event, NULL);
+
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "leave_notify_event",
+ (GtkSignalFunc) leave_notify_event, NULL);
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "proximity_out_event",
+ (GtkSignalFunc) proximity_out_event, NULL);
+
+ gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK
+ | GDK_PROXIMITY_OUT_MASK);
+
+ /* The following call enables tracking and processing of extension
+ events for the drawing area */
+ gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_ALL);
+
+ /* .. And create some buttons */
+ button = gtk_button_new_with_label ("Input Dialog");
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (create_input_dialog), NULL);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Quit");
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ GTK_OBJECT (window));
+ gtk_widget_show (button);
+
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/gtk/testselection.c b/gtk/testselection.c
new file mode 100644
index 0000000000..3377cc6230
--- /dev/null
+++ b/gtk/testselection.c
@@ -0,0 +1,466 @@
+/* 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 "gtk.h"
+
+typedef enum {
+ SEL_TYPE_NONE,
+ APPLE_PICT,
+ ATOM,
+ ATOM_PAIR,
+ BITMAP,
+ C_STRING,
+ COLORMAP,
+ COMPOUND_TEXT,
+ DRAWABLE,
+ INTEGER,
+ PIXEL,
+ PIXMAP,
+ SPAN,
+ STRING,
+ TEXT,
+ WINDOW,
+ LAST_SEL_TYPE,
+} SelType;
+
+GdkAtom seltypes[LAST_SEL_TYPE];
+
+typedef struct _Target {
+ gchar *target_name;
+ SelType type;
+ GdkAtom target;
+ gint format;
+ GtkSelectionFunction *handler;
+} Target;
+
+/* The following is a list of all the selection targets defined
+ in the ICCCM */
+
+static Target targets[] = {
+ { "ADOBE_PORTABLE_DOCUMENT_FORMAT", STRING, 0, 8, NULL },
+ { "APPLE_PICT", APPLE_PICT, 0, 8, NULL },
+ { "BACKGROUND", PIXEL, 0, 32, NULL },
+ { "BITMAP", BITMAP, 0, 32, NULL },
+ { "CHARACTER_POSITION", SPAN, 0, 32, NULL },
+ { "CLASS", TEXT, 0, 8, NULL },
+ { "CLIENT_WINDOW", WINDOW, 0, 32, NULL },
+ { "COLORMAP", COLORMAP, 0, 32, NULL },
+ { "COLUMN_NUMBER", SPAN, 0, 32, NULL },
+ { "COMPOUND_TEXT", COMPOUND_TEXT, 0, 8, NULL },
+ /* { "DELETE", "NULL", 0, ?, NULL }, */
+ { "DRAWABLE", DRAWABLE, 0, 32, NULL },
+ { "ENCAPSULATED_POSTSCRIPT", STRING, 0, 8, NULL },
+ { "ENCAPSULATED_POSTSCRIPT_INTERCHANGE", STRING, 0, 8, NULL },
+ { "FILE_NAME", TEXT, 0, 8, NULL },
+ { "FOREGROUND", PIXEL, 0, 32, NULL },
+ { "HOST_NAME", TEXT, 0, 8, NULL },
+ /* { "INSERT_PROPERTY", "NULL", 0, ? NULL }, */
+ /* { "INSERT_SELECTION", "NULL", 0, ? NULL }, */
+ { "LENGTH", INTEGER, 0, 32, NULL },
+ { "LINE_NUMBER", SPAN, 0, 32, NULL },
+ { "LIST_LENGTH", INTEGER, 0, 32, NULL },
+ { "MODULE", TEXT, 0, 8, NULL },
+ /* { "MULTIPLE", "ATOM_PAIR", 0, 32, NULL }, */
+ { "NAME", TEXT, 0, 8, NULL },
+ { "ODIF", TEXT, 0, 8, NULL },
+ { "OWNER_OS", TEXT, 0, 8, NULL },
+ { "PIXMAP", PIXMAP, 0, 32, NULL },
+ { "POSTSCRIPT", STRING, 0, 8, NULL },
+ { "PROCEDURE", TEXT, 0, 8, NULL },
+ { "PROCESS", INTEGER, 0, 32, NULL },
+ { "STRING", STRING, 0, 8, NULL },
+ { "TARGETS", ATOM, 0, 32, NULL },
+ { "TASK", INTEGER, 0, 32, NULL },
+ { "TEXT", TEXT, 0, 8 , NULL },
+ { "TIMESTAMP", INTEGER, 0, 32, NULL },
+ { "USER", TEXT, 0, 8, NULL },
+};
+
+static int num_targets = sizeof(targets)/sizeof(Target);
+
+static int have_selection = FALSE;
+
+GtkWidget *selection_text;
+GtkWidget *selection_button;
+GString *selection_string = NULL;
+
+static void
+init_atoms ()
+{
+ int i;
+
+ seltypes[SEL_TYPE_NONE] = GDK_NONE;
+ seltypes[APPLE_PICT] = gdk_atom_intern ("APPLE_PICT",FALSE);
+ seltypes[ATOM] = gdk_atom_intern ("ATOM",FALSE);
+ seltypes[ATOM_PAIR] = gdk_atom_intern ("ATOM_PAIR",FALSE);
+ seltypes[BITMAP] = gdk_atom_intern ("BITMAP",FALSE);
+ seltypes[C_STRING] = gdk_atom_intern ("C_STRING",FALSE);
+ seltypes[COLORMAP] = gdk_atom_intern ("COLORMAP",FALSE);
+ seltypes[COMPOUND_TEXT] = gdk_atom_intern ("COMPOUND_TEXT",FALSE);
+ seltypes[DRAWABLE] = gdk_atom_intern ("DRAWABLE",FALSE);
+ seltypes[INTEGER] = gdk_atom_intern ("INTEGER",FALSE);
+ seltypes[PIXEL] = gdk_atom_intern ("PIXEL",FALSE);
+ seltypes[PIXMAP] = gdk_atom_intern ("PIXMAP",FALSE);
+ seltypes[SPAN] = gdk_atom_intern ("SPAN",FALSE);
+ seltypes[STRING] = gdk_atom_intern ("STRING",FALSE);
+ seltypes[TEXT] = gdk_atom_intern ("TEXT",FALSE);
+ seltypes[WINDOW] = gdk_atom_intern ("WINDOW",FALSE);
+
+ for (i=0; i<num_targets; i++)
+ targets[i].target = gdk_atom_intern (targets[i].target_name, FALSE);
+}
+
+void
+selection_toggled (GtkWidget *widget)
+{
+ if (GTK_TOGGLE_BUTTON(widget)->active)
+ {
+ have_selection = gtk_selection_owner_set (widget,
+ GDK_SELECTION_PRIMARY,
+ GDK_CURRENT_TIME);
+ if (!have_selection)
+ gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
+ }
+ else
+ {
+ if (have_selection)
+ {
+ if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
+ gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
+ GDK_CURRENT_TIME);
+ have_selection = FALSE;
+ }
+ }
+}
+
+void
+selection_handle (GtkWidget *widget,
+ GtkSelectionData *selection_data, gpointer data)
+{
+ guchar *buffer;
+ gint len;
+
+ if (!selection_string)
+ {
+ buffer = NULL;
+ len = 0;
+ }
+ else
+ {
+ buffer = selection_string->str;
+ len = selection_string->len;
+ }
+
+ gtk_selection_data_set (selection_data,
+ selection_data->target == seltypes[COMPOUND_TEXT] ?
+ seltypes[COMPOUND_TEXT] : seltypes[STRING],
+ 8, buffer, len);
+}
+
+gint
+selection_clear (GtkWidget *widget, GdkEventSelection *event)
+{
+ have_selection = FALSE;
+ gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
+
+ return TRUE;
+}
+
+gchar *
+stringify_atom (guchar *data, gint *position)
+{
+ gchar *str = gdk_atom_name (*(GdkAtom *)(data+*position));
+ *position += sizeof(GdkAtom);
+
+ return str;
+}
+
+gchar *
+stringify_text (guchar *data, gint *position)
+{
+ gchar *str = g_strdup ((gchar *)(data+*position));
+ *position += strlen (str) + 1;
+
+ return str;
+}
+
+gchar *
+stringify_xid (guchar *data, gint *position)
+{
+ gchar buffer[20];
+ gchar *str;
+
+ sprintf(buffer,"0x%x",*(guint32 *)(data+*position));
+ str = g_strdup (buffer);
+
+ *position += sizeof(guint32);
+
+ return str;
+}
+
+gchar *
+stringify_integer (guchar *data, gint *position)
+{
+ gchar buffer[20];
+ gchar *str;
+
+ sprintf(buffer,"%d",*(int *)(data+*position));
+ str = g_strdup (buffer);
+
+ *position += sizeof(int);
+
+ return str;
+}
+
+gchar *
+stringify_span (guchar *data, gint *position)
+{
+ gchar buffer[42];
+ gchar *str;
+
+ sprintf(buffer,"%d - %d",((int *)(data+*position))[0],
+ ((int *)(data+*position))[1]);
+ str = g_strdup (buffer);
+
+ *position += 2*sizeof(int);
+
+ return str;
+}
+
+void
+selection_received (GtkWidget *widget, GtkSelectionData *data)
+{
+ int position;
+ int i;
+ SelType seltype;
+ char *str;
+
+ if (data->length < 0)
+ {
+ g_print("Error retrieving selection\n");
+ return;
+ }
+
+ seltype = SEL_TYPE_NONE;
+ for (i=0; i<LAST_SEL_TYPE; i++)
+ {
+ if (seltypes[i] == data->type)
+ {
+ seltype = i;
+ break;
+ }
+ }
+
+ if (seltype == SEL_TYPE_NONE)
+ {
+ char *name = gdk_atom_name (data->type);
+ g_print("Don't know how to handle type: %s (%ld)\n",
+ name?name:"<unknown>",
+ data->type);
+ return;
+ }
+
+ if (selection_string != NULL)
+ g_string_free (selection_string, TRUE);
+
+ selection_string = g_string_new (NULL);
+
+ gtk_text_freeze (GTK_TEXT (selection_text));
+ gtk_text_set_point (GTK_TEXT (selection_text), 0);
+ gtk_text_foreward_delete (GTK_TEXT (selection_text),
+ gtk_text_get_length (GTK_TEXT (selection_text)));
+
+ position = 0;
+ while (position < data->length)
+ {
+ switch (seltype)
+ {
+ case ATOM:
+ str = stringify_atom (data->data, &position);
+ break;
+ case COMPOUND_TEXT:
+ case STRING:
+ case TEXT:
+ str = stringify_text (data->data, &position);
+ break;
+ case BITMAP:
+ case DRAWABLE:
+ case PIXMAP:
+ case WINDOW:
+ case COLORMAP:
+ str = stringify_xid (data->data, &position);
+ break;
+ case INTEGER:
+ case PIXEL:
+ str = stringify_integer (data->data, &position);
+ break;
+ case SPAN:
+ str = stringify_span (data->data, &position);
+ break;
+ default:
+ {
+ char *name = gdk_atom_name (data->type);
+ g_print("Can't convert type %s (%ld) to string\n",
+ name?name:"<unknown>",
+ data->type);
+ position = data->length;
+ }
+ }
+ gtk_text_insert (GTK_TEXT (selection_text), NULL,
+ &selection_text->style->black,
+ NULL, str, -1);
+ gtk_text_insert (GTK_TEXT (selection_text), NULL,
+ &selection_text->style->black,
+ NULL, "\n", -1);
+ g_string_append (selection_string, str);
+ g_free (str);
+ }
+ gtk_text_thaw (GTK_TEXT (selection_text));
+}
+
+void
+paste (GtkWidget *widget, GtkWidget *entry)
+{
+ char *name;
+ GdkAtom atom;
+
+ name = gtk_entry_get_text (GTK_ENTRY(entry));
+ atom = gdk_atom_intern (name, FALSE);
+
+ if (atom == GDK_NONE)
+ {
+ g_print("Could not create atom: \"%s\"\n",name);
+ return;
+ }
+
+ gtk_selection_convert (selection_button, GDK_SELECTION_PRIMARY, atom,
+ GDK_CURRENT_TIME);
+}
+
+void
+quit ()
+{
+ gtk_exit (0);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *dialog;
+ GtkWidget *button;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *entry;
+ GtkWidget *hscrollbar;
+ GtkWidget *vscrollbar;
+ GtkWidget *hbox;
+
+ gtk_init (&argc, &argv);
+
+ init_atoms();
+
+ dialog = gtk_dialog_new ();
+ gtk_widget_set_name (dialog, "Test Input");
+ gtk_container_border_width (GTK_CONTAINER(dialog), 0);
+
+ gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
+ GTK_SIGNAL_FUNC (quit), NULL);
+
+ table = gtk_table_new (4, 2, FALSE);
+ gtk_container_border_width (GTK_CONTAINER(table), 10);
+
+ gtk_table_set_row_spacing (GTK_TABLE (table), 0, 5);
+ gtk_table_set_row_spacing (GTK_TABLE (table), 1, 2);
+ gtk_table_set_row_spacing (GTK_TABLE (table), 2, 2);
+ gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->vbox),
+ table, TRUE, TRUE, 0);
+ gtk_widget_show (table);
+
+ selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
+ gtk_table_attach (GTK_TABLE (table), selection_button, 0, 2, 0, 1,
+ GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ gtk_widget_show (selection_button);
+
+ gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
+ GTK_SIGNAL_FUNC (selection_toggled), NULL);
+ gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
+ GTK_SIGNAL_FUNC (selection_clear), NULL);
+ gtk_signal_connect (GTK_OBJECT(selection_button), "selection_received",
+ GTK_SIGNAL_FUNC (selection_received), NULL);
+
+ gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
+ seltypes[STRING], selection_handle, NULL, NULL);
+
+ gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
+ seltypes[TEXT], selection_handle, NULL, NULL);
+
+ gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
+ seltypes[COMPOUND_TEXT],
+ selection_handle, NULL, NULL);
+
+ selection_text = gtk_text_new (NULL, NULL);
+ gtk_table_attach_defaults (GTK_TABLE (table), selection_text, 0, 1, 1, 2);
+ gtk_widget_show (selection_text);
+
+ hscrollbar = gtk_hscrollbar_new (GTK_TEXT (selection_text)->hadj);
+ gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 2, 3,
+ GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
+ gtk_widget_show (hscrollbar);
+
+ vscrollbar = gtk_vscrollbar_new (GTK_TEXT (selection_text)->vadj);
+ gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 1, 2,
+ GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_widget_show (vscrollbar);
+
+ hbox = gtk_hbox_new (FALSE, 2);
+ gtk_table_attach (GTK_TABLE (table), hbox, 0, 2, 3, 4,
+ GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ gtk_widget_show (hbox);
+
+ label = gtk_label_new ("Target:");
+ gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ entry = gtk_entry_new ();
+ gtk_box_pack_start (GTK_BOX(hbox), entry, TRUE, TRUE, 0);
+ gtk_widget_show (entry);
+
+ /* .. And create some buttons */
+ button = gtk_button_new_with_label ("Paste");
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area),
+ button, TRUE, TRUE, 0);
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (paste), entry);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Quit");
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area),
+ button, TRUE, TRUE, 0);
+
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy),
+ GTK_OBJECT (dialog));
+ gtk_widget_show (button);
+
+ gtk_widget_show (dialog);
+
+ gtk_main ();
+
+ return 0;
+}