gimp/app/gdisplay_ops.c

317 lines
7.9 KiB
C

/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "libgimpwidgets/gimpwidgets.h"
#include "core/core-types.h"
#include "core/gimp.h"
#include "core/gimpimage.h"
#include "colormaps.h"
#include "gdisplay_ops.h"
#include "gimprc.h"
#include "libgimp/gimpintl.h"
static void gdisplay_close_warning_callback (GtkWidget *widget,
gboolean close,
gpointer data);
static void gdisplay_close_warning_dialog (const gchar *image_name,
GDisplay *gdisp);
/*
* This file is for operations on the gdisplay object
*/
gulong
gdisplay_white_pixel (GDisplay *gdisp)
{
return g_white_pixel;
}
gulong
gdisplay_gray_pixel (GDisplay *gdisp)
{
return g_gray_pixel;
}
gulong
gdisplay_black_pixel (GDisplay *gdisp)
{
return g_black_pixel;
}
gulong
gdisplay_color_pixel (GDisplay *gdisp)
{
return g_color_pixel;
}
void
gdisplay_xserver_resolution (gdouble *xres,
gdouble *yres)
{
gint width, height;
gint widthMM, heightMM;
width = gdk_screen_width ();
height = gdk_screen_height ();
widthMM = gdk_screen_width_mm ();
heightMM = gdk_screen_height_mm ();
/*
* From xdpyinfo.c:
*
* there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
*
* dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
* = N pixels / (M inch / 25.4)
* = N * 25.4 pixels / M inch
*/
*xres = (width * 25.4) / ((gdouble) widthMM);
*yres = (height * 25.4) / ((gdouble) heightMM);
}
void
gdisplay_new_view (GDisplay *gdisp)
{
GDisplay *new_gdisp;
/* make sure the image has been fully loaded... */
if (gdisp->gimage)
{
new_gdisp = gdisplay_new (gdisp->gimage, gdisp->scale);
}
}
void
gdisplay_close_window (GDisplay *gdisp,
gboolean kill_it)
{
/* FIXME: gimp_busy HACK not really appropriate here because we only
* want to prevent the busy image and display to be closed. --Mitch
*/
if (gdisp->gimage->gimp->busy)
return;
/* If the image has been modified, give the user a chance to save
* it before nuking it--this only applies if its the last view
* to an image canvas. (a gimage with disp_count = 1)
*/
if (! kill_it &&
(gdisp->gimage->disp_count == 1) &&
gdisp->gimage->dirty &&
gimprc.confirm_on_close)
{
gdisplay_close_warning_dialog
(g_basename (gimp_image_filename (gdisp->gimage)), gdisp);
}
else
{
gtk_widget_destroy (gdisp->shell);
}
}
void
gdisplay_shrink_wrap (GDisplay *gdisp)
{
/*
* I'm pretty sure this assumes that the current size is < display size
* Is this a valid assumption?
*/
GtkAllocation allocation;
gint disp_width, disp_height;
gint width, height;
gint shell_x, shell_y;
gint shell_width, shell_height;
gint max_auto_width, max_auto_height;
gint border_x, border_y;
gint s_width, s_height;
gboolean resize = FALSE;
s_width = gdk_screen_width ();
s_height = gdk_screen_height ();
width = SCALEX (gdisp, gdisp->gimage->width);
height = SCALEY (gdisp, gdisp->gimage->height);
disp_width = gdisp->disp_width;
disp_height = gdisp->disp_height;
shell_width = gdisp->shell->allocation.width;
shell_height = gdisp->shell->allocation.height;
border_x = shell_width - disp_width;
border_y = shell_height - disp_height;
max_auto_width = (s_width - border_x) * 0.75;
max_auto_height = (s_height - border_y) * 0.75;
allocation.x = 0;
allocation.y = 0;
/* If one of the display dimensions has changed and one of the
* dimensions fits inside the screen
*/
if (((width + border_x) < s_width || (height + border_y) < s_height) &&
(width != disp_width || height != disp_height))
{
width = ((width + border_x) < s_width) ? width : max_auto_width;
height = ((height + border_y) < s_height) ? height : max_auto_height;
resize = TRUE;
}
/* If the projected dimension is greater than current, but less than
* 3/4 of the screen size, expand automagically
*/
else if ((width > disp_width || height > disp_height) &&
(disp_width < max_auto_width || disp_height < max_auto_height))
{
width = MIN (max_auto_width, width);
height = MIN (max_auto_height, height);
resize = TRUE;
}
if (resize)
{
if (width < gdisp->statusarea->requisition.width)
{
width = gdisp->statusarea->requisition.width;
}
#undef RESIZE_DEBUG
#ifdef RESIZE_DEBUG
g_print ("1w:%d/%d d:%d/%d s:%d/%d b:%d/%d\n",
width, height,
disp_width, disp_height,
shell_width, shell_height,
border_x, border_y);
#endif /* RESIZE_DEBUG */
gdisp->disp_width = width;
gdisp->disp_height = height;
allocation.width = width + border_x;
allocation.height = height + border_y;
/* don't call gdisplay_canvas_events() on any of the following
* changes because our caller has to do a full display update anyway
*/
gtk_signal_handler_block_by_data (GTK_OBJECT (gdisp->canvas), gdisp);
gtk_widget_size_allocate (gdisp->shell, &allocation);
gdk_window_resize (gdisp->shell->window,
allocation.width,
allocation.height);
/* let Gtk/X/WM position the window */
while (gtk_events_pending ())
gtk_main_iteration ();
gdk_window_get_origin (gdisp->shell->window, &shell_x, &shell_y);
/* if the window is offscreen, center it... */
if (shell_x > s_width || shell_y > s_height ||
(shell_x + width + border_x) < 0 || (shell_y + height + border_y) < 0)
{
shell_x = (s_width - width - border_x) >> 1;
shell_y = (s_height - height - border_y) >> 1;
gdk_window_move (gdisp->shell->window, shell_x, shell_y);
}
gtk_signal_handler_unblock_by_data (GTK_OBJECT (gdisp->canvas), gdisp);
}
/* If the width or height of the display has changed, recalculate
* the display offsets...
*/
if (disp_width != gdisp->disp_width ||
disp_height != gdisp->disp_height)
{
gdisp->offset_x += (disp_width - gdisp->disp_width) / 2;
gdisp->offset_y += (disp_height - gdisp->disp_height) / 2;
}
}
/********************************************************
* Routines to query before closing a dirty image *
********************************************************/
static void
gdisplay_close_warning_callback (GtkWidget *widget,
gboolean close,
gpointer data)
{
GDisplay *gdisp;
gdisp = (GDisplay *) data;
gdisp->warning_dialog = NULL;
if (close)
gtk_widget_destroy (gdisp->shell);
}
static void
gdisplay_close_warning_dialog (const gchar *image_name,
GDisplay *gdisp)
{
GtkWidget *mbox;
gchar *warning_buf;
if (gdisp->warning_dialog != NULL)
{
gdk_window_raise (gdisp->warning_dialog->window);
return;
}
warning_buf =
g_strdup_printf (_("Changes were made to %s.\nClose anyway?"), image_name);
gdisp->warning_dialog = mbox =
gimp_query_boolean_box (image_name,
gimp_standard_help_func,
"dialogs/really_close.html",
FALSE,
warning_buf,
GTK_STOCK_CLOSE, GTK_STOCK_CANCEL,
NULL, NULL,
gdisplay_close_warning_callback,
gdisp);
g_free (warning_buf);
gtk_widget_show (mbox);
}