diff --git a/src/Makefile.am b/src/Makefile.am index ba8ab92..59d15a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ virt_viewer_SOURCES = \ virt-viewer-events.h virt-viewer-events.c \ virt-viewer.h virt-viewer.c \ virt-viewer-priv.h \ + virt-viewer-align.h virt-viewer-align.c \ virt-viewer-display.h virt-viewer-display.c \ virt-viewer-display-vnc.h virt-viewer-display-vnc.c \ view/autoDrawer.c \ diff --git a/src/virt-viewer-align.c b/src/virt-viewer-align.c new file mode 100644 index 0000000..ab42fed --- /dev/null +++ b/src/virt-viewer-align.c @@ -0,0 +1,342 @@ +/* + * Virt Viewer: A virtual machine console viewer + * + * Copyright (C) 2007-2011 Red Hat, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ + +#include + +#include + +#include "virt-viewer-align.h" + + +#define VIRT_VIEWER_ALIGN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), VIRT_VIEWER_TYPE_ALIGN, VirtViewerAlignPrivate)) + +struct _VirtViewerAlignPrivate +{ + gboolean dirty; + guint preferred_width; + guint preferred_height; + guint zoom_level; + gboolean zoom; +}; + +static void virt_viewer_align_size_request(GtkWidget *widget, + GtkRequisition *requisition); +static void virt_viewer_align_size_allocate(GtkWidget *widget, + GtkAllocation *allocation); +static void virt_viewer_align_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void virt_viewer_align_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +G_DEFINE_TYPE(VirtViewerAlign, virt_viewer_align, GTK_TYPE_BIN) + +enum { + PROP_0, + + PROP_PREFERRED_WIDTH, + PROP_PREFERRED_HEIGHT, + PROP_ZOOM, + PROP_ZOOM_LEVEL, +}; + +static void +virt_viewer_align_class_init(VirtViewerAlignClass *class) +{ + GObjectClass *gobject_class; + GtkWidgetClass *widget_class; + + gobject_class = (GObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + gobject_class->set_property = virt_viewer_align_set_property; + gobject_class->get_property = virt_viewer_align_get_property; + + widget_class->size_request = virt_viewer_align_size_request; + widget_class->size_allocate = virt_viewer_align_size_allocate; + + g_object_class_install_property(gobject_class, + PROP_PREFERRED_WIDTH, + g_param_spec_int("preferred-width", + "Width", + "Preferred width", + 100, + G_MAXINT32, + 100, + G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, + PROP_PREFERRED_HEIGHT, + g_param_spec_int("preferred-height", + "Height", + "Preferred height", + 100, + G_MAXINT32, + 100, + G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, + PROP_ZOOM, + g_param_spec_boolean("zoom", + "Zoom", + "Zoom", + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, + PROP_ZOOM_LEVEL, + g_param_spec_int("zoom-level", + "Zoom", + "Zoom level", + 10, + 400, + 100, + G_PARAM_READWRITE)); + + g_type_class_add_private(gobject_class, sizeof(VirtViewerAlignPrivate)); +} + +static void +virt_viewer_align_init(VirtViewerAlign *align) +{ + gtk_widget_set_has_window(GTK_WIDGET(align), FALSE); + gtk_widget_set_redraw_on_allocate(GTK_WIDGET(align), FALSE); + + align->priv = VIRT_VIEWER_ALIGN_GET_PRIVATE(align); + + align->priv->preferred_width = 100; + align->priv->preferred_height = 100; + align->priv->zoom_level = 100; + align->priv->zoom = TRUE; +} + +GtkWidget* +virt_viewer_align_new(void) +{ + return g_object_new (VIRT_VIEWER_TYPE_ALIGN, NULL); +} + +static void +virt_viewer_align_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + VirtViewerAlign *align = VIRT_VIEWER_ALIGN(object); + VirtViewerAlignPrivate *priv = align->priv; + + switch (prop_id) { + case PROP_PREFERRED_WIDTH: + virt_viewer_align_set_preferred_size(align, + g_value_get_int(value), + priv->preferred_height); + break; + case PROP_PREFERRED_HEIGHT: + virt_viewer_align_set_preferred_size(align, + priv->preferred_width, + g_value_get_int(value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +virt_viewer_align_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + VirtViewerAlign *align = VIRT_VIEWER_ALIGN(object); + VirtViewerAlignPrivate *priv = align->priv; + + switch (prop_id) { + case PROP_PREFERRED_WIDTH: + g_value_set_int(value, priv->preferred_width); + break; + case PROP_PREFERRED_HEIGHT: + g_value_set_int(value, priv->preferred_height); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static gboolean +virt_viewer_align_idle(gpointer opaque) +{ + VirtViewerAlign *align = opaque; + VirtViewerAlignPrivate *priv = align->priv; + if (!priv->dirty) + gtk_widget_queue_resize_no_redraw(GTK_WIDGET(align)); + return FALSE; +} + + +static void +virt_viewer_align_size_request(GtkWidget *widget, + GtkRequisition *requisition) +{ + VirtViewerAlign *align = VIRT_VIEWER_ALIGN(widget); + VirtViewerAlignPrivate *priv = align->priv; + + requisition->width = GTK_CONTAINER(widget)->border_width * 2; + requisition->height = GTK_CONTAINER(widget)->border_width * 2; + + if (priv->dirty) { + if (priv->zoom) + requisition->width += priv->preferred_width * priv->zoom_level / 100; + else + requisition->width += priv->preferred_width; + } else { + requisition->width += 50; + } + if (priv->dirty) { + if (priv->zoom) + requisition->height += priv->preferred_height * priv->zoom_level / 100; + else + requisition->height += priv->preferred_height; + } else { + requisition->height += 50; + } + + if (priv->dirty) { + g_idle_add(virt_viewer_align_idle, widget); + priv->dirty = FALSE; + } +} + +static void +virt_viewer_align_size_allocate(GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin = GTK_BIN(widget); + VirtViewerAlign *align = VIRT_VIEWER_ALIGN(widget); + VirtViewerAlignPrivate *priv = align->priv; + GtkAllocation child_allocation; + gint width, height; + gint border_width; + double preferredAspect; + double actualAspect; + + widget->allocation = *allocation; + + preferredAspect = (double)priv->preferred_width / (double)priv->preferred_height; + + if (bin->child && gtk_widget_get_visible(bin->child)) { + border_width = GTK_CONTAINER(align)->border_width; + + width = MAX(1, allocation->width - 2 * border_width); + height = MAX(1, allocation->height - 2 * border_width); + actualAspect = (double)width / (double)height; + + if (actualAspect > preferredAspect) { + child_allocation.width = height * preferredAspect; + child_allocation.height = height; + } else { + child_allocation.width = width; + child_allocation.height = width / preferredAspect; + } + + child_allocation.x = 0.5 * (width - child_allocation.width) + allocation->x + border_width; + child_allocation.y = 0.5 * (height - child_allocation.height) + allocation->y + border_width; + + gtk_widget_size_allocate(bin->child, &child_allocation); + } +} + + +void virt_viewer_align_set_preferred_size(VirtViewerAlign *align, + guint width, + guint height) +{ + VirtViewerAlignPrivate *priv = align->priv; + + priv->preferred_width = width; + priv->preferred_height = height; + priv->dirty = TRUE; + + gtk_widget_queue_resize(GTK_WIDGET(align)); +} + +void virt_viewer_align_set_zoom_level(VirtViewerAlign *align, + guint zoom) +{ + VirtViewerAlignPrivate *priv = align->priv; + GtkBin *bin = GTK_BIN(align); + + if (zoom < 10) + zoom = 10; + if (zoom > 400) + zoom = 400; + priv->zoom_level = zoom; + + if (bin->child && gtk_widget_get_visible(bin->child)) { + priv->dirty = TRUE; + gtk_widget_queue_resize(GTK_WIDGET(align)); + } +} + + +void virt_viewer_align_zoom_in(VirtViewerAlign *align) +{ + VirtViewerAlignPrivate *priv = align->priv; + virt_viewer_align_set_zoom_level(align, priv->zoom_level + 10); +} + +void virt_viewer_align_zoom_out(VirtViewerAlign *align) +{ + VirtViewerAlignPrivate *priv = align->priv; + virt_viewer_align_set_zoom_level(align, priv->zoom_level - 10); +} + +void virt_viewer_align_zoom_normal(VirtViewerAlign *align) +{ + virt_viewer_align_set_zoom_level(align, 100); +} + + +void virt_viewer_align_set_zoom(VirtViewerAlign *align, + gboolean zoom) +{ + VirtViewerAlignPrivate *priv = align->priv; + GtkBin *bin = GTK_BIN(align); + + priv->zoom = zoom; + if (bin->child && gtk_widget_get_visible(bin->child)) { + priv->dirty = TRUE; + gtk_widget_queue_resize(GTK_WIDGET(align)); + } +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/src/virt-viewer-align.h b/src/virt-viewer-align.h new file mode 100644 index 0000000..db1194c --- /dev/null +++ b/src/virt-viewer-align.h @@ -0,0 +1,86 @@ +/* + * Virt Viewer: A virtual machine console viewer + * + * Copyright (C) 2007-2011 Red Hat, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange + */ +#ifndef _VIRT_VIEWER_ALIGN_H +#define _VIRT_VIEWER_ALIGN_H + +#include + +G_BEGIN_DECLS + +#define VIRT_VIEWER_TYPE_ALIGN virt_viewer_align_get_type() + +#define VIRT_VIEWER_ALIGN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIRT_VIEWER_TYPE_ALIGN, VirtViewerAlign)) + +#define VIRT_VIEWER_ALIGN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), VIRT_VIEWER_TYPE_ALIGN, VirtViewerAlignClass)) + +#define VIRT_VIEWER_IS_ALIGN(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIRT_VIEWER_TYPE_ALIGN)) + +#define VIRT_VIEWER_IS_ALIGN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), VIRT_VIEWER_TYPE_ALIGN)) + +#define VIRT_VIEWER_ALIGN_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), VIRT_VIEWER_TYPE_ALIGN, VirtViewerAlignClass)) + +typedef struct _VirtViewerAlign VirtViewerAlign; +typedef struct _VirtViewerAlignClass VirtViewerAlignClass; +typedef struct _VirtViewerAlignPrivate VirtViewerAlignPrivate; + + +struct _VirtViewerAlign { + GtkBin parent; + + VirtViewerAlignPrivate *priv; +}; + +struct _VirtViewerAlignClass { + GtkBinClass parent_class; +}; + +GType virt_viewer_align_get_type(void); + +GtkWidget *virt_viewer_align_new(void); + +void virt_viewer_align_set_preferred_size(VirtViewerAlign *align, + guint width, + guint height); + +void virt_viewer_align_zoom_in(VirtViewerAlign *align); +void virt_viewer_align_zoom_out(VirtViewerAlign *align); +void virt_viewer_align_zoom_normal(VirtViewerAlign *align); +void virt_viewer_align_set_zoom_level(VirtViewerAlign *align, + guint zoom); +void virt_viewer_align_set_zoom(VirtViewerAlign *align, + gboolean zoom); + +G_END_DECLS + +#endif /* _VIRT_VIEWER_ALIGN_H */ +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/src/virt-viewer-priv.h b/src/virt-viewer-priv.h index 1cadda2..074e67a 100644 --- a/src/virt-viewer-priv.h +++ b/src/virt-viewer-priv.h @@ -65,8 +65,6 @@ struct _VirtViewer { char *pretty_address; - int zoomlevel; - int desktopWidth; int desktopHeight; gboolean autoResize; diff --git a/src/virt-viewer.c b/src/virt-viewer.c index a8f6a6f..9f3d1b2 100644 --- a/src/virt-viewer.c +++ b/src/virt-viewer.c @@ -47,6 +47,7 @@ #include "virt-viewer.h" #include "virt-viewer-priv.h" +#include "virt-viewer-align.h" #include "virt-viewer-events.h" #include "virt-viewer-auth.h" #include "virt-viewer-display-vnc.h" @@ -57,8 +58,6 @@ #include "view/autoDrawer.h" -#define SCALE(x) do { x = viewer->fullscreen ? x : x * viewer->zoomlevel / 100; } while (0); - gboolean doDebug = FALSE; /* Signal handlers for main window */ @@ -161,69 +160,6 @@ virt_viewer_add_display_and_realize(VirtViewer *viewer) gtk_widget_realize(viewer->display->widget); } -/* Now that the size is set to our preferred sizing, this - * triggers another resize calculation but without our - * scrolled window callback active. This is the key that - * allows us to set the fixed size, but then allow the user - * to later resize it smaller again - */ -static gboolean -virt_viewer_unset_widget_size_cb(gpointer data) -{ - GtkWidget *widget = data; - DEBUG_LOG("Unset requisition on widget=%p", widget); - - gtk_widget_queue_resize_no_redraw (widget); - - return FALSE; -} - -/* - * This sets the actual size of the widget, and then - * sets an idle callback to resize again, without constraints - * activated - */ -static gboolean -virt_viewer_set_widget_size_cb(GtkWidget *widget, - GtkRequisition *req, - gpointer data) -{ - VirtViewerSize *size = data; - DEBUG_LOG("Set requisition on widget=%p to %dx%d", widget, size->width, size->height); - - req->width = size->width; - req->height = size->height; - - g_signal_handler_disconnect(widget, size->sig_id); - g_free(size); - g_idle_add(virt_viewer_unset_widget_size_cb, widget); - - return FALSE; -} - - -/* - * Registers a callback used to set the widget size once - */ -static void -virt_viewer_set_widget_size(VirtViewer *viewer, - GtkWidget *widget, - int width, - int height) -{ - VirtViewerSize *size = g_new (VirtViewerSize, 1); - DEBUG_LOG("Queue resize widget=%p width=%d height=%d", widget, width, height); - size->viewer = viewer; - size->width = width; - size->height = height; - size->sig_id = g_signal_connect - (widget, "size-request", - G_CALLBACK (virt_viewer_set_widget_size_cb), - size); - - gtk_widget_queue_resize (widget); -} - /* * This code attempts to resize the top level window to be large enough @@ -273,44 +209,32 @@ virt_viewer_resize_main_window(VirtViewer *viewer) height = viewer->desktopHeight; } - SCALE(width); - SCALE(height); - - virt_viewer_set_widget_size(viewer, - viewer->align, - width, - height); + virt_viewer_align_set_preferred_size(VIRT_VIEWER_ALIGN(viewer->align), + width, height); } void virt_viewer_menu_view_zoom_out(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer) { - viewer->zoomlevel -= 10; - if (viewer->zoomlevel < 10) - viewer->zoomlevel = 10; - - virt_viewer_resize_main_window(viewer); + gtk_window_resize(GTK_WINDOW(viewer->window), 1, 1); + virt_viewer_align_zoom_out(VIRT_VIEWER_ALIGN(viewer->align)); } void virt_viewer_menu_view_zoom_in(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer) { - viewer->zoomlevel += 10; - if (viewer->zoomlevel > 200) - viewer->zoomlevel = 200; - - virt_viewer_resize_main_window(viewer); + gtk_window_resize(GTK_WINDOW(viewer->window), 1, 1); + virt_viewer_align_zoom_in(VIRT_VIEWER_ALIGN(viewer->align)); } void virt_viewer_menu_view_zoom_reset(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer) { - viewer->zoomlevel = 100; - - virt_viewer_resize_main_window(viewer); + gtk_window_resize(GTK_WINDOW(viewer->window), 1, 1); + virt_viewer_align_zoom_normal(VIRT_VIEWER_ALIGN(viewer->align)); } void @@ -1397,7 +1321,6 @@ virt_viewer_start(const char *uri, viewer->verbose = verbose; viewer->domkey = g_strdup(name); viewer->uri = g_strdup(uri); - viewer->zoomlevel = zoom; g_value_init(&viewer->accelSetting, G_TYPE_STRING); @@ -1427,7 +1350,9 @@ virt_viewer_start(const char *uri, } viewer->status = gtk_label_new(""); - viewer->align = gtk_alignment_new(0.5, 0.5, 0, 0); + viewer->align = virt_viewer_align_new(); + + virt_viewer_align_set_zoom_level(VIRT_VIEWER_ALIGN(viewer->align), zoom); viewer->notebook = gtk_notebook_new(); gtk_notebook_set_show_tabs(GTK_NOTEBOOK(viewer->notebook), FALSE); diff --git a/src/virt-viewer.xml b/src/virt-viewer.xml index 8f2eb0b..783313c 100644 --- a/src/virt-viewer.xml +++ b/src/virt-viewer.xml @@ -41,6 +41,7 @@ True True + @@ -60,6 +61,7 @@ True Full screen True + @@ -72,17 +74,21 @@ True - + True gtk-zoom-in + True + True - + True gtk-zoom-out + True + True @@ -93,9 +99,11 @@ - + True gtk-zoom-100 + True + True