/* bonobo-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 "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "bonobo-dock.h"
#include "bonobo-dock-band.h"
#include "bonobo-dock-item.h"
#include <libgnome/gnome-macros.h>
GNOME_CLASS_BOILERPLATE (BonoboDock, bonobo_dock,
GtkContainer, GTK_TYPE_CONTAINER)
#define noBONOBO_DOCK_DEBUG
/* FIXME: To be removed. */
#if defined BONOBO_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 _BonoboDockPrivate
{
GdkDragContext *current_drag;
};
enum {
LAYOUT_CHANGED,
LAST_SIGNAL
};
static void bonobo_dock_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void bonobo_dock_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void bonobo_dock_map (GtkWidget *widget);
static void bonobo_dock_unmap (GtkWidget *widget);
static void bonobo_dock_add (GtkContainer *container,
GtkWidget *child);
static void bonobo_dock_remove (GtkContainer *container,
GtkWidget *widget);
static void bonobo_dock_forall (GtkContainer *container,
gboolean include_internals,
GtkCallback callback,
gpointer callback_data);
static void bonobo_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,
BonoboDockBand *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,
BonoboDockItem *item);
static void drag_end (GtkWidget *widget,
gpointer data);
static gboolean drag_new (BonoboDock *dock,
BonoboDockItem *item,
GList **area,
GList *where,
gint x, gint y,
gboolean is_vertical);
static gboolean drag_to (BonoboDock *dock,
BonoboDockItem *item,
GList *where,
gint x, gint y,
gboolean is_vertical);
static gboolean drag_floating (BonoboDock *dock,
BonoboDockItem *item,
gint x, gint y,
gint rel_x, gint rel_y);
static gboolean drag_check (BonoboDock *dock,
BonoboDockItem *item,
GList **area,
gint x, gint y,
gboolean is_vertical);
static void drag_snap (BonoboDock *dock,
GtkWidget *widget,
gint x, gint y);
static void drag_motion (GtkWidget *widget,
gint x, gint y,
gpointer data);
static BonoboDockItem *get_docked_item_by_name (BonoboDock *dock,
const gchar *name,
BonoboDockPlacement *placement_return,
guint *num_band_return,
guint *band_position_return,
guint *offset_return);
static BonoboDockItem *get_floating_item_by_name (BonoboDock *dock,
const gchar *name);
static void connect_drag_signals (BonoboDock *dock,
GtkWidget *item);
static guint dock_signals[LAST_SIGNAL] = { 0 };
static void
bonobo_dock_class_init (BonoboDockClass *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 = bonobo_dock_finalize;
widget_class->size_request = bonobo_dock_size_request;
widget_class->size_allocate = bonobo_dock_size_allocate;
widget_class->map = bonobo_dock_map;
widget_class->unmap = bonobo_dock_unmap;
container_class->add = bonobo_dock_add;
container_class->remove = bonobo_dock_remove;
container_class->forall = bonobo_dock_forall;
dock_signals[LAYOUT_CHANGED] =
g_signal_new ("layout_changed",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (BonoboDockClass,
layout_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static void
bonobo_dock_instance_init (BonoboDock *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(BonoboDockPrivate, 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
bonobo_dock_size_request (GtkWidget *widget, GtkRequisition *requisition)
{
BonoboDock *dock;
GList *lp;
dock = BONOBO_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.