mirror of
git://projects.qi-hardware.com/fped.git
synced 2024-11-26 05:19:41 +02:00
Working towards the dragging of frames. Changed the press/drag/release logic of
tables such that items are selected on release and we can thus drag without selecting. (From a user point of view, selecting would be fine. But selecting may sometimes cause a change_world or similar, destroying the widget, which upsets drag and drop.) - gui_frame_drag.c (setup_var_drag, setup_value_drag): moved targets to file scope - gui_frame_drag.c (has_target, drag_var_motion, drag_value_motion): Gtk doesn't check target compatibility for us, so we have to do this explicitly - gui_frame_drag.c (drag_begin): don't leak the pixbuf - gui_frame_drag.c (is_dragging, drag_end), gui_frame_drag.h: for drag vs. activations on button release, we now can test what is being dragged. For this, we have to explicitly clear the variable "dragging" when done. - gui_frame_drag.c (setup_var_drag, setup_value_drag): moved common setup to setup_drag_common - gui_frame_drag.c (setup_frame_drag, drag_frame_motion), gui_frame_drag.h, gui_frame.c (frame_select_event, build_frame_label): added infrastructure for dragging frames - gui_frame_drag.c (setup_canvas_drag, drag_canvas_motion), gui_frame_drag.h, gui_canvas.c (motion_notify_event, make_canvas): added infrastructure for dragging to the canvas - gui_frame.c (table_var_select_event, table_value_select_event, build_table): split logic into press and release action, so that we can drag without implicitly selecting git-svn-id: http://svn.openmoko.org/trunk/eda/fped@5930 99fdad57-331a-0410-800a-d7fa5415bdb3
This commit is contained in:
parent
093a34f860
commit
a4d2926b2d
@ -24,6 +24,7 @@
|
|||||||
#include "gui_status.h"
|
#include "gui_status.h"
|
||||||
#include "gui_tool.h"
|
#include "gui_tool.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
#include "gui_frame_drag.h"
|
||||||
#include "gui_canvas.h"
|
#include "gui_canvas.h"
|
||||||
|
|
||||||
|
|
||||||
@ -182,7 +183,7 @@ static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event,
|
|||||||
if (event->state & GDK_BUTTON2_MASK)
|
if (event->state & GDK_BUTTON2_MASK)
|
||||||
drag_middle(pos);
|
drag_middle(pos);
|
||||||
update_pos(pos);
|
update_pos(pos);
|
||||||
return TRUE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -541,6 +542,8 @@ GtkWidget *make_canvas(void)
|
|||||||
|
|
||||||
gtk_widget_set_double_buffered(canvas, FALSE);
|
gtk_widget_set_double_buffered(canvas, FALSE);
|
||||||
|
|
||||||
|
setup_canvas_drag(canvas);
|
||||||
|
|
||||||
draw_ctx.widget = canvas;
|
draw_ctx.widget = canvas;
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
|
91
gui_frame.c
91
gui_frame.c
@ -886,30 +886,59 @@ static void set_row_values(void *user, const struct value *values,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean table_var_select_event(GtkWidget *widget,
|
static gboolean table_var_press_event(GtkWidget *widget,
|
||||||
|
GdkEventButton *event, gpointer data)
|
||||||
|
{
|
||||||
|
struct var *var = data;
|
||||||
|
|
||||||
|
switch (event->button) {
|
||||||
|
case 3:
|
||||||
|
pop_up_table_var(var, event);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean table_var_release_event(GtkWidget *widget,
|
||||||
GdkEventButton *event, gpointer data)
|
GdkEventButton *event, gpointer data)
|
||||||
{
|
{
|
||||||
struct var *var = data;
|
struct var *var = data;
|
||||||
|
|
||||||
switch (event->button) {
|
switch (event->button) {
|
||||||
case 1:
|
case 1:
|
||||||
|
if (is_dragging(var))
|
||||||
|
return FALSE;
|
||||||
edit_var(var, set_col_values, var, -1);
|
edit_var(var, set_col_values, var, -1);
|
||||||
return FALSE;
|
return TRUE;
|
||||||
case 3:
|
|
||||||
pop_up_table_var(var, event);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return TRUE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean table_value_select_event(GtkWidget *widget,
|
static gboolean table_value_press_event(GtkWidget *widget,
|
||||||
|
GdkEventButton *event, gpointer data)
|
||||||
|
{
|
||||||
|
struct value *value = data;
|
||||||
|
|
||||||
|
switch (event->button) {
|
||||||
|
case 3:
|
||||||
|
pop_up_table_value(value, event);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean table_value_release_event(GtkWidget *widget,
|
||||||
GdkEventButton *event, gpointer data)
|
GdkEventButton *event, gpointer data)
|
||||||
{
|
{
|
||||||
struct value *value = data;
|
struct value *value = data;
|
||||||
|
|
||||||
switch (event->button) {
|
switch (event->button) {
|
||||||
case 1:
|
case 1:
|
||||||
|
if (is_dragging(value))
|
||||||
|
return FALSE;
|
||||||
if (!value->row ||
|
if (!value->row ||
|
||||||
value->row->table->active_row == value->row) {
|
value->row->table->active_row == value->row) {
|
||||||
edit_nothing();
|
edit_nothing();
|
||||||
@ -919,12 +948,9 @@ static gboolean table_value_select_event(GtkWidget *widget,
|
|||||||
select_row(value->row);
|
select_row(value->row);
|
||||||
change_world();
|
change_world();
|
||||||
}
|
}
|
||||||
return FALSE;
|
return TRUE;
|
||||||
case 3:
|
|
||||||
pop_up_table_value(value, event);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return TRUE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1009,7 +1035,10 @@ static void build_table(GtkWidget *vbox, struct frame *frame,
|
|||||||
label_in_box_bg(field, COLOR_VAR_PASSIVE);
|
label_in_box_bg(field, COLOR_VAR_PASSIVE);
|
||||||
g_signal_connect(G_OBJECT(box_of_label(field)),
|
g_signal_connect(G_OBJECT(box_of_label(field)),
|
||||||
"button_press_event",
|
"button_press_event",
|
||||||
G_CALLBACK(table_var_select_event), var);
|
G_CALLBACK(table_var_press_event), var);
|
||||||
|
g_signal_connect(G_OBJECT(box_of_label(field)),
|
||||||
|
"button_release_event",
|
||||||
|
G_CALLBACK(table_var_release_event), var);
|
||||||
g_signal_connect(G_OBJECT(box_of_label(field)),
|
g_signal_connect(G_OBJECT(box_of_label(field)),
|
||||||
"scroll_event",
|
"scroll_event",
|
||||||
G_CALLBACK(table_scroll_event), table);
|
G_CALLBACK(table_scroll_event), table);
|
||||||
@ -1034,7 +1063,10 @@ static void build_table(GtkWidget *vbox, struct frame *frame,
|
|||||||
COLOR_ROW_SELECTED : COLOR_ROW_UNSELECTED);
|
COLOR_ROW_SELECTED : COLOR_ROW_UNSELECTED);
|
||||||
g_signal_connect(G_OBJECT(box_of_label(field)),
|
g_signal_connect(G_OBJECT(box_of_label(field)),
|
||||||
"button_press_event",
|
"button_press_event",
|
||||||
G_CALLBACK(table_value_select_event), value);
|
G_CALLBACK(table_value_press_event), value);
|
||||||
|
g_signal_connect(G_OBJECT(box_of_label(field)),
|
||||||
|
"button_release_event",
|
||||||
|
G_CALLBACK(table_value_release_event), value);
|
||||||
g_signal_connect(G_OBJECT(box_of_label(field)),
|
g_signal_connect(G_OBJECT(box_of_label(field)),
|
||||||
"scroll_event",
|
"scroll_event",
|
||||||
G_CALLBACK(table_scroll_event), table);
|
G_CALLBACK(table_scroll_event), table);
|
||||||
@ -1653,13 +1685,29 @@ void select_frame(struct frame *frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean frame_select_event(GtkWidget *widget, GdkEventButton *event,
|
static gboolean frame_press_event(GtkWidget *widget, GdkEventButton *event,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
struct frame *frame = data;
|
||||||
|
|
||||||
|
switch (event->button) {
|
||||||
|
case 3:
|
||||||
|
pop_up_frame(frame, event);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean frame_release_event(GtkWidget *widget, GdkEventButton *event,
|
||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
struct frame *frame = data;
|
struct frame *frame = data;
|
||||||
|
|
||||||
switch (event->button) {
|
switch (event->button) {
|
||||||
case 1:
|
case 1:
|
||||||
|
if (is_dragging(frame))
|
||||||
|
return FALSE;
|
||||||
if (active_frame != frame)
|
if (active_frame != frame)
|
||||||
select_frame(frame);
|
select_frame(frame);
|
||||||
else {
|
else {
|
||||||
@ -1668,12 +1716,9 @@ static gboolean frame_select_event(GtkWidget *widget, GdkEventButton *event,
|
|||||||
edit_frame(frame);
|
edit_frame(frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
return TRUE;
|
||||||
case 3:
|
|
||||||
pop_up_frame(frame, event);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return TRUE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1691,9 +1736,13 @@ static GtkWidget *build_frame_label(struct frame *frame)
|
|||||||
COLOR_FRAME_SELECTED : COLOR_FRAME_UNSELECTED);
|
COLOR_FRAME_SELECTED : COLOR_FRAME_UNSELECTED);
|
||||||
|
|
||||||
g_signal_connect(G_OBJECT(box_of_label(label)),
|
g_signal_connect(G_OBJECT(box_of_label(label)),
|
||||||
"button_press_event", G_CALLBACK(frame_select_event), frame);
|
"button_press_event", G_CALLBACK(frame_press_event), frame);
|
||||||
|
g_signal_connect(G_OBJECT(box_of_label(label)),
|
||||||
|
"button_release_event", G_CALLBACK(frame_release_event), frame);
|
||||||
frame->label = label;
|
frame->label = label;
|
||||||
|
|
||||||
|
setup_frame_drag(frame);
|
||||||
|
|
||||||
return box_of_label(label);
|
return box_of_label(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
158
gui_frame_drag.c
158
gui_frame_drag.c
@ -18,12 +18,49 @@
|
|||||||
#include "gui_frame_drag.h"
|
#include "gui_frame_drag.h"
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
target_id_var,
|
||||||
|
target_id_value,
|
||||||
|
target_id_frame,
|
||||||
|
target_id_canvas,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static GtkTargetEntry target_var = {
|
||||||
|
.target = "var",
|
||||||
|
.flags = GTK_TARGET_SAME_APP,
|
||||||
|
.info = target_id_var,
|
||||||
|
};
|
||||||
|
|
||||||
|
static GtkTargetEntry target_value = {
|
||||||
|
.target = "value",
|
||||||
|
.flags = GTK_TARGET_SAME_APP,
|
||||||
|
.info = target_id_value,
|
||||||
|
};
|
||||||
|
|
||||||
|
static GtkTargetEntry target_frame = {
|
||||||
|
.target = "frame",
|
||||||
|
.flags = GTK_TARGET_SAME_APP,
|
||||||
|
.info = target_id_frame,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- dragging status --------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pointer to whatever it is we're dragging. Undefined if not dragging.
|
* Pointer to whatever it is we're dragging. NULL if not dragging.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void *dragging;
|
static void *dragging;
|
||||||
|
|
||||||
|
|
||||||
|
int is_dragging(void *this)
|
||||||
|
{
|
||||||
|
return this == dragging;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----- helper functions for indexed list and swapping -------------------- */
|
/* ----- helper functions for indexed list and swapping -------------------- */
|
||||||
|
|
||||||
|
|
||||||
@ -148,7 +185,27 @@ static void swap_rows(struct row **a, struct row **b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----- common callback --------------------------------------------------- */
|
/* ----- common functions -------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* according to
|
||||||
|
* http://www.pubbs.net/201004/gtk/22819-re-drag-and-drop-drag-motion-cursor-lockup-fixed-.html
|
||||||
|
* http://www.cryingwolf.org/articles/gtk-dnd.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int has_target(GtkWidget *widget, GdkDragContext *drag_context,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
GdkAtom target;
|
||||||
|
|
||||||
|
target = gtk_drag_dest_find_target(widget, drag_context, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Force allocation so that we don't have to check for GDK_NONE.
|
||||||
|
*/
|
||||||
|
return target == gdk_atom_intern(name, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void drag_begin(GtkWidget *widget,
|
static void drag_begin(GtkWidget *widget,
|
||||||
@ -163,11 +220,28 @@ static void drag_begin(GtkWidget *widget,
|
|||||||
pixbuf =
|
pixbuf =
|
||||||
gdk_pixbuf_get_from_drawable(NULL, DA, NULL, 0, 0, 0, 0, 1, 1);
|
gdk_pixbuf_get_from_drawable(NULL, DA, NULL, 0, 0, 0, 0, 1, 1);
|
||||||
gtk_drag_source_set_icon_pixbuf(widget, pixbuf);
|
gtk_drag_source_set_icon_pixbuf(widget, pixbuf);
|
||||||
|
g_object_unref(pixbuf);
|
||||||
|
|
||||||
dragging = user_data;
|
dragging = user_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void drag_end(GtkWidget *widget, GdkDragContext *drag_context,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
dragging = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void setup_drag_common(GtkWidget *widget, void *user_arg)
|
||||||
|
{
|
||||||
|
g_signal_connect(G_OBJECT(widget), "drag-begin",
|
||||||
|
G_CALLBACK(drag_begin), user_arg);
|
||||||
|
g_signal_connect(G_OBJECT(widget), "drag-end",
|
||||||
|
G_CALLBACK(drag_end), user_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----- drag variables ---------------------------------------------------- */
|
/* ----- drag variables ---------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
@ -179,6 +253,8 @@ static gboolean drag_var_motion(GtkWidget *widget,
|
|||||||
struct var *to = user_data;
|
struct var *to = user_data;
|
||||||
int from_n, to_n, i;
|
int from_n, to_n, i;
|
||||||
|
|
||||||
|
if (!has_target(widget, drag_context, "var"))
|
||||||
|
return FALSE;
|
||||||
if (from == to || from->table != to->table)
|
if (from == to || from->table != to->table)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
from_n = NDX(from->table->vars, from);
|
from_n = NDX(from->table->vars, from);
|
||||||
@ -192,19 +268,14 @@ static gboolean drag_var_motion(GtkWidget *widget,
|
|||||||
|
|
||||||
void setup_var_drag(struct var *var)
|
void setup_var_drag(struct var *var)
|
||||||
{
|
{
|
||||||
static GtkTargetEntry target = {
|
|
||||||
.target = "var",
|
|
||||||
.flags = GTK_TARGET_SAME_APP,
|
|
||||||
};
|
|
||||||
GtkWidget *box;
|
GtkWidget *box;
|
||||||
|
|
||||||
box = box_of_label(var->widget);
|
box = box_of_label(var->widget);
|
||||||
gtk_drag_source_set(box, GDK_BUTTON1_MASK,
|
gtk_drag_source_set(box, GDK_BUTTON1_MASK,
|
||||||
&target, 1, GDK_ACTION_PRIVATE);
|
&target_var, 1, GDK_ACTION_PRIVATE);
|
||||||
gtk_drag_dest_set(box, GTK_DEST_DEFAULT_HIGHLIGHT,
|
gtk_drag_dest_set(box, GTK_DEST_DEFAULT_HIGHLIGHT,
|
||||||
&target, 1, GDK_ACTION_PRIVATE);
|
&target_var, 1, GDK_ACTION_PRIVATE);
|
||||||
g_signal_connect(G_OBJECT(box), "drag-begin",
|
setup_drag_common(box, var);
|
||||||
G_CALLBACK(drag_begin), var);
|
|
||||||
g_signal_connect(G_OBJECT(box), "drag-motion",
|
g_signal_connect(G_OBJECT(box), "drag-motion",
|
||||||
G_CALLBACK(drag_var_motion), var);
|
G_CALLBACK(drag_var_motion), var);
|
||||||
}
|
}
|
||||||
@ -219,10 +290,13 @@ static gboolean drag_value_motion(GtkWidget *widget,
|
|||||||
{
|
{
|
||||||
struct value *from = dragging;
|
struct value *from = dragging;
|
||||||
struct value *to = user_data;
|
struct value *to = user_data;
|
||||||
struct table *table = from->row->table;
|
struct table *table;
|
||||||
struct row **row, *end;
|
struct row **row, *end;
|
||||||
int from_n, to_n, i;
|
int from_n, to_n, i;
|
||||||
|
|
||||||
|
if (!has_target(widget, drag_context, "value"))
|
||||||
|
return FALSE;
|
||||||
|
table = from->row->table;
|
||||||
if (table != to->row->table)
|
if (table != to->row->table)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@ -263,19 +337,65 @@ static gboolean drag_value_motion(GtkWidget *widget,
|
|||||||
|
|
||||||
void setup_value_drag(struct value *value)
|
void setup_value_drag(struct value *value)
|
||||||
{
|
{
|
||||||
static GtkTargetEntry target = {
|
|
||||||
.target = "value",
|
|
||||||
.flags = GTK_TARGET_SAME_APP,
|
|
||||||
};
|
|
||||||
GtkWidget *box;
|
GtkWidget *box;
|
||||||
|
|
||||||
box = box_of_label(value->widget);
|
box = box_of_label(value->widget);
|
||||||
gtk_drag_source_set(box, GDK_BUTTON1_MASK,
|
gtk_drag_source_set(box, GDK_BUTTON1_MASK,
|
||||||
&target, 1, GDK_ACTION_PRIVATE);
|
&target_value, 1, GDK_ACTION_PRIVATE);
|
||||||
gtk_drag_dest_set(box, GTK_DEST_DEFAULT_HIGHLIGHT,
|
gtk_drag_dest_set(box, GTK_DEST_DEFAULT_HIGHLIGHT,
|
||||||
&target, 1, GDK_ACTION_PRIVATE);
|
&target_value, 1, GDK_ACTION_PRIVATE);
|
||||||
g_signal_connect(G_OBJECT(box), "drag-begin",
|
setup_drag_common(box, value);
|
||||||
G_CALLBACK(drag_begin), value);
|
|
||||||
g_signal_connect(G_OBJECT(box), "drag-motion",
|
g_signal_connect(G_OBJECT(box), "drag-motion",
|
||||||
G_CALLBACK(drag_value_motion), value);
|
G_CALLBACK(drag_value_motion), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- drag frame labels ------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean drag_frame_motion(GtkWidget *widget,
|
||||||
|
GdkDragContext *drag_context, gint x, gint y, guint time_,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
if (!has_target(widget, drag_context, "frame"))
|
||||||
|
return FALSE;
|
||||||
|
//fprintf(stderr, "frame\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setup_frame_drag(struct frame *frame)
|
||||||
|
{
|
||||||
|
GtkWidget *box;
|
||||||
|
|
||||||
|
box = box_of_label(frame->label);
|
||||||
|
gtk_drag_source_set(box, GDK_BUTTON1_MASK,
|
||||||
|
&target_frame, 1, GDK_ACTION_PRIVATE);
|
||||||
|
setup_drag_common(box, frame);
|
||||||
|
g_signal_connect(G_OBJECT(box), "drag-motion",
|
||||||
|
G_CALLBACK(drag_frame_motion), frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----- drag to the canvas ------------------------------------------------ */
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean drag_canvas_motion(GtkWidget *widget,
|
||||||
|
GdkDragContext *drag_context, gint x, gint y, guint time_,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
if (!has_target(widget, drag_context, "frame"))
|
||||||
|
return FALSE;
|
||||||
|
//fprintf(stderr, "canvas\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setup_canvas_drag(GtkWidget *canvas)
|
||||||
|
{
|
||||||
|
gtk_drag_dest_set(canvas, GTK_DEST_DEFAULT_HIGHLIGHT,
|
||||||
|
&target_frame, 1, GDK_ACTION_PRIVATE);
|
||||||
|
setup_drag_common(canvas, NULL);
|
||||||
|
g_signal_connect(G_OBJECT(canvas), "drag-motion",
|
||||||
|
G_CALLBACK(drag_canvas_motion), NULL);
|
||||||
|
}
|
||||||
|
@ -19,7 +19,11 @@
|
|||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
|
|
||||||
|
|
||||||
|
int is_dragging(void *this);
|
||||||
|
|
||||||
void setup_var_drag(struct var *var);
|
void setup_var_drag(struct var *var);
|
||||||
void setup_value_drag(struct value *value);
|
void setup_value_drag(struct value *value);
|
||||||
|
void setup_frame_drag(struct frame *frame);
|
||||||
|
void setup_canvas_drag(GtkWidget *canvas);
|
||||||
|
|
||||||
#endif /* !GUI_FRAME_DRAG_H */
|
#endif /* !GUI_FRAME_DRAG_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user