mirror of https://github.com/Gnucash/gnucash
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1817 lines
48 KiB
1817 lines
48 KiB
/* File import from bonoboui to gnumeric by import-bonobo. Do not edit. */
|
|
|
|
/* go-dock.c
|
|
|
|
Copyright (C) 1998 Free Software Foundation
|
|
|
|
The Gnome Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
The Gnome Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with the Gnome Library; see the file COPYING.LIB. If not,
|
|
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
Boston, MA 02111-1307, USA.
|
|
|
|
Author: Ettore Perazzoli <ettore@comm2000.it>
|
|
*/
|
|
/*
|
|
@NOTATION@
|
|
*/
|
|
|
|
#include "gnumeric-config.h"
|
|
#include <glib/gi18n.h>
|
|
#include <string.h>
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
#include "go-dock.h"
|
|
#include "go-dock-band.h"
|
|
#include "go-dock-item.h"
|
|
#include <libgnome/gnome-macros.h>
|
|
|
|
GNOME_CLASS_BOILERPLATE (GoDock, go_dock,
|
|
GtkContainer, GTK_TYPE_CONTAINER);
|
|
|
|
#define noBONOBO_DOCK_DEBUG
|
|
|
|
/* FIXME: To be removed. */
|
|
#if defined GO_DOCK_DEBUG && defined __GNUC__
|
|
#define DEBUG(x) \
|
|
do \
|
|
{ \
|
|
printf ("%s.%d: ", __FUNCTION__, __LINE__); \
|
|
printf x; \
|
|
putchar ('\n'); \
|
|
} \
|
|
while (0)
|
|
#else
|
|
#define DEBUG(x)
|
|
#endif
|
|
|
|
|
|
|
|
struct _GoDockPrivate
|
|
{
|
|
GdkDragContext *current_drag;
|
|
};
|
|
|
|
enum {
|
|
LAYOUT_CHANGED,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
|
|
|
|
static void go_dock_size_request (GtkWidget *widget,
|
|
GtkRequisition *requisition);
|
|
static void go_dock_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation);
|
|
static void go_dock_map (GtkWidget *widget);
|
|
static void go_dock_unmap (GtkWidget *widget);
|
|
static void go_dock_add (GtkContainer *container,
|
|
GtkWidget *child);
|
|
static void go_dock_remove (GtkContainer *container,
|
|
GtkWidget *widget);
|
|
static void go_dock_forall (GtkContainer *container,
|
|
gboolean include_internals,
|
|
GtkCallback callback,
|
|
gpointer callback_data);
|
|
static void go_dock_finalize (GObject *object);
|
|
|
|
static void size_request_v (GList *list,
|
|
GtkRequisition *requisition);
|
|
static void size_request_h (GList *list,
|
|
GtkRequisition *requisition);
|
|
static gint size_allocate_v (GList *list,
|
|
gint start_x, gint start_y,
|
|
guint width, gint direction);
|
|
static gint size_allocate_h (GList *list,
|
|
gint start_x, gint start_y,
|
|
guint width, gint direction);
|
|
static void map_widget (GtkWidget *w);
|
|
static void map_widget_foreach (gpointer data,
|
|
gpointer user_data);
|
|
static void map_band_list (GList *list);
|
|
static void unmap_widget (GtkWidget *w);
|
|
static void unmap_widget_foreach (gpointer data,
|
|
gpointer user_data);
|
|
static void unmap_band_list (GList *list);
|
|
static gboolean remove_from_band_list (GList **list,
|
|
GoDockBand *child);
|
|
static void forall_helper (GList *list,
|
|
GtkCallback callback,
|
|
gpointer callback_data);
|
|
|
|
static void drag_begin (GtkWidget *widget,
|
|
gpointer data);
|
|
static void drag_end_bands (GList **list,
|
|
GoDockItem *item);
|
|
static void drag_end (GtkWidget *widget,
|
|
gpointer data);
|
|
static gboolean drag_new (GoDock *dock,
|
|
GoDockItem *item,
|
|
GList **area,
|
|
GList *where,
|
|
gint x, gint y,
|
|
gboolean is_vertical);
|
|
static gboolean drag_to (GoDock *dock,
|
|
GoDockItem *item,
|
|
GList *where,
|
|
gint x, gint y,
|
|
gboolean is_vertical);
|
|
static gboolean drag_floating (GoDock *dock,
|
|
GoDockItem *item,
|
|
gint x, gint y,
|
|
gint rel_x, gint rel_y);
|
|
static gboolean drag_check (GoDock *dock,
|
|
GoDockItem *item,
|
|
GList **area,
|
|
gint x, gint y,
|
|
gboolean is_vertical);
|
|
static void drag_snap (GoDock *dock,
|
|
GtkWidget *widget,
|
|
gint x, gint y);
|
|
static void drag_motion (GtkWidget *widget,
|
|
gint x, gint y,
|
|
gpointer data);
|
|
|
|
static GoDockItem *get_docked_item_by_name (GoDock *dock,
|
|
const gchar *name,
|
|
GoDockPlacement *placement_return,
|
|
guint *num_band_return,
|
|
guint *band_position_return,
|
|
guint *offset_return);
|
|
static GoDockItem *get_floating_item_by_name (GoDock *dock,
|
|
const gchar *name);
|
|
|
|
static void connect_drag_signals (GoDock *dock,
|
|
GtkWidget *item);
|
|
|
|
|
|
static guint dock_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
|
|
static void
|
|
go_dock_class_init (GoDockClass *class)
|
|
{
|
|
GtkObjectClass *object_class;
|
|
GObjectClass *gobject_class;
|
|
GtkWidgetClass *widget_class;
|
|
GtkContainerClass *container_class;
|
|
|
|
object_class = (GtkObjectClass *) class;
|
|
gobject_class = (GObjectClass *) class;
|
|
widget_class = (GtkWidgetClass *) class;
|
|
container_class = (GtkContainerClass *) class;
|
|
|
|
gobject_class->finalize = go_dock_finalize;
|
|
|
|
widget_class->size_request = go_dock_size_request;
|
|
widget_class->size_allocate = go_dock_size_allocate;
|
|
widget_class->map = go_dock_map;
|
|
widget_class->unmap = go_dock_unmap;
|
|
|
|
container_class->add = go_dock_add;
|
|
container_class->remove = go_dock_remove;
|
|
container_class->forall = go_dock_forall;
|
|
|
|
dock_signals[LAYOUT_CHANGED] =
|
|
g_signal_new ("layout_changed",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (GoDockClass,
|
|
layout_changed),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE,
|
|
0);
|
|
}
|
|
|
|
static void
|
|
go_dock_instance_init (GoDock *dock)
|
|
{
|
|
GTK_WIDGET_SET_FLAGS (GTK_WIDGET (dock), GTK_NO_WINDOW);
|
|
|
|
dock->_priv = NULL;
|
|
/* XXX: when there is some private stuff enable this
|
|
dock->_priv = g_new0(GoDockPrivate, 1);
|
|
*/
|
|
|
|
dock->client_area = NULL;
|
|
|
|
dock->top_bands = NULL;
|
|
dock->bottom_bands = NULL;
|
|
dock->right_bands = NULL;
|
|
dock->left_bands = NULL;
|
|
|
|
dock->floating_children = NULL;
|
|
|
|
dock->floating_items_allowed = TRUE;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
size_request_v (GList *list, GtkRequisition *requisition)
|
|
{
|
|
for (; list != NULL; list = list->next)
|
|
{
|
|
GtkWidget *w;
|
|
GtkRequisition req;
|
|
|
|
w = GTK_WIDGET (list->data);
|
|
gtk_widget_size_request (w, &req);
|
|
requisition->width += req.width;
|
|
requisition->height = MAX (requisition->height, req.height);
|
|
}
|
|
}
|
|
|
|
static void
|
|
size_request_h (GList *list, GtkRequisition *requisition)
|
|
{
|
|
for (list = list; list != NULL; list = list->next)
|
|
{
|
|
GtkWidget *w;
|
|
GtkRequisition req;
|
|
|
|
w = GTK_WIDGET (list->data);
|
|
gtk_widget_size_request (w, &req);
|
|
requisition->height += req.height;
|
|
requisition->width = MAX (requisition->width, req.width);
|
|
}
|
|
}
|
|
|
|
static void
|
|
go_dock_size_request (GtkWidget *widget, GtkRequisition *requisition)
|
|
{
|
|
GoDock *dock;
|
|
GList *lp;
|
|
|
|
dock = GO_DOCK (widget);
|
|
|
|
if (dock->client_area != NULL && GTK_WIDGET_VISIBLE (dock->client_area))
|
|
gtk_widget_size_request (dock->client_area, requisition);
|
|
else
|
|
{
|
|
requisition->width = 0;
|
|
requisition->height = 0;
|
|
}
|
|
|
|
size_request_v (dock->left_bands, requisition);
|
|
size_request_v (dock->right_bands, requisition);
|
|
size_request_h (dock->top_bands, requisition);
|
|
size_request_h (dock->bottom_bands, requisition);
|
|
|
|
lp = dock->floating_children;
|
|
while (lp != NULL)
|
|
{
|
|
GtkWidget *w;
|
|
GtkRequisition float_item_requisition;
|
|
|
|
w = lp->data;
|
|
lp = lp->next;
|
|
gtk_widget_size_request (w, &float_item_requisition);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static gint
|
|
size_allocate_h (GList *list, gint start_x, gint start_y, guint width,
|
|
gint direction)
|
|
{
|
|
GtkAllocation allocation;
|
|
|
|
allocation.x = start_x;
|
|
allocation.y = start_y;
|
|
allocation.width = width;
|
|
|
|
if (direction < 0)
|
|
list = g_list_last (list);
|
|
while (list != NULL)
|
|
{
|
|
GtkWidget *w;
|
|
|
|
w = GTK_WIDGET (list->data);
|
|
allocation.height = w->requisition.height;
|
|
|
|
if (direction > 0)
|
|
{
|
|
gtk_widget_size_allocate (w, &allocation);
|
|
allocation.y += allocation.height;
|
|
list = list->next;
|
|
}
|
|
else
|
|
{
|
|
allocation.y -= allocation.height;
|
|
gtk_widget_size_allocate (w, &allocation);
|
|
list = list->prev;
|
|
}
|
|
}
|
|
|
|
return allocation.y;
|
|
}
|
|
|
|
static gint
|
|
size_allocate_v (GList *list, gint start_x, gint start_y, guint height,
|
|
gint direction)
|
|
{
|
|
GtkAllocation allocation;
|
|
|
|
allocation.x = start_x;
|
|
allocation.y = start_y;
|
|
allocation.height = height;
|
|
|
|
if (direction < 0)
|
|
list = g_list_last (list);
|
|
|
|
while (list != NULL)
|
|
{
|
|
GtkWidget *w;
|
|
|
|
w = GTK_WIDGET (list->data);
|
|
allocation.width = w->requisition.width;
|
|
|
|
if (direction > 0)
|
|
{
|
|
gtk_widget_size_allocate (w, &allocation);
|
|
allocation.x += allocation.width;
|
|
list = list->next;
|
|
}
|
|
else
|
|
{
|
|
allocation.x -= allocation.width;
|
|
gtk_widget_size_allocate (w, &allocation);
|
|
list = list->prev;
|
|
}
|
|
}
|
|
|
|
return allocation.x;
|
|
}
|
|
|
|
static void
|
|
go_dock_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
|
|
{
|
|
GoDock *dock;
|
|
gint top_bands_y, bottom_bands_y;
|
|
gint left_bands_x, right_bands_x;
|
|
GtkAllocation child_allocation;
|
|
GList *lp;
|
|
|
|
dock = GO_DOCK (widget);
|
|
|
|
widget->allocation = *allocation;
|
|
|
|
top_bands_y = size_allocate_h (dock->top_bands,
|
|
allocation->x,
|
|
allocation->y,
|
|
allocation->width,
|
|
+1);
|
|
|
|
bottom_bands_y = size_allocate_h (dock->bottom_bands,
|
|
allocation->x,
|
|
allocation->y + allocation->height,
|
|
allocation->width,
|
|
-1);
|
|
|
|
child_allocation.height = MAX (bottom_bands_y - top_bands_y, 1);
|
|
|
|
left_bands_x = size_allocate_v (dock->left_bands,
|
|
allocation->x,
|
|
top_bands_y,
|
|
child_allocation.height,
|
|
+1);
|
|
|
|
right_bands_x = size_allocate_v (dock->right_bands,
|
|
allocation->x + allocation->width,
|
|
top_bands_y,
|
|
child_allocation.height,
|
|
-1);
|
|
|
|
child_allocation.width = MAX (right_bands_x - left_bands_x, 1);
|
|
|
|
child_allocation.x = left_bands_x;
|
|
child_allocation.y = top_bands_y;
|
|
|
|
dock->client_rect = child_allocation;
|
|
|
|
if (dock->client_area != NULL && GTK_WIDGET_VISIBLE (dock->client_area))
|
|
gtk_widget_size_allocate (dock->client_area, &child_allocation);
|
|
|
|
lp = dock->floating_children;
|
|
while (lp != NULL)
|
|
{
|
|
GtkWidget *w;
|
|
GtkAllocation float_item_allocation;
|
|
|
|
w = lp->data;
|
|
lp = lp->next;
|
|
float_item_allocation.x = 0;
|
|
float_item_allocation.y = 0;
|
|
float_item_allocation.width = w->requisition.width;
|
|
float_item_allocation.height = w->requisition.height;
|
|
gtk_widget_size_allocate (w, &float_item_allocation);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
map_widget (GtkWidget *w)
|
|
{
|
|
if (w != NULL && GTK_WIDGET_VISIBLE (w) && ! GTK_WIDGET_MAPPED (w))
|
|
gtk_widget_map (w);
|
|
}
|
|
|
|
static void
|
|
unmap_widget (GtkWidget *w)
|
|
{
|
|
if (w != NULL && GTK_WIDGET_VISIBLE (w) && GTK_WIDGET_MAPPED (w))
|
|
gtk_widget_unmap (w);
|
|
}
|
|
|
|
static void
|
|
map_widget_foreach (gpointer data,
|
|
gpointer user_data)
|
|
{
|
|
map_widget (GTK_WIDGET (data));
|
|
}
|
|
|
|
static void
|
|
unmap_widget_foreach (gpointer data,
|
|
gpointer user_data)
|
|
{
|
|
unmap_widget (GTK_WIDGET (data));
|
|
}
|
|
|
|
static void
|
|
map_band_list (GList *list)
|
|
{
|
|
while (list != NULL)
|
|
{
|
|
GtkWidget *w;
|
|
|
|
w = GTK_WIDGET (list->data);
|
|
map_widget (w);
|
|
|
|
list = list->next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
unmap_band_list (GList *list)
|
|
{
|
|
while (list != NULL)
|
|
{
|
|
GtkWidget *w;
|
|
|
|
w = GTK_WIDGET (list->data);
|
|
unmap_widget (w);
|
|
|
|
list = list->next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
go_dock_map (GtkWidget *widget)
|
|
{
|
|
GoDock *dock;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GO_IS_DOCK(widget));
|
|
|
|
GNOME_CALL_PARENT (GTK_WIDGET_CLASS, map, (widget));
|
|
|
|
dock = GO_DOCK (widget);
|
|
|
|
map_widget (dock->client_area);
|
|
|
|
map_band_list (dock->top_bands);
|
|
map_band_list (dock->bottom_bands);
|
|
map_band_list (dock->left_bands);
|
|
map_band_list (dock->right_bands);
|
|
|
|
g_list_foreach (dock->floating_children, map_widget_foreach, NULL);
|
|
}
|
|
|
|
static void
|
|
go_dock_unmap (GtkWidget *widget)
|
|
{
|
|
GoDock *dock;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GO_IS_DOCK(widget));
|
|
|
|
dock = GO_DOCK (widget);
|
|
|
|
unmap_widget (dock->client_area);
|
|
|
|
unmap_band_list (dock->top_bands);
|
|
unmap_band_list (dock->bottom_bands);
|
|
unmap_band_list (dock->left_bands);
|
|
unmap_band_list (dock->right_bands);
|
|
|
|
g_list_foreach (dock->floating_children, unmap_widget_foreach, NULL);
|
|
|
|
GNOME_CALL_PARENT (GTK_WIDGET_CLASS, unmap, (widget));
|
|
}
|
|
|
|
|
|
|
|
/* GtkContainer methods. */
|
|
|
|
static void
|
|
go_dock_add (GtkContainer *container, GtkWidget *child)
|
|
{
|
|
GoDock *dock;
|
|
|
|
dock = GO_DOCK (container);
|
|
go_dock_add_item (dock, GO_DOCK_ITEM(child), GO_DOCK_TOP, 0, 0, 0, TRUE);
|
|
}
|
|
|
|
static gboolean
|
|
remove_from_band_list (GList **list, GoDockBand *child)
|
|
{
|
|
GList *lp;
|
|
|
|
for (lp = *list; lp != NULL; lp = lp->next)
|
|
{
|
|
if (lp->data == child)
|
|
{
|
|
gtk_widget_unparent (GTK_WIDGET (child));
|
|
*list = g_list_remove_link (*list, lp);
|
|
g_list_free (lp);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
go_dock_remove (GtkContainer *container, GtkWidget *widget)
|
|
{
|
|
GoDock *dock;
|
|
|
|
dock = GO_DOCK (container);
|
|
|
|
if (dock->client_area == widget)
|
|
{
|
|
gtk_widget_unparent (widget);
|
|
dock->client_area = NULL;
|
|
gtk_widget_queue_resize (GTK_WIDGET (dock));
|
|
}
|
|
else
|
|
{
|
|
/* Check if it's a floating child. */
|
|
{
|
|
GList *lp;
|
|
|
|
lp = dock->floating_children;
|
|
while (lp != NULL)
|
|
{
|
|
GtkWidget *w;
|
|
|
|
w = lp->data;
|
|
if (w == widget)
|
|
{
|
|
gtk_widget_unparent (w);
|
|
dock->floating_children
|
|
= g_list_remove_link (dock->floating_children, lp);
|
|
g_list_free (lp);
|
|
return;
|
|
}
|
|
|
|
lp = lp->next;
|
|
}
|
|
}
|
|
|
|
/* Then it must be one of the bands. */
|
|
{
|
|
GoDockBand *band;
|
|
|
|
g_return_if_fail (GO_IS_DOCK_BAND (widget));
|
|
|
|
band = GO_DOCK_BAND (widget);
|
|
if (remove_from_band_list (&dock->top_bands, band)
|
|
|| remove_from_band_list (&dock->bottom_bands, band)
|
|
|| remove_from_band_list (&dock->left_bands, band)
|
|
|| remove_from_band_list (&dock->right_bands, band))
|
|
{
|
|
gtk_widget_queue_resize (GTK_WIDGET (dock));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
forall_helper (GList *list,
|
|
GtkCallback callback,
|
|
gpointer callback_data)
|
|
{
|
|
while (list != NULL)
|
|
{
|
|
GtkWidget *w;
|
|
|
|
w = GTK_WIDGET(list->data);
|
|
list = list->next;
|
|
(* callback) (w, callback_data);
|
|
}
|
|
}
|
|
|
|
static void
|
|
go_dock_forall (GtkContainer *container,
|
|
gboolean include_internals,
|
|
GtkCallback callback,
|
|
gpointer callback_data)
|
|
{
|
|
GoDock *dock;
|
|
GList *lp;
|
|
|
|
g_return_if_fail (container != NULL);
|
|
g_return_if_fail (GO_IS_DOCK (container));
|
|
g_return_if_fail (callback != NULL);
|
|
|
|
dock = GO_DOCK (container);
|
|
|
|
forall_helper (dock->top_bands, callback, callback_data);
|
|
forall_helper (dock->bottom_bands, callback, callback_data);
|
|
forall_helper (dock->left_bands, callback, callback_data);
|
|
forall_helper (dock->right_bands, callback, callback_data);
|
|
|
|
lp = dock->floating_children;
|
|
while (lp != NULL)
|
|
{
|
|
GtkWidget *w;
|
|
|
|
w = lp->data;
|
|
lp = lp->next;
|
|
(* callback) (w, callback_data);
|
|
}
|
|
|
|
if (dock->client_area != NULL)
|
|
(* callback) (dock->client_area, callback_data);
|
|
}
|
|
|
|
static void
|
|
go_dock_finalize (GObject *object)
|
|
{
|
|
GoDock *self = GO_DOCK (object);
|
|
|
|
g_free (self->_priv);
|
|
self->_priv = NULL;
|
|
|
|
if (G_OBJECT_CLASS (parent_class)->finalize)
|
|
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
new_band_setup (GoDock *dock,
|
|
GtkWidget *new_band,
|
|
GtkOrientation orientation)
|
|
{
|
|
go_dock_band_set_orientation (
|
|
GO_DOCK_BAND (new_band), orientation);
|
|
gtk_widget_set_parent (GTK_WIDGET (new_band), GTK_WIDGET (dock));
|
|
gtk_widget_queue_resize (GTK_WIDGET (new_band));
|
|
gtk_widget_show (GTK_WIDGET (new_band));
|
|
}
|
|
|
|
|
|
/* When an item is being dragged, there can be 3 situations:
|
|
|
|
(I) A new band is created and the item is docked to it.
|
|
|
|
(II) The item is docked to an existing band.
|
|
|
|
(III) The item must be floating, so it has to be detached if
|
|
currently not floating, and moved around in its own window. */
|
|
|
|
/* Case (I): Dock `item' into a new band next to `where' in the
|
|
docking area `area'. If `where' is NULL, the band becomes the
|
|
first one in `area'. */
|
|
static gboolean
|
|
drag_new (GoDock *dock,
|
|
GoDockItem *item,
|
|
GList **area,
|
|
GList *where,
|
|
gint x, gint y,
|
|
gboolean is_vertical)
|
|
{
|
|
GoDockBand *new_band;
|
|
GList *next;
|
|
|
|
DEBUG (("entering function"));
|
|
|
|
new_band = NULL;
|
|
|
|
/* We need a new band next to `where', but we try to re-use the band
|
|
next to it if either it contains no children, or it only contains
|
|
`item'. */
|
|
|
|
next = NULL;
|
|
if (where == NULL && area != NULL)
|
|
next = *area;
|
|
else
|
|
next = where->next;
|
|
if (next != NULL)
|
|
{
|
|
GoDockBand *band;
|
|
guint num_children;
|
|
|
|
band = GO_DOCK_BAND (next->data);
|
|
|
|
num_children = go_dock_band_get_num_children (band);
|
|
|
|
if (num_children == 0
|
|
|| (num_children == 1
|
|
&& GTK_WIDGET (band) == GTK_WIDGET (item)->parent))
|
|
new_band = GO_DOCK_BAND (next->data);
|
|
}
|
|
|
|
/* Create the new band and make it our child if we cannot re-use an
|
|
existing one. */
|
|
if (new_band == NULL)
|
|
{
|
|
new_band = GO_DOCK_BAND (go_dock_band_new ());
|
|
|
|
/* This is mostly to remember that `drag_allocation' for this
|
|
child is bogus, as it was not previously allocated. */
|
|
new_band->new_for_drag = TRUE;
|
|
|
|
if (where == NULL)
|
|
*area = where = g_list_prepend (*area, new_band);
|
|
else if (where->next == NULL)
|
|
g_list_append (where, new_band);
|
|
else
|
|
g_list_prepend (where->next, new_band);
|
|
|
|
new_band_setup (dock, GTK_WIDGET (new_band),
|
|
is_vertical ? GTK_ORIENTATION_VERTICAL
|
|
: GTK_ORIENTATION_HORIZONTAL);
|
|
}
|
|
|
|
/* Move the item to the new band. (This is a no-op if we are using
|
|
`where->next' and it already contains `item'.) */
|
|
go_dock_item_attach (item, GTK_WIDGET (new_band), x, y);
|
|
|
|
/* Prepare the band for dragging of `item'. */
|
|
go_dock_band_drag_begin (new_band, item);
|
|
|
|
/* Set the offset of `item' in the band. */
|
|
if (is_vertical)
|
|
go_dock_band_set_child_offset (new_band, GTK_WIDGET (item),
|
|
MAX (y - dock->client_rect.y, 0));
|
|
else
|
|
go_dock_band_set_child_offset (new_band, GTK_WIDGET (item),
|
|
MAX (x - GTK_WIDGET (dock)->allocation.x, 0));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Case (II): Drag into an existing band. */
|
|
static gboolean
|
|
drag_to (GoDock *dock,
|
|
GoDockItem *item,
|
|
GList *where,
|
|
gint x, gint y,
|
|
gboolean is_vertical)
|
|
{
|
|
DEBUG (("x %d y %d", x, y));
|
|
|
|
return go_dock_band_drag_to (GO_DOCK_BAND (where->data), item, x, y);
|
|
}
|
|
|
|
/* Case (III): Move a floating (i.e. floating) item. */
|
|
static gboolean
|
|
drag_floating (GoDock *dock,
|
|
GoDockItem *item,
|
|
gint x,
|
|
gint y,
|
|
gint rel_x,
|
|
gint rel_y)
|
|
{
|
|
GtkWidget *item_widget, *dock_widget;
|
|
|
|
item_widget = GTK_WIDGET (item);
|
|
dock_widget = GTK_WIDGET (dock);
|
|
|
|
if (!item->is_floating && item_widget->parent != dock_widget)
|
|
{
|
|
GtkAllocation *dock_allocation, *client_allocation;
|
|
|
|
/* The item is currently not floating (so it is not our child).
|
|
Make it so if we are outside the docking areas. */
|
|
|
|
dock_allocation = &dock_widget->allocation;
|
|
if (dock->client_area)
|
|
client_allocation = &dock->client_area->allocation;
|
|
else
|
|
client_allocation = NULL;
|
|
|
|
if (rel_x < 0
|
|
|| rel_x >= dock_allocation->width
|
|
|| rel_y < 0
|
|
|| rel_y >= dock_allocation->height
|
|
|| (client_allocation != NULL
|
|
&& rel_x >= client_allocation->x
|
|
&& rel_x < client_allocation->x + client_allocation->width
|
|
&& rel_y >= client_allocation->y
|
|
&& rel_y < client_allocation->y + client_allocation->height))
|
|
{
|
|
gtk_widget_ref (item_widget);
|
|
|
|
gtk_container_remove (GTK_CONTAINER (item_widget->parent),
|
|
item_widget);
|
|
gtk_widget_set_parent (item_widget, dock_widget);
|
|
|
|
dock->floating_children = g_list_prepend (dock->floating_children,
|
|
item);
|
|
|
|
gtk_widget_realize (item_widget);
|
|
gtk_widget_map (item_widget);
|
|
gtk_widget_queue_resize (item_widget);
|
|
|
|
go_dock_item_detach (item, x, y);
|
|
if (item->in_drag)
|
|
go_dock_item_grab_pointer (item);
|
|
|
|
gtk_widget_unref (item_widget);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* The item is already floating; all we have to do is move it to
|
|
the current dragging position. */
|
|
go_dock_item_drag_floating (item, x, y);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/* Check if `item' can be docked to any of the DockBands of the dock
|
|
area `area'. If so, dock it and return TRUE; otherwise, return
|
|
FALSE. */
|
|
static gboolean
|
|
drag_check (GoDock *dock,
|
|
GoDockItem *item,
|
|
GList **area,
|
|
gint x, gint y,
|
|
gboolean is_vertical)
|
|
{
|
|
GList *lp;
|
|
GtkAllocation *alloc;
|
|
|
|
for (lp = *area; lp != NULL; lp = lp->next)
|
|
{
|
|
GoDockBand *band;
|
|
|
|
band = GO_DOCK_BAND (lp->data);
|
|
|
|
if (! band->new_for_drag)
|
|
{
|
|
alloc = &band->drag_allocation;
|
|
|
|
if (x >= alloc->x - 10 && x < alloc->x + alloc->width
|
|
&& y >= alloc->y && y < alloc->y + alloc->height)
|
|
{
|
|
if (is_vertical)
|
|
{
|
|
if (x < alloc->x + alloc->width / 2
|
|
&& drag_to (dock, item, lp, x, y, TRUE))
|
|
return TRUE;
|
|
else
|
|
return drag_new (dock, item, area, lp, x, y, TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (y < alloc->y + alloc->height / 2
|
|
&& drag_to (dock, item, lp, x, y, FALSE))
|
|
return TRUE;
|
|
else
|
|
return drag_new (dock, item, area, lp, x, y, FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Snap the GoDockItem `widget' to `dock' at the specified
|
|
position. */
|
|
static void
|
|
drag_snap (GoDock *dock,
|
|
GtkWidget *widget,
|
|
gint x, gint y)
|
|
{
|
|
#define SNAP 50
|
|
GoDockItem *item;
|
|
GoDockItemBehavior item_behavior;
|
|
gint win_x, win_y;
|
|
gint rel_x, rel_y;
|
|
gboolean item_allows_horizontal, item_allows_vertical;
|
|
|
|
item = GO_DOCK_ITEM (widget);
|
|
|
|
item_behavior = go_dock_item_get_behavior (item);
|
|
item_allows_horizontal = ! (item_behavior
|
|
& GO_DOCK_ITEM_BEH_NEVER_HORIZONTAL);
|
|
item_allows_vertical = ! (item_behavior
|
|
& GO_DOCK_ITEM_BEH_NEVER_VERTICAL);
|
|
|
|
gdk_window_get_origin (GTK_WIDGET (dock)->window, &win_x, &win_y);
|
|
rel_x = x - win_x;
|
|
rel_y = y - win_y;
|
|
|
|
DEBUG (("(%d,%d)", x, y));
|
|
DEBUG (("relative (%d,%d)", rel_x, rel_y));
|
|
|
|
if (item_allows_horizontal
|
|
&& rel_x >= 0 && rel_x < GTK_WIDGET (dock)->allocation.width)
|
|
{
|
|
/* Check prepending to top/bottom bands. */
|
|
if (rel_y < 0 && rel_y >= -SNAP
|
|
&& drag_new (dock, item, &dock->top_bands, NULL,
|
|
rel_x, rel_y, FALSE))
|
|
return;
|
|
else if (rel_y >= dock->client_rect.y + dock->client_rect.height - SNAP
|
|
&& rel_y < dock->client_rect.y + dock->client_rect.height
|
|
&& drag_new (dock, item, &dock->bottom_bands, NULL,
|
|
rel_x, rel_y, FALSE))
|
|
return;
|
|
}
|
|
|
|
if (item_allows_vertical
|
|
&& rel_y >= dock->client_rect.y
|
|
&& rel_y < dock->client_rect.y + dock->client_rect.height)
|
|
{
|
|
/* Check prepending to left/right bands. */
|
|
if (rel_x < 0 && rel_x >= -SNAP
|
|
&& drag_new (dock, item, &dock->left_bands, NULL,
|
|
rel_x, rel_y, TRUE))
|
|
return;
|
|
else if (rel_x >= dock->client_rect.x + dock->client_rect.width - SNAP
|
|
&& rel_x < dock->client_rect.x + dock->client_rect.width
|
|
&& drag_new (dock, item, &dock->right_bands, NULL,
|
|
rel_x, rel_y, TRUE))
|
|
return;
|
|
}
|
|
|
|
/* Check dragging into bands. */
|
|
if (item_allows_horizontal
|
|
&& drag_check (dock, item, &dock->top_bands, rel_x, rel_y, FALSE))
|
|
return;
|
|
else if (item_allows_horizontal
|
|
&& drag_check (dock, item, &dock->bottom_bands, rel_x, rel_y, FALSE))
|
|
return;
|
|
else if (item_allows_vertical
|
|
&& drag_check (dock, item, &dock->left_bands, rel_x, rel_y, TRUE))
|
|
return;
|
|
else if (item_allows_vertical
|
|
&& drag_check (dock, item, &dock->right_bands, rel_x, rel_y, TRUE))
|
|
return;
|
|
|
|
/* We are not in any "interesting" area: the item must be floating
|
|
if allowed to. */
|
|
if (dock->floating_items_allowed
|
|
&& ! (item_behavior & GO_DOCK_ITEM_BEH_NEVER_DETACH))
|
|
drag_floating (dock, item, x, y, rel_x, rel_y);
|
|
|
|
/* If still not floating, fall back to moving the item in its own
|
|
band. */
|
|
if (! item->is_floating)
|
|
go_dock_band_drag_to (GO_DOCK_BAND (GTK_WIDGET (item)->parent),
|
|
item, rel_x, rel_y);
|
|
}
|
|
|
|
|
|
|
|
/* "drag_begin" signal handling. */
|
|
static void
|
|
drag_begin (GtkWidget *widget, gpointer data)
|
|
{
|
|
GoDock *dock;
|
|
GoDockItem *item;
|
|
|
|
DEBUG (("entering function"));
|
|
|
|
dock = GO_DOCK (data);
|
|
item = GO_DOCK_ITEM (widget);
|
|
|
|
/* Communicate all the bands that `widget' is currently being
|
|
dragged. */
|
|
g_list_foreach (dock->top_bands, (GFunc) go_dock_band_drag_begin, item);
|
|
g_list_foreach (dock->bottom_bands, (GFunc) go_dock_band_drag_begin, item);
|
|
g_list_foreach (dock->right_bands, (GFunc) go_dock_band_drag_begin, item);
|
|
g_list_foreach (dock->left_bands, (GFunc) go_dock_band_drag_begin, item);
|
|
}
|
|
|
|
|
|
|
|
/* "drag_end" signal handling. */
|
|
|
|
static void
|
|
drag_end_bands (GList **list, GoDockItem *item)
|
|
{
|
|
GList *lp;
|
|
GoDockBand *band;
|
|
|
|
lp = *list;
|
|
while (lp != NULL)
|
|
{
|
|
band = GO_DOCK_BAND(lp->data);
|
|
go_dock_band_drag_end (band, item);
|
|
|
|
if (go_dock_band_get_num_children (band) == 0)
|
|
{
|
|
GList *next;
|
|
|
|
next = lp->next;
|
|
|
|
/* This will remove this link, too. */
|
|
gtk_widget_destroy (GTK_WIDGET (band));
|
|
|
|
lp = next;
|
|
}
|
|
else
|
|
lp = lp->next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
drag_end (GtkWidget *widget, gpointer data)
|
|
{
|
|
GoDockItem *item;
|
|
GoDock *dock;
|
|
|
|
DEBUG (("entering function"));
|
|
|
|
item = GO_DOCK_ITEM (widget);
|
|
dock = GO_DOCK (data);
|
|
|
|
/* Communicate to all the bands that `item' is no longer being
|
|
dragged. */
|
|
drag_end_bands (&dock->top_bands, item);
|
|
drag_end_bands (&dock->bottom_bands, item);
|
|
drag_end_bands (&dock->left_bands, item);
|
|
drag_end_bands (&dock->right_bands, item);
|
|
|
|
g_signal_emit (data, dock_signals[LAYOUT_CHANGED], 0);
|
|
}
|
|
|
|
|
|
|
|
/* "drag_motion" signal handling. */
|
|
|
|
/* Handle a drag motion on the GoDockItem `widget'. This is
|
|
connected to the "drag_motion" of all the children being added to
|
|
the GoDock, and tries to dock the dragged item at the current
|
|
(`x', `y') position of the pointer. */
|
|
static void
|
|
drag_motion (GtkWidget *widget,
|
|
gint x, gint y,
|
|
gpointer data)
|
|
{
|
|
drag_snap (GO_DOCK (data), widget, x, y);
|
|
}
|
|
|
|
|
|
|
|
static GoDockItem *
|
|
get_docked_item_by_name (GoDock *dock,
|
|
const gchar *name,
|
|
GoDockPlacement *placement_return,
|
|
guint *num_band_return,
|
|
guint *band_position_return,
|
|
guint *offset_return)
|
|
{
|
|
{
|
|
struct
|
|
{
|
|
GList *band_list;
|
|
GoDockPlacement placement;
|
|
}
|
|
areas[] =
|
|
{
|
|
{ NULL, GO_DOCK_TOP },
|
|
{ NULL, GO_DOCK_BOTTOM },
|
|
{ NULL, GO_DOCK_LEFT },
|
|
{ NULL, GO_DOCK_RIGHT },
|
|
{ NULL, GO_DOCK_FLOATING },
|
|
};
|
|
GList *lp;
|
|
guint i;
|
|
|
|
areas[0].band_list = dock->top_bands;
|
|
areas[1].band_list = dock->bottom_bands;
|
|
areas[2].band_list = dock->left_bands;
|
|
areas[3].band_list = dock->right_bands;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
guint num_band;
|
|
|
|
for (lp = areas[i].band_list, num_band = 0;
|
|
lp != NULL;
|
|
lp = lp->next, num_band++)
|
|
{
|
|
GoDockBand *band;
|
|
GoDockItem *item;
|
|
|
|
band = GO_DOCK_BAND(lp->data);
|
|
item = go_dock_band_get_item_by_name (band,
|
|
name,
|
|
band_position_return,
|
|
offset_return);
|
|
if (item != NULL)
|
|
{
|
|
if (num_band_return != NULL)
|
|
*num_band_return = num_band;
|
|
if (placement_return != NULL)
|
|
*placement_return = areas[i].placement;
|
|
|
|
return item;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static GoDockItem *
|
|
get_floating_item_by_name (GoDock *dock,
|
|
const gchar *name)
|
|
{
|
|
GList *lp;
|
|
GoDockItem *item;
|
|
|
|
for (lp = dock->floating_children; lp != NULL; lp = lp->next)
|
|
{
|
|
item = lp->data;
|
|
if (strcmp (item->name, name) == 0)
|
|
return item;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
connect_drag_signals (GoDock *dock,
|
|
GtkWidget *item)
|
|
{
|
|
if (GO_IS_DOCK_ITEM (item))
|
|
{
|
|
DEBUG (("here"));
|
|
g_signal_connect (item, "dock_drag_begin",
|
|
G_CALLBACK (drag_begin), dock);
|
|
g_signal_connect (item, "dock_drag_motion",
|
|
G_CALLBACK (drag_motion), dock);
|
|
g_signal_connect (item, "dock_drag_end",
|
|
G_CALLBACK (drag_end), dock);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* go_dock_new:
|
|
*
|
|
* Description: Creates a new #GoDock widget.
|
|
*
|
|
* Return value: The new widget.
|
|
**/
|
|
GtkWidget *
|
|
go_dock_new (void)
|
|
{
|
|
GoDock *dock;
|
|
GtkWidget *widget;
|
|
|
|
dock = g_object_new (go_dock_get_type (), NULL);
|
|
widget = GTK_WIDGET (dock);
|
|
|
|
#if 0 /* FIXME: should I? */
|
|
if (GTK_WIDGET_VISIBLE (widget))
|
|
gtk_widget_queue_resize (widget);
|
|
#endif
|
|
|
|
return widget;
|
|
}
|
|
|
|
/**
|
|
* go_dock_allow_floating_items:
|
|
* @dock: A pointer to a #GoDock widget
|
|
* @enable: Specifies whether floating items are allowed in this dock
|
|
*
|
|
* Description: Enable or disable floating items on @dock, according
|
|
* to @enable.
|
|
**/
|
|
void
|
|
go_dock_allow_floating_items (GoDock *dock,
|
|
gboolean enable)
|
|
{
|
|
dock->floating_items_allowed = enable;
|
|
}
|
|
|
|
static GList **
|
|
get_band_list (GoDock *dock, GoDockPlacement placement)
|
|
{
|
|
GList **band_ptr = NULL;
|
|
|
|
switch (placement)
|
|
{
|
|
case GO_DOCK_TOP:
|
|
band_ptr = &dock->top_bands;
|
|
break;
|
|
case GO_DOCK_BOTTOM:
|
|
band_ptr = &dock->bottom_bands;
|
|
break;
|
|
case GO_DOCK_LEFT:
|
|
band_ptr = &dock->left_bands;
|
|
break;
|
|
case GO_DOCK_RIGHT:
|
|
band_ptr = &dock->right_bands;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return band_ptr;
|
|
}
|
|
|
|
/**
|
|
* go_dock_add_item:
|
|
* @dock: A pointer to a #GoDock widget
|
|
* @item: The item to add
|
|
* @placement: Placement for the new item
|
|
* @band_num: Number of the band the new item must be added to
|
|
* @position: Position of the item in the specified band
|
|
* @offset: Offset (in pixels) from the previous item in the same band
|
|
* @in_new_band: Specifies whether a new band must be created for this item
|
|
*
|
|
* Description: Add @item to @dock. @placement can be either
|
|
* %GO_DOCK_TOP, %GO_DOCK_RIGHT, %GO_DOCK_BOTTOM or
|
|
* %GO_DOCK_LEFT, and specifies what area of the dock should
|
|
* contain the item. If @in_new_band is %TRUE, a new dock band is
|
|
* created at the position specified by @band_num; otherwise, the item
|
|
* is added to the @band_num'th band.
|
|
**/
|
|
void
|
|
go_dock_add_item (GoDock *dock,
|
|
GoDockItem *item,
|
|
GoDockPlacement placement,
|
|
guint band_num,
|
|
gint position,
|
|
guint offset,
|
|
gboolean in_new_band)
|
|
{
|
|
GoDockBand *band;
|
|
GList **band_ptr;
|
|
GList *p;
|
|
|
|
DEBUG (("band_num %d offset %d position %d in_new_band %d",
|
|
band_num, offset, position, in_new_band));
|
|
|
|
if (placement == GO_DOCK_FLOATING)
|
|
{
|
|
g_warning ("Floating dock items not supported by `go_dock_add_item'.");
|
|
return;
|
|
}
|
|
band_ptr = get_band_list (dock, placement);
|
|
g_return_if_fail (band_ptr != NULL);
|
|
|
|
p = g_list_nth (*band_ptr, band_num);
|
|
if (in_new_band || p == NULL)
|
|
{
|
|
GtkWidget *new_band;
|
|
|
|
new_band = go_dock_band_new ();
|
|
|
|
/* FIXME: slow. */
|
|
if (in_new_band)
|
|
{
|
|
*band_ptr = g_list_insert (*band_ptr, new_band, band_num);
|
|
p = g_list_nth (*band_ptr, band_num);
|
|
if (p == NULL)
|
|
p = g_list_last (*band_ptr);
|
|
}
|
|
else
|
|
{
|
|
*band_ptr = g_list_append (*band_ptr, new_band);
|
|
p = g_list_last (*band_ptr);
|
|
}
|
|
|
|
if (placement == GO_DOCK_TOP || placement == GO_DOCK_BOTTOM)
|
|
go_dock_band_set_orientation (GO_DOCK_BAND (new_band),
|
|
GTK_ORIENTATION_HORIZONTAL);
|
|
else
|
|
go_dock_band_set_orientation (GO_DOCK_BAND (new_band),
|
|
GTK_ORIENTATION_VERTICAL);
|
|
|
|
gtk_widget_set_parent (new_band, GTK_WIDGET (dock));
|
|
gtk_widget_show (new_band);
|
|
gtk_widget_queue_resize (GTK_WIDGET (dock));
|
|
}
|
|
|
|
band = GO_DOCK_BAND (p->data);
|
|
go_dock_band_insert (band, GTK_WIDGET(item), offset, position);
|
|
|
|
connect_drag_signals (dock, GTK_WIDGET(item));
|
|
|
|
g_signal_emit (dock, dock_signals[LAYOUT_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* go_dock_add_floating_item:
|
|
* @dock: A #GoDock widget
|
|
* @item: The item to be added
|
|
* @x: X-coordinate for the floating item
|
|
* @y: Y-coordinate for the floating item
|
|
* @orientation: Orientation for the new item.
|
|
*
|
|
* Description: Add @item to @dock and make it floating at the
|
|
* specified (@x, @y) coordinates (relative to the root window of the
|
|
* screen).
|
|
**/
|
|
void
|
|
go_dock_add_floating_item (GoDock *dock,
|
|
GoDockItem *item,
|
|
gint x, gint y,
|
|
GtkOrientation orientation)
|
|
{
|
|
GtkWidget *widget;
|
|
|
|
g_return_if_fail (GO_IS_DOCK_ITEM (item));
|
|
|
|
go_dock_item_set_orientation (item, orientation);
|
|
|
|
widget = GTK_WIDGET(item);
|
|
gtk_widget_ref (widget);
|
|
|
|
#if 0
|
|
if (widget->parent != NULL)
|
|
gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
|
|
#endif
|
|
|
|
gtk_widget_set_parent (widget, GTK_WIDGET (dock));
|
|
|
|
if (GTK_WIDGET_REALIZED (widget->parent))
|
|
gtk_widget_realize (widget);
|
|
|
|
if (GTK_WIDGET_VISIBLE (widget->parent) && GTK_WIDGET_VISIBLE (widget))
|
|
{
|
|
if (GTK_WIDGET_MAPPED (widget->parent))
|
|
gtk_widget_map (widget);
|
|
|
|
gtk_widget_queue_resize (widget);
|
|
}
|
|
|
|
go_dock_item_detach (item, x, y);
|
|
dock->floating_children = g_list_prepend (dock->floating_children, widget);
|
|
|
|
connect_drag_signals (dock, widget);
|
|
|
|
gtk_widget_unref (widget);
|
|
|
|
g_signal_emit (dock, dock_signals[LAYOUT_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* go_dock_set_client_area:
|
|
* @dock: A #GoDock widget
|
|
* @widget: The widget to be used for the client area.
|
|
*
|
|
* Description: Specify a widget for the dock's client area.
|
|
**/
|
|
void
|
|
go_dock_set_client_area (GoDock *dock, GtkWidget *widget)
|
|
{
|
|
g_return_if_fail (dock != NULL);
|
|
|
|
if (widget != NULL)
|
|
gtk_widget_ref (widget);
|
|
|
|
if (dock->client_area != NULL)
|
|
gtk_widget_unparent (dock->client_area);
|
|
|
|
if (widget != NULL)
|
|
{
|
|
gtk_widget_set_parent (widget, GTK_WIDGET (dock));
|
|
dock->client_area = widget;
|
|
|
|
if (GTK_WIDGET_REALIZED (widget->parent))
|
|
gtk_widget_realize (widget);
|
|
|
|
if (GTK_WIDGET_VISIBLE (widget->parent) && GTK_WIDGET_VISIBLE (widget))
|
|
{
|
|
if (GTK_WIDGET_MAPPED (widget->parent))
|
|
gtk_widget_map (widget);
|
|
|
|
gtk_widget_queue_resize (widget);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dock->client_area != NULL && GTK_WIDGET_VISIBLE (dock))
|
|
gtk_widget_queue_resize (GTK_WIDGET (dock));
|
|
dock->client_area = NULL;
|
|
}
|
|
|
|
if (widget != NULL)
|
|
gtk_widget_unref (widget);
|
|
}
|
|
|
|
/**
|
|
* go_dock_get_client_area:
|
|
* @dock: A #GoDock widget.
|
|
*
|
|
* Description: Retrieve the widget being used as the client area in
|
|
* @dock.
|
|
*
|
|
* Returns: The client area widget.
|
|
**/
|
|
GtkWidget *
|
|
go_dock_get_client_area (GoDock *dock)
|
|
{
|
|
return dock->client_area;
|
|
}
|
|
|
|
/**
|
|
* go_dock_get_item_by_name:
|
|
* @dock: A #GoDock widget.
|
|
* @name: The name of the dock item to retrieve
|
|
* @placement_return: A pointer to a variable holding the item's placement
|
|
* @num_band_return: A pointer to a variable holding the band number
|
|
* @band_position_return: A pointer to a variable holding the position
|
|
* of the item within the band
|
|
* @offset_return: A pointer to a variable holding the offset of the item
|
|
* from the previous item in the same band
|
|
*
|
|
* Description: Retrieve the dock item named @name; information about
|
|
* its position in the dock is returned via @placement_return,
|
|
* @num_band_return, @band_position_return and @offset_return. If
|
|
* the placement is %GO_DOCK_FLOATING *@num_band_return,
|
|
* *@band_position_return and *@offset_return are not set.
|
|
*
|
|
* Returns: The named #GoDockItem widget, or %NULL if no item with
|
|
* such name exists.
|
|
**/
|
|
GoDockItem *
|
|
go_dock_get_item_by_name (GoDock *dock,
|
|
const gchar *name,
|
|
GoDockPlacement *placement_return,
|
|
guint *num_band_return,
|
|
guint *band_position_return,
|
|
guint *offset_return)
|
|
{
|
|
GoDockItem *item;
|
|
|
|
item = get_docked_item_by_name (dock,
|
|
name,
|
|
placement_return,
|
|
num_band_return,
|
|
band_position_return,
|
|
offset_return);
|
|
if (item != NULL)
|
|
return item;
|
|
|
|
item = get_floating_item_by_name (dock, name);
|
|
if (item != NULL)
|
|
{
|
|
if (placement_return != NULL)
|
|
*placement_return = GO_DOCK_FLOATING;
|
|
return item;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
/* Layout functions. */
|
|
|
|
static void
|
|
layout_add_floating (GoDock *dock,
|
|
GoDockLayout *layout)
|
|
{
|
|
GList *lp;
|
|
|
|
for (lp = dock->floating_children; lp != NULL; lp = lp->next)
|
|
{
|
|
GtkOrientation orientation;
|
|
gint x, y;
|
|
GoDockItem *item;
|
|
|
|
item = GO_DOCK_ITEM (lp->data);
|
|
|
|
orientation = go_dock_item_get_orientation (item);
|
|
go_dock_item_get_floating_position (item, &x, &y);
|
|
|
|
go_dock_layout_add_floating_item (layout, item,
|
|
x, y,
|
|
orientation);
|
|
}
|
|
}
|
|
|
|
static void
|
|
layout_add_bands (GoDock *dock,
|
|
GoDockLayout *layout,
|
|
GoDockPlacement placement,
|
|
GList *band_list)
|
|
{
|
|
guint band_num;
|
|
GList *lp;
|
|
|
|
for (lp = band_list, band_num = 0;
|
|
lp != NULL;
|
|
lp = lp->next, band_num++)
|
|
{
|
|
GoDockBand *band;
|
|
|
|
band = GO_DOCK_BAND(lp->data);
|
|
go_dock_band_layout_add (band, layout, placement, band_num);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* go_dock_get_layout:
|
|
* @dock: A #GoDock widget
|
|
*
|
|
* Description: Retrieve the layout of @dock.
|
|
*
|
|
* Returns: @dock's layout as a #GoDockLayout object.
|
|
**/
|
|
GoDockLayout *
|
|
go_dock_get_layout (GoDock *dock)
|
|
{
|
|
GoDockLayout *layout;
|
|
|
|
layout = go_dock_layout_new ();
|
|
|
|
layout_add_bands (dock, layout, GO_DOCK_TOP, dock->top_bands);
|
|
layout_add_bands (dock, layout, GO_DOCK_BOTTOM, dock->bottom_bands);
|
|
layout_add_bands (dock, layout, GO_DOCK_LEFT, dock->left_bands);
|
|
layout_add_bands (dock, layout, GO_DOCK_RIGHT, dock->right_bands);
|
|
|
|
layout_add_floating (dock, layout);
|
|
|
|
return layout;
|
|
}
|
|
|
|
/**
|
|
* go_dock_add_from_layout:
|
|
* @dock: The #GoDock widget
|
|
* @layout: A #GoDockLayout widget
|
|
*
|
|
* Description: Add all the items in @layout to the specified @dock.
|
|
*
|
|
* Returns: %TRUE if the operation succeeds, %FALSE if it fails.
|
|
**/
|
|
gboolean
|
|
go_dock_add_from_layout (GoDock *dock,
|
|
GoDockLayout *layout)
|
|
{
|
|
return go_dock_layout_add_to_dock (layout, dock);
|
|
}
|
|
|
|
static GList **
|
|
find_band_list (GoDock *dock,
|
|
GoDockBand *band,
|
|
GoDockPlacement *placement)
|
|
{
|
|
GList **band_list = NULL;
|
|
|
|
if (g_list_find (dock->top_bands, band))
|
|
{
|
|
*placement = GO_DOCK_TOP;
|
|
band_list = &dock->top_bands;
|
|
}
|
|
|
|
if (g_list_find (dock->bottom_bands, band))
|
|
{
|
|
*placement = GO_DOCK_BOTTOM;
|
|
band_list = &dock->bottom_bands;
|
|
}
|
|
|
|
if (g_list_find (dock->left_bands, band))
|
|
{
|
|
*placement = GO_DOCK_LEFT;
|
|
band_list = &dock->left_bands;
|
|
}
|
|
|
|
if (g_list_find (dock->right_bands, band))
|
|
{
|
|
*placement = GO_DOCK_RIGHT;
|
|
band_list = &dock->right_bands;
|
|
}
|
|
|
|
return band_list;
|
|
}
|
|
|
|
static gboolean
|
|
insert_into_band_list (GoDock *dock,
|
|
GList **band_list,
|
|
GtkOrientation orientation,
|
|
GoDockItem *item,
|
|
gboolean prepend)
|
|
{
|
|
GtkWidget *new_band;
|
|
|
|
new_band = go_dock_band_new ();
|
|
|
|
if (item->behavior & GO_DOCK_ITEM_BEH_NEVER_VERTICAL)
|
|
orientation = GTK_ORIENTATION_HORIZONTAL;
|
|
|
|
if (item->behavior & GO_DOCK_ITEM_BEH_NEVER_HORIZONTAL)
|
|
orientation = GTK_ORIENTATION_VERTICAL;
|
|
|
|
if (!go_dock_band_append (
|
|
GO_DOCK_BAND (new_band), GTK_WIDGET (item), 0))
|
|
return FALSE;
|
|
|
|
if (prepend)
|
|
*band_list = g_list_prepend (*band_list, new_band);
|
|
else
|
|
*band_list = g_list_append (*band_list, new_band);
|
|
|
|
new_band_setup (dock, new_band, orientation);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gint
|
|
_bonobo_dock_handle_key_nav (GoDock *dock,
|
|
GoDockBand *band,
|
|
GoDockItem *item,
|
|
GdkEventKey *event)
|
|
{
|
|
GList *entry;
|
|
GList **band_list;
|
|
int cross_band_dir = 0;
|
|
int switch_side_dir = 0;
|
|
gboolean end_stop = FALSE;
|
|
gboolean was_inserted = FALSE;
|
|
GtkOrientation orientation;
|
|
GoDockPlacement placement;
|
|
|
|
if (!(event->state & GDK_CONTROL_MASK))
|
|
return FALSE;
|
|
|
|
switch (event->keyval)
|
|
{
|
|
case GDK_Up:
|
|
cross_band_dir = -1;
|
|
break;
|
|
case GDK_Down:
|
|
cross_band_dir = +1;
|
|
break;
|
|
case GDK_Left:
|
|
switch_side_dir = -1;
|
|
break;
|
|
case GDK_Right:
|
|
switch_side_dir = +1;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
band_list = find_band_list (dock, band, &placement);
|
|
g_return_val_if_fail (band_list != NULL, FALSE);
|
|
|
|
if (placement == GO_DOCK_LEFT ||
|
|
placement == GO_DOCK_RIGHT)
|
|
{
|
|
int tmp = switch_side_dir;
|
|
switch_side_dir = cross_band_dir;
|
|
cross_band_dir = tmp;
|
|
orientation = GTK_ORIENTATION_VERTICAL;
|
|
}
|
|
else
|
|
{
|
|
orientation = GTK_ORIENTATION_HORIZONTAL;
|
|
}
|
|
|
|
g_object_ref (G_OBJECT (item));
|
|
|
|
gtk_container_remove (GTK_CONTAINER (band), GTK_WIDGET (item));
|
|
|
|
/*
|
|
* Find somewhere new for it ...
|
|
*/
|
|
entry = g_list_find (*band_list, band);
|
|
g_return_val_if_fail (entry != NULL, FALSE);
|
|
|
|
if (cross_band_dir == -1)
|
|
{
|
|
for (entry = entry->prev; !was_inserted && entry;
|
|
entry = entry->prev)
|
|
was_inserted = go_dock_band_append (
|
|
entry->data, GTK_WIDGET (item), 0);
|
|
|
|
if (!was_inserted &&
|
|
((*band_list)->data != band ||
|
|
go_dock_band_get_num_children (band) > 0))
|
|
{
|
|
was_inserted = insert_into_band_list (
|
|
dock, band_list, orientation, item, TRUE);
|
|
}
|
|
|
|
if (!was_inserted)
|
|
{
|
|
if (placement == GO_DOCK_BOTTOM)
|
|
{
|
|
was_inserted = insert_into_band_list (
|
|
dock, &dock->top_bands, orientation, item, FALSE);
|
|
}
|
|
else if (placement == GO_DOCK_RIGHT)
|
|
{
|
|
was_inserted = insert_into_band_list (
|
|
dock, &dock->left_bands, orientation, item, FALSE);
|
|
}
|
|
else
|
|
end_stop = TRUE;
|
|
}
|
|
}
|
|
|
|
if (cross_band_dir == +1)
|
|
{
|
|
for (entry = entry->next; !was_inserted && entry;
|
|
entry = entry->next)
|
|
was_inserted = go_dock_band_append (
|
|
entry->data, GTK_WIDGET (item), 0);
|
|
|
|
if (!was_inserted &&
|
|
(g_list_last (*band_list)->data != band ||
|
|
go_dock_band_get_num_children (band) > 0))
|
|
{
|
|
was_inserted = insert_into_band_list (
|
|
dock, band_list, orientation, item, FALSE);
|
|
}
|
|
|
|
if (!was_inserted)
|
|
{
|
|
if (placement == GO_DOCK_TOP)
|
|
{
|
|
was_inserted = insert_into_band_list (
|
|
dock, &dock->bottom_bands, orientation, item, TRUE);
|
|
}
|
|
else if (placement == GO_DOCK_LEFT)
|
|
{
|
|
was_inserted = insert_into_band_list (
|
|
dock, &dock->right_bands, orientation, item, TRUE);
|
|
}
|
|
else
|
|
end_stop = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!end_stop && !was_inserted)
|
|
{
|
|
orientation = (orientation == GTK_ORIENTATION_HORIZONTAL) ?
|
|
GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL;
|
|
if (placement == GO_DOCK_TOP ||
|
|
placement == GO_DOCK_BOTTOM)
|
|
{
|
|
if (switch_side_dir == -1)
|
|
was_inserted = insert_into_band_list (
|
|
dock, &dock->left_bands, orientation, item, FALSE);
|
|
else
|
|
was_inserted = insert_into_band_list (
|
|
dock, &dock->right_bands, orientation, item, TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (switch_side_dir == -1)
|
|
was_inserted = insert_into_band_list (
|
|
dock, &dock->top_bands, orientation, item, FALSE);
|
|
else
|
|
was_inserted = insert_into_band_list (
|
|
dock, &dock->bottom_bands, orientation, item, TRUE);
|
|
}
|
|
}
|
|
|
|
if (!was_inserted)
|
|
{ /* geometry issue */
|
|
if (!go_dock_band_append (band, GTK_WIDGET (item), 0))
|
|
g_error ("no space in fallback original band");
|
|
}
|
|
|
|
if (go_dock_band_get_num_children (band) == 0)
|
|
gtk_widget_destroy (GTK_WIDGET (band));
|
|
|
|
g_object_unref (G_OBJECT (item));
|
|
|
|
return TRUE;
|
|
}
|