📄 gtklayout.c
字号:
}static voidgtk_layout_position_children (GtkLayout *layout){ GList *tmp_list; tmp_list = layout->children; while (tmp_list) { GtkLayoutChild *child = tmp_list->data; tmp_list = tmp_list->next; gtk_layout_position_child (layout, child); }}static voidgtk_layout_adjust_allocations_recurse (GtkWidget *widget, gpointer cb_data){ GtkLayoutAdjData *data = cb_data; widget->allocation.x += data->dx; widget->allocation.y += data->dy; if (GTK_WIDGET_NO_WINDOW (widget) && GTK_IS_CONTAINER (widget)) gtk_container_forall (GTK_CONTAINER (widget), gtk_layout_adjust_allocations_recurse, cb_data);}static voidgtk_layout_adjust_allocations (GtkLayout *layout, gint dx, gint dy){ GList *tmp_list; GtkLayoutAdjData data; data.dx = dx; data.dy = dy; tmp_list = layout->children; while (tmp_list) { GtkLayoutChild *child = tmp_list->data; tmp_list = tmp_list->next; child->widget->allocation.x += dx; child->widget->allocation.y += dy; if (GTK_WIDGET_NO_WINDOW (child->widget) && GTK_IS_CONTAINER (child->widget)) gtk_container_forall (GTK_CONTAINER (child->widget), gtk_layout_adjust_allocations_recurse, &data); }} /* Callbacks *//* Send a synthetic expose event to the widget */static voidgtk_layout_expose_area (GtkLayout *layout, gint x, gint y, gint width, gint height){ if (layout->visibility == GDK_VISIBILITY_UNOBSCURED) { GdkEventExpose event; event.type = GDK_EXPOSE; event.send_event = TRUE; event.window = layout->bin_window; event.count = 0; event.area.x = x; event.area.y = y; event.area.width = width; event.area.height = height; gdk_window_ref (event.window); gtk_widget_event (GTK_WIDGET (layout), (GdkEvent *)&event); gdk_window_unref (event.window); }}/* This function is used to find events to process while scrolling */static Bool gtk_layout_expose_predicate (Display *display, XEvent *xevent, XPointer arg){ if ((xevent->type == Expose) || ((xevent->xany.window == *(Window *)arg) && (xevent->type == ConfigureNotify))) return True; else return False;}/* This is the main routine to do the scrolling. Scrolling is * done by "Guffaw" scrolling, as in the Mozilla XFE, with * a few modifications. * * The main improvement is that we keep track of whether we * are obscured or not. If not, we ignore the generated expose * events and instead do the exposes ourself, without having * to wait for a roundtrip to the server. This also provides * a limited form of expose-event compression, since we do * the affected area as one big chunk. * * Real expose event compression, as in the XFE, could be added * here. It would help opaque drags over the region, and the * obscured case. * * Code needs to be added here to do the scrolling on machines * that don't have working WindowGravity. That could be done * * - XCopyArea and move the windows, and accept trailing the * background color. (Since it is only a fallback method) * - XmHTML style. As above, but turn off expose events when * not obscured and do the exposures ourself. * - gzilla-style. Move the window continuously, and reset * every 32768 pixels */static voidgtk_layout_adjustment_changed (GtkAdjustment *adjustment, GtkLayout *layout){ GtkWidget *widget; XEvent xevent; gint dx, dy; widget = GTK_WIDGET (layout); dx = (gint)layout->hadjustment->value - layout->xoffset; dy = (gint)layout->vadjustment->value - layout->yoffset; layout->xoffset = (gint)layout->hadjustment->value; layout->yoffset = (gint)layout->vadjustment->value; if (layout->freeze_count) return; if (!GTK_WIDGET_MAPPED (layout)) { gtk_layout_position_children (layout); return; } gtk_layout_adjust_allocations (layout, -dx, -dy); if (dx > 0) { if (gravity_works) { gdk_window_resize (layout->bin_window, widget->allocation.width + dx, widget->allocation.height); gdk_window_move (layout->bin_window, -dx, 0); gdk_window_move_resize (layout->bin_window, 0, 0, widget->allocation.width, widget->allocation.height); } else { /* FIXME */ } gtk_layout_expose_area (layout, MAX ((gint)widget->allocation.width - dx, 0), 0, MIN (dx, widget->allocation.width), widget->allocation.height); } else if (dx < 0) { if (gravity_works) { gdk_window_move_resize (layout->bin_window, dx, 0, widget->allocation.width - dx, widget->allocation.height); gdk_window_move (layout->bin_window, 0, 0); gdk_window_resize (layout->bin_window, widget->allocation.width, widget->allocation.height); } else { /* FIXME */ } gtk_layout_expose_area (layout, 0, 0, MIN (-dx, widget->allocation.width), widget->allocation.height); } if (dy > 0) { if (gravity_works) { gdk_window_resize (layout->bin_window, widget->allocation.width, widget->allocation.height + dy); gdk_window_move (layout->bin_window, 0, -dy); gdk_window_move_resize (layout->bin_window, 0, 0, widget->allocation.width, widget->allocation.height); } else { /* FIXME */ } gtk_layout_expose_area (layout, 0, MAX ((gint)widget->allocation.height - dy, 0), widget->allocation.width, MIN (dy, widget->allocation.height)); } else if (dy < 0) { if (gravity_works) { gdk_window_move_resize (layout->bin_window, 0, dy, widget->allocation.width, widget->allocation.height - dy); gdk_window_move (layout->bin_window, 0, 0); gdk_window_resize (layout->bin_window, widget->allocation.width, widget->allocation.height); } else { /* FIXME */ } gtk_layout_expose_area (layout, 0, 0, widget->allocation.width, MIN (-dy, (gint)widget->allocation.height)); } gtk_layout_position_children (layout); /* We have to make sure that all exposes from this scroll get * processed before we scroll again, or the expose events will * have invalid coordinates. * * We also do expose events for other windows, since otherwise * their updating will fall behind the scrolling * * This also avoids a problem in pre-1.0 GTK where filters don't * have access to configure events that were compressed. */ gdk_flush(); while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (layout->bin_window), &xevent, gtk_layout_expose_predicate, (XPointer)&GDK_WINDOW_XWINDOW (layout->bin_window))) { GdkEvent event; GtkWidget *event_widget; if ((xevent.xany.window == GDK_WINDOW_XWINDOW (layout->bin_window)) && (gtk_layout_filter (&xevent, &event, layout) == GDK_FILTER_REMOVE)) continue; if (xevent.type == Expose) { event.expose.window = gdk_window_lookup (xevent.xany.window); gdk_window_get_user_data (event.expose.window, (gpointer *)&event_widget); if (event_widget) { event.expose.type = GDK_EXPOSE; event.expose.area.x = xevent.xexpose.x; event.expose.area.y = xevent.xexpose.y; event.expose.area.width = xevent.xexpose.width; event.expose.area.height = xevent.xexpose.height; event.expose.count = xevent.xexpose.count; gdk_window_ref (event.expose.window); gtk_widget_event (event_widget, &event); gdk_window_unref (event.expose.window); } } }}/* The main event filter. Actually, we probably don't really need * to install this as a filter at all, since we are calling it * directly above in the expose-handling hack. But in case scrollbars * are fixed up in some manner... * * This routine identifies expose events that are generated when * we've temporarily moved the bin_window_origin, and translates * them or discards them, depending on whether we are obscured * or not. */static GdkFilterReturn gtk_layout_filter (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data){ XEvent *xevent; GtkLayout *layout; xevent = (XEvent *)gdk_xevent; layout = GTK_LAYOUT (data); switch (xevent->type) { case Expose: if (xevent->xexpose.serial == layout->configure_serial) { if (layout->visibility == GDK_VISIBILITY_UNOBSCURED) return GDK_FILTER_REMOVE; else { xevent->xexpose.x += layout->scroll_x; xevent->xexpose.y += layout->scroll_y; break; } } break; case ConfigureNotify: if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0)) { layout->configure_serial = xevent->xconfigure.serial; layout->scroll_x = xevent->xconfigure.x; layout->scroll_y = xevent->xconfigure.y; } break; } return GDK_FILTER_CONTINUE;}/* Although GDK does have a GDK_VISIBILITY_NOTIFY event, * there is no corresponding event in GTK, so we have * to get the events from a filter */static GdkFilterReturn gtk_layout_main_filter (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data){ XEvent *xevent; GtkLayout *layout; xevent = (XEvent *)gdk_xevent; layout = GTK_LAYOUT (data); if (xevent->type == VisibilityNotify) { switch (xevent->xvisibility.state) { case VisibilityFullyObscured: layout->visibility = GDK_VISIBILITY_FULLY_OBSCURED; break; case VisibilityPartiallyObscured: layout->visibility = GDK_VISIBILITY_PARTIAL; break; case VisibilityUnobscured: layout->visibility = GDK_VISIBILITY_UNOBSCURED; break; } return GDK_FILTER_REMOVE; } return GDK_FILTER_CONTINUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -