From 6d6e7066b57397f459a485e35d1240fec6e5f2ab Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Fri, 10 Oct 2003 14:56:43 +0000 Subject: [PATCH 1/1] Se agrega ejemplo de DND con icono. --- tests/gtkmm/dnd_pixmap/cone.xpm | 171 ++++++ tests/gtkmm/dnd_pixmap/cube.xpm | 197 +++++++ tests/gtkmm/dnd_pixmap/dnd.c | 899 ++++++++++++++++++++++++++++++ tests/gtkmm/dnd_pixmap/sphere.xpm | 196 +++++++ 4 files changed, 1463 insertions(+) create mode 100644 tests/gtkmm/dnd_pixmap/cone.xpm create mode 100644 tests/gtkmm/dnd_pixmap/cube.xpm create mode 100644 tests/gtkmm/dnd_pixmap/dnd.c create mode 100644 tests/gtkmm/dnd_pixmap/sphere.xpm diff --git a/tests/gtkmm/dnd_pixmap/cone.xpm b/tests/gtkmm/dnd_pixmap/cone.xpm new file mode 100644 index 0000000..f3b0663 --- /dev/null +++ b/tests/gtkmm/dnd_pixmap/cone.xpm @@ -0,0 +1,171 @@ +/* XPM */ +static char * cone_xpm[] = { +"20 20 148 2", +" c None", +". c #1F9715", +"+ c #1E9614", +"@ c #80D579", +"# c #64C75B", +"$ c #1B9310", +"% c #42C835", +"& c #A6E99F", +"* c #79E06E", +"= c #39BD2E", +"- c #239B17", +"; c #72E468", +"> c #BBF0B6", +", c #78E66E", +"' c #4AD23D", +") c #138909", +"! c #239D18", +"~ c #3EBE32", +"{ c #8FE888", +"] c #B3EEAD", +"^ c #68E75C", +"/ c #4DD440", +"( c #1E9914", +"_ c #0D7F03", +": c #32B226", +"< c #54D749", +"[ c #A9EBA3", +"} c #A7ECA0", +"| c #5EE152", +"1 c #4ACE3E", +"2 c #31B126", +"3 c #1B9110", +"4 c #1C9212", +"5 c #32B128", +"6 c #6DDF62", +"7 c #B4EEAF", +"8 c #91EA88", +"9 c #59DC4D", +"0 c #48CC3C", +"a c #3CBE31", +"b c #28A61D", +"c c #2FAD24", +"d c #54D849", +"e c #8BE882", +"f c #AFEEA9", +"g c #7BE871", +"h c #56DA4A", +"i c #44C738", +"j c #3EC033", +"k c #2EAC22", +"l c #18910D", +"m c #39B92E", +"n c #66E15A", +"o c #A1ED9C", +"p c #A9EEA3", +"q c #6EE563", +"r c #52D546", +"s c #43C637", +"t c #42C537", +"u c #35B62A", +"v c #25A119", +"w c #108406", +"x c #2FAF24", +"y c #52D745", +"z c #80E877", +"A c #A5ED9D", +"B c #99EC92", +"C c #67E45B", +"D c #4ED242", +"E c #47C93B", +"F c #3CBD30", +"G c #1B9410", +"H c #7F7F7F", +"I c #35B629", +"J c #5DDC51", +"K c #8BE983", +"L c #A7EDA1", +"M c #8EEA86", +"N c #5FE153", +"O c #48CB3C", +"P c #49CC3D", +"Q c #3CBE30", +"R c #2AA91F", +"S c #219E16", +"T c #118607", +"U c #27A31C", +"V c #41C835", +"W c #6FDD64", +"X c #89E681", +"Y c #A1EC9A", +"Z c #84E87A", +"` c #5ADC4E", +" . c #3EC133", +".. c #2AAA1F", +"+. c #23A018", +"@. c #1A930F", +"#. c #2AA61E", +"$. c #3EC333", +"%. c #69DB5E", +"&. c #8EE786", +"*. c #98EA90", +"=. c #7EE674", +"-. c #58DB4C", +";. c #45CA39", +">. c #47CA3B", +",. c #3FC033", +"'. c #2FB024", +"). c #28A61C", +"!. c #1F9B15", +"~. c #0B7C01", +"{. c #29A51E", +"]. c #3CC030", +"^. c #50D544", +"/. c #7AE271", +"(. c #82E677", +"_. c #71E367", +":. c #53D647", +"<. c #47CB3B", +"[. c #44C739", +"}. c #39BA2E", +"|. c #2DAC22", +"1. c #29A81E", +"2. c #1D9913", +"3. c #1B9111", +"4. c #229C18", +"5. c #39B92D", +"6. c #42C336", +"7. c #4FD143", +"8. c #57D64C", +"9. c #45C739", +"0. c #44C638", +"a. c #3BBC2F", +"b. c #2AA81F", +"c. c #209A15", +"d. c #1A9210", +"e. c #2FAB25", +"f. c #30AD26", +"g. c #2CA720", +"h. c #32B026", +"i. c #35B429", +"j. c #37B62C", +"k. c #38B82C", +"l. c #24A019", +"m. c #128607", +"n. c #0C7E02", +"o. c #198E0D", +"p. c #178B0D", +"q. c #128507", +" ", +" . . ", +" + @ # $ ", +" % & * = ", +" - ; > , ' ) ", +" - ; > , ' ) ", +" ! ~ { ] ^ / ( _ ", +" : < [ } | 1 2 3 ", +" 4 5 6 7 8 9 0 a b _ ", +" c d e f g h i j k l ", +" 4 m n o p q r s t u v w ", +" x y z A B C D E E F b G H ", +" 4 I J K L M N D O P Q R S T H ", +" U V W X Y Z ` 0 O 0 ...+.@.H H ", +" 4 #.$.%.&.*.=.-.;.O >.,.'.).!.~.H H ", +" 4 {.].^./.(._.:.<.>.[.}.|.1.2.~.H ", +" 3.4.5.6.7.8.0 9.0.a.b.c.d.T H ", +" e.f.g.h.i.j.k.l.m.n.H ", +" 3.o.p.q. ", +" "}; diff --git a/tests/gtkmm/dnd_pixmap/cube.xpm b/tests/gtkmm/dnd_pixmap/cube.xpm new file mode 100644 index 0000000..e82fc1d --- /dev/null +++ b/tests/gtkmm/dnd_pixmap/cube.xpm @@ -0,0 +1,197 @@ +/* XPM */ +static char * cube_xpm[] = { +"20 20 174 2", +" c None", +". c #3C3CAD", +"+ c #6161D1", +"@ c #5757CA", +"# c #4E4EC7", +"$ c #4C4CC8", +"% c #5454CB", +"& c #5959CD", +"* c #5858CD", +"= c #4747C4", +"- c #3838BA", +"; c #3A3ABD", +"> c #3737B9", +", c #22229D", +"' c #3434A5", +") c #8181E6", +"! c #9393ED", +"~ c #9D9DEF", +"{ c #8B8BED", +"] c #8080EC", +"^ c #7474EB", +"/ c #7171EB", +"( c #7070EB", +"_ c #6565E9", +": c #5E5EE5", +"< c #4F4FDA", +"[ c #2D2DB1", +"} c #0B0B7E", +"| c #4B4BA4", +"1 c #8F8FEB", +"2 c #9B9BEE", +"3 c #A2A2EF", +"4 c #A5A5F0", +"5 c #9696EF", +"6 c #8C8CED", +"7 c #7B7BEC", +"8 c #7575EC", +"9 c #6262E7", +"0 c #5D5DE2", +"a c #1F1FA6", +"b c #0B0B90", +"c c #04047B", +"d c #5151A1", +"e c #8484E4", +"f c #9C9CED", +"g c #A1A1EF", +"h c #A4A4F1", +"i c #A4A4EF", +"j c #9A9AEC", +"k c #8989E7", +"l c #8484E6", +"m c #7878E6", +"n c #6868E3", +"o c #5C5CE1", +"p c #2424AA", +"q c #0E0E98", +"r c #09098A", +"s c #7171C5", +"t c #9F9FEC", +"u c #A4A4EE", +"v c #A4A4ED", +"w c #A3A3ED", +"x c #A1A1ED", +"y c #A0A0ED", +"z c #9C9CEC", +"A c #9A9AEA", +"B c #9898E9", +"C c #8888E8", +"D c #8080E4", +"E c #0B0B8E", +"F c #0A0A84", +"G c #5858CF", +"H c #6A6AD5", +"I c #6969D4", +"J c #6767D3", +"K c #6969D5", +"L c #5D5DD1", +"M c #5050D2", +"N c #4E4ED2", +"O c #5353CD", +"P c #4C4CC7", +"Q c #3A3AC8", +"R c #090984", +"S c #5B5BD0", +"T c #6565D4", +"U c #6262D1", +"V c #5C5CCC", +"W c #5D5DD5", +"X c #4C4CD0", +"Y c #4D4DCB", +"Z c #4F4FCC", +"` c #4B4BCA", +" . c #3939C6", +".. c #5656D0", +"+. c #5959D0", +"@. c #5D5DCD", +"#. c #6060D2", +"$. c #5D5DD8", +"%. c #6060D7", +"&. c #5151CE", +"*. c #4343C9", +"=. c #3C3CC5", +"-. c #2C2CC2", +";. c #0A0A8C", +">. c #4F4FCF", +",. c #5B5BCD", +"'. c #5656CB", +"). c #4E4EC8", +"!. c #5252CE", +"~. c #5151D4", +"{. c #4949CB", +"]. c #4747C9", +"^. c #4343CB", +"/. c #3232C1", +"(. c #2525C1", +"_. c #0F0F9A", +":. c #060682", +"<. c #7F7F7F", +"[. c #4A4ACD", +"}. c #5050C6", +"|. c #5858D0", +"1. c #5151CF", +"2. c #4949C6", +"3. c #4747C8", +"4. c #4040C7", +"5. c #3E3ECA", +"6. c #2727BE", +"7. c #2424BF", +"8. c #1313A2", +"9. c #020275", +"0. c #0F0F87", +"a. c #3C3CC9", +"b. c #4B4BC4", +"c. c #5454C8", +"d. c #4A4AC9", +"e. c #4545C5", +"f. c #4141C9", +"g. c #3D3DCA", +"h. c #2D2DBE", +"i. c #2525C0", +"j. c #2323BE", +"k. c #1313A1", +"l. c #0C0C91", +"m. c #000070", +"n. c #3434C7", +"o. c #3E3EC6", +"p. c #4242CA", +"q. c #4444C2", +"r. c #4646C9", +"s. c #4040C9", +"t. c #2828C4", +"u. c #2727C4", +"v. c #1313A0", +"w. c #04047D", +"x. c #2E2EC6", +"y. c #3232BC", +"z. c #3737BC", +"A. c #3838BF", +"B. c #3333C3", +"C. c #2828BE", +"D. c #2323BD", +"E. c #2222BB", +"F. c #2222BC", +"G. c #13139F", +"H. c #050580", +"I. c #2626C2", +"J. c #2424BD", +"K. c #2424BE", +"L. c #2626C3", +"M. c #0B0B8C", +"N. c #07077F", +"O. c #090983", +"P. c #0E0E8E", +"Q. c #04047A", +" ", +" ", +" ", +" . + @ # $ % & * = - ; > , ", +" ' ) ! ~ { ] ^ / ( _ : < [ } ", +" | 1 2 3 4 5 6 7 8 ( 9 0 a b c ", +" d e f g h i j k l m n o p q q r ", +" s t u v w x y z A B C D q q q E ", +" F G H I J K L M N O P Q q q q E ", +" R S T U V L W X Y Z ` .q q q E ", +" R ..+.@.#.$.%.M &.*.=.-.q q q ;. ", +" R >.,.'.).!.~.{.].^./.(._.q q :.<. ", +" F [.}.|.1.>.2.3.4.5.6.7.8.q q 9.<.<.", +" 0.a.b.c.1.d.e.f.g.h.i.j.k.q l.m.<.<.", +" 0.n.o.p.q.r.s.n.t.u.i.7.v.b w.m.<.<.", +" F x.y.z.A.B.C.D.u.E.F.7.G.H.m.<.<. ", +" m.I.J.J.K.K.K.J.J.I.L.(.M.9.<.<. ", +" m.N.O.O.O.O.O.O.O.O.P.Q.m.<. ", +" ", +" "}; diff --git a/tests/gtkmm/dnd_pixmap/dnd.c b/tests/gtkmm/dnd_pixmap/dnd.c new file mode 100644 index 0000000..63df3ca --- /dev/null +++ b/tests/gtkmm/dnd_pixmap/dnd.c @@ -0,0 +1,899 @@ +/* + GTK Drag & Drop Tutorial - Example Source Code + + Copyright (C) 2000-2002 WolfPack Entertainment + http://wolfpack.twu.net/ + + + To compile: + + cc `gtk-config --cflags --libs` dnd.c -o dnd + + + Important: DND does not appear to work properly with GTK+ 1.2.9 + or older!! Please try to obtain GTK+ 1.2.10 or newer before + attempting to run this demo. + + + Order of GTK DND events are as follows (for one complete drag + and drop operation): + + 1. "drag_begin_event" notifies source that drag started + 2. "drag_motion" notifies target about drag pointer motion + 3. "drag_data_get" request for drag data from source + 4. "drag_data_received" source has sent target the requested data + 5. "drag_data_delete" source should/can delete data + 6. "drag_end_event" notifies source that drag is done + + Sequences 1, 3, 5, and 6 are sent to the source widget, while + sequences 2 and 4 are sent to the target widget. + + */ + +#include /* Needed for pixmap loading. */ +#include + +/* Data for the pixmaps that we will be using in the GtkCList cells + * and DND icons. + */ +#include "sphere.xpm" +#include "cube.xpm" +#include "cone.xpm" + + +/* + * DND data format type idenficaition, it identifies what format + * the drag data is in for internal parsing by this program. + * Remember that this is the data format type (not to be confused + * with data type, like string, binary, etc). + * + * These values are passed to gtk_drag_dest_set() and + * gtk_drag_source_set() and will be given as inputs in DND signal + * callbacks. + * + * In each callback, we have the choice of using either the name + * (a string) or the info (an int). In this example we will use + * the info (an int) since it is easier and more commonly practiced. + * + * Below we define the name and info pairs that are commonly used + * in most GTK+ and GNOME applications: + */ +#define DRAG_TAR_NAME_0 "text/plain" +#define DRAG_TAR_INFO_0 0 + +#define DRAG_TAR_NAME_1 "text/uri-list" /* not url-list */ +#define DRAG_TAR_INFO_1 1 + +#define DRAG_TAR_NAME_2 "STRING" +#define DRAG_TAR_INFO_2 2 + + +/* + * Our window structure, it's just a toplevel GtkWindow and a + * GtkCList. The GtkCList will not be set reorderable, so that + * we can demostrate the (more advanced) DND abilities of this + * program. + */ +typedef struct { + + GtkWidget *toplevel; + GtkWidget *clist; + +} my_prog_window_struct; + + +/* General event/signal callbacks. */ +static gint HandleCloseCB( + GtkWidget *widget, gpointer *event, gpointer data +); +static void CListSelectRowCB( + GtkWidget *widget, + gint row, gint column, + GdkEventButton *event, gpointer data +); +static void CListUnselectRowCB( + GtkWidget *widget, + gint row, gint column, + GdkEventButton *event, gpointer data +); + +/* DND specific event/signal callbacks. */ +static void DNDBeginCB( + GtkWidget *widget, GdkDragContext *dc, gpointer data +); +static void DNDEndCB( + GtkWidget *widget, GdkDragContext *dc, gpointer data +); +static gboolean DNDDragMotionCB( + GtkWidget *widget, GdkDragContext *dc, + gint x, gint y, guint t, + gpointer data +); +static void DNDDataRequestCB( + GtkWidget *widget, GdkDragContext *dc, + GtkSelectionData *selection_data, guint info, guint t, + gpointer data +); +static void DNDDataRecievedCB( + GtkWidget *widget, GdkDragContext *dc, + gint x, gint y, GtkSelectionData *selection_data, + guint info, guint t, gpointer data +); +static void DNDDataDeleteCB( + GtkWidget *widget, GdkDragContext *dc, gpointer data +); + +/* Some convience functions for our example. */ +static my_prog_window_struct *WindowNew(const gchar *title); +static void WindowDelete(my_prog_window_struct *win); + + +/* Pixmap and mask pairs used for GtkCList cell pixmaps and + * DND icons. + */ +static GdkPixmap *sphere_pixmap, + *cube_pixmap, + *cone_pixmap; +static GdkBitmap *sphere_mask, + *cube_mask, + *cone_mask; + + +/* + * "delete_event" signal callback. + * + * Called when a GtkWindow closes. + */ +static gint HandleCloseCB( + GtkWidget *widget, gpointer *event, gpointer data +) +{ + /* Make it simple, when one window closes we just effectively + * close them all by breaking out of the last GTK+ main loop + * so that they will all be destroyed. + */ + gtk_main_quit(); + + return(TRUE); +} + +/* + * "select_row" signal callback. + * + * Called when a row is selected on a GtkCList. + */ +static void CListSelectRowCB( + GtkWidget *widget, + gint row, gint column, + GdkEventButton *event, gpointer data +) +{ + GtkCList *clist; + my_prog_window_struct *win = (my_prog_window_struct *)data; + if((widget == NULL) || (win == NULL)) + return; + + clist = GTK_CLIST(widget); + + /* Selected row in bounds? */ + if((row >= 0) && (row < clist->rows)) + { + gint cell_type; + guint8 spacing = 0; + gchar *text = NULL; + GdkPixmap *pixmap = NULL; + GdkBitmap *mask = NULL; + + + /* Obtain the pixmap and mask pair of the icon of the + * selected row and update the DND icon. + */ + cell_type = gtk_clist_get_cell_type(clist, row, 0); + switch(cell_type) + { + case GTK_CELL_PIXMAP: + gtk_clist_get_pixmap( + clist, row, 0, &pixmap, &mask + ); + case GTK_CELL_PIXTEXT: + gtk_clist_get_pixtext( + clist, row, 0, + &text, &spacing, &pixmap, &mask + ); + } + /* Selected row has pixmap? */ + if(pixmap != NULL) + { + gint w = 15, h = 15; + + /* Get size of pixmap. */ + gdk_window_get_size( + (GdkWindow *)pixmap, &w, &h + ); + /* Update the DND icon to be used on the next + * drag based on this pixmap. Set the hot spot + * to be at the center of this pixmap. + */ + gtk_drag_set_default_icon( + gdk_colormap_get_system(), + pixmap, mask, + w / 2, h / 2 + ); + } + + /* If the selected row is not fully visible, attempt to + * scroll and make it visible in the center of the + * list. + */ + if(gtk_clist_row_is_visible(clist, row) != + GTK_VISIBILITY_FULL + ) + gtk_clist_moveto( + clist, + row, 0, /* Row, column. */ + 0.5, 0.0 /* Row, column. */ + ); + } +} + +/* + * "unselect_row" signal callback. + * + * Called when a row is selected on a GtkCList. + */ +static void CListUnselectRowCB( + GtkWidget *widget, + gint row, gint column, + GdkEventButton *event, gpointer data +) +{ + /* Ignore this. */ +} + + +/* + * DND "drag_begin" handler, this is called whenever a drag starts. + */ +static void DNDBeginCB( + GtkWidget *widget, GdkDragContext *dc, gpointer data +) +{ + my_prog_window_struct *win = (my_prog_window_struct *)data; + if((widget == NULL) || (win == NULL) || (dc == NULL)) + return; + + /* Put any needed drag begin setup code here. */ +} + +/* + * DND "drag_end" handler, this is called when a drag and drop has + * completed. So this function is the last one to be called in + * any given DND operation. + */ +static void DNDEndCB( + GtkWidget *widget, GdkDragContext *dc, gpointer data +) +{ + my_prog_window_struct *win = (my_prog_window_struct *)data; + if((win == NULL) || (dc == NULL)) + return; + + /* Put any needed drag end cleanup code here. */ +} + +/* + * DND "drag_motion" handler, this is called whenever the + * pointer is dragging over the target widget. + */ +static gboolean DNDDragMotionCB( + GtkWidget *widget, GdkDragContext *dc, + gint x, gint y, guint t, + gpointer data +) +{ + gboolean same_widget; + GdkDragAction suggested_action; + GtkWidget *src_widget, *tar_widget; + my_prog_window_struct *win = (my_prog_window_struct *)data; + if((win == NULL) || (dc == NULL)) + return(FALSE); + + /* Get source widget and target widget. */ + src_widget = gtk_drag_get_source_widget(dc); + tar_widget = widget; + + /* Note if source widget is the same as the target. */ + same_widget = (src_widget == tar_widget) ? TRUE : FALSE; + + + /* If this is the same widget, our suggested action should be + * move. For all other case we assume copy. + */ + if(same_widget) + suggested_action = GDK_ACTION_MOVE; + else + suggested_action = GDK_ACTION_COPY; + + /* Respond with default drag action (status). First we check + * the dc's list of actions. If the list only contains + * move, copy, or link then we select just that, otherwise we + * return with our default suggested action. + * If no valid actions are listed then we respond with 0. + */ + + /* Only move? */ + if(dc->actions == GDK_ACTION_MOVE) + gdk_drag_status(dc, GDK_ACTION_MOVE, t); + /* Only copy? */ + else if(dc->actions == GDK_ACTION_COPY) + gdk_drag_status(dc, GDK_ACTION_COPY, t); + /* Only link? */ + else if(dc->actions == GDK_ACTION_LINK) + gdk_drag_status(dc, GDK_ACTION_LINK, t); + /* Other action, check if listed in our actions list? */ + else if(dc->actions & suggested_action) + gdk_drag_status(dc, suggested_action, t); + /* All else respond with 0. */ + else + gdk_drag_status(dc, 0, t); + + return(FALSE); +} + +/* + * DND "drag_data_get" handler, for handling requests for DND + * data on the specified widget. This function is called when + * there is need for DND data on the source, so this function is + * responsable for setting up the dynamic data exchange buffer + * (DDE as sometimes it is called) and sending it out. + */ +static void DNDDataRequestCB( + GtkWidget *widget, GdkDragContext *dc, + GtkSelectionData *selection_data, guint info, guint t, + gpointer data +) +{ + gboolean data_sent = FALSE; + gint row; + GList *glist; + GtkCList *clist; + my_prog_window_struct *win = (my_prog_window_struct *)data; + if((widget == NULL) || (win == NULL) || (dc == NULL)) + return; + + clist = GTK_CLIST(widget); + + /* Get last selected row on the clist. */ + glist = clist->selection_end; + row = (glist != NULL) ? (gint)glist->data : -1; + + /* Selected row in bounds? */ + if((row >= 0) && (row < clist->rows)) + { + gint cell_type; + guint8 spacing = 0; + gchar *text = NULL; + GdkPixmap *pixmap = NULL; + GdkBitmap *mask = NULL; + + + /* Obtain the text of the first cell of the selected + * row, then use this text and send it out to the DDE. + */ + cell_type = gtk_clist_get_cell_type(clist, row, 0); + switch(cell_type) + { + case GTK_CELL_TEXT: + gtk_clist_get_text( + clist, row, 0, &text + ); + case GTK_CELL_PIXTEXT: + gtk_clist_get_pixtext( + clist, row, 0, + &text, &spacing, &pixmap, &mask + ); + } + /* Selected row has text? */ + if(text != NULL) + { + /* Send out the data using the selection system, + * this is also used for cut and paste but + * GTK uses it for drag and drop as well. When + * sending a string, GTK will ensure that a null + * terminating byte is added to the end so we + * do not need to add it. GTK also coppies the + * data so the original will never be modified. + */ + gtk_selection_data_set( + selection_data, + GDK_SELECTION_TYPE_STRING, + 8, /* 8 bits per character. */ + text, strlen(text) + ); + data_sent = TRUE; + } + } + + /* If we did not send out any data (for whatever reason), + * then send out an error response since this function + * needs to gaurantee a response when reasonably possible. + */ + if(!data_sent) + { + const gchar *cstrptr = "Error"; + + gtk_selection_data_set( + selection_data, + GDK_SELECTION_TYPE_STRING, + 8, /* 8 bits per character. */ + cstrptr, strlen(cstrptr) + ); + data_sent = TRUE; + } +} + +/* + * DND "drag_data_received" handler. When DNDDataRequestCB() + * calls gtk_selection_data_set() to send out the data, this function + * recieves it and is responsible for handling it. + * + * This is also the only DND callback function where the given + * inputs may reflect those of the drop target so we need to check + * if this is the same structure or not. + */ +static void DNDDataRecievedCB( + GtkWidget *widget, GdkDragContext *dc, + gint x, gint y, GtkSelectionData *selection_data, + guint info, guint t, gpointer data +) +{ + gboolean same; + gint row, column; + GtkWidget *source_widget; + GtkCList *clist; + my_prog_window_struct *win = (my_prog_window_struct *)data; + if((widget == NULL) || (win == NULL) || (dc == NULL)) + return; + + /* Important, check if we actually got data. Sometimes errors + * occure and selection_data will be NULL. + */ + if(selection_data == NULL) + return; + if(selection_data->length < 0) + return; + + /* Source and target widgets are the same? */ + source_widget = gtk_drag_get_source_widget(dc); + same = (source_widget == widget) ? TRUE : FALSE; + + clist = GTK_CLIST(widget); + + /* Calculate the row and column at which the drop has occured + * over on the clist based on the given x and y coordinates. + */ + if(!gtk_clist_get_selection_info( + clist, + x, + y - ((clist->flags & GTK_CLIST_SHOW_TITLES) ? + clist->column_title_area.height + + clist->column_title_area.y : 0), + &row, &column + )) + { + row = -1; + column = 0; + } + + /* Now check if the data format type is one that we support + * (remember, data format type, not data type). + * + * We check this by testing if info matches one of the info + * values that we have defined. + * + * Note that we can also iterate through the atoms in: + * GList *glist = dc->targets; + * + * while(glist != NULL) + * { + * gchar *name = gdk_atom_name((GdkAtom)glist->data); + * * strcmp the name to see if it matches + * * one that we support + * * + * glist = glist->next; + * } + */ + if((info == DRAG_TAR_INFO_0) || + (info == DRAG_TAR_INFO_1) || + (info == DRAG_TAR_INFO_2) + ) + { + gint new_row; + gchar *new_text = selection_data->data; + gchar *text[1]; + GdkPixmap *pixmap = NULL; + GdkBitmap *mask = NULL; + + + /* Reset cells text array for adding a new row, we'll + * set the actual text after the row has been created. + */ + text[0] = ""; + + /* Append or insert the new row? */ + if((row >= 0) && (row < clist->rows)) + new_row = gtk_clist_insert(clist, row, text); + else + new_row = gtk_clist_append(clist, text); + + /* Check the name of the cell obtained from the received + * data and decipher which pixmap and mask pair to + * use for the new cell (if any). + */ + if(!strcmp(new_text, "Sphere")) + { + pixmap = sphere_pixmap; + mask = sphere_mask; + } + else if(!strcmp(new_text, "Cube")) + { + pixmap = cube_pixmap; + mask = cube_mask; + } + else if(!strcmp(new_text, "Cone")) + { + pixmap = cone_pixmap; + mask = cone_mask; + } + /* Update the new row's cell with the pixmap (if + * available) and the received data as the text. + */ + if(pixmap != NULL) + gtk_clist_set_pixtext( + clist, new_row, 0, + new_text, 2, pixmap, mask + ); + else + gtk_clist_set_text( + clist, new_row, 0, + new_text + ); + } +} + +/* + * DND "drag_data_delete" handler, this function is called when + * the data on the source `should' be deleted (ie if the DND was + * a move). + */ +static void DNDDataDeleteCB( + GtkWidget *widget, GdkDragContext *dc, gpointer data +) +{ + gint row; + GList *glist; + GtkCList *clist; + my_prog_window_struct *win = (my_prog_window_struct *)data; + if((widget == NULL) || (win == NULL) || (dc == NULL)) + return; + + clist = GTK_CLIST(widget); + + /* Get last selected row on the clist. */ + glist = clist->selection_end; + row = (glist != NULL) ? (gint)glist->data : -1; + + /* Remove the last selected row. */ + gtk_clist_remove(clist, row); +} + + +/* + * Creates a new window with everything set up. + */ +static my_prog_window_struct *WindowNew(const gchar *title) +{ + gchar *heading[1]; + GtkWidget *w, *parent, *scrolled_window; + GtkCList *clist; + GtkTargetEntry target_entry[3]; + my_prog_window_struct *win = (my_prog_window_struct *)g_malloc0( + sizeof(my_prog_window_struct) + ); + if(win == NULL) + return(NULL); + + /* Create toplevel. */ + w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + win->toplevel = w; + gtk_signal_connect( + GTK_OBJECT(w), "delete_event", + GTK_SIGNAL_FUNC(HandleCloseCB), win + ); + gtk_widget_set_usize(w, 200, 150); + gtk_window_set_title( + GTK_WINDOW(w), + (title == NULL) ? "Untitled" : title + ); + /* Do not show the toplevel just yet. */ + parent = w; + + /* Main vbox to hold clist. */ + w = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(parent), w); + gtk_widget_show(w); + parent = w; + + /* Create the scrolled window for the clist and the clist + * itself. + */ + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_box_pack_start(GTK_BOX(parent), scrolled_window, TRUE, TRUE, 0); + gtk_scrolled_window_set_policy( + GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC + ); + gtk_widget_show(scrolled_window); + + heading[0] = "Name"; + w = gtk_clist_new_with_titles(1, heading); + clist = GTK_CLIST(w); + win->clist = w; + gtk_clist_set_selection_mode(clist, GTK_SELECTION_SINGLE); + gtk_clist_set_shadow_type(clist, GTK_SHADOW_IN); + gtk_clist_column_titles_passive(clist); + gtk_clist_set_column_justification( + clist, 0, GTK_JUSTIFY_LEFT + ); + gtk_clist_set_row_height(clist, 20); + gtk_signal_connect( + GTK_OBJECT(w), "select_row", + GTK_SIGNAL_FUNC(CListSelectRowCB), win + ); + gtk_signal_connect( + GTK_OBJECT(w), "unselect_row", + GTK_SIGNAL_FUNC(CListUnselectRowCB), win + ); + gtk_container_add(GTK_CONTAINER(scrolled_window), w); + + /* Realize the clist widget and make sure it has a window, + * this will be for DND setup. + */ + gtk_widget_realize(w); + if(!GTK_WIDGET_NO_WINDOW(w)) + { + /* DND: Set up the clist as a potential DND destination. + * First we set up target_entry which is a sequence of of + * structure which specify the kinds (which we define) of + * drops accepted on this widget. + */ + + /* Set up the list of data format types that our DND + * callbacks will accept. + */ + target_entry[0].target = DRAG_TAR_NAME_0; + target_entry[0].flags = 0; + target_entry[0].info = DRAG_TAR_INFO_0; + target_entry[1].target = DRAG_TAR_NAME_1; + target_entry[1].flags = 0; + target_entry[1].info = DRAG_TAR_INFO_1; + target_entry[2].target = DRAG_TAR_NAME_2; + target_entry[2].flags = 0; + target_entry[2].info = DRAG_TAR_INFO_2; + + /* Set the drag destination for this widget, using the + * above target entry types, accept move's and coppies'. + */ + gtk_drag_dest_set( + w, + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | + GTK_DEST_DEFAULT_DROP, + target_entry, + sizeof(target_entry) / sizeof(GtkTargetEntry), + GDK_ACTION_MOVE | GDK_ACTION_COPY + ); + gtk_signal_connect( + GTK_OBJECT(w), "drag_motion", + GTK_SIGNAL_FUNC(DNDDragMotionCB), + win + ); + + /* Set the drag source for this widget, allowing the user + * to drag items off of this clist. + */ + gtk_drag_source_set( + w, + GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + target_entry, + sizeof(target_entry) / sizeof(GtkTargetEntry), + GDK_ACTION_MOVE | GDK_ACTION_COPY + ); + /* Set DND signals on clist. */ + gtk_signal_connect( + GTK_OBJECT(w), "drag_begin", + GTK_SIGNAL_FUNC(DNDBeginCB), win + ); + gtk_signal_connect( + GTK_OBJECT(w), "drag_end", + GTK_SIGNAL_FUNC(DNDEndCB), win + ); + gtk_signal_connect( + GTK_OBJECT(w), "drag_data_get", + GTK_SIGNAL_FUNC(DNDDataRequestCB), win + ); + gtk_signal_connect( + GTK_OBJECT(w), "drag_data_received", + GTK_SIGNAL_FUNC(DNDDataRecievedCB), win + ); + gtk_signal_connect( + GTK_OBJECT(w), "drag_data_delete", + GTK_SIGNAL_FUNC(DNDDataDeleteCB), win + ); + } + + + gtk_widget_show(w); + + + /* Now show the toplevel. */ + gtk_widget_show(win->toplevel); + + return(win); +} + +/* + * Dealloactes the given window and all its resources. + */ +static void WindowDelete(my_prog_window_struct *win) +{ + GtkWidget *w; + + + if(win == NULL) + return; + + /* Destroy the GtkCList, first remove the DND settings on it + * and then destroy it. + */ + w = win->clist; + if(w != NULL) + { + /* Remove DND settings on this widget. */ + gtk_drag_dest_unset(w); + gtk_drag_source_unset(w); + + win->clist = NULL; + gtk_widget_destroy(w); + } + + /* Destroy toplevel GtkWindow, thus destroying all of its + * child widgets. + */ + w = win->toplevel; + if(w != NULL) + { + win->toplevel = NULL; + gtk_widget_destroy(w); + } + + /* Deallocate the structure itself. */ + g_free(win); +} + + +int main(int argc, char **argv) +{ + GtkStyle *style; + GdkWindow *window; + GdkPixmap **pixmap; + GdkBitmap **mask; + gchar **pixmap_data; + my_prog_window_struct *win[2]; + + + gtk_init(&argc, &argv); + + + /* Load the pixmaps that we will be using as GtkCList cell + * pixmaps and DND icons. + * + * This requires that we use the root window for loading of + * the pixmaps (hence the need to include gdk/gdkx.h). + */ + style = gtk_widget_get_default_style(); + window = (GdkWindow *)GDK_ROOT_PARENT(); + + pixmap = &sphere_pixmap; + mask = &sphere_mask; + pixmap_data = sphere_xpm; + *pixmap = gdk_pixmap_create_from_xpm_d( + window, mask, + &style->bg[GTK_STATE_NORMAL], + pixmap_data + ); + + pixmap = &cube_pixmap; + mask = &cube_mask; + pixmap_data = cube_xpm; + *pixmap = gdk_pixmap_create_from_xpm_d( + window, mask, + &style->bg[GTK_STATE_NORMAL], + pixmap_data + ); + + pixmap = &cone_pixmap; + mask = &cone_mask; + pixmap_data = cone_xpm; + *pixmap = gdk_pixmap_create_from_xpm_d( + window, mask, + &style->bg[GTK_STATE_NORMAL], + pixmap_data + ); + + + /* Create two windows. */ + win[0] = WindowNew("List 1"); + win[1] = WindowNew("List 2"); + + /* Add some items to the first list. */ + if(win[0] != NULL) + { + GtkCList *clist = (GtkCList *)win[0]->clist; + if(clist != NULL) + { + gint new_row; + gchar *text[1]; + + + /* Reset cells text array for adding a new row, + * we'll set the actual text after the row has + * been created. + */ + text[0] = ""; + + /* Begin creating new rows. */ + + new_row = gtk_clist_append(clist, text); + gtk_clist_set_pixtext( + clist, new_row, 0, + "Sphere", 2, + sphere_pixmap, sphere_mask + ); + + new_row = gtk_clist_append(clist, text); + gtk_clist_set_pixtext( + clist, new_row, 0, + "Cube", 2, + cube_pixmap, cube_mask + ); + + new_row = gtk_clist_append(clist, text); + gtk_clist_set_pixtext( + clist, new_row, 0, + "Cone", 2, + cone_pixmap, cone_mask + ); + } + } + + + /* Enter main gtk loop. */ + gtk_main(); + + + /* Application now shutting down, begin deallocating + * resources. + */ + WindowDelete(win[0]); + WindowDelete(win[1]); + + gdk_pixmap_unref(sphere_pixmap); + gdk_bitmap_unref(sphere_mask); + gdk_pixmap_unref(cube_pixmap); + gdk_bitmap_unref(cube_mask); + gdk_pixmap_unref(cone_pixmap); + gdk_bitmap_unref(cone_mask); + + + return(0); +} diff --git a/tests/gtkmm/dnd_pixmap/sphere.xpm b/tests/gtkmm/dnd_pixmap/sphere.xpm new file mode 100644 index 0000000..3c93587 --- /dev/null +++ b/tests/gtkmm/dnd_pixmap/sphere.xpm @@ -0,0 +1,196 @@ +/* XPM */ +static char * sphere_xpm[] = { +"20 20 173 2", +" c None", +". c #770F0F", +"+ c #8E1414", +"@ c #901212", +"# c #841010", +"$ c #6E0B0B", +"% c #801515", +"& c #952222", +"* c #D23F3F", +"= c #D53939", +"- c #D02C2C", +"; c #C32424", +"> c #B71E1E", +", c #7D0D0D", +"' c #730A0A", +") c #8D1A1A", +"! c #DA5555", +"~ c #E47878", +"{ c #E68080", +"] c #E36868", +"^ c #DB4343", +"/ c #D22D2D", +"( c #C82323", +"_ c #BB1D1D", +": c #A91919", +"< c #760B0B", +"[ c #7F1111", +"} c #D64A4A", +"| c #EB8787", +"1 c #F2AFAF", +"2 c #EA8C8C", +"3 c #E05C5C", +"4 c #DB3535", +"5 c #D22828", +"6 c #C22020", +"7 c #AE1B1B", +"8 c #991212", +"9 c #650505", +"0 c #951A1A", +"a c #E15B5B", +"b c #EE9A9A", +"c c #F5BBBB", +"d c #F6B8B8", +"e c #ED9292", +"f c #E25F5F", +"g c #DE3838", +"h c #D52A2A", +"i c #C32121", +"j c #AC1919", +"k c #991414", +"l c #750909", +"m c #6E0C0C", +"n c #D02F2F", +"o c #E05757", +"p c #EC8B8B", +"q c #F0A3A3", +"r c #F29E9E", +"s c #E87A7A", +"t c #E14D4D", +"u c #DA3131", +"v c #CF2626", +"w c #BD1F1F", +"x c #AA1919", +"y c #9B1313", +"z c #8F1010", +"A c #5E0101", +"B c #7E1010", +"C c #CE2E2E", +"D c #DC4A4A", +"E c #E66969", +"F c #E77575", +"G c #E56969", +"H c #E04F4F", +"I c #DD3434", +"J c #D32929", +"K c #C72323", +"L c #B51D1D", +"M c #A41818", +"N c #971515", +"O c #8B1010", +"P c #640404", +"Q c #7F1010", +"R c #CB2B2B", +"S c #D64040", +"T c #DE4E4E", +"U c #E04D4D", +"V c #DD4141", +"W c #DA3434", +"X c #D52929", +"Y c #CB2424", +"Z c #C02020", +"` c #B11A1A", +" . c #A11616", +".. c #941313", +"+. c #891010", +"@. c #650707", +"#. c #750D0D", +"$. c #C02525", +"%. c #CB3232", +"&. c #D13B3B", +"*. c #D53A3A", +"=. c #D33232", +"-. c #D02929", +";. c #CB2525", +">. c #C32222", +",. c #B91D1D", +"'. c #AD1919", +"). c #9E1414", +"!. c #8E1111", +"~. c #820C0C", +"{. c #600505", +"]. c #5F0707", +"^. c #B41D1D", +"/. c #BD2424", +"(. c #C22828", +"_. c #C32626", +":. c #C62424", +"<. c #C52323", +"[. c #C12121", +"}. c #BD2020", +"|. c #B21B1B", +"1. c #A51818", +"2. c #961414", +"3. c #870E0E", +"4. c #780A0A", +"5. c #540000", +"6. c #810F0F", +"7. c #AD1B1B", +"8. c #B31D1D", +"9. c #B61E1E", +"0. c #B91F1F", +"a. c #B91E1E", +"b. c #B81E1E", +"c. c #B51C1C", +"d. c #AB1A1A", +"e. c #9A1414", +"f. c #870F0F", +"g. c #790A0A", +"h. c #6B0707", +"i. c #490000", +"j. c #5B0505", +"k. c #9E1616", +"l. c #A41717", +"m. c #A81818", +"n. c #AB1919", +"o. c #A41616", +"p. c #8C0F0F", +"q. c #790B0B", +"r. c #6F0909", +"s. c #7F7F7F", +"t. c #610606", +"u. c #981414", +"v. c #991313", +"w. c #961313", +"x. c #901010", +"y. c #7B0C0C", +"z. c #700909", +"A. c #590202", +"B. c #440000", +"C. c #560202", +"D. c #700A0A", +"E. c #850F0F", +"F. c #840D0D", +"G. c #800D0D", +"H. c #7D0C0C", +"I. c #770A0A", +"J. c #6C0505", +"K. c #540101", +"L. c #500000", +"M. c #560303", +"N. c #5A0404", +"O. c #580303", +"P. c #520202", +" ", +" ", +" . + @ # $ ", +" % & * = - ; > , ' ", +" ) ! ~ { ] ^ / ( _ : < ", +" [ } | 1 1 2 3 4 5 6 7 8 9 ", +" 0 a b c d e f g h i j k l ", +" m n o p q r s t u v w x y z A ", +" B C D E F G H I J K L M N O P ", +" Q R S T U V W X Y Z ` ...+.@. ", +" #.$.%.&.*.=.-.;.>.,.'.).!.~.{. ", +" ].^./.(._.:.<.[.}.|.1.2.3.4.5. ", +" 6.7.8.9.0.a.b.c.d.e.f.g.h.i. ", +" j.k.l.m.n.j n.o.y p.q.r.5.s.s. ", +" t.u.v.k k w.x.3.y.z.A.B.s.s. ", +" C.D.E.F.G.H.I.J.K.B.s.s. ", +" L.M.N.O.P.s.s. ", +" ", +" ", +" "}; -- 2.43.0