static void gdl_dock_get_size (GtkWidget *widget, GtkOrientation orientation, gint *minimum, gint *natural) { GdlDock *dock; GtkContainer *container; g_return_if_fail (widget != NULL); g_return_if_fail (GDL_IS_DOCK (widget)); dock = GDL_DOCK (widget); container = GTK_CONTAINER (widget); *minimum = *natural = 0; /* make request to root */ if (dock->priv->root && gtk_widget_get_visible (GTK_WIDGET (dock->priv->root))) { if (orientation == GTK_ORIENTATION_HORIZONTAL) { gtk_widget_get_preferred_width (GTK_WIDGET (dock->priv->root), minimum, natural); } else { gtk_widget_get_preferred_height (GTK_WIDGET (dock->priv->root), minimum, natural); } } }
static void gdl_dock_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GdlDock *dock; GtkContainer *container; guint border_width; g_return_if_fail (widget != NULL); g_return_if_fail (GDL_IS_DOCK (widget)); dock = GDL_DOCK (widget); container = GTK_CONTAINER (widget); border_width = container->border_width; widget->allocation = *allocation; /* reduce allocation by border width */ allocation->x += border_width; allocation->y += border_width; allocation->width = MAX (1, allocation->width - 2 * border_width); allocation->height = MAX (1, allocation->height - 2 * border_width); if (dock->root && GTK_WIDGET_VISIBLE (dock->root)) gtk_widget_size_allocate (GTK_WIDGET (dock->root), allocation); }
/** * gdl_dock_get_root: * @dock: A #GdlDockObject * * Get the first child of the #GdlDockObject. * * Returns: (allow-none) (transfer none): A #GdlDockObject or %NULL. */ GdlDockObject * gdl_dock_get_root (GdlDock *dock) { g_return_val_if_fail (GDL_IS_DOCK (dock), NULL); return dock->priv->root; }
static void gdl_dock_size_request (GtkWidget *widget, GtkRequisition *requisition) { GdlDock *dock; GtkContainer *container; guint border_width; g_return_if_fail (widget != NULL); g_return_if_fail (GDL_IS_DOCK (widget)); dock = GDL_DOCK (widget); container = GTK_CONTAINER (widget); border_width = container->border_width; /* make request to root */ if (dock->root && GTK_WIDGET_VISIBLE (dock->root)) gtk_widget_size_request (GTK_WIDGET (dock->root), requisition); else { requisition->width = 0; requisition->height = 0; }; requisition->width += 2 * border_width; requisition->height += 2 * border_width; widget->requisition = *requisition; }
GdlDock * gdl_dock_object_get_toplevel (GdlDockObject *object) { GdlDockObject *parent = object; g_return_val_if_fail (object != NULL, NULL); while (parent && !GDL_IS_DOCK (parent)) parent = gdl_dock_object_get_parent_object (parent); return parent ? GDL_DOCK (parent) : NULL; }
static void _gdl_dock_master_remove (GdlDockObject *object, GdlDockMaster *master) { g_return_if_fail (master != NULL && object != NULL); if (GDL_IS_DOCK (object)) { GList *found_link; found_link = g_list_find (master->toplevel_docks, object); if (found_link) master->toplevel_docks = g_list_delete_link (master->toplevel_docks, found_link); if (object == master->controller) { GList *last; GdlDockObject *new_controller = NULL; /* now find some other non-automatic toplevel to use as a new controller. start from the last dock, since it's probably a non-floating and manual */ last = g_list_last (master->toplevel_docks); while (last) { if (!GDL_DOCK_OBJECT_AUTOMATIC (last->data)) { new_controller = GDL_DOCK_OBJECT (last->data); break; } last = last->prev; }; if (new_controller) { /* the new controller gets the ref (implicitly of course) */ master->controller = new_controller; } else { master->controller = NULL; /* no controller, no master */ g_object_unref (master); } } } /* disconnect dock object signals */ g_signal_handlers_disconnect_matched (object, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, master); /* unref the object from the hash if it's there */ if (object->name) { GdlDockObject *found_object; found_object = g_hash_table_lookup (master->dock_objects, object->name); if (found_object == object) { g_hash_table_remove (master->dock_objects, object->name); g_object_unref (object); } } }
static void gdl_dock_add (GtkContainer *container, GtkWidget *widget) { g_return_if_fail (container != NULL); g_return_if_fail (GDL_IS_DOCK (container)); g_return_if_fail (GDL_IS_DOCK_ITEM (widget)); gdl_dock_add_item (GDL_DOCK (container), GDL_DOCK_ITEM (widget), GDL_DOCK_TOP); /* default position */ }
static void gdl_dock_notify_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { GdlDock *dock; g_return_if_fail (object != NULL || GDL_IS_DOCK (object)); dock = GDL_DOCK (object); dock->_priv->auto_title = FALSE; gdl_dock_set_title (dock); }
static void gdl_dock_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) { GdlDock *dock; g_return_if_fail (container != NULL); g_return_if_fail (GDL_IS_DOCK (container)); g_return_if_fail (callback != NULL); dock = GDL_DOCK (container); if (dock->root) (*callback) (GTK_WIDGET (dock->root), callback_data); }
static gboolean gdl_dock_floating_configure_event_cb (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data) { GdlDock *dock; g_return_val_if_fail (user_data != NULL && GDL_IS_DOCK (user_data), TRUE); dock = GDL_DOCK (user_data); dock->_priv->float_x = event->x; dock->_priv->float_y = event->y; dock->_priv->width = event->width; dock->_priv->height = event->height; return FALSE; }
static void gdl_dock_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GdlDock *dock; GtkContainer *container; g_return_if_fail (widget != NULL); g_return_if_fail (GDL_IS_DOCK (widget)); dock = GDL_DOCK (widget); container = GTK_CONTAINER (widget); gtk_widget_set_allocation (widget, allocation); if (dock->priv->root && gtk_widget_get_visible (GTK_WIDGET (dock->priv->root))) gtk_widget_size_allocate (GTK_WIDGET (dock->priv->root), allocation); }
static void gdl_dock_map (GtkWidget *widget) { GtkWidget *child; GdlDock *dock; g_return_if_fail (widget != NULL); g_return_if_fail (GDL_IS_DOCK (widget)); dock = GDL_DOCK (widget); GTK_WIDGET_CLASS (gdl_dock_parent_class)->map (widget); if (dock->priv->root) { child = GTK_WIDGET (dock->priv->root); if (gtk_widget_get_visible (child) && !gtk_widget_get_mapped (child)) gtk_widget_map (child); } }
static void gdl_dock_map (GtkWidget *widget) { GtkWidget *child; GdlDock *dock; g_return_if_fail (widget != NULL); g_return_if_fail (GDL_IS_DOCK (widget)); dock = GDL_DOCK (widget); GDL_CALL_PARENT (GTK_WIDGET_CLASS, map, (widget)); if (dock->root) { child = GTK_WIDGET (dock->root); if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child)) gtk_widget_map (child); } }
static void gdl_dock_notify_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { GdlDock *dock; gchar* long_name; g_return_if_fail (object != NULL || GDL_IS_DOCK (object)); g_object_get (object, "long-name", &long_name, NULL); if (long_name) { dock = GDL_DOCK (object); dock->priv->auto_title = FALSE; gdl_dock_set_title (dock); } g_free (long_name); }
static void gdl_dock_hide (GtkWidget *widget) { GdlDock *dock; g_return_if_fail (widget != NULL); g_return_if_fail (GDL_IS_DOCK (widget)); GDL_CALL_PARENT (GTK_WIDGET_CLASS, hide, (widget)); dock = GDL_DOCK (widget); if (dock->_priv->floating && dock->_priv->window) gtk_widget_hide (dock->_priv->window); if (GDL_DOCK_IS_CONTROLLER (dock)) { gdl_dock_master_foreach_toplevel (GDL_DOCK_OBJECT_GET_MASTER (dock), FALSE, (GFunc) gdl_dock_foreach_automatic, gtk_widget_hide); } }
static void gdl_dock_hide (GtkWidget *widget) { GdlDock *dock; GdlDockMaster *master; g_return_if_fail (widget != NULL); g_return_if_fail (GDL_IS_DOCK (widget)); GTK_WIDGET_CLASS (gdl_dock_parent_class)->hide (widget); dock = GDL_DOCK (widget); if (dock->priv->floating && dock->priv->window) gtk_widget_hide (dock->priv->window); master = GDL_DOCK_MASTER (gdl_dock_object_get_master (GDL_DOCK_OBJECT (dock))); if (GDL_DOCK (gdl_dock_master_get_controller (master)) == dock) { gdl_dock_master_foreach_toplevel (master, FALSE, (GFunc) gdl_dock_foreach_automatic, gtk_widget_hide); } }
void gdl_dock_master_add (GdlDockMaster *master, GdlDockObject *object) { g_return_if_fail (master != NULL && object != NULL); if (!GDL_DOCK_OBJECT_AUTOMATIC (object)) { GdlDockObject *found_object; /* create a name for the object if it doesn't have one */ if (!object->name) /* directly set the name, since it's a construction only property */ object->name = g_strdup_printf ("__dock_%u", master->_priv->number++); /* add the object to our hash list */ if ((found_object = g_hash_table_lookup (master->dock_objects, object->name))) { g_warning (_("master %p: unable to add object %p[%s] to the hash. " "There already is an item with that name (%p)."), master, object, object->name, found_object); } else { g_object_ref_sink (object); g_hash_table_insert (master->dock_objects, g_strdup (object->name), object); } } if (GDL_IS_DOCK (object)) { gboolean floating; /* if this is the first toplevel we are adding, name it controller */ if (!master->toplevel_docks) /* the dock should already have the ref */ master->controller = object; /* add dock to the toplevel list */ g_object_get (object, "floating", &floating, NULL); if (floating) master->toplevel_docks = g_list_prepend (master->toplevel_docks, object); else master->toplevel_docks = g_list_append (master->toplevel_docks, object); /* we are interested in the dock request this toplevel * receives to update the layout */ g_signal_connect (object, "dock", G_CALLBACK (item_dock_cb), master); } else if (GDL_IS_DOCK_ITEM (object)) { /* we need to connect the item's signals */ g_signal_connect (object, "dock_drag_begin", G_CALLBACK (gdl_dock_master_drag_begin), master); g_signal_connect (object, "dock_drag_motion", G_CALLBACK (gdl_dock_master_drag_motion), master); g_signal_connect (object, "dock_drag_end", G_CALLBACK (gdl_dock_master_drag_end), master); g_signal_connect (object, "dock", G_CALLBACK (item_dock_cb), master); g_signal_connect (object, "detach", G_CALLBACK (item_detach_cb), master); /* register to "locked" notification if the item has a grip, * and add the item to the corresponding hash */ if (GDL_DOCK_ITEM_HAS_GRIP (GDL_DOCK_ITEM (object))) { g_signal_connect (object, "notify::locked", G_CALLBACK (item_notify_cb), master); item_notify_cb (object, NULL, master); } /* If the item is notebook, set the switcher style */ if (GDL_IS_DOCK_NOTEBOOK (object) && GDL_IS_SWITCHER (GDL_DOCK_ITEM (object)->child)) { g_object_set (GDL_DOCK_ITEM (object)->child, "switcher-style", master->_priv->switcher_style, NULL); } /* post a layout_changed emission if the item is not automatic * (since it should be added to the items model) */ if (!GDL_DOCK_OBJECT_AUTOMATIC (object)) { if (!master->_priv->idle_layout_changed_id) master->_priv->idle_layout_changed_id = g_idle_add (idle_emit_layout_changed, master); } } }
static void gdl_dock_master_drag_motion (GdlDockItem *item, gint root_x, gint root_y, gpointer data) { GdlDockMaster *master; GdlDockRequest my_request, *request; GdkWindow *window; gint win_x, win_y; gint x, y; GdlDock *dock = NULL; gboolean may_dock = FALSE; g_return_if_fail (item != NULL && data != NULL); master = GDL_DOCK_MASTER (data); request = master->_priv->drag_request; g_return_if_fail (GDL_DOCK_OBJECT (item) == request->applicant); my_request = *request; /* first look under the pointer */ window = gdk_window_at_pointer (&win_x, &win_y); if (window) { GtkWidget *widget; /* ok, now get the widget who owns that window and see if we can get to a GdlDock by walking up the hierarchy */ gdk_window_get_user_data (window, (gpointer) &widget); if (GTK_IS_WIDGET (widget)) { while (widget && (!GDL_IS_DOCK (widget) || GDL_DOCK_OBJECT_GET_MASTER (widget) != master)) widget = widget->parent; if (widget) { gint win_w, win_h; /* verify that the pointer is still in that dock (the user could have moved it) */ gdk_window_get_geometry (widget->window, NULL, NULL, &win_w, &win_h, NULL); gdk_window_get_origin (widget->window, &win_x, &win_y); if (root_x >= win_x && root_x < win_x + win_w && root_y >= win_y && root_y < win_y + win_h) dock = GDL_DOCK (widget); } } } if (dock) { /* translate root coordinates into dock object coordinates (i.e. widget coordinates) */ gdk_window_get_origin (GTK_WIDGET (dock)->window, &win_x, &win_y); x = root_x - win_x; y = root_y - win_y; may_dock = gdl_dock_object_dock_request (GDL_DOCK_OBJECT (dock), x, y, &my_request); } else { GList *l; /* try to dock the item in all the docks in the ring in turn */ for (l = master->toplevel_docks; l; l = l->next) { dock = GDL_DOCK (l->data); /* translate root coordinates into dock object coordinates (i.e. widget coordinates) */ gdk_window_get_origin (GTK_WIDGET (dock)->window, &win_x, &win_y); x = root_x - win_x; y = root_y - win_y; may_dock = gdl_dock_object_dock_request (GDL_DOCK_OBJECT (dock), x, y, &my_request); if (may_dock) break; } } if (!may_dock) { GtkRequisition req; /* Special case for GdlDockItems : they must respect the flags */ if(GDL_IS_DOCK_ITEM(item) && GDL_DOCK_ITEM(item)->behavior & GDL_DOCK_ITEM_BEH_NEVER_FLOATING) return; dock = NULL; my_request.target = GDL_DOCK_OBJECT ( gdl_dock_object_get_toplevel (request->applicant)); my_request.position = GDL_DOCK_FLOATING; gdl_dock_item_preferred_size (GDL_DOCK_ITEM (request->applicant), &req); my_request.rect.width = req.width; my_request.rect.height = req.height; my_request.rect.x = root_x - GDL_DOCK_ITEM (request->applicant)->dragoff_x; my_request.rect.y = root_y - GDL_DOCK_ITEM (request->applicant)->dragoff_y; /* setup extra docking information */ if (G_IS_VALUE (&my_request.extra)) g_value_unset (&my_request.extra); g_value_init (&my_request.extra, GDK_TYPE_RECTANGLE); g_value_set_boxed (&my_request.extra, &my_request.rect); } /* if we want to enforce GDL_DOCK_ITEM_BEH_NEVER_FLOATING */ /* the item must remain attached to the controller, otherwise */ /* it could be inserted in another floating dock */ /* so check for the flag at this moment */ else if(GDL_IS_DOCK_ITEM(item) && GDL_DOCK_ITEM(item)->behavior & GDL_DOCK_ITEM_BEH_NEVER_FLOATING && dock != GDL_DOCK(master->controller)) return; if (!(my_request.rect.x == request->rect.x && my_request.rect.y == request->rect.y && my_request.rect.width == request->rect.width && my_request.rect.height == request->rect.height && dock == master->_priv->rect_owner)) { /* erase the previous rectangle */ if (master->_priv->rect_drawn) gdl_dock_master_xor_rect (master); } /* set the new values */ *request = my_request; master->_priv->rect_owner = dock; /* draw the previous rectangle */ if (~master->_priv->rect_drawn) gdl_dock_master_xor_rect (master); }
static void gdl_dock_dock (GdlDockObject *object, GdlDockObject *requestor, GdlDockPlacement position, GValue *user_data) { GdlDock *dock; g_return_if_fail (GDL_IS_DOCK (object)); /* only dock items allowed at this time */ g_return_if_fail (GDL_IS_DOCK_ITEM (requestor)); dock = GDL_DOCK (object); if (position == GDL_DOCK_FLOATING) { GdlDockItem *item = GDL_DOCK_ITEM (requestor); gint x, y, width, height; if (user_data && G_VALUE_HOLDS (user_data, GDK_TYPE_RECTANGLE)) { GdkRectangle *rect; rect = g_value_get_boxed (user_data); x = rect->x; y = rect->y; width = rect->width; height = rect->height; } else { x = y = 0; width = height = -1; } gdl_dock_add_floating_item (dock, item, x, y, width, height); } else if (dock->root) { /* This is somewhat a special case since we know which item to pass the request on because we only have on child */ gdl_dock_object_dock (dock->root, requestor, position, NULL); gdl_dock_set_title (dock); } else { /* Item about to be added is root item. */ GtkWidget *widget = GTK_WIDGET (requestor); dock->root = requestor; GDL_DOCK_OBJECT_SET_FLAGS (requestor, GDL_DOCK_ATTACHED); gtk_widget_set_parent (widget, GTK_WIDGET (dock)); gdl_dock_item_show_grip (GDL_DOCK_ITEM (requestor)); /* Realize the item (create its corresponding GdkWindow) when GdlDock has been realized. */ if (GTK_WIDGET_REALIZED (dock)) gtk_widget_realize (widget); /* Map the widget if it's visible and the parent is visible and has been mapped. This is done to make sure that the GdkWindow is visible. */ if (GTK_WIDGET_VISIBLE (dock) && GTK_WIDGET_VISIBLE (widget)) { if (GTK_WIDGET_MAPPED (dock)) gtk_widget_map (widget); /* Make the widget resize. */ gtk_widget_queue_resize (widget); } gdl_dock_set_title (dock); } }
static gboolean gdl_dock_dock_request (GdlDockObject *object, gint x, gint y, GdlDockRequest *request) { GdlDock *dock; guint bw; gint rel_x, rel_y; GtkAllocation *alloc; gboolean may_dock = FALSE; GdlDockRequest my_request; g_return_val_if_fail (GDL_IS_DOCK (object), FALSE); /* we get (x,y) in our allocation coordinates system */ dock = GDL_DOCK (object); /* Get dock size. */ alloc = &(GTK_WIDGET (dock)->allocation); bw = GTK_CONTAINER (dock)->border_width; /* Get coordinates relative to our allocation area. */ rel_x = x - alloc->x; rel_y = y - alloc->y; if (request) my_request = *request; /* Check if coordinates are in GdlDock widget. */ if (rel_x > 0 && rel_x < alloc->width && rel_y > 0 && rel_y < alloc->height) { /* It's inside our area. */ may_dock = TRUE; /* Set docking indicator rectangle to the GdlDock size. */ my_request.rect.x = alloc->x + bw; my_request.rect.y = alloc->y + bw; my_request.rect.width = alloc->width - 2*bw; my_request.rect.height = alloc->height - 2*bw; /* If GdlDock has no root item yet, set the dock itself as possible target. */ if (!dock->root) { my_request.position = GDL_DOCK_TOP; my_request.target = object; } else { my_request.target = dock->root; /* See if it's in the border_width band. */ if (rel_x < bw) { my_request.position = GDL_DOCK_LEFT; my_request.rect.width *= SPLIT_RATIO; } else if (rel_x > alloc->width - bw) { my_request.position = GDL_DOCK_RIGHT; my_request.rect.x += my_request.rect.width * (1 - SPLIT_RATIO); my_request.rect.width *= SPLIT_RATIO; } else if (rel_y < bw) { my_request.position = GDL_DOCK_TOP; my_request.rect.height *= SPLIT_RATIO; } else if (rel_y > alloc->height - bw) { my_request.position = GDL_DOCK_BOTTOM; my_request.rect.y += my_request.rect.height * (1 - SPLIT_RATIO); my_request.rect.height *= SPLIT_RATIO; } else { /* Otherwise try our children. */ /* give them allocation coordinates (we are a GTK_NO_WINDOW) widget */ may_dock = gdl_dock_object_dock_request (GDL_DOCK_OBJECT (dock->root), x, y, &my_request); } } } if (may_dock && request) *request = my_request; return may_dock; }