diff options
Diffstat (limited to 'gtk')
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 = >K_ASPECT_FRAME(widget)->center_allocation; + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + height_extra = frame->label_height - widget->style->klass->xthickness; + height_extra = MAX (height_extra, 0); + + x = GTK_CONTAINER (frame)->border_width; + y = GTK_CONTAINER (frame)->border_width; + + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, frame->shadow_type, + allocation->x + x, + allocation->y + y + height_extra / 2, + allocation->width - x * 2, + allocation->height - y * 2 - height_extra / 2); + + if (frame->label) + { + label_area_width = (allocation->width + + GTK_CONTAINER (frame)->border_width * 2 - + widget->style->klass->xthickness * 2); + + x = ((label_area_width - frame->label_width) * frame->label_xalign + + GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness); + y = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent); + + gdk_window_clear_area (widget->window, + allocation->x + x + 2, + allocation->y + GTK_CONTAINER (frame)->border_width, + frame->label_width - 4, frame->label_height); + gtk_draw_string (widget->style, widget->window, state, + allocation->x + x + 3, + allocation->y + y, + frame->label); + } + } +} + +/* the only modification to the next two routines is to call + gtk_aspect_frame_paint instead of gtk_frame_paint */ + +static void +gtk_aspect_frame_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkBin *bin; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_aspect_frame_paint (widget, area); + + if (bin->child && gtk_widget_intersect (bin->child, area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } +} + +static gint +gtk_aspect_frame_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_ASPECT_FRAME (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + bin = GTK_BIN (widget); + + gtk_aspect_frame_paint (widget, &event->area); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static void +gtk_aspect_frame_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkFrame *frame; + GtkAspectFrame *aspect_frame; + GtkBin *bin; + + GtkAllocation child_allocation; + gint x,y; + gint width,height; + gdouble ratio; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_ASPECT_FRAME (widget)); + g_return_if_fail (allocation != NULL); + + aspect_frame = GTK_ASPECT_FRAME (widget); + frame = GTK_FRAME (widget); + bin = GTK_BIN (widget); + + if (GTK_WIDGET_MAPPED (widget) && + ((widget->allocation.x != allocation->x) || + (widget->allocation.y != allocation->y) || + (widget->allocation.width != allocation->width) || + (widget->allocation.height != allocation->height)) && + (widget->allocation.width != 0) && + (widget->allocation.height != 0)) + gdk_window_clear_area (widget->window, + widget->allocation.x, + widget->allocation.y, + widget->allocation.width, + widget->allocation.height); + + widget->allocation = *allocation; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + if (aspect_frame->obey_child) + { + if (bin->child->requisition.height != 0) + { + ratio = (gdouble)bin->child->requisition.width / + bin->child->requisition.height; + if (ratio < MIN_RATIO) ratio = MIN_RATIO; + } + else + if (bin->child->requisition.height != 0) + ratio = MAX_RATIO; + else + ratio = 1.0; + } + else + ratio = aspect_frame->ratio; + + x = (GTK_CONTAINER (frame)->border_width + + GTK_WIDGET (frame)->style->klass->xthickness); + width = allocation->width - x * 2; + + y = (GTK_CONTAINER (frame)->border_width + + MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness)); + height = (allocation->height - y - + GTK_CONTAINER (frame)->border_width - + GTK_WIDGET (frame)->style->klass->ythickness); + + if (ratio * height > width) + { + child_allocation.width = width; + child_allocation.height = width/ratio; + } + else + { + child_allocation.width = ratio*height; + child_allocation.height = height; + } + + child_allocation.x = aspect_frame->xalign * (width - child_allocation.width) + allocation->x + x; + child_allocation.y = aspect_frame->yalign * (height - child_allocation.height) + allocation->y + y; + + aspect_frame->center_allocation.width = child_allocation.width + 2*x; + aspect_frame->center_allocation.x = child_allocation.x - x; + aspect_frame->center_allocation.height = child_allocation.height + y + + GTK_CONTAINER (frame)->border_width + + GTK_WIDGET (frame)->style->klass->ythickness; + aspect_frame->center_allocation.y = child_allocation.y - y; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} diff --git a/gtk/gtkaspectframe.h b/gtk/gtkaspectframe.h new file mode 100644 index 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 (¤t_event, NULL, NULL); + } + + /* "gdk_event_get" can return FALSE if the timer goes off + * and no events are pending. Therefore, we should make + * sure that we got an event before continuing. + */ + if (have_event) + { + have_event = FALSE; + + /* If there are any events pending then get the next one. + */ + if (gdk_events_pending () > 0) + have_next_event = gdk_event_get (&next_event, NULL, NULL); + + /* Try to compress enter/leave notify events. These event + * pairs occur when the mouse is dragged quickly across + * a window with many buttons (or through a menu). Instead + * of highlighting and de-highlighting each widget that + * is crossed it is better to simply de-highlight the widget + * which contained the mouse initially and highlight the + * widget which ends up containing the mouse. + */ + if (have_next_event) + if (((current_event.type == GDK_ENTER_NOTIFY) || + (current_event.type == GDK_LEAVE_NOTIFY)) && + ((next_event.type == GDK_ENTER_NOTIFY) || + (next_event.type == GDK_LEAVE_NOTIFY)) && + (next_event.type != current_event.type) && + (next_event.any.window == current_event.any.window)) + return done; + + /* Find the widget which got the event. We store the widget + * in the user_data field of GdkWindow's. + */ + event_widget = gtk_get_event_widget (¤t_event); + + /* If there is a grab in effect... + */ + if (grabs) + { + grab_widget = grabs->data; + + /* If the grab widget is an ancestor of the event widget + * then we send the event to the original event widget. + * This is the key to implementing modality. + */ + if (gtk_widget_is_ancestor (event_widget, grab_widget)) + grab_widget = event_widget; + } + else + { + grab_widget = event_widget; + } + + /* Not all events get sent to the grabbing widget. + * The delete, destroy, expose, focus change and resize + * events still get sent to the event widget because + * 1) these events have no meaning for the grabbing widget + * and 2) redirecting these events to the grabbing widget + * could cause the display to be messed up. + */ + event_copy = current_event; + switch (event_copy.type) + { + case GDK_NOTHING: + break; + + case GDK_DELETE: + if (gtk_widget_event (event_widget, &event_copy)) + gtk_widget_destroy (event_widget); + break; + + case GDK_DESTROY: + gtk_widget_event (event_widget, &event_copy); + gtk_widget_destroy (event_widget); + break; + + case GDK_PROPERTY_NOTIFY: + /* To handle selection INCR transactions, we select + PropertyNotify events on the requestor window and create + a corresponding (fake) GdkWindow so that events get + here. There won't be a widget though, so we have to handle + them specially */ + + if (event_widget == NULL) + { + gtk_selection_incr_event (event_copy.any.window, + &event_copy.property); + break; + } + /* otherwise fall through */ + + case GDK_EXPOSE: + case GDK_FOCUS_CHANGE: + case GDK_CONFIGURE: + case GDK_MAP: + case GDK_UNMAP: + case GDK_SELECTION_CLEAR: + case GDK_SELECTION_REQUEST: + case GDK_SELECTION_NOTIFY: + case GDK_CLIENT_EVENT: + gtk_widget_event (event_widget, &event_copy); + break; + + case GDK_MOTION_NOTIFY: + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + case GDK_PROXIMITY_IN: + case GDK_PROXIMITY_OUT: + case GDK_OTHER_EVENT: + case GDK_DRAG_BEGIN: + case GDK_DRAG_REQUEST: + case GDK_DROP_ENTER: + case GDK_DROP_LEAVE: + case GDK_DROP_DATA_AVAIL: + gtk_propagate_event (grab_widget, &event_copy); + break; + + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + if (grab_widget && GTK_WIDGET_IS_SENSITIVE (grab_widget)) + gtk_widget_event (grab_widget, &event_copy); + break; + } + } + else + { + if (gdk_events_pending() == 0) + gtk_handle_idle (); + } + + /* Handle a timeout functions that may have expired. + */ + gtk_handle_timeouts (); + + return done; +} + +gint +gtk_true (void) +{ + return TRUE; +} + +gint +gtk_false (void) +{ + return FALSE; +} + +void +gtk_grab_add (GtkWidget *widget) +{ + /* Place the grab on the front of the list of grabs. + */ + grabs = g_list_prepend (grabs, widget); +} + +void +gtk_grab_remove (GtkWidget *widget) +{ + /* Remove the grab from the list of grabs. + * Note: the grab being removed may be in + * the middle of the list. + */ + grabs = g_list_remove (grabs, widget); +} + +void +gtk_init_add (GtkFunction function, + gpointer data) +{ + GtkInitFunction *init; + + init = g_new (GtkInitFunction, 1); + init->function = function; + init->data = data; + + init_functions = g_list_prepend (init_functions, init); +} + +static gint +gtk_timeout_add_internal (guint32 interval, + gint interp, + GtkFunction function, + gpointer data, + GtkDestroyNotify destroy) +{ + static gint timeout_tag = 1; + GtkTimeoutFunction *timeoutf; + + /* Create a new timeout function structure. + * The start time is the current time. + */ + if (!timeout_mem_chunk) + timeout_mem_chunk = g_mem_chunk_new ("timeout mem chunk", sizeof (GtkTimeoutFunction), + 1024, G_ALLOC_AND_FREE); + + timeoutf = g_chunk_new (GtkTimeoutFunction, timeout_mem_chunk); + + timeoutf->tag = timeout_tag++; + timeoutf->start = gdk_time_get (); + timeoutf->interval = interval; + timeoutf->originterval = interval; + timeoutf->interp = interp; + timeoutf->function = function; + timeoutf->data = data; + timeoutf->destroy = destroy; + + gtk_timeout_insert (timeoutf); + + return timeoutf->tag; +} + +static void +gtk_timeout_destroy (GtkTimeoutFunction *timeoutf) +{ + if (timeoutf->destroy) + (timeoutf->destroy) (timeoutf->data); + g_mem_chunk_free (timeout_mem_chunk, timeoutf); +} + +gint +gtk_timeout_add (guint32 interval, + GtkFunction function, + gpointer data) +{ + return gtk_timeout_add_internal (interval, FALSE, function, data, NULL); +} + +gint +gtk_timeout_add_interp (guint32 interval, + GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify destroy) +{ + return gtk_timeout_add_internal (interval, TRUE, + (GtkFunction) function, + data, destroy); +} + +void +gtk_timeout_remove (gint tag) +{ + GtkTimeoutFunction *timeoutf; + GList *tmp_list; + + /* Remove a timeout function. + * (Which, basically, involves searching the + * list for the tag). + */ + tmp_list = timeout_functions; + while (tmp_list) + { + timeoutf = tmp_list->data; + + if (timeoutf->tag == tag) + { + timeout_functions = g_list_remove_link (timeout_functions, tmp_list); + g_list_free (tmp_list); + gtk_timeout_destroy (timeoutf); + + return; + } + + tmp_list = tmp_list->next; + } + + tmp_list = current_timeouts; + while (tmp_list) + { + timeoutf = tmp_list->data; + + if (timeoutf->tag == tag) + { + current_timeouts = g_list_remove_link (current_timeouts, tmp_list); + g_list_free (tmp_list); + gtk_timeout_destroy (timeoutf); + + return; + } + + tmp_list = tmp_list->next; + } +} + +static gint +gtk_idle_add_internal (gint interp, + GtkFunction function, + gpointer data, + GtkDestroyNotify destroy) +{ + static gint idle_tag = 1; + GtkIdleFunction *idlef; + + if (!idle_mem_chunk) + idle_mem_chunk = g_mem_chunk_new ("idle mem chunk", sizeof (GtkIdleFunction), + 1024, G_ALLOC_AND_FREE); + + idlef = g_chunk_new (GtkIdleFunction, idle_mem_chunk); + + idlef->tag = idle_tag++; + idlef->interp = interp; + idlef->function = function; + idlef->data = data; + idlef->destroy = destroy; + + idle_functions = g_list_append (idle_functions, idlef); + + return idlef->tag; +} + +static void +gtk_idle_destroy (GtkIdleFunction *idlef) +{ + if (idlef->destroy) + idlef->destroy (idlef->data); + g_mem_chunk_free (idle_mem_chunk, idlef); +} + +gint +gtk_idle_add (GtkFunction function, + gpointer data) +{ + return gtk_idle_add_internal (FALSE, function, data, NULL); +} + +gint +gtk_idle_add_interp (GtkCallbackMarshal function, + gpointer data, + GtkDestroyNotify destroy) +{ + return gtk_idle_add_internal (TRUE, (GtkFunction)function, data, destroy); +} + +void +gtk_idle_remove (gint tag) +{ + GtkIdleFunction *idlef; + GList *tmp_list; + + tmp_list = idle_functions; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->tag == tag) + { + idle_functions = g_list_remove_link (idle_functions, tmp_list); + g_list_free (tmp_list); + gtk_idle_destroy (idlef); + + return; + } + + tmp_list = tmp_list->next; + } + + tmp_list = current_idles; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->tag == tag) + { + current_idles = g_list_remove_link (current_idles, tmp_list); + g_list_free (tmp_list); + gtk_idle_destroy (idlef); + + return; + } + + tmp_list = tmp_list->next; + } +} + +void +gtk_idle_remove_by_data (gpointer data) +{ + GtkIdleFunction *idlef; + GList *tmp_list; + + tmp_list = idle_functions; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->data == data) + { + idle_functions = g_list_remove_link (idle_functions, tmp_list); + g_list_free (tmp_list); + g_mem_chunk_free (idle_mem_chunk, idlef); + + return; + } + + tmp_list = tmp_list->next; + } + + tmp_list = current_idles; + while (tmp_list) + { + idlef = tmp_list->data; + + if (idlef->data == data) + { + current_idles = g_list_remove_link (current_idles, tmp_list); + g_list_free (tmp_list); + g_mem_chunk_free (idle_mem_chunk, idlef); + + return; + } + + tmp_list = tmp_list->next; + } +} + +void +gtk_get_current_event (GdkEvent *event) +{ + g_assert (event != NULL); + + *event = current_event; +} + +GtkWidget* +gtk_get_event_widget (GdkEvent *event) +{ + GtkWidget *widget; + gdk_window_get_user_data (event->any.window, (void**) &widget); + + return widget; +} + +static void +gtk_exit_func () +{ + if (initialized) + { + initialized = FALSE; + gtk_preview_uninit (); + } +} + +static void +gtk_timeout_insert (GtkTimeoutFunction *timeoutf) +{ + GtkTimeoutFunction *temp; + GList *temp_list; + GList *new_list; + + g_assert (timeoutf != NULL); + + /* Insert the timeout function appropriately. + * Appropriately meaning sort it into the list + * of timeout functions. + */ + temp_list = timeout_functions; + while (temp_list) + { + temp = temp_list->data; + if (timeoutf->interval < temp->interval) + { + new_list = g_list_alloc (); + new_list->data = timeoutf; + new_list->next = temp_list; + new_list->prev = temp_list->prev; + if (temp_list->prev) + temp_list->prev->next = new_list; + temp_list->prev = new_list; + + if (temp_list == timeout_functions) + timeout_functions = new_list; + + return; + } + + temp_list = temp_list->next; + } + + timeout_functions = g_list_append (timeout_functions, timeoutf); +} + +static gint +gtk_invoke_timeout_function (GtkTimeoutFunction *timeoutf) +{ + if (!timeoutf->interp) + return timeoutf->function (timeoutf->data); + else + { + GtkArg args[1]; + gint ret_val = FALSE; + args[0].name = NULL; + args[0].type = GTK_TYPE_BOOL; + args[0].d.pointer_data = &ret_val; + ((GtkCallbackMarshal)timeoutf->function) (NULL, + timeoutf->data, + 0, args); + return ret_val; + } +} + +static void +gtk_handle_current_timeouts (guint32 the_time) +{ + GList *tmp_list; + GtkTimeoutFunction *timeoutf; + + while (current_timeouts) + { + tmp_list = current_timeouts; + timeoutf = tmp_list->data; + + current_timeouts = g_list_remove_link (current_timeouts, tmp_list); + g_list_free (tmp_list); + + if (gtk_invoke_timeout_function (timeoutf) == FALSE) + { + gtk_timeout_destroy (timeoutf); + } + else + { + timeoutf->interval = timeoutf->originterval; + timeoutf->start = the_time; + gtk_timeout_insert (timeoutf); + } + } +} + +/* Utility function - make up for an ommision in glib */ +static GList * +gtk_main_list_concat (GList *list1, GList *list2) +{ + GList *tmp_list; + GList *list; + + if (list2) + { + tmp_list = g_list_last (list1); + if (tmp_list) + tmp_list->next = list2; + else + list1 = list2; + list2->prev = tmp_list; + } + + return list1; +} + +static void +gtk_handle_timeouts () +{ + guint32 the_time; + GList *tmp_list; + GList *tmp_list2; + GList *tmp_list3; + GtkTimeoutFunction *timeoutf; + + /* Caller must already have called gtk_handle_current_timeouts if + * necessary */ + g_assert (current_timeouts == NULL); + + if (timeout_functions) + { + the_time = gdk_time_get (); + + tmp_list = timeout_functions; + while (tmp_list) + { + timeoutf = tmp_list->data; + + if (timeoutf->interval <= (the_time - timeoutf->start)) + { + tmp_list2 = tmp_list; + tmp_list = tmp_list->next; + + timeout_functions = g_list_remove_link (timeout_functions, tmp_list2); + current_timeouts = gtk_main_list_concat (current_timeouts, tmp_list2); + } + else + { + timeoutf->interval -= (the_time - timeoutf->start); + timeoutf->start = the_time; + tmp_list = tmp_list->next; + } + } + + if (current_timeouts) + gtk_handle_current_timeouts(the_time); + } +} + +static gint +gtk_idle_invoke_function (GtkIdleFunction *idlef) +{ + if (!idlef->interp) + return idlef->function (idlef->data); + else + { + GtkArg args[1]; + gint ret_val = FALSE; + args[0].name = NULL; + args[0].type = GTK_TYPE_BOOL; + args[0].d.pointer_data = &ret_val; + ((GtkCallbackMarshal)idlef->function) (NULL, + idlef->data, + 0, args); + return ret_val; + } +} + +static void +gtk_handle_current_idles () +{ + GList *tmp_list; + GtkIdleFunction *idlef; + + while (current_idles) + { + tmp_list = current_idles; + idlef = tmp_list->data; + + current_idles = g_list_remove_link (current_idles, tmp_list); + + if (gtk_idle_invoke_function (idlef) == FALSE) + { + g_list_free (tmp_list); + gtk_idle_destroy (idlef); + } + else + { + idle_functions = gtk_main_list_concat (idle_functions, tmp_list); + } + } +} + +static void +gtk_handle_idle () +{ + GtkIdleFunction *idlef; + GList *tmp_list; + GList *tmp_list2; + + /* Caller must already have called gtk_handle_current_idles if + necessary */ + g_assert (current_idles == NULL); + + if (idle_functions) + { + current_idles = idle_functions; + idle_functions = NULL; + + gtk_handle_current_idles(); + } +} + +static void +gtk_handle_timer () +{ + GtkTimeoutFunction *timeoutf; + + if (idle_functions) + { + gdk_timer_set (0); + gdk_timer_enable (); + } + else if (timeout_functions) + { + timeoutf = timeout_functions->data; + gdk_timer_set (timeoutf->interval); + gdk_timer_enable (); + } + else + { + gdk_timer_set (0); + gdk_timer_disable (); + } +} + +static void +gtk_propagate_event (GtkWidget *widget, + GdkEvent *event) +{ + GtkWidget *parent; + gint handled_event; + gint parent_old_value; + gint old_value; + + g_return_if_fail (widget != NULL); + g_return_if_fail (event != NULL); + + handled_event = FALSE; + + if ((event->type == GDK_KEY_PRESS) || + (event->type == GDK_KEY_RELEASE)) + { + /* Only send key events to window widgets. + * The window widget will in turn pass the + * key event on to the currently focused widget + * for that window. + */ + parent = gtk_widget_get_ancestor (widget, gtk_window_get_type ()); + if (parent && GTK_WIDGET_IS_SENSITIVE (parent)) + { + parent_old_value = GTK_OBJECT_IN_CALL (parent); + GTK_OBJECT_SET_FLAGS (parent, GTK_IN_CALL); + + handled_event = gtk_widget_event (parent, event); + + if (!parent_old_value) + GTK_OBJECT_UNSET_FLAGS (parent, GTK_IN_CALL); + + if (GTK_OBJECT_NEED_DESTROY (parent) && !GTK_OBJECT_IN_CALL (parent)) + { + gtk_object_destroy (GTK_OBJECT (parent)); + return; + } + } + } + + if (!handled_event) + { + old_value = GTK_OBJECT_IN_CALL (widget); + GTK_OBJECT_SET_FLAGS (widget, GTK_IN_CALL); + + /* Other events get propagated up the widget tree + * so that parents can see the button and motion + * events of the children. + */ + parent = widget; + while (parent) + { + parent_old_value = GTK_OBJECT_IN_CALL (parent); + GTK_OBJECT_SET_FLAGS (parent, GTK_IN_CALL); + + handled_event = (!GTK_WIDGET_IS_SENSITIVE (parent) || + gtk_widget_event (parent, event)); + + if (!parent_old_value) + GTK_OBJECT_UNSET_FLAGS (parent, GTK_IN_CALL); + + if (handled_event) + break; + + if (GTK_OBJECT_NEED_DESTROY (parent) && !GTK_OBJECT_IN_CALL (parent)) + { + gtk_object_destroy (GTK_OBJECT (parent)); + break; + } + + parent = parent->parent; + } + + if (!old_value) + GTK_OBJECT_UNSET_FLAGS (widget, GTK_IN_CALL); + + if (GTK_OBJECT_NEED_DESTROY (widget) && !GTK_OBJECT_IN_CALL (widget)) + gtk_object_destroy (GTK_OBJECT (widget)); + } +} + + +static void +gtk_error (char *str) +{ + gtk_print (str); +} + +static void +gtk_warning (char *str) +{ + gtk_print (str); +} + +static void +gtk_message (char *str) +{ + gtk_print (str); +} + +static void +gtk_print (char *str) +{ + static GtkWidget *window = NULL; + static GtkWidget *text; + static int level = 0; + GtkWidget *box1; + GtkWidget *box2; + GtkWidget *table; + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + GtkWidget *separator; + GtkWidget *button; + + if (level > 0) + { + fputs (str, stdout); + fflush (stdout); + return; + } + + if (!window) + { + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + /* + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) gtk_widget_destroyed, + &window); + */ + gtk_window_set_title (GTK_WINDOW (window), "Messages"); + + box1 = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), box1); + gtk_widget_show (box1); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0); + gtk_widget_show (box2); + + + table = gtk_table_new (2, 2, FALSE); + gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2); + gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2); + gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0); + gtk_widget_show (table); + + text = gtk_text_new (NULL, NULL); + gtk_text_set_editable (GTK_TEXT (text), FALSE); + gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1); + gtk_widget_show (text); + gtk_widget_realize (text); + + hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj); + gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (hscrollbar); + + vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj); + gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (vscrollbar); + + separator = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0); + gtk_widget_show (separator); + + + box2 = gtk_vbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (box2), 10); + gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0); + gtk_widget_show (box2); + + + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_hide, + GTK_OBJECT (window)); + gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_grab_default (button); + gtk_widget_show (button); + } + + level += 1; + gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1); + level -= 1; + + if (!GTK_WIDGET_VISIBLE (window)) + gtk_widget_show (window); +} diff --git a/gtk/gtkmain.h b/gtk/gtkmain.h new file mode 100644 index 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), + >K_WIDGET (container)->requisition); + + allocation.x = GTK_WIDGET (container)->allocation.x; + allocation.y = GTK_WIDGET (container)->allocation.y; + allocation.width = GTK_WIDGET (container)->requisition.width; + allocation.height = GTK_WIDGET (container)->requisition.height; + + gtk_widget_size_allocate (GTK_WIDGET (container), &allocation); + } + else + { + GTK_MENU_SHELL (container)->menu_flag = TRUE; + } + + return FALSE; +} + +static void +gtk_menu_deactivate (GtkMenuShell *menu_shell) +{ + GtkMenuShell *parent; + + g_return_if_fail (menu_shell != NULL); + g_return_if_fail (GTK_IS_MENU (menu_shell)); + + parent = GTK_MENU_SHELL (menu_shell->parent_menu_shell); + + menu_shell->activate_time = 0; + gtk_menu_popdown (GTK_MENU (menu_shell)); + + if (parent) + gtk_menu_shell_deactivate (parent); +} diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h new file mode 100644 index 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 (), ¬ebook_info); + } + + return notebook_type; +} + +static void +gtk_notebook_class_init (GtkNotebookClass *class) +{ + GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + container_class = (GtkContainerClass*) class; + + parent_class = gtk_type_class (gtk_container_get_type ()); + + object_class->destroy = gtk_notebook_destroy; + + widget_class->map = gtk_notebook_map; + widget_class->unmap = gtk_notebook_unmap; + widget_class->realize = gtk_notebook_realize; + widget_class->unrealize = gtk_notebook_unrealize; + widget_class->size_request = gtk_notebook_size_request; + widget_class->size_allocate = gtk_notebook_size_allocate; + widget_class->draw = gtk_notebook_draw; + widget_class->expose_event = gtk_notebook_expose; + widget_class->button_press_event = gtk_notebook_button_press; + + container_class->add = gtk_notebook_add; + container_class->remove = gtk_notebook_remove; + container_class->foreach = gtk_notebook_foreach; +} + +static void +gtk_notebook_init (GtkNotebook *notebook) +{ + notebook->cur_page = NULL; + notebook->children = NULL; + notebook->show_tabs = TRUE; + notebook->show_border = TRUE; + notebook->tab_pos = GTK_POS_TOP; +} + +GtkWidget* +gtk_notebook_new () +{ + return GTK_WIDGET (gtk_type_new (gtk_notebook_get_type ())); +} + +void +gtk_notebook_append_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (child != NULL); + g_return_if_fail (tab_label != NULL); + + gtk_notebook_insert_page (notebook, child, tab_label, -1); +} + +void +gtk_notebook_prepend_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (child != NULL); + g_return_if_fail (tab_label != NULL); + + gtk_notebook_insert_page (notebook, child, tab_label, 0); +} + +void +gtk_notebook_insert_page (GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label, + gint position) +{ + GtkNotebookPage *page; + gint nchildren; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (child != NULL); + g_return_if_fail (tab_label != NULL); + + page = g_new (GtkNotebookPage, 1); + page->child = child; + page->tab_label = tab_label; + page->requisition.width = 0; + page->requisition.height = 0; + page->allocation.x = 0; + page->allocation.y = 0; + page->allocation.width = 0; + page->allocation.height = 0; + + nchildren = g_list_length (notebook->children); + if ((position < 0) || (position > nchildren)) + position = nchildren; + + notebook->children = g_list_insert (notebook->children, page, position); + + if (!notebook->cur_page) + notebook->cur_page = page; + + gtk_widget_show (tab_label); + gtk_widget_set_parent (child, GTK_WIDGET (notebook)); + gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook)); + + if (GTK_WIDGET_VISIBLE (notebook)) + { + if (GTK_WIDGET_REALIZED (notebook) && + !GTK_WIDGET_REALIZED (child)) + gtk_widget_realize (child); + + if (GTK_WIDGET_MAPPED (notebook) && + !GTK_WIDGET_MAPPED (child) && notebook->cur_page == page) + gtk_widget_map (child); + + if (GTK_WIDGET_REALIZED (notebook) && + !GTK_WIDGET_REALIZED (tab_label)) + gtk_widget_realize (tab_label); + + if (GTK_WIDGET_MAPPED (notebook) && + !GTK_WIDGET_MAPPED (tab_label)) + gtk_widget_map (tab_label); + } + + if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (child); +} + +void +gtk_notebook_remove_page (GtkNotebook *notebook, + gint page_num) +{ + GtkNotebookPage *page; + GList *tmp_list; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + tmp_list = g_list_nth (notebook->children, page_num); + if (tmp_list) + { + page = tmp_list->data; + + if (notebook->cur_page == page) + gtk_notebook_prev_page (notebook); + if (notebook->cur_page == page) + notebook->cur_page = NULL; + + notebook->children = g_list_remove_link (notebook->children, tmp_list); + g_list_free (tmp_list); + g_free (page); + } +} + +gint +gtk_notebook_current_page (GtkNotebook *notebook) +{ + GList *children; + gint cur_page; + + g_return_val_if_fail (notebook != NULL, -1); + g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1); + + if (notebook->cur_page) + { + cur_page = 0; + children = notebook->children; + + while (children) + { + if (children->data == notebook->cur_page) + break; + children = children->next; + cur_page += 1; + } + + if (!children) + cur_page = -1; + } + else + { + cur_page = -1; + } + + return cur_page; +} + +void +gtk_notebook_set_page (GtkNotebook *notebook, + gint page_num) +{ + GtkNotebookPage *page; + GList *tmp_list; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + tmp_list = g_list_nth (notebook->children, page_num); + if (tmp_list) + { + page = tmp_list->data; + gtk_notebook_switch_page (notebook, page); + } +} + +void +gtk_notebook_next_page (GtkNotebook *notebook) +{ + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + children = notebook->children; + while (children) + { + page = children->data; + + if (notebook->cur_page == page) + { + children = children->next; + if (!children) + children = notebook->children; + page = children->data; + + gtk_notebook_switch_page (notebook, page); + } + + children = children->next; + } +} + +void +gtk_notebook_prev_page (GtkNotebook *notebook) +{ + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + children = notebook->children; + while (children) + { + page = children->data; + + if (notebook->cur_page == page) + { + children = children->prev; + if (!children) + children = g_list_last (notebook->children); + page = children->data; + + gtk_notebook_switch_page (notebook, page); + } + + children = children->next; + } +} + +void +gtk_notebook_set_tab_pos (GtkNotebook *notebook, + GtkPositionType pos) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + if (notebook->tab_pos != pos) + { + notebook->tab_pos = pos; + + if (GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (GTK_WIDGET (notebook)); + } +} + +void +gtk_notebook_set_show_tabs (GtkNotebook *notebook, + gint show_tabs) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + if (notebook->show_tabs != show_tabs) + { + notebook->show_tabs = show_tabs; + + if (GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (GTK_WIDGET (notebook)); + } +} + +void +gtk_notebook_set_show_border (GtkNotebook *notebook, + gint show_border) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + + if (notebook->show_border != show_border) + { + notebook->show_border = show_border; + + if (GTK_WIDGET_VISIBLE (notebook)) + gtk_widget_queue_resize (GTK_WIDGET (notebook)); + } +} + +static void +gtk_notebook_destroy (GtkObject *object) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (object)); + + notebook = GTK_NOTEBOOK (object); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + page->child->parent = NULL; + page->tab_label->parent = NULL; + + gtk_object_unref (GTK_OBJECT (page->child)); + gtk_object_unref (GTK_OBJECT (page->tab_label)); + + gtk_widget_destroy (page->child); + gtk_widget_destroy (page->tab_label); + + g_free (page); + } + + g_list_free (notebook->children); + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + +static void +gtk_notebook_map (GtkWidget *widget) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + gdk_window_show (widget->window); + + notebook = GTK_NOTEBOOK (widget); + + if (notebook->cur_page && + GTK_WIDGET_VISIBLE (notebook->cur_page->child) && + !GTK_WIDGET_MAPPED (notebook->cur_page->child)) + gtk_widget_map (notebook->cur_page->child); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child) && + !GTK_WIDGET_MAPPED (page->tab_label)) + gtk_widget_map (page->tab_label); + } +} + +static void +gtk_notebook_unmap (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + gdk_window_hide (widget->window); +} + +static void +gtk_notebook_realize (GtkWidget *widget) +{ + GtkNotebook *notebook; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + notebook = GTK_NOTEBOOK (widget); + GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, notebook); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +gtk_notebook_unrealize (GtkWidget *widget) +{ + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + gdk_window_destroy (widget->window); + widget->window = NULL; +} + +static void +gtk_notebook_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + gint tab_width; + gint tab_height; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (requisition != NULL); + + notebook = GTK_NOTEBOOK (widget); + widget->requisition.width = 0; + widget->requisition.height = 0; + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + gtk_widget_size_request (page->child, &page->child->requisition); + + widget->requisition.width = MAX (widget->requisition.width, + page->child->requisition.width); + widget->requisition.height = MAX (widget->requisition.height, + page->child->requisition.height); + } + } + + widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2; + widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2; + + if (notebook->show_tabs) + { + widget->requisition.width += GTK_WIDGET (widget)->style->klass->xthickness * 2; + widget->requisition.height += GTK_WIDGET (widget)->style->klass->ythickness * 2; + + tab_width = 0; + tab_height = 0; + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + gtk_widget_size_request (page->tab_label, &page->tab_label->requisition); + + page->requisition.width = (page->tab_label->requisition.width + + (GTK_WIDGET (widget)->style->klass->xthickness + + CHILD_SPACING) * 2); + page->requisition.height = (page->tab_label->requisition.height + + (GTK_WIDGET (widget)->style->klass->ythickness + + CHILD_SPACING) * 2); + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + page->requisition.width -= TAB_OVERLAP; + page->requisition.height -= GTK_WIDGET (widget)->style->klass->ythickness; + + tab_width += page->requisition.width; + tab_height = MAX (tab_height, page->requisition.height); + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + page->requisition.width -= GTK_WIDGET (widget)->style->klass->xthickness; + page->requisition.height -= TAB_OVERLAP; + + tab_width = MAX (tab_width, page->requisition.width); + tab_height += page->requisition.height; + break; + } + } + } + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + if ((notebook->tab_pos == GTK_POS_TOP) || + (notebook->tab_pos == GTK_POS_BOTTOM)) + page->requisition.height = tab_height; + else + page->requisition.width = tab_width; + } + } + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + tab_width += GTK_WIDGET (widget)->style->klass->xthickness; + widget->requisition.width = MAX (widget->requisition.width, tab_width); + widget->requisition.height += tab_height; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + tab_height += GTK_WIDGET (widget)->style->klass->ythickness; + widget->requisition.width += tab_width; + widget->requisition.height = MAX (widget->requisition.height, tab_height); + break; + } + } + else if (notebook->show_border) + { + widget->requisition.width += GTK_WIDGET (widget)->style->klass->xthickness * 2; + widget->requisition.height += GTK_WIDGET (widget)->style->klass->ythickness * 2; + } +} + +static void +gtk_notebook_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GtkAllocation child_allocation; + GList *children; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + if (GTK_WIDGET_REALIZED (widget)) + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + notebook = GTK_NOTEBOOK (widget); + if (notebook->children) + { + child_allocation.x = GTK_CONTAINER (widget)->border_width; + child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.width = allocation->width - child_allocation.x * 2; + child_allocation.height = allocation->height - child_allocation.y * 2; + + if (notebook->show_tabs || notebook->show_border) + { + child_allocation.x += GTK_WIDGET (widget)->style->klass->xthickness; + child_allocation.y += GTK_WIDGET (widget)->style->klass->ythickness; + child_allocation.width -= GTK_WIDGET (widget)->style->klass->xthickness * 2; + child_allocation.height -= GTK_WIDGET (widget)->style->klass->ythickness * 2; + + if (notebook->show_tabs && notebook->children) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + child_allocation.y += notebook->cur_page->requisition.height; + case GTK_POS_BOTTOM: + child_allocation.height -= notebook->cur_page->requisition.height; + break; + case GTK_POS_LEFT: + child_allocation.x += notebook->cur_page->requisition.width; + case GTK_POS_RIGHT: + child_allocation.width -= notebook->cur_page->requisition.width; + break; + } + } + } + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + gtk_widget_size_allocate (page->child, &child_allocation); + } + + if (notebook->show_tabs && notebook->children) + gtk_notebook_pages_allocate (notebook, allocation); + } +} + +static void +gtk_notebook_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + GdkPoint points[6]; + gint width, height; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + notebook = GTK_NOTEBOOK (widget); + + gdk_window_clear_area (widget->window, + area->x, area->y, + area->width, area->height); + + if (notebook->show_tabs || notebook->show_border) + { + x = GTK_CONTAINER (widget)->border_width; + y = GTK_CONTAINER (widget)->border_width; + width = widget->allocation.width - x * 2; + height = widget->allocation.height - y * 2; + + if (notebook->show_tabs && notebook->children) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + y += notebook->cur_page->allocation.height; + case GTK_POS_BOTTOM: + height -= notebook->cur_page->allocation.height; + break; + case GTK_POS_LEFT: + x += notebook->cur_page->allocation.width; + case GTK_POS_RIGHT: + width -= notebook->cur_page->allocation.width; + break; + } + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + points[0].x = notebook->cur_page->allocation.x; + points[0].y = y; + points[1].x = x; + points[1].y = y; + points[2].x = x; + points[2].y = y + height - 1; + points[3].x = x + width - 1; + points[3].y = y + height - 1; + points[4].x = x + width - 1; + points[4].y = y; + points[5].x = (notebook->cur_page->allocation.x + + notebook->cur_page->allocation.width - + GTK_WIDGET (notebook)->style->klass->xthickness); + points[5].y = y; + + if (points[5].x == (x + width)) + points[5].x -= 1; + break; + case GTK_POS_BOTTOM: + points[0].x = (notebook->cur_page->allocation.x + + notebook->cur_page->allocation.width - + GTK_WIDGET (notebook)->style->klass->xthickness); + points[0].y = y + height - 1; + points[1].x = x + width - 1; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y; + points[3].x = x; + points[3].y = y; + points[4].x = x; + points[4].y = y + height - 1; + points[5].x = notebook->cur_page->allocation.x; + points[5].y = y + height - 1; + + if (points[0].x == (x + width)) + points[0].x -= 1; + break; + case GTK_POS_LEFT: + points[0].x = x; + points[0].y = (notebook->cur_page->allocation.y + + notebook->cur_page->allocation.height - + GTK_WIDGET (notebook)->style->klass->ythickness); + points[1].x = x; + points[1].y = y + height - 1; + points[2].x = x + width - 1; + points[2].y = y + height - 1; + points[3].x = x + width - 1; + points[3].y = y; + points[4].x = x; + points[4].y = y; + points[5].x = x; + points[5].y = notebook->cur_page->allocation.y; + + if (points[0].y == (y + height)) + points[0].y -= 1; + break; + case GTK_POS_RIGHT: + points[0].x = x + width - 1; + points[0].y = notebook->cur_page->allocation.y; + points[1].x = x + width - 1; + points[1].y = y; + points[2].x = x; + points[2].y = y; + points[3].x = x; + points[3].y = y + height - 1; + points[4].x = x + width - 1; + points[4].y = y + height - 1; + points[5].x = x + width - 1; + points[5].y = (notebook->cur_page->allocation.y + + notebook->cur_page->allocation.height - + GTK_WIDGET (notebook)->style->klass->ythickness); + + if (points[5].y == (y + height)) + points[5].y -= 1; + break; + } + + gtk_draw_polygon (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + points, 6, FALSE); + + children = g_list_last (notebook->children); + while (children) + { + page = children->data; + children = children->prev; + + if (notebook->cur_page != page) + gtk_notebook_draw_tab (notebook, page, area); + } + + if (notebook->cur_page) + gtk_notebook_draw_tab (notebook, notebook->cur_page, area); + } + else if (notebook->show_border) + { + gtk_draw_shadow (widget->style, widget->window, + GTK_STATE_NORMAL, GTK_SHADOW_OUT, + x, y, width, height); + } + } + } +} + +static void +gtk_notebook_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkNotebook *notebook; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + notebook = GTK_NOTEBOOK (widget); + + gtk_notebook_paint (widget, area); + + if (notebook->cur_page && + gtk_widget_intersect (notebook->cur_page->child, area, &child_area)) + gtk_widget_draw (notebook->cur_page->child, &child_area); + } +} + +static gint +gtk_notebook_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkNotebook *notebook; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + notebook = GTK_NOTEBOOK (widget); + + gtk_notebook_paint (widget, &event->area); + + child_event = *event; + if (notebook->cur_page && GTK_WIDGET_NO_WINDOW (notebook->cur_page->child) && + gtk_widget_intersect (notebook->cur_page->child, &event->area, &child_event.area)) + gtk_widget_event (notebook->cur_page->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static gint +gtk_notebook_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if ((event->type != GDK_BUTTON_PRESS) || + (event->window != widget->window)) + return FALSE; + + notebook = GTK_NOTEBOOK (widget); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child) && + (event->x >= page->allocation.x) && + (event->y >= page->allocation.y) && + (event->x <= (page->allocation.x + page->allocation.width)) && + (event->y <= (page->allocation.y + page->allocation.height))) + { + gtk_notebook_switch_page (notebook, page); + break; + } + } + + return FALSE; +} + +static void +gtk_notebook_add (GtkContainer *container, + GtkWidget *widget) +{ + g_warning ("gtk_notebook_add: use gtk_notebook_{append,prepend}_page instead\n"); +} + +static void +gtk_notebook_remove (GtkContainer *container, + GtkWidget *widget) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (container)); + g_return_if_fail (widget != NULL); + + notebook = GTK_NOTEBOOK (container); + + children = notebook->children; + while (children) + { + page = children->data; + + if (page->child == widget) + { + gtk_widget_unparent (page->child); + gtk_widget_unparent (page->tab_label); + + notebook->children = g_list_remove_link (notebook->children, children); + g_list_free (children); + g_free (page); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container)) + gtk_widget_queue_resize (GTK_WIDGET (container)); + + break; + } + + children = children->next; + } +} + +static void +gtk_notebook_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) +{ + GtkNotebook *notebook; + GtkNotebookPage *page; + GList *children; + + g_return_if_fail (container != NULL); + g_return_if_fail (GTK_IS_NOTEBOOK (container)); + g_return_if_fail (callback != NULL); + + notebook = GTK_NOTEBOOK (container); + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + (* callback) (page->child, callback_data); + } +} + +static void +gtk_notebook_switch_page (GtkNotebook *notebook, + GtkNotebookPage *page) +{ + g_return_if_fail (notebook != NULL); + g_return_if_fail (page != NULL); + + if (notebook->cur_page != page) + { + if (notebook->cur_page && GTK_WIDGET_MAPPED (notebook->cur_page->child)) + gtk_widget_unmap (notebook->cur_page->child); + + notebook->cur_page = page; + gtk_notebook_pages_allocate (notebook, >K_WIDGET (notebook)->allocation); + + if (GTK_WIDGET_MAPPED (notebook)) + gtk_widget_map (notebook->cur_page->child); + + if (GTK_WIDGET_DRAWABLE (notebook)) + gtk_widget_queue_draw (GTK_WIDGET (notebook)); + } +} + +static void +gtk_notebook_draw_tab (GtkNotebook *notebook, + GtkNotebookPage *page, + GdkRectangle *area) +{ + GdkRectangle child_area; + GdkRectangle page_area; + GtkStateType state_type; + GdkPoint points[6]; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (page != NULL); + g_return_if_fail (area != NULL); + + page_area.x = page->allocation.x; + page_area.y = page->allocation.y; + page_area.width = page->allocation.width; + page_area.height = page->allocation.height; + + if (gdk_rectangle_intersect (&page_area, area, &child_area)) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + points[0].x = page->allocation.x + page->allocation.width - 1; + points[0].y = page->allocation.y + page->allocation.height - 1; + + points[1].x = page->allocation.x + page->allocation.width - 1; + points[1].y = page->allocation.y + TAB_CURVATURE; + + points[2].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[2].y = page->allocation.y; + + points[3].x = page->allocation.x + TAB_CURVATURE; + points[3].y = page->allocation.y; + + points[4].x = page->allocation.x; + points[4].y = page->allocation.y + TAB_CURVATURE; + + points[5].x = page->allocation.x; + points[5].y = page->allocation.y + page->allocation.height - 1; + break; + case GTK_POS_BOTTOM: + points[0].x = page->allocation.x; + points[0].y = page->allocation.y; + + points[1].x = page->allocation.x; + points[1].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[2].x = page->allocation.x + TAB_CURVATURE; + points[2].y = page->allocation.y + page->allocation.height - 1; + + points[3].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[3].y = page->allocation.y + page->allocation.height - 1; + + points[4].x = page->allocation.x + page->allocation.width - 1; + points[4].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[5].x = page->allocation.x + page->allocation.width - 1; + points[5].y = page->allocation.y; + break; + case GTK_POS_LEFT: + points[0].x = page->allocation.x + page->allocation.width - 1; + points[0].y = page->allocation.y; + + points[1].x = page->allocation.x + TAB_CURVATURE; + points[1].y = page->allocation.y; + + points[2].x = page->allocation.x; + points[2].y = page->allocation.y + TAB_CURVATURE; + + points[3].x = page->allocation.x; + points[3].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[4].x = page->allocation.x + TAB_CURVATURE; + points[4].y = page->allocation.y + page->allocation.height - 1; + + points[5].x = page->allocation.x + page->allocation.width - 1; + points[5].y = page->allocation.y + page->allocation.height - 1; + break; + case GTK_POS_RIGHT: + points[0].x = page->allocation.x; + points[0].y = page->allocation.y + page->allocation.height - 1; + + points[1].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[1].y = page->allocation.y + page->allocation.height - 1; + + points[2].x = page->allocation.x + page->allocation.width - 1; + points[2].y = page->allocation.y + page->allocation.height - TAB_CURVATURE - 1; + + points[3].x = page->allocation.x + page->allocation.width - 1; + points[3].y = page->allocation.y + TAB_CURVATURE; + + points[4].x = page->allocation.x + page->allocation.width - TAB_CURVATURE - 1; + points[4].y = page->allocation.y; + + points[5].x = page->allocation.x; + points[5].y = page->allocation.y; + break; + } + + if (notebook->cur_page == page) + state_type = GTK_STATE_NORMAL; + else + state_type = GTK_STATE_ACTIVE; + + gtk_draw_polygon (GTK_WIDGET (notebook)->style, + GTK_WIDGET (notebook)->window, + state_type, GTK_SHADOW_OUT, + points, 6, (notebook->cur_page != page)); + + if (gtk_widget_intersect (page->tab_label, area, &child_area)) + gtk_widget_draw (page->tab_label, &child_area); + } +} + +static void +gtk_notebook_pages_allocate (GtkNotebook *notebook, + GtkAllocation *allocation) +{ + GtkNotebookPage *page; + GtkAllocation child_allocation; + GList *children; + + if (notebook->show_tabs && notebook->children) + { + child_allocation.x = GTK_CONTAINER (notebook)->border_width; + child_allocation.y = GTK_CONTAINER (notebook)->border_width; + + switch (notebook->tab_pos) + { + case GTK_POS_BOTTOM: + child_allocation.y = allocation->height - notebook->cur_page->requisition.height; + case GTK_POS_TOP: + child_allocation.height = notebook->cur_page->requisition.height; + break; + case GTK_POS_RIGHT: + child_allocation.x = allocation->width - notebook->cur_page->requisition.width; + case GTK_POS_LEFT: + child_allocation.width = notebook->cur_page->requisition.width; + break; + } + + children = notebook->children; + while (children) + { + page = children->data; + children = children->next; + + if (GTK_WIDGET_VISIBLE (page->child)) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + child_allocation.width = page->requisition.width + TAB_OVERLAP; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + child_allocation.height = page->requisition.height + TAB_OVERLAP; + break; + } + + gtk_notebook_page_allocate (notebook, page, &child_allocation); + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + child_allocation.x += child_allocation.width - TAB_OVERLAP; + break; + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + child_allocation.y += child_allocation.height - TAB_OVERLAP; + break; + } + } + } + } +} + +static void +gtk_notebook_page_allocate (GtkNotebook *notebook, + GtkNotebookPage *page, + GtkAllocation *allocation) +{ + GtkAllocation child_allocation; + gint xthickness, ythickness; + + g_return_if_fail (notebook != NULL); + g_return_if_fail (page != NULL); + g_return_if_fail (allocation != NULL); + + page->allocation = *allocation; + + xthickness = GTK_WIDGET (notebook)->style->klass->xthickness; + ythickness = GTK_WIDGET (notebook)->style->klass->ythickness; + + if (notebook->cur_page != page) + { + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + page->allocation.y += ythickness; + case GTK_POS_BOTTOM: + page->allocation.height -= ythickness; + break; + case GTK_POS_LEFT: + page->allocation.x += xthickness; + case GTK_POS_RIGHT: + page->allocation.width -= xthickness; + break; + } + } + + switch (notebook->tab_pos) + { + case GTK_POS_TOP: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x * 2; + child_allocation.height = page->allocation.height - child_allocation.y; + child_allocation.x += page->allocation.x; + child_allocation.y += page->allocation.y; + break; + case GTK_POS_BOTTOM: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x * 2; + child_allocation.height = page->allocation.height - child_allocation.y; + child_allocation.x += page->allocation.x; + child_allocation.y = page->allocation.y; + break; + case GTK_POS_LEFT: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x; + child_allocation.height = page->allocation.height - child_allocation.y * 2; + child_allocation.x += page->allocation.x; + child_allocation.y += page->allocation.y; + break; + case GTK_POS_RIGHT: + child_allocation.x = xthickness + CHILD_SPACING; + child_allocation.y = ythickness + CHILD_SPACING; + child_allocation.width = page->allocation.width - child_allocation.x; + child_allocation.height = page->allocation.height - child_allocation.y * 2; + child_allocation.x = page->allocation.x; + child_allocation.y += page->allocation.y; + break; + } + + gtk_widget_size_allocate (page->tab_label, &child_allocation); +} diff --git a/gtk/gtknotebook.h b/gtk/gtknotebook.h new file mode 100644 index 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 (¤t_emissions, object, signal_type); + + restart: + if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_LAST) + { + signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset); + if (*signal_func_offset) + (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset, NULL, params); + if (GTK_OBJECT_NEED_DESTROY (object)) + goto done; + } + + info.object = object; + info.marshaller = signal->marshaller; + info.params = params; + info.param_types = signal->params; + info.return_val = signal->return_val; + info.nparams = signal->nparams; + info.run_type = signal->run_type; + info.signal_type = signal_type; + + handlers = gtk_signal_get_handlers (object, signal_type); + switch (gtk_handlers_run (handlers, &info, FALSE)) + { + case DONE: + goto done; + case RESTART: + goto restart; + } + + if (GTK_RUN_TYPE (signal->run_type) != GTK_RUN_FIRST) + { + signal_func_offset = (guchar**) ((guchar*) object->klass + signal->function_offset); + if (*signal_func_offset) + (* signal->marshaller) (object, (GtkSignalFunc) *signal_func_offset, NULL, params); + if (being_destroyed || GTK_OBJECT_NEED_DESTROY (object)) + goto done; + } + + switch (gtk_handlers_run (handlers, &info, TRUE)) + { + case DONE: + goto done; + case RESTART: + goto restart; + } + + done: + gtk_emission_remove (¤t_emissions, object, signal_type); + + if (signal->run_type & GTK_RUN_NO_RECURSE) + gtk_emission_remove (&restart_emissions, object, signal_type); + + if (!being_destroyed && !old_value) + GTK_OBJECT_UNSET_FLAGS (object, GTK_IN_CALL); + } + + if (!being_destroyed && GTK_OBJECT_NEED_DESTROY (object) && !GTK_OBJECT_IN_CALL (object)) + { + gtk_object_destroy (object); + return FALSE; + } + + return TRUE; +} + +static GtkHandler* +gtk_signal_get_handlers (GtkObject *object, + gint signal_type) +{ + GtkHandler *handlers; + + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (signal_type >= 1, NULL); + + handlers = gtk_object_get_data (object, handler_key); + + while (handlers) + { + if (handlers->signal_type == signal_type) + return handlers; + handlers = handlers->next; + } + + return NULL; +} + +static gint +gtk_signal_connect_by_type (GtkObject *object, + gint signal_type, + gint object_signal, + GtkSignalFunc func, + gpointer func_data, + GtkSignalDestroy destroy_func, + gint after, + gint no_marshal) +{ + GtkHandler *handler; + gint *object_signals; + gint nsignals; + gint found_it; + gint i; + + g_return_val_if_fail (object != NULL, 0); + g_return_val_if_fail (object->klass != NULL, 0); + g_return_val_if_fail (object->klass->signals != NULL, 0); + + /* Search through the signals for this object and make + * sure the one we are adding is valid. If it isn't then + * issue a warning and return. + */ + object_signals = object->klass->signals; + nsignals = object->klass->nsignals; + found_it = FALSE; + + for (i = 0; i < nsignals; i++) + if (object_signals[i] == signal_type) + { + found_it = TRUE; + break; + } + + if (!found_it) + { + g_warning ("could not find signal (%d) in object's list of signals", signal_type); + return 0; + } + + handler = gtk_signal_handler_new (); + handler->id = next_handler_id++; + handler->signal_type = signal_type; + handler->object_signal = object_signal; + handler->func = func; + handler->func_data = func_data; + handler->destroy_func = destroy_func; + + if (after) + handler->after = TRUE; + handler->no_marshal = no_marshal; + + gtk_signal_handler_insert (object, handler); + return handler->id; +} + +static GtkEmission* +gtk_emission_new () +{ + GtkEmission *emission; + + if (!emission_mem_chunk) + emission_mem_chunk = g_mem_chunk_new ("emission mem chunk", sizeof (GtkEmission), + 1024, G_ALLOC_AND_FREE); + + emission = g_chunk_new (GtkEmission, emission_mem_chunk); + + emission->object = NULL; + emission->signal_type = 0; + + return emission; +} + +static void +gtk_emission_destroy (GtkEmission *emission) +{ + g_mem_chunk_free (emission_mem_chunk, emission); +} + +static void +gtk_emission_add (GList **emissions, + GtkObject *object, + gint signal_type) +{ + GtkEmission *emission; + + g_return_if_fail (emissions != NULL); + g_return_if_fail (object != NULL); + + emission = gtk_emission_new (); + emission->object = object; + emission->signal_type = signal_type; + + *emissions = g_list_prepend (*emissions, emission); +} + +static void +gtk_emission_remove (GList **emissions, + GtkObject *object, + gint signal_type) +{ + GtkEmission *emission; + GList *tmp; + + g_return_if_fail (emissions != NULL); + g_return_if_fail (object != NULL); + + tmp = *emissions; + while (tmp) + { + emission = tmp->data; + + if ((emission->object == object) && + (emission->signal_type == signal_type)) + { + gtk_emission_destroy (emission); + *emissions = g_list_remove_link (*emissions, tmp); + g_list_free (tmp); + break; + } + + tmp = tmp->next; + } +} + +static gint +gtk_emission_check (GList *emissions, + GtkObject *object, + gint signal_type) +{ + GtkEmission *emission; + GList *tmp; + + g_return_val_if_fail (object != NULL, FALSE); + + tmp = emissions; + while (tmp) + { + emission = tmp->data; + tmp = tmp->next; + + if ((emission->object == object) && + (emission->signal_type == signal_type)) + return TRUE; + } + return FALSE; +} + +static gint +gtk_handlers_run (GtkHandler *handlers, + GtkHandlerInfo *info, + gint after) +{ + while (handlers && (handlers->signal_type == info->signal_type)) + { + if (!handlers->blocked && (handlers->after == after)) + { + if (handlers->func) + { + if (handlers->no_marshal) + (* (GtkCallbackMarshal)handlers->func) (info->object, + handlers->func_data, + info->nparams, + info->params); + else if (handlers->object_signal) + (* info->marshaller) (GTK_OBJECT (handlers->func_data), + handlers->func, + handlers->func_data, + info->params); + else + (* info->marshaller) (info->object, + handlers->func, + handlers->func_data, + info->params); + } + else if (marshal) + (* marshal) (info->object, + handlers->func_data, + info->nparams, + info->params, + info->param_types, + info->return_val); + + if (GTK_OBJECT_NEED_DESTROY (info->object)) + return DONE; + else if (gtk_emission_check (stop_emissions, info->object, info->signal_type)) + { + gtk_emission_remove (&stop_emissions, info->object, info->signal_type); + + if (info->run_type & GTK_RUN_NO_RECURSE) + gtk_emission_remove (&restart_emissions, info->object, info->signal_type); + return DONE; + } + else if ((info->run_type & GTK_RUN_NO_RECURSE) && + gtk_emission_check (restart_emissions, info->object, info->signal_type)) + { + gtk_emission_remove (&restart_emissions, info->object, info->signal_type); + return RESTART; + } + } + + handlers = handlers->next; + } + + return 0; +} + +static void +gtk_params_get (GtkArg *params, + gint nparams, + GtkType *param_types, + GtkType return_val, + va_list args) +{ + int i; + + for (i = 0; i < nparams; i++) + { + if (param_types[i] != GTK_TYPE_NONE) + { + params[i].type = param_types[i]; + params[i].name = NULL; + } + + switch (GTK_FUNDAMENTAL_TYPE (param_types[i])) + { + case GTK_TYPE_INVALID: + break; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + GTK_VALUE_CHAR(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_BOOL: + GTK_VALUE_BOOL(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_INT: + GTK_VALUE_INT(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_UINT: + GTK_VALUE_UINT(params[i]) = va_arg (args, guint); + break; + case GTK_TYPE_ENUM: + GTK_VALUE_ENUM(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_FLAGS: + GTK_VALUE_FLAGS(params[i]) = va_arg (args, gint); + break; + case GTK_TYPE_LONG: + GTK_VALUE_LONG(params[i]) = va_arg (args, glong); + break; + case GTK_TYPE_ULONG: + GTK_VALUE_ULONG(params[i]) = va_arg (args, gulong); + break; + case GTK_TYPE_FLOAT: + GTK_VALUE_FLOAT(params[i]) = va_arg (args, gfloat); + break; + case GTK_TYPE_STRING: + GTK_VALUE_STRING(params[i]) = va_arg (args, gchar*); + break; + case GTK_TYPE_POINTER: + GTK_VALUE_POINTER(params[i]) = va_arg (args, gpointer); + break; + case GTK_TYPE_BOXED: + GTK_VALUE_BOXED(params[i]) = va_arg (args, gpointer); + break; + case GTK_TYPE_SIGNAL: + GTK_VALUE_SIGNAL(params[i]).f = va_arg (args, GtkFunction); + GTK_VALUE_SIGNAL(params[i]).d = va_arg (args, gpointer); + break; + case GTK_TYPE_FOREIGN: + GTK_VALUE_FOREIGN(params[i]).data = va_arg (args, gpointer); + GTK_VALUE_FOREIGN(params[i]).notify = + va_arg (args, GtkDestroyNotify); + break; + case GTK_TYPE_CALLBACK: + GTK_VALUE_CALLBACK(params[i]).marshal = + va_arg (args, GtkCallbackMarshal); + GTK_VALUE_CALLBACK(params[i]).data = va_arg (args, gpointer); + GTK_VALUE_CALLBACK(params[i]).notify = + va_arg (args, GtkDestroyNotify); + break; + case GTK_TYPE_C_CALLBACK: + GTK_VALUE_C_CALLBACK(params[i]).func = va_arg (args, GtkFunction); + GTK_VALUE_C_CALLBACK(params[i]).func_data = va_arg (args, gpointer); + break; + case GTK_TYPE_ARGS: + GTK_VALUE_ARGS(params[i]).n_args = va_arg (args, int); + GTK_VALUE_ARGS(params[i]).args = va_arg (args, GtkArg*); + break; + case GTK_TYPE_OBJECT: + GTK_VALUE_OBJECT(params[i]) = va_arg (args, GtkObject*); + g_assert (GTK_VALUE_OBJECT(params[i]) == NULL || + GTK_CHECK_TYPE (GTK_VALUE_OBJECT(params[i]), + params[i].type)); + break; + default: + g_error ("unsupported type %s in signal arg", + gtk_type_name (params[i].type)); + break; + } + } + + if (return_val != GTK_TYPE_NONE) + { + params[i].type = return_val; + params[i].name = NULL; + } + + switch (GTK_FUNDAMENTAL_TYPE (return_val)) + { + case GTK_TYPE_INVALID: + break; + case GTK_TYPE_NONE: + break; + case GTK_TYPE_CHAR: + params[i].d.pointer_data = va_arg (args, gchar*); + break; + case GTK_TYPE_BOOL: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_INT: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_UINT: + params[i].d.pointer_data = va_arg (args, guint*); + break; + case GTK_TYPE_ENUM: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_FLAGS: + params[i].d.pointer_data = va_arg (args, gint*); + break; + case GTK_TYPE_LONG: + params[i].d.pointer_data = va_arg (args, glong*); + break; + case GTK_TYPE_ULONG: + params[i].d.pointer_data = va_arg (args, gulong*); + break; + case GTK_TYPE_FLOAT: + params[i].d.pointer_data = va_arg (args, gfloat*); + break; + case GTK_TYPE_STRING: + params[i].d.pointer_data = va_arg (args, gchar**); + break; + case GTK_TYPE_POINTER: + params[i].d.pointer_data = va_arg (args, gpointer*); + break; + case GTK_TYPE_BOXED: + params[i].d.pointer_data = va_arg (args, gpointer*); + break; + case GTK_TYPE_OBJECT: + params[i].d.pointer_data = va_arg (args, GtkObject**); + break; + case GTK_TYPE_SIGNAL: + case GTK_TYPE_FOREIGN: + case GTK_TYPE_CALLBACK: + case GTK_TYPE_C_CALLBACK: + case GTK_TYPE_ARGS: + default: + g_error ("unsupported type %s in signal return", + gtk_type_name (return_val)); + break; + } +} diff --git a/gtk/gtksignal.h b/gtk/gtksignal.h new file mode 100644 index 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 = >K_WIDGET (GTK_BIN (viewport)->child)->requisition; + attributes.width = child_requisition->width; + attributes.height = child_requisition->height; + } + + widget->window = gdk_window_new (viewport->view_window, &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, viewport); + + widget->style = gtk_style_attach (widget->style, viewport->main_window); + gtk_style_set_background (widget->style, viewport->main_window, GTK_STATE_NORMAL); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); + + gdk_window_show (widget->window); + gdk_window_show (viewport->view_window); +} + +static void +gtk_viewport_unrealize (GtkWidget *widget) +{ + GtkViewport *viewport; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + + viewport = GTK_VIEWPORT (widget); + GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED); + + gtk_style_detach (widget->style); + + gdk_window_destroy (widget->window); + gdk_window_destroy (viewport->view_window); + gdk_window_destroy (viewport->main_window); + + widget->window = NULL; + viewport->view_window = NULL; + viewport->main_window = NULL; +} + +static void +gtk_viewport_paint (GtkWidget *widget, + GdkRectangle *area) +{ + GtkViewport *viewport; + GtkStateType state; + gint x, y; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + viewport = GTK_VIEWPORT (widget); + + state = widget->state; + if (!GTK_WIDGET_IS_SENSITIVE (widget)) + state = GTK_STATE_INSENSITIVE; + + x = GTK_CONTAINER (viewport)->border_width; + y = GTK_CONTAINER (viewport)->border_width; + + gtk_draw_shadow (widget->style, viewport->main_window, + GTK_STATE_NORMAL, viewport->shadow_type, + 0, 0, -1, -1); + } +} + +static void +gtk_viewport_draw (GtkWidget *widget, + GdkRectangle *area) +{ + GtkViewport *viewport; + GtkBin *bin; + GdkRectangle tmp_area; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (area != NULL); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + gtk_viewport_paint (widget, area); + + if (bin->child) + { + tmp_area = *area; + tmp_area.x += viewport->hadjustment->value; + tmp_area.y += viewport->vadjustment->value; + + if (gtk_widget_intersect (bin->child, &tmp_area, &child_area)) + gtk_widget_draw (bin->child, &child_area); + } + } +} + +static gint +gtk_viewport_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkViewport *viewport; + GtkBin *bin; + GdkEventExpose child_event; + + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VIEWPORT (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + if (GTK_WIDGET_DRAWABLE (widget)) + { + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + if (event->window == viewport->main_window) + gtk_viewport_paint (widget, &event->area); + + child_event = *event; + if (bin->child && + GTK_WIDGET_NO_WINDOW (bin->child) && + gtk_widget_intersect (bin->child, &event->area, &child_event.area)) + gtk_widget_event (bin->child, (GdkEvent*) &child_event); + } + + return FALSE; +} + +static void +gtk_viewport_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkViewport *viewport; + GtkBin *bin; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (requisition != NULL); + + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + requisition->width = (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->klass->xthickness) * 2 + 5; + + requisition->height = (GTK_CONTAINER (widget)->border_width * 2 + + GTK_WIDGET (widget)->style->klass->ythickness) * 2 + 5; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + gtk_widget_size_request (bin->child, &bin->child->requisition); +} + +static void +gtk_viewport_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkViewport *viewport; + GtkBin *bin; + GtkAllocation child_allocation; + gint hval, vval; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (widget)); + g_return_if_fail (allocation != NULL); + + widget->allocation = *allocation; + viewport = GTK_VIEWPORT (widget); + bin = GTK_BIN (widget); + + child_allocation.x = GTK_WIDGET (viewport)->style->klass->xthickness; + child_allocation.width = allocation->width - child_allocation.x * 2; + + child_allocation.y = GTK_WIDGET (viewport)->style->klass->ythickness; + child_allocation.height = allocation->height - child_allocation.y * 2; + + if (GTK_WIDGET_REALIZED (widget)) + { + gdk_window_move_resize (viewport->main_window, + allocation->x + GTK_CONTAINER (viewport)->border_width, + allocation->y + GTK_CONTAINER (viewport)->border_width, + allocation->width - GTK_CONTAINER (viewport)->border_width * 2, + allocation->height - GTK_CONTAINER (viewport)->border_width * 2); + + gdk_window_move_resize (viewport->view_window, + child_allocation.x, + child_allocation.y, + child_allocation.width, + child_allocation.height); + } + + viewport->hadjustment->page_size = child_allocation.width; + viewport->hadjustment->page_increment = viewport->hadjustment->page_size / 2; + viewport->hadjustment->step_increment = 10; + + viewport->vadjustment->page_size = child_allocation.height; + viewport->vadjustment->page_increment = viewport->vadjustment->page_size / 2; + viewport->vadjustment->step_increment = 10; + + hval = viewport->hadjustment->value; + vval = viewport->vadjustment->value; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + viewport->hadjustment->lower = 0; + viewport->hadjustment->upper = MAX (bin->child->requisition.width, + child_allocation.width); + + hval = CLAMP (hval, 0, + viewport->hadjustment->upper - + viewport->hadjustment->page_size); + + viewport->vadjustment->lower = 0; + viewport->vadjustment->upper = MAX (bin->child->requisition.height, + child_allocation.height); + + vval = CLAMP (vval, 0, + viewport->vadjustment->upper - + viewport->vadjustment->page_size); + } + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + child_allocation.x = 0; + child_allocation.y = 0; + + child_allocation.width = viewport->hadjustment->upper; + child_allocation.height = viewport->vadjustment->upper; + + if (!GTK_WIDGET_REALIZED (widget)) + gtk_widget_realize (widget); + + gdk_window_resize (widget->window, + child_allocation.width, + child_allocation.height); + + child_allocation.x = 0; + child_allocation.y = 0; + gtk_widget_size_allocate (bin->child, &child_allocation); + } + + gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "changed"); + gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "changed"); + if (viewport->hadjustment->value != hval) + { + viewport->hadjustment->value = hval; + gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "value_changed"); + } + if (viewport->vadjustment->value != vval) + { + viewport->vadjustment->value = vval; + gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "value_changed"); + } +} + +static gint +gtk_viewport_need_resize (GtkContainer *container) +{ + GtkBin *bin; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (GTK_IS_VIEWPORT (container), FALSE); + + if (GTK_WIDGET_REALIZED (container)) + { + bin = GTK_BIN (container); + + gtk_widget_size_request (bin->child, &bin->child->requisition); + + gtk_widget_size_allocate (GTK_WIDGET (container), + &(GTK_WIDGET (container)->allocation)); + } + + return FALSE; +} + +static void +gtk_viewport_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkViewport *viewport; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (data)); + + viewport = GTK_VIEWPORT (data); +} + +static void +gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) +{ + GtkViewport *viewport; + GtkBin *bin; + GtkAllocation child_allocation; + gint width, height; + + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); + g_return_if_fail (GTK_IS_VIEWPORT (data)); + + viewport = GTK_VIEWPORT (data); + bin = GTK_BIN (data); + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gdk_window_get_size (viewport->view_window, &width, &height); + + child_allocation.x = 0; + child_allocation.y = 0; + + if (viewport->hadjustment->lower != (viewport->hadjustment->upper - + viewport->hadjustment->page_size)) + child_allocation.x = viewport->hadjustment->lower - viewport->hadjustment->value; + + if (viewport->vadjustment->lower != (viewport->vadjustment->upper - + viewport->vadjustment->page_size)) + child_allocation.y = viewport->vadjustment->lower - viewport->vadjustment->value; + + if (GTK_WIDGET_REALIZED (viewport)) + gdk_window_move (GTK_WIDGET (viewport)->window, + child_allocation.x, + child_allocation.y); + } +} diff --git a/gtk/gtkviewport.h b/gtk/gtkviewport.h new file mode 100644 index 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; +} |