1999-07-29 08:23:51 +08:00
|
|
|
/*
|
|
|
|
* WinSnap Win32 Window Capture Plug-in
|
|
|
|
* Copyright (C) 1999 Craig Setera
|
2000-05-12 03:27:26 +08:00
|
|
|
* Craig Setera <setera@home.com>
|
1999-07-29 08:23:51 +08:00
|
|
|
* 07/14/1999
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* Based on (at least) the following plug-ins:
|
|
|
|
* Screenshot
|
|
|
|
* TWAIN
|
|
|
|
*
|
|
|
|
* Any suggestions, bug-reports or patches are welcome.
|
|
|
|
*
|
|
|
|
* This plug-in provides Win32 users with screen snapshot ability.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Revision history
|
|
|
|
*
|
|
|
|
* (07/13/99) v0.5 First working version (internal)
|
|
|
|
* (07/14/99) v0.55 Switched to g_error, g_message, etc.
|
|
|
|
* (07/16/99) v0.60 Better timing, comment cleanup
|
|
|
|
* (07/16/99) v0.70 Switched name
|
|
|
|
*/
|
|
|
|
|
2000-01-19 04:52:16 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <windows.h>
|
2000-01-19 04:52:16 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
#include "resource.h"
|
2000-01-19 04:52:16 +08:00
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
#include "libgimp/gimp.h"
|
2000-06-07 05:33:19 +08:00
|
|
|
#include "libgimp/gimpui.h"
|
2000-01-19 04:52:16 +08:00
|
|
|
#include "libgimp/stdplugins-intl.h"
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Plug-in Definitions
|
|
|
|
*/
|
Changed the semantics of GIMP_EXTENSION and (to some extent) of
2003-06-19 Michael Natterer <mitch@gimp.org>
Changed the semantics of GIMP_EXTENSION and (to some extent)
of GIMP_PLUGIN:
The old meaning of EXTENSION was "I live in the toolbox" and
PLUGIN meant "I take RUN-MODE,IMAGE,DRAWABLE args (but only if I
am invoked interactively)". This is completely useless, since
living in the toolbox means having "<Toolbox>" in the menu_path
and taking RUN-MODE,IMAGE,DRAWABLE means just that, regardless of
what type of procedure we are.
The new meaning of GIMP_PLUGIN is just "I am an ordinary procedure,
I am invoked, do my job and finish", while GIMP_EXTENSION means
"I will install temporary procedures and I will keep running to
keep them available".
(A GIMP_EXTENSION *must* call gimp_extension_ack() now to tell the
core that it's ready to run, or the core will block waiting for
the message !!!).
* configure.in: bumped version number to 1.3.16.
* libgimpbase/gimpprotocol.h: increased protocol version number so
old extensions will refuse to load.
* app/gui/plug-in-commands.c (plug_in_run_cmd_callback): don't
blindly pass RUN-MODE,IMAGE,DRAWABLE to GIMP_PLUGIN procedures but
look at their parameters and pass them either RUN-MODE, or
RUN-MODE,IMAGE, or RUN-MODE,IMAGE,DRAWABLE.
* app/pdb/procedural_db.c: cleaned up, better error reporting,
replaced an impossible error message by g_return_if_fail()
* app/plug-in/plug-in-message.c (plug_in_handle_proc_install):
better error messages.
* app/plug-in/plug-in-params.c: allocate parameter arrays using
g_new0() so we don't have to worry about uninitialized stuff
later.
* app/plug-in/plug-in-run.c (plug_in_run): wait for
gimp_extension_ack() installation confirmation for ALL extensions,
not just for automatically started ones.
* app/plug-in/plug-ins.c: cleanup.
* libgimp/gimp.[ch]: cleaned up and API-documented massively. Made
all magic values given in the GPConfig message static and added
accessor functions for them. Added gimp_tile_width()/height().
Added new function gimp_extension_enable() which turns on
asynchronous processing of temp_proc run requests without having
to enter an endless gimp_extension_process() loop. Moved all
private functions to the end of the file. Added tons of
g_return_if_fail() all over the place. Call gimp_run_procedure2()
from gimp_run_procedure() instead of duplicating the
code. Indentation, spacing, stuff...
* libgimp/gimptile.[ch]: removed gimp_tile_width()/height().
* libgimp/gimpdrawable.c
* libgimp/gimppixelrgn.c
* libgimp/gimptile.c: use the gimp_tile_width()/height() accessor
functions.
* libgimp/gimp.def: added gimp_extension_enable.
* libgimp/gimpmenu.c: removed evil code which connected to
_readchannel manually and use gimp_extension_enable() for watching
temp_procs.
* plug-ins/helpbrowser/helpbrowser.c: removed the same evil code
here and call gimp_extension_enable(). Call gimp_extension_ack()
to let the core know that the temp_proc is installed.
* plug-ins/script-fu/script-fu.c: made all procedures except the
permanently running "extension_script_fu" ordinary GIMP_PLUGIN
procedures.
* plug-ins/common/curve_bend.c
* plug-ins/common/plugindetails.c
* plug-ins/common/screenshot.c
* plug-ins/common/uniteditor.c
* plug-ins/common/winclipboard.c
* plug-ins/dbbrowser/dbbrowser.c
* plug-ins/gfli/gfli.c
* plug-ins/twain/twain.c
* plug-ins/webbrowser/webbrowser.c
* plug-ins/winsnap/winsnap.c: made them all ordinary GIMP_PLUGIN
procedures and renamed them from "extension_*" to "plug_in_*".
Random cleanups.
* app/widgets/gimphelp.c
* plug-ins/maze/maze_face.c: call "plug_in_web_browser" now.
2003-06-20 01:12:00 +08:00
|
|
|
#define PLUG_IN_NAME "plug_in_winsnap"
|
1999-07-29 08:23:51 +08:00
|
|
|
#define PLUG_IN_PRINT_NAME "WinSnap"
|
2000-01-31 10:32:30 +08:00
|
|
|
#define PLUG_IN_DESCRIPTION "Capture a Win32 window or desktop image"
|
|
|
|
#define PLUG_IN_HELP "This plug-in will capture an image of a Win32 window or desktop"
|
2000-05-12 03:27:26 +08:00
|
|
|
#define PLUG_IN_AUTHOR "Craig Setera (setera@home.com)"
|
1999-07-29 08:23:51 +08:00
|
|
|
#define PLUG_IN_COPYRIGHT "Craig Setera"
|
|
|
|
#define PLUG_IN_VERSION "v0.70 (07/16/1999)"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Application definitions
|
|
|
|
*/
|
|
|
|
#define SELECT_FRAME 0
|
|
|
|
#define SELECT_CLIENT 1
|
|
|
|
#define SELECT_WINDOW 2
|
|
|
|
|
|
|
|
#define SHOW_WINDOW FALSE
|
|
|
|
#define APP_NAME PLUG_IN_NAME
|
|
|
|
#define WM_DOCAPTURE (WM_USER + 100)
|
|
|
|
|
|
|
|
/* File variables */
|
|
|
|
static int captureType;
|
|
|
|
static char buffer[512];
|
|
|
|
static char *capBytes = NULL;
|
|
|
|
static HWND mainHwnd = NULL;
|
|
|
|
static HINSTANCE hInst = NULL;
|
|
|
|
static HCURSOR selectCursor = 0;
|
|
|
|
static ICONINFO iconInfo;
|
|
|
|
|
|
|
|
/* Forward declarations */
|
2003-07-02 08:15:09 +08:00
|
|
|
static void query (void);
|
|
|
|
static void run (const gchar *name,
|
|
|
|
gint nparams,
|
|
|
|
const GimpParam *param,
|
|
|
|
gint *nreturn_vals,
|
|
|
|
GimpParam **return_vals);
|
|
|
|
|
2000-01-15 05:38:47 +08:00
|
|
|
static void sendBMPToGimp(HBITMAP hBMP, HDC hDC, RECT rect);
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
BOOL CALLBACK dialogProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
|
|
|
|
/* Data structure holding data between runs */
|
|
|
|
typedef struct {
|
|
|
|
gint root;
|
2000-03-11 22:30:36 +08:00
|
|
|
guint delay;
|
1999-07-29 08:23:51 +08:00
|
|
|
gint decor;
|
|
|
|
} WinSnapValues;
|
|
|
|
|
|
|
|
/* Default WinSnap values */
|
|
|
|
static WinSnapValues winsnapvals =
|
|
|
|
{
|
|
|
|
FALSE,
|
2000-03-11 22:30:36 +08:00
|
|
|
0,
|
|
|
|
TRUE,
|
1999-07-29 08:23:51 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* The dialog information */
|
|
|
|
typedef struct {
|
2000-03-11 22:30:36 +08:00
|
|
|
#ifdef CAN_SET_DECOR
|
1999-07-29 08:23:51 +08:00
|
|
|
GtkWidget *decor_button;
|
2000-03-11 22:30:36 +08:00
|
|
|
#endif
|
1999-07-29 08:23:51 +08:00
|
|
|
GtkWidget *single_button;
|
|
|
|
GtkWidget *root_button;
|
2000-03-11 22:30:36 +08:00
|
|
|
GtkWidget *delay_spinner;
|
2003-07-02 08:15:09 +08:00
|
|
|
gboolean run;
|
1999-07-29 08:23:51 +08:00
|
|
|
} WinSnapInterface;
|
|
|
|
|
|
|
|
/* The dialog data */
|
|
|
|
static WinSnapInterface winsnapintf =
|
|
|
|
{
|
2000-03-11 22:30:36 +08:00
|
|
|
#ifdef CAN_SET_DECOR
|
|
|
|
NULL,
|
|
|
|
#endif
|
1999-07-29 08:23:51 +08:00
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
FALSE /* run */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* This plug-in's functions */
|
2000-08-24 07:11:07 +08:00
|
|
|
GimpPlugInInfo PLUG_IN_INFO =
|
1999-07-29 08:23:51 +08:00
|
|
|
{
|
|
|
|
NULL, /* init_proc */
|
|
|
|
NULL, /* quit_proc */
|
|
|
|
query, /* query_proc */
|
|
|
|
run, /* run_proc */
|
|
|
|
};
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* We create a DIB section to hold the grabbed area. The scanlines in
|
|
|
|
* DIB sections are aligned ona LONG (four byte) boundary. Its pixel
|
|
|
|
* data is in RGB (BGR actually) format, three bytes per pixel.
|
|
|
|
*
|
|
|
|
* The GIMP uses no alignment for its pixel regions. The GIMP image we
|
|
|
|
* create is of type RGB, i.e. three bytes per pixel, too. Thus in
|
|
|
|
* order to be able to quickly transfer all of the image at a time, we
|
1999-10-12 07:30:40 +08:00
|
|
|
* must use a DIB section and pixel region the scanline width in
|
1999-10-26 03:20:41 +08:00
|
|
|
* bytes of which is evenly divisible with both 3 and 4. I.e. it must
|
1999-10-12 07:30:40 +08:00
|
|
|
* be a multiple of 12 bytes, or in pixels, a multiple of four pixels.
|
1999-07-29 08:23:51 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define ROUND4(width) (((width-1)/4+1)*4)
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* Debug stuff
|
|
|
|
******************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* formatWindowsError
|
|
|
|
*
|
|
|
|
* Format the latest Windows error message into
|
|
|
|
* a readable string. Store in the provided
|
|
|
|
* buffer.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
formatWindowsError(char *buffer)
|
|
|
|
{
|
|
|
|
LPVOID lpMsgBuf;
|
|
|
|
|
|
|
|
/* Format the message */
|
|
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, GetLastError(),
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
(LPTSTR) &lpMsgBuf, 0, NULL );
|
|
|
|
|
|
|
|
/* Copy to the buffer */
|
|
|
|
strcpy(buffer, lpMsgBuf);
|
|
|
|
|
|
|
|
LocalFree(lpMsgBuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* Bitmap capture and handling
|
|
|
|
******************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* primDoWindowCapture
|
|
|
|
*
|
|
|
|
* The primitive window capture functionality. Accepts
|
|
|
|
* the two device contexts and the rectangle to be
|
|
|
|
* captured.
|
|
|
|
*/
|
|
|
|
static HBITMAP
|
|
|
|
primDoWindowCapture(HDC hdcWindow, HDC hdcCompat, RECT rect)
|
|
|
|
{
|
|
|
|
HBITMAP hbmCopy;
|
|
|
|
HGDIOBJ oldObject;
|
|
|
|
BITMAPINFO bmi;
|
|
|
|
|
|
|
|
int width = (rect.right - rect.left);
|
1999-10-12 07:30:40 +08:00
|
|
|
int height = (rect.bottom - rect.top);
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Create the bitmap info header */
|
|
|
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
bmi.bmiHeader.biWidth = ROUND4(width);
|
|
|
|
bmi.bmiHeader.biHeight = -height;
|
|
|
|
bmi.bmiHeader.biPlanes = 1;
|
|
|
|
bmi.bmiHeader.biBitCount = 24;
|
|
|
|
bmi.bmiHeader.biCompression = BI_RGB;
|
|
|
|
bmi.bmiHeader.biSizeImage = 0;
|
|
|
|
bmi.bmiHeader.biXPelsPerMeter =
|
|
|
|
bmi.bmiHeader.biYPelsPerMeter = 0;
|
|
|
|
bmi.bmiHeader.biClrUsed = 0;
|
|
|
|
bmi.bmiHeader.biClrImportant = 0;
|
|
|
|
|
|
|
|
/* Create the bitmap storage space */
|
|
|
|
hbmCopy = CreateDIBSection(hdcCompat,
|
|
|
|
(BITMAPINFO *) &bmi,
|
|
|
|
DIB_RGB_COLORS,
|
|
|
|
&capBytes, NULL, 0);
|
|
|
|
if (!hbmCopy) {
|
|
|
|
formatWindowsError(buffer);
|
|
|
|
g_error("Error creating DIB section: %s", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Select the bitmap into the compatible DC. */
|
|
|
|
oldObject = SelectObject(hdcCompat, hbmCopy);
|
|
|
|
if (!oldObject) {
|
|
|
|
formatWindowsError(buffer);
|
|
|
|
g_error("Error selecting object: %s", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the data from the application to the bitmap. Even if we did
|
|
|
|
* round up the width, BitBlt only the actual data.
|
|
|
|
*/
|
|
|
|
if (!BitBlt(hdcCompat, 0,0,
|
|
|
|
width, height,
|
|
|
|
hdcWindow, 0,0,
|
|
|
|
SRCCOPY)) {
|
|
|
|
formatWindowsError(buffer);
|
|
|
|
g_error("Error copying bitmap: %s", buffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore the original object */
|
|
|
|
SelectObject(hdcCompat, oldObject);
|
|
|
|
|
|
|
|
return hbmCopy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* doCapture
|
|
|
|
*
|
|
|
|
* Do the capture. Accepts the window
|
|
|
|
* handle to be captured or the NULL value
|
|
|
|
* to specify the root window.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
doCapture(HWND selectedHwnd)
|
|
|
|
{
|
|
|
|
HDC hdcSrc;
|
|
|
|
HDC hdcCompat;
|
|
|
|
MSG msg;
|
|
|
|
HRGN capRegion;
|
|
|
|
HWND oldForeground;
|
|
|
|
RECT rect;
|
|
|
|
HBITMAP hbm;
|
|
|
|
HANDLE tHandle;
|
|
|
|
|
|
|
|
/* Try and get everything out of the way before the
|
|
|
|
* capture.
|
|
|
|
*/
|
2000-03-11 22:30:36 +08:00
|
|
|
Sleep(500 + winsnapvals.delay * 1000);
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Are we capturing a window or the whole screen */
|
|
|
|
if (selectedHwnd) {
|
|
|
|
|
|
|
|
/* Set to foreground window */
|
|
|
|
oldForeground = GetForegroundWindow();
|
|
|
|
SetForegroundWindow(selectedHwnd);
|
|
|
|
BringWindowToTop(selectedHwnd);
|
|
|
|
|
|
|
|
Sleep(500);
|
|
|
|
|
|
|
|
/* Build a region for the capture */
|
|
|
|
GetWindowRect(selectedHwnd, &rect);
|
|
|
|
capRegion = CreateRectRgn(rect.left, rect.top,
|
|
|
|
rect.right, rect.bottom);
|
|
|
|
if (!capRegion) {
|
|
|
|
formatWindowsError(buffer);
|
|
|
|
g_error("Error creating region: %s", buffer);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the device context for the selected
|
|
|
|
* window. Create a memory DC to use for the
|
|
|
|
* Bit copy.
|
|
|
|
*/
|
|
|
|
hdcSrc = GetDCEx(selectedHwnd, capRegion,
|
|
|
|
DCX_WINDOW | DCX_PARENTCLIP | DCX_INTERSECTRGN);
|
|
|
|
} else {
|
|
|
|
/* Get the device context for the whole screen */
|
|
|
|
hdcSrc = CreateDC("DISPLAY", NULL, NULL, NULL);
|
|
|
|
|
|
|
|
/* Get the screen's rectangle */
|
Must call gimp_set_remove_handler() to remove the browser_info_update
1999-11-09 Tor Lillqvist <tml@iki.fi>
* app/module_db.c (browser_destroy_callback): Must call
gimp_set_remove_handler() to remove the browser_info_update
handler from the GimpSet 'modules'.
Otherwise if we bring up the module browser, then close it, this
will call browser_destroy_callback(), which will free the
'browser_st' struct. Later when we exit the GIMP, the modules will
be unloaded, which will cause browser_info_update() to be called,
and passed the pointer to the already freed 'browser_st'. Whoopee.
Thanks to Electric Fence for pointing this out.
* app/makefile.{cygwin,msc}: Remove actionarea.
* libgimp/gimp.h: Change declaration of nonexistent function
gimp_layer_attach_new_parasite() to declaration of
gimp_drawable_attach_new_parasite(), which was missing.
* libgimp/gimpui.def
* libgimp/makefile.{cygwin,msc}: Add gimpcolorbutton.
* plug-ins/makefile.{cygwin,msc}: Add gap_filter and gap_plugins.
* plug-ins/common/gz.c: Fix renamed variable in Win32 part.
* plug-ins/gap/gap_lib.c: Use G_DIR_SEPARATOR_S.
* plug-ins/gdyntext/font_selection.c: When compiling with current
CVS GTk+ (i.e., on Win32 most likely) use the gdk_font_list_*
functions instead of Xlib's XListFonts() and XFreeFontNames().
* plug-ins/gdyntext/gdyntext.c: Use G_PI.
* plug-ins/gdyntext/gdyntext_ui.c: Guard inclusion of
unistd.h. Don't unnecessarily include gdkx.h and Xlib.h
* plug-ins/winsnap/winsnap.c: Fix rectangle orientation.
1999-11-10 07:01:31 +08:00
|
|
|
rect.top = 0;
|
|
|
|
rect.bottom = GetDeviceCaps(hdcSrc, VERTRES);
|
1999-07-29 08:23:51 +08:00
|
|
|
rect.left = 0;
|
|
|
|
rect.right = GetDeviceCaps(hdcSrc, HORZRES);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hdcSrc) {
|
|
|
|
formatWindowsError(buffer);
|
|
|
|
g_error("Error getting device context: %s", buffer);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
hdcCompat = CreateCompatibleDC(hdcSrc);
|
|
|
|
if (!hdcCompat) {
|
|
|
|
formatWindowsError(buffer);
|
|
|
|
g_error("Error getting compat device context: %s", buffer);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do the window capture */
|
|
|
|
hbm = primDoWindowCapture(hdcSrc, hdcCompat, rect);
|
|
|
|
if (!hbm)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Release the device context */
|
|
|
|
ReleaseDC(selectedHwnd, hdcSrc);
|
|
|
|
|
|
|
|
/* Replace the previous foreground window */
|
|
|
|
if (selectedHwnd && oldForeground)
|
|
|
|
SetForegroundWindow(oldForeground);
|
|
|
|
|
|
|
|
/* Send the bitmap */
|
|
|
|
if (hbm != NULL) {
|
|
|
|
sendBMPToGimp(hbm, hdcCompat, rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* Win32 entry point and setup...
|
|
|
|
******************************************************************/
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
#define DINV 3
|
|
|
|
|
|
|
|
/*
|
|
|
|
* highlightWindowFrame
|
|
|
|
*
|
|
|
|
* Highlight (or unhighlight) the specified
|
|
|
|
* window handle's frame.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
highlightWindowFrame(HWND hWnd)
|
|
|
|
{
|
|
|
|
HDC hdc;
|
|
|
|
RECT rc;
|
|
|
|
|
|
|
|
if (!IsWindow(hWnd))
|
|
|
|
return;
|
|
|
|
|
|
|
|
hdc = GetWindowDC(hWnd);
|
|
|
|
GetWindowRect(hWnd, &rc);
|
|
|
|
OffsetRect(&rc, -rc.left, -rc.top);
|
|
|
|
|
|
|
|
if (!IsRectEmpty(&rc)) {
|
|
|
|
PatBlt(hdc, rc.left, rc.top, rc.right-rc.left, DINV, DSTINVERT);
|
|
|
|
PatBlt(hdc, rc.left, rc.bottom-DINV, DINV, -(rc.bottom-rc.top-2*DINV),
|
|
|
|
DSTINVERT);
|
|
|
|
PatBlt(hdc, rc.right-DINV, rc.top+DINV, DINV, rc.bottom-rc.top-2*DINV,
|
|
|
|
DSTINVERT);
|
|
|
|
PatBlt(hdc, rc.right, rc.bottom-DINV, -(rc.right-rc.left), DINV,
|
|
|
|
DSTINVERT);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseDC(hWnd, hdc);
|
|
|
|
UpdateWindow(hWnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* setCaptureType
|
|
|
|
*
|
|
|
|
* Set the capture type. Should be one of:
|
|
|
|
* SELECT_FRAME
|
|
|
|
* SELECT_CLIENT
|
|
|
|
* SELECT_WINDOW
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
setCaptureType(int capType)
|
|
|
|
{
|
|
|
|
captureType = capType;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* myWindowFromPoint
|
|
|
|
*
|
|
|
|
* Map to the appropriate window from the
|
|
|
|
* specified point. The chosen window is
|
|
|
|
* based on the current capture type.
|
|
|
|
*/
|
|
|
|
static HWND
|
|
|
|
myWindowFromPoint(POINT pt)
|
|
|
|
{
|
|
|
|
HWND myHwnd;
|
|
|
|
HWND nextHwnd;
|
|
|
|
|
|
|
|
switch (captureType) {
|
|
|
|
case SELECT_FRAME:
|
|
|
|
case SELECT_CLIENT:
|
|
|
|
nextHwnd = WindowFromPoint(pt);
|
|
|
|
|
|
|
|
do {
|
|
|
|
myHwnd = nextHwnd;
|
|
|
|
nextHwnd = GetParent(myHwnd);
|
|
|
|
} while (nextHwnd);
|
|
|
|
|
|
|
|
return myHwnd;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SELECT_WINDOW:
|
|
|
|
return WindowFromPoint(pt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return WindowFromPoint(pt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dialogProc
|
|
|
|
*
|
|
|
|
* The window procedure for the window
|
|
|
|
* selection dialog box.
|
|
|
|
*/
|
|
|
|
BOOL CALLBACK
|
|
|
|
dialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
static int mouseCaptured;
|
|
|
|
static int buttonDown;
|
|
|
|
static HCURSOR oldCursor;
|
|
|
|
static RECT bitmapRect;
|
|
|
|
static HWND highlightedHwnd = NULL;
|
|
|
|
|
|
|
|
switch (msg) {
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
{
|
|
|
|
int nonclientHeight;
|
|
|
|
HWND hwndGroup;
|
|
|
|
RECT dlgRect;
|
|
|
|
RECT clientRect;
|
|
|
|
RECT groupRect;
|
|
|
|
BITMAP bm;
|
|
|
|
|
|
|
|
/* Set the mouse capture flag */
|
|
|
|
buttonDown = 0;
|
|
|
|
mouseCaptured = 0;
|
|
|
|
|
|
|
|
/* Calculate the bitmap dimensions */
|
|
|
|
GetObject(iconInfo.hbmMask, sizeof(BITMAP), (VOID *)&bm);
|
|
|
|
|
|
|
|
/* Calculate the dialog window dimensions */
|
|
|
|
GetWindowRect(hwndDlg, &dlgRect);
|
|
|
|
|
|
|
|
/* Calculate the group box dimensions */
|
|
|
|
hwndGroup = GetDlgItem(hwndDlg, IDC_GROUP);
|
|
|
|
GetWindowRect(hwndGroup, &groupRect);
|
|
|
|
OffsetRect(&groupRect, -dlgRect.left, -dlgRect.top);
|
|
|
|
|
|
|
|
/* The client's rectangle */
|
|
|
|
GetClientRect(hwndDlg, &clientRect);
|
|
|
|
|
|
|
|
/* The non-client height */
|
|
|
|
nonclientHeight = (dlgRect.bottom - dlgRect.top) -
|
|
|
|
(clientRect.bottom - clientRect.top);
|
|
|
|
|
|
|
|
/* Calculate the bitmap rectangle */
|
|
|
|
bitmapRect.top = ((groupRect.top + groupRect.bottom) / 2) -
|
|
|
|
(bm.bmHeight / 2);
|
|
|
|
bitmapRect.top -= nonclientHeight;
|
|
|
|
bitmapRect.bottom = bitmapRect.top + bm.bmHeight;
|
|
|
|
bitmapRect.left = ((groupRect.left + groupRect.right) / 2) - (bm.bmWidth / 2);
|
|
|
|
bitmapRect.right = bitmapRect.left + bm.bmWidth;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
/* Track the button down state */
|
|
|
|
buttonDown = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
buttonDown = 0;
|
|
|
|
|
|
|
|
/* If we have mouse captured
|
|
|
|
* we do this stuff.
|
|
|
|
*/
|
|
|
|
if (mouseCaptured) {
|
1999-10-12 07:30:40 +08:00
|
|
|
HWND selectedHwnd;
|
|
|
|
POINT cursorPos;
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Release the capture */
|
|
|
|
mouseCaptured = 0;
|
|
|
|
SetCursor(oldCursor);
|
|
|
|
ReleaseCapture();
|
|
|
|
|
|
|
|
/* Remove the highlight */
|
|
|
|
if (highlightedHwnd)
|
|
|
|
highlightWindowFrame(highlightedHwnd);
|
|
|
|
RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
|
|
|
|
|
|
|
|
/* Return the selected window */
|
|
|
|
GetCursorPos(&cursorPos);
|
|
|
|
selectedHwnd = myWindowFromPoint(cursorPos);
|
|
|
|
EndDialog(hwndDlg, (int) selectedHwnd);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
/* If the mouse is captured, show
|
|
|
|
* the window which is tracking
|
|
|
|
* under the mouse position.
|
|
|
|
*/
|
|
|
|
if (mouseCaptured) {
|
1999-10-12 07:30:40 +08:00
|
|
|
HWND currentHwnd;
|
1999-07-29 08:23:51 +08:00
|
|
|
POINT cursorPos;
|
|
|
|
|
|
|
|
/* Get the window */
|
|
|
|
GetCursorPos(&cursorPos);
|
|
|
|
currentHwnd = myWindowFromPoint(cursorPos);
|
|
|
|
|
|
|
|
/* Do the highlighting */
|
|
|
|
if (highlightedHwnd != currentHwnd) {
|
|
|
|
if (highlightedHwnd)
|
|
|
|
highlightWindowFrame(highlightedHwnd);
|
|
|
|
if (currentHwnd)
|
|
|
|
highlightWindowFrame(currentHwnd);
|
|
|
|
highlightedHwnd = currentHwnd;
|
|
|
|
}
|
|
|
|
/* If the mouse has not been captured,
|
|
|
|
* try to figure out if we should capture
|
|
|
|
* the mouse.
|
|
|
|
*/
|
|
|
|
} else if (buttonDown) {
|
|
|
|
POINT cursorPos;
|
|
|
|
|
|
|
|
/* Get the current client position */
|
|
|
|
GetCursorPos(&cursorPos);
|
|
|
|
ScreenToClient(hwndDlg, &cursorPos);
|
|
|
|
|
|
|
|
/* Check if within the rectangle formed
|
|
|
|
* by the bitmap
|
|
|
|
*/
|
|
|
|
if (PtInRect(&bitmapRect, cursorPos)) {
|
|
|
|
mouseCaptured = 1;
|
|
|
|
oldCursor = SetCursor(selectCursor);
|
|
|
|
SetCapture(hwndDlg);
|
|
|
|
RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_PAINT:
|
|
|
|
{
|
1999-10-12 07:30:40 +08:00
|
|
|
HDC hDC;
|
|
|
|
PAINTSTRUCT ps;
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* If the mouse is not captured draw
|
|
|
|
* the cursor image
|
|
|
|
*/
|
|
|
|
if (!mouseCaptured) {
|
|
|
|
hDC = BeginPaint(hwndDlg, &ps);
|
|
|
|
DrawIconEx(hDC, bitmapRect.left, bitmapRect.top, selectCursor,
|
|
|
|
0, 0, 0, NULL, DI_NORMAL);
|
2003-11-15 21:53:33 +08:00
|
|
|
EndPaint(hwndDlg, &ps);
|
1999-07-29 08:23:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
/* Handle the cancel button */
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hwndDlg, 0);
|
|
|
|
return TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't use the normal WinMain from gimp.h */
|
|
|
|
#define WinMain WinMain_no_thanks
|
|
|
|
MAIN()
|
|
|
|
#undef WinMain
|
|
|
|
|
|
|
|
/*
|
|
|
|
* WinMain
|
|
|
|
*
|
|
|
|
* The standard gimp plug-in WinMain won't quite cut it for
|
|
|
|
* this plug-in.
|
|
|
|
*/
|
|
|
|
int APIENTRY
|
|
|
|
WinMain(HINSTANCE hInstance,
|
|
|
|
HINSTANCE hPrevInstance,
|
|
|
|
LPSTR lpCmdLine,
|
|
|
|
int nCmdShow)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Normally, we would do all of the Windows-ish set up of
|
|
|
|
* the window classes and stuff here in WinMain. But,
|
|
|
|
* the only time we really need the window and message
|
|
|
|
* queues is during the plug-in run. So, all of that will
|
|
|
|
* be done during run(). This avoids all of the Windows
|
|
|
|
* setup stuff for the query(). Stash the instance handle now
|
|
|
|
* so it is available from the run() procedure.
|
|
|
|
*/
|
|
|
|
hInst = hInstance;
|
|
|
|
|
|
|
|
/*
|
2003-05-25 01:00:03 +08:00
|
|
|
* Now, call gimp_main... This is what the normal WinMain()
|
1999-07-29 08:23:51 +08:00
|
|
|
* would do.
|
|
|
|
*/
|
2003-05-25 01:00:03 +08:00
|
|
|
return gimp_main(&PLUG_IN_INFO, __argc, __argv);
|
1999-07-29 08:23:51 +08:00
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/*
|
|
|
|
* InitApplication
|
|
|
|
*
|
|
|
|
* Initialize window data and register the window class
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
InitApplication(HINSTANCE hInstance)
|
|
|
|
{
|
|
|
|
WNDCLASS wc;
|
|
|
|
BOOL retValue;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Get some resources */
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
/* For some reason this works only with MSVC */
|
|
|
|
selectCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_SELECT));
|
|
|
|
#else
|
|
|
|
selectCursor = LoadCursor(NULL, IDC_CROSS);
|
|
|
|
#endif
|
|
|
|
GetIconInfo(selectCursor, &iconInfo);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill in window class structure with parameters to describe
|
|
|
|
* the main window.
|
|
|
|
*/
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
wc.lpfnWndProc = (WNDPROC) WndProc;
|
|
|
|
wc.cbClsExtra = 0;
|
|
|
|
wc.cbWndExtra = 0;
|
|
|
|
wc.hInstance = hInstance;
|
|
|
|
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
|
|
|
wc.lpszClassName = APP_NAME;
|
|
|
|
wc.lpszMenuName = NULL;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Register the window class and stash success/failure code. */
|
|
|
|
retValue = RegisterClass(&wc);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Log error */
|
|
|
|
if (!retValue) {
|
|
|
|
formatWindowsError(buffer);
|
2000-01-19 04:52:16 +08:00
|
|
|
g_error("Error registering class: %s", buffer);
|
1999-07-29 08:23:51 +08:00
|
|
|
return retValue;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
return retValue;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/*
|
|
|
|
* InitInstance
|
|
|
|
*
|
|
|
|
* Create the main window for the application.
|
|
|
|
*/
|
|
|
|
BOOL
|
|
|
|
InitInstance(HINSTANCE hInstance, int nCmdShow)
|
|
|
|
{
|
|
|
|
/* Create our window */
|
|
|
|
mainHwnd = CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
|
|
|
|
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
|
|
|
|
NULL, NULL, hInstance, NULL);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
if (!mainHwnd) {
|
|
|
|
return (FALSE);
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
ShowWindow(mainHwnd, nCmdShow);
|
|
|
|
UpdateWindow(mainHwnd);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/*
|
|
|
|
* winsnapWinMain
|
|
|
|
*
|
|
|
|
* This is the function that represents the code that
|
|
|
|
* would normally reside in WinMain (see above). This
|
|
|
|
* function will get called during run() in order to set
|
|
|
|
* up the windowing environment necessary for WinSnap to
|
|
|
|
* operate.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
winsnapWinMain(void)
|
|
|
|
{
|
|
|
|
MSG msg;
|
|
|
|
|
|
|
|
/* Perform instance initialization */
|
|
|
|
if (!InitApplication(hInst))
|
|
|
|
return (FALSE);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Perform application initialization */
|
|
|
|
if (!InitInstance(hInst, SHOW_WINDOW))
|
|
|
|
return (FALSE);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Main message loop */
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0)) {
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (msg.wParam);
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/*
|
|
|
|
* WndProc
|
|
|
|
*
|
|
|
|
* Process window message for the main window.
|
|
|
|
*/
|
|
|
|
LRESULT CALLBACK
|
|
|
|
WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
HWND selectedHwnd;
|
|
|
|
|
|
|
|
switch (message) {
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
case WM_CREATE:
|
|
|
|
/* The window is created... Send the capture message */
|
|
|
|
PostMessage(hwnd, WM_DOCAPTURE, 0, 0);
|
|
|
|
break;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
case WM_DOCAPTURE:
|
|
|
|
/* Get the selected window handle */
|
|
|
|
selectedHwnd = (HWND) DialogBox(hInst, MAKEINTRESOURCE(IDD_SELECT),
|
|
|
|
hwnd, (DLGPROC) dialogProc);
|
|
|
|
if (selectedHwnd)
|
|
|
|
doCapture(selectedHwnd);
|
|
|
|
|
|
|
|
PostQuitMessage(0);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_DESTROY:
|
|
|
|
PostQuitMessage(0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return (DefWindowProc(hwnd, message, wParam, lParam));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* doRootWindowCapture
|
|
|
|
*
|
|
|
|
* Capture the root window
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
doRootWindowCapture(void)
|
|
|
|
{
|
|
|
|
/* Do the window capture */
|
|
|
|
doCapture(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* doNonRootWindowCapture
|
|
|
|
*
|
|
|
|
* Capture a selected window.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
doWindowCapture(void)
|
|
|
|
{
|
|
|
|
/* Start up a standard Win32
|
|
|
|
* message handling loop for
|
|
|
|
* selection of the window
|
|
|
|
* to be captured
|
|
|
|
*/
|
|
|
|
winsnapWinMain();
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/******************************************************************
|
|
|
|
* Snapshot configuration dialog
|
|
|
|
******************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* snap_close_callback
|
|
|
|
*
|
|
|
|
* The close button has been pressed... Close
|
|
|
|
* down the widgetry.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
snap_close_callback(GtkWidget *widget,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
gtk_main_quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* snap_grab_callback
|
|
|
|
*
|
|
|
|
* The "grab" button has been selected.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
snap_grab_callback(GtkWidget *widget,
|
2000-03-11 22:30:36 +08:00
|
|
|
gpointer data)
|
1999-07-29 08:23:51 +08:00
|
|
|
{
|
|
|
|
winsnapintf.run = TRUE;
|
2003-11-15 21:53:33 +08:00
|
|
|
winsnapvals.delay =
|
2000-03-11 22:30:36 +08:00
|
|
|
gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (winsnapintf.delay_spinner));
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_widget_destroy(GTK_WIDGET (data));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* snap_toggle_update
|
|
|
|
*
|
|
|
|
* The radio buttons have been updated.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
snap_toggle_update (GtkWidget *widget,
|
2000-03-11 22:30:36 +08:00
|
|
|
gpointer radio_button)
|
1999-07-29 08:23:51 +08:00
|
|
|
{
|
|
|
|
gint *toggle_val;
|
|
|
|
|
|
|
|
toggle_val = (gint *) radio_button;
|
|
|
|
|
|
|
|
if (GTK_TOGGLE_BUTTON (widget)->active)
|
|
|
|
*toggle_val = TRUE;
|
|
|
|
else
|
|
|
|
*toggle_val = FALSE;
|
|
|
|
|
|
|
|
#ifdef CAN_SET_DECOR
|
|
|
|
if (widget == winsnapintf.single_button)
|
|
|
|
gtk_widget_set_sensitive (winsnapintf.decor_button, *toggle_val);
|
|
|
|
#endif /* CAN_SET_DECOR */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* snap_dialog
|
|
|
|
*
|
|
|
|
* Bring up the GTK dialog for setting snapshot
|
|
|
|
* parameters.
|
|
|
|
*/
|
|
|
|
static gint
|
|
|
|
snap_dialog(void)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
|
|
|
GtkWidget *frame;
|
|
|
|
GtkWidget *vbox;
|
|
|
|
GtkWidget *button;
|
|
|
|
GtkWidget *hbox;
|
|
|
|
GtkWidget *radio_label;
|
2000-03-11 22:30:36 +08:00
|
|
|
GtkWidget *label;
|
|
|
|
GtkAdjustment *adj;
|
1999-07-29 08:23:51 +08:00
|
|
|
GSList *radio_group = NULL;
|
|
|
|
gint radio_pressed[2];
|
|
|
|
gint decorations;
|
2000-03-11 22:30:36 +08:00
|
|
|
guint delay;
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Set defaults */
|
|
|
|
radio_pressed[0] = (winsnapvals.root == FALSE);
|
|
|
|
radio_pressed[1] = (winsnapvals.root == TRUE);
|
|
|
|
decorations = winsnapvals.decor;
|
2000-03-11 22:30:36 +08:00
|
|
|
delay = winsnapvals.delay;
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Init GTK */
|
2000-05-01 02:17:55 +08:00
|
|
|
gimp_ui_init ("winsnap", FALSE);
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Main Dialog */
|
|
|
|
dialog = gtk_dialog_new ();
|
|
|
|
gtk_window_set_title(GTK_WINDOW(dialog), PLUG_IN_PRINT_NAME);
|
2003-06-01 06:23:55 +08:00
|
|
|
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_MOUSE);
|
2003-01-07 09:47:04 +08:00
|
|
|
g_signal_connect (dialog, "destroy",
|
|
|
|
G_CALLBACK (snap_close_callback),
|
|
|
|
NULL);
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Action area */
|
2000-01-19 04:52:16 +08:00
|
|
|
button = gtk_button_new_with_label(_("Grab"));
|
1999-07-29 08:23:51 +08:00
|
|
|
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
|
2003-01-07 09:47:04 +08:00
|
|
|
g_signal_connect (button, "clicked",
|
|
|
|
G_CALLBACK (snap_grab_callback),
|
|
|
|
dialog);
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),
|
|
|
|
button, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_grab_default(button);
|
|
|
|
gtk_widget_show(button);
|
|
|
|
|
2001-08-04 03:52:08 +08:00
|
|
|
button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
|
1999-07-29 08:23:51 +08:00
|
|
|
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
|
2003-01-07 09:47:04 +08:00
|
|
|
g_signal_connect_swapped (button, "clicked",
|
|
|
|
G_CALLBACK (gtk_widget_destroy),
|
|
|
|
dialog);
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG (dialog)->action_area),
|
|
|
|
button, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show(button);
|
|
|
|
|
|
|
|
/* Single Window */
|
|
|
|
frame = gtk_frame_new(NULL);
|
2000-12-12 02:46:32 +08:00
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(frame), 4);
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
|
|
|
|
frame, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new(FALSE, 4);
|
2000-12-12 02:46:32 +08:00
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_container_add(GTK_CONTAINER(frame), vbox);
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 4);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox),
|
|
|
|
hbox, TRUE, TRUE, 0);
|
|
|
|
winsnapintf.single_button = gtk_radio_button_new ( radio_group );
|
2003-06-01 06:23:55 +08:00
|
|
|
radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (winsnapintf.single_button) );
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (hbox),
|
|
|
|
winsnapintf.single_button, TRUE, TRUE, 0);
|
2003-01-07 09:47:04 +08:00
|
|
|
g_signal_connect (winsnapintf.single_button, "toggled",
|
|
|
|
G_CALLBACK (snap_toggle_update),
|
|
|
|
&radio_pressed[0]);
|
2000-12-12 02:46:32 +08:00
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (winsnapintf.single_button),
|
|
|
|
radio_pressed[0]);
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_widget_show (winsnapintf.single_button);
|
2000-01-19 04:52:16 +08:00
|
|
|
radio_label = gtk_label_new (_("Grab a single window"));
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (hbox),
|
|
|
|
radio_label, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show (radio_label);
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
|
|
|
|
#ifdef CAN_SET_DECOR
|
2000-03-11 22:30:36 +08:00
|
|
|
/* With decorations */
|
1999-07-29 08:23:51 +08:00
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
|
|
gtk_box_pack_end (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
|
2000-01-19 04:52:16 +08:00
|
|
|
winsnapintf.decor_button =
|
|
|
|
gtk_check_button_new_with_label (_("Include decorations"));
|
2003-01-07 09:47:04 +08:00
|
|
|
g_signal_connect (winsnapintf.decor_button, "toggled",
|
|
|
|
G_CALLBACK (snap_toggle_update),
|
|
|
|
&decorations);
|
2000-12-12 02:46:32 +08:00
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (winsnapintf.decor_button),
|
|
|
|
decorations);
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_box_pack_end (GTK_BOX (hbox), winsnapintf.decor_button, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_set_sensitive (winsnapintf.decor_button, radio_pressed[0]);
|
|
|
|
gtk_widget_show (winsnapintf.decor_button);
|
|
|
|
#endif /* CAN_SET_DECOR */
|
|
|
|
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
gtk_widget_show (vbox);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
|
|
|
|
/* Root Window */
|
|
|
|
frame = gtk_frame_new (NULL);
|
2000-12-12 02:46:32 +08:00
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (frame), 4);
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
|
|
|
|
frame, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 4);
|
2000-12-12 02:46:32 +08:00
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_container_add (GTK_CONTAINER (frame), hbox);
|
|
|
|
|
|
|
|
winsnapintf.root_button = gtk_radio_button_new ( radio_group );
|
2003-06-01 06:23:55 +08:00
|
|
|
radio_group = gtk_radio_button_get_group ( GTK_RADIO_BUTTON (winsnapintf.root_button) );
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), winsnapintf.root_button, TRUE, TRUE, 0);
|
2003-01-07 09:47:04 +08:00
|
|
|
g_signal_connect (winsnapintf.root_button, "toggled",
|
|
|
|
G_CALLBACK (snap_toggle_update),
|
|
|
|
&radio_pressed[1]);
|
2000-12-12 02:46:32 +08:00
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (winsnapintf.root_button),
|
|
|
|
radio_pressed[1]);
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_widget_show (winsnapintf.root_button);
|
|
|
|
|
2000-01-19 04:52:16 +08:00
|
|
|
radio_label = gtk_label_new (_("Grab the whole screen"));
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), radio_label, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show (radio_label);
|
|
|
|
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
|
2000-03-11 22:30:36 +08:00
|
|
|
/* with delay */
|
|
|
|
frame = gtk_frame_new (NULL);
|
2000-12-12 02:46:32 +08:00
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (frame), 4);
|
2000-03-11 22:30:36 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
|
|
|
|
frame, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 4);
|
2000-12-12 02:46:32 +08:00
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
|
2000-03-11 22:30:36 +08:00
|
|
|
gtk_container_add (GTK_CONTAINER (frame), hbox);
|
|
|
|
|
|
|
|
label = gtk_label_new (_("after"));
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show (label);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
2000-03-11 22:30:36 +08:00
|
|
|
adj = (GtkAdjustment *) gtk_adjustment_new ((gfloat)delay, 0.0, 100.0, 1.0, 5.0, 0.0);
|
|
|
|
winsnapintf.delay_spinner = gtk_spin_button_new (adj, 0, 0);
|
|
|
|
gtk_box_pack_start (GTK_BOX(hbox), winsnapintf.delay_spinner, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show (winsnapintf.delay_spinner);
|
|
|
|
|
|
|
|
label = gtk_label_new (_("Seconds Delay"));
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show (label);
|
|
|
|
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
gtk_widget_show (dialog);
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
gdk_flush ();
|
|
|
|
|
|
|
|
winsnapvals.root = radio_pressed[1];
|
|
|
|
winsnapvals.decor = decorations;
|
|
|
|
|
|
|
|
return winsnapintf.run;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* GIMP Plug-in entry points
|
|
|
|
******************************************************************/
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/*
|
|
|
|
* Plug-in Parameter definitions
|
|
|
|
*/
|
|
|
|
#define NUMBER_IN_ARGS 3
|
2000-08-24 07:11:07 +08:00
|
|
|
#define IN_ARGS { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },\
|
|
|
|
{ GIMP_PDB_INT32, "root", "Root window { TRUE, FALSE }" },\
|
|
|
|
{ GIMP_PDB_INT32, "decorations", \
|
1999-07-29 08:23:51 +08:00
|
|
|
"Include Window Decorations { TRUE, FALSE }" }
|
|
|
|
|
|
|
|
#define NUMBER_OUT_ARGS 1
|
2000-08-24 07:11:07 +08:00
|
|
|
#define OUT_ARGS { GIMP_PDB_IMAGE, "image", "Output image" }
|
1999-07-29 08:23:51 +08:00
|
|
|
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/*
|
|
|
|
* query
|
|
|
|
*
|
|
|
|
* The plug-in is being queried. Install our procedure for
|
|
|
|
* capturing windows.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
query(void)
|
|
|
|
{
|
2000-08-24 07:11:07 +08:00
|
|
|
static GimpParamDef args[] = { IN_ARGS };
|
|
|
|
static GimpParamDef return_vals[] = { OUT_ARGS };
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* the installation of the plugin */
|
2004-05-06 21:51:56 +08:00
|
|
|
gimp_install_procedure (PLUG_IN_NAME,
|
|
|
|
PLUG_IN_DESCRIPTION,
|
|
|
|
PLUG_IN_HELP,
|
|
|
|
PLUG_IN_AUTHOR,
|
|
|
|
PLUG_IN_COPYRIGHT,
|
|
|
|
PLUG_IN_VERSION,
|
2004-05-07 21:15:52 +08:00
|
|
|
N_("_Screen Shot..."),
|
2004-05-06 21:51:56 +08:00
|
|
|
NULL,
|
|
|
|
GIMP_PLUGIN,
|
|
|
|
NUMBER_IN_ARGS,
|
|
|
|
NUMBER_OUT_ARGS,
|
|
|
|
args,
|
|
|
|
return_vals);
|
|
|
|
|
2004-05-07 21:15:52 +08:00
|
|
|
gimp_plugin_menu_register (PLUG_IN_NAME, N_("<Toolbox>/File/Acquire"));
|
|
|
|
/* gimp_plugin_menu_register (PLUG_IN_NAME, N_("<Image>/File/Acquire")); */
|
1999-07-29 08:23:51 +08:00
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Return values storage */
|
2000-08-24 07:11:07 +08:00
|
|
|
static GimpParam values[2];
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* run
|
|
|
|
*
|
|
|
|
* The plug-in is being requested to run.
|
|
|
|
* Capture an window image.
|
|
|
|
*/
|
|
|
|
static void
|
2003-07-02 08:15:09 +08:00
|
|
|
run (const gchar *name,
|
|
|
|
gint nparams,
|
|
|
|
const GimpParam *param,
|
|
|
|
gint *nreturn_vals,
|
|
|
|
GimpParam **return_vals)
|
1999-07-29 08:23:51 +08:00
|
|
|
{
|
2001-12-19 08:13:16 +08:00
|
|
|
GimpRunMode run_mode;
|
1999-07-29 08:23:51 +08:00
|
|
|
int wait = 1;
|
|
|
|
|
|
|
|
/* Initialize the return values
|
|
|
|
* Always return at least the status to the caller.
|
|
|
|
*/
|
2000-08-24 07:11:07 +08:00
|
|
|
values[0].type = GIMP_PDB_STATUS;
|
|
|
|
values[0].data.d_status = GIMP_PDB_SUCCESS;
|
1999-07-29 08:23:51 +08:00
|
|
|
*nreturn_vals = 1;
|
|
|
|
*return_vals = values;
|
|
|
|
|
|
|
|
/* Get the runmode from the in-parameters */
|
|
|
|
run_mode = param[0].data.d_int32;
|
2001-04-11 02:36:37 +08:00
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
INIT_I18N ();
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Set up the rest of the return parameters */
|
2000-08-24 07:11:07 +08:00
|
|
|
values[1].type = GIMP_PDB_INT32;
|
1999-07-29 08:23:51 +08:00
|
|
|
values[1].data.d_int32 = 0;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Get the data from last run */
|
|
|
|
gimp_get_data(PLUG_IN_NAME, &winsnapvals);
|
|
|
|
|
|
|
|
/* How are we running today? */
|
|
|
|
switch (run_mode) {
|
2000-08-24 07:11:07 +08:00
|
|
|
case GIMP_RUN_INTERACTIVE:
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Get information from the dialog */
|
|
|
|
if (!snap_dialog())
|
|
|
|
return;
|
|
|
|
break;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
2000-08-24 07:11:07 +08:00
|
|
|
case GIMP_RUN_NONINTERACTIVE:
|
|
|
|
case GIMP_RUN_WITH_LAST_VALS:
|
1999-07-29 08:23:51 +08:00
|
|
|
if (!winsnapvals.root)
|
2000-08-24 07:11:07 +08:00
|
|
|
values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
|
1999-07-29 08:23:51 +08:00
|
|
|
break;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
} /* switch */
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Do the actual window capture */
|
|
|
|
if (winsnapvals.root)
|
|
|
|
doRootWindowCapture();
|
|
|
|
else
|
|
|
|
doWindowCapture();
|
|
|
|
|
|
|
|
/* Check to make sure we got at least one valid
|
|
|
|
* image.
|
|
|
|
*/
|
|
|
|
if (values[1].data.d_int32 > 0) {
|
|
|
|
/* A window was captured.
|
|
|
|
* Do final Interactive steps.
|
|
|
|
*/
|
2000-08-24 07:11:07 +08:00
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE) {
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Store variable states for next run */
|
|
|
|
gimp_set_data(PLUG_IN_NAME, &winsnapvals, sizeof(WinSnapValues));
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Set return values */
|
|
|
|
*nreturn_vals = 2;
|
|
|
|
} else {
|
2000-08-24 07:11:07 +08:00
|
|
|
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
|
1999-07-29 08:23:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* GIMP format and transfer functions
|
|
|
|
******************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* flipRedAndBlueBytes
|
|
|
|
*
|
|
|
|
* Microsoft has chosen to provide us a very nice (not!)
|
|
|
|
* interface for retrieving bitmap bits. DIBSections have
|
|
|
|
* RGB information as BGR instead. So, we have to swap
|
|
|
|
* the silly red and blue bytes before sending to the
|
|
|
|
* GIMP.
|
|
|
|
*/
|
|
|
|
static void
|
1999-10-12 07:30:40 +08:00
|
|
|
flipRedAndBlueBytes(int width, int height)
|
1999-07-29 08:23:51 +08:00
|
|
|
{
|
1999-10-12 07:30:40 +08:00
|
|
|
int i, j;
|
|
|
|
guchar *bufp;
|
1999-07-29 08:23:51 +08:00
|
|
|
guchar temp;
|
1999-10-12 07:30:40 +08:00
|
|
|
|
|
|
|
j = 0;
|
|
|
|
while (j < height) {
|
|
|
|
i = width;
|
|
|
|
bufp = capBytes + j*ROUND4(width)*3;
|
|
|
|
while (i--) {
|
|
|
|
temp = bufp[2];
|
|
|
|
bufp[2] = bufp[0];
|
|
|
|
bufp[0] = temp;
|
|
|
|
bufp += 3;
|
|
|
|
}
|
|
|
|
j++;
|
1999-07-29 08:23:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sendBMPToGIMP
|
|
|
|
*
|
|
|
|
* Take the captured data and send it across
|
|
|
|
* to the GIMP.
|
|
|
|
*/
|
2000-01-15 05:38:47 +08:00
|
|
|
static void
|
1999-07-29 08:23:51 +08:00
|
|
|
sendBMPToGimp(HBITMAP hBMP, HDC hDC, RECT rect)
|
|
|
|
{
|
|
|
|
int row;
|
|
|
|
int width, height;
|
|
|
|
int imageType, layerType;
|
|
|
|
gint32 image_id;
|
|
|
|
gint32 layer_id;
|
2000-08-24 07:11:07 +08:00
|
|
|
GimpPixelRgn pixel_rgn;
|
|
|
|
GimpDrawable *drawable;
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Our width and height */
|
|
|
|
width = (rect.right - rect.left);
|
1999-10-12 07:30:40 +08:00
|
|
|
height = (rect.bottom - rect.top);
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Check that we got the memory */
|
|
|
|
if (!capBytes) {
|
2003-11-15 21:53:33 +08:00
|
|
|
g_message (_("No data captured"));
|
2000-03-11 22:30:36 +08:00
|
|
|
return;
|
1999-07-29 08:23:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Flip the red and blue bytes */
|
1999-10-12 07:30:40 +08:00
|
|
|
flipRedAndBlueBytes(width, height);
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Set up the image and layer types */
|
2000-08-24 07:11:07 +08:00
|
|
|
imageType = GIMP_RGB;
|
|
|
|
layerType = GIMP_RGB_IMAGE;
|
1999-07-29 08:23:51 +08:00
|
|
|
|
|
|
|
/* Create the GIMP image and layers */
|
|
|
|
image_id = gimp_image_new(width, height, imageType);
|
2000-01-19 04:52:16 +08:00
|
|
|
layer_id = gimp_layer_new(image_id, _("Background"),
|
1999-07-29 08:23:51 +08:00
|
|
|
ROUND4(width), height,
|
2000-08-24 07:11:07 +08:00
|
|
|
layerType, 100, GIMP_NORMAL_MODE);
|
1999-07-29 08:23:51 +08:00
|
|
|
gimp_image_add_layer(image_id, layer_id, 0);
|
|
|
|
|
|
|
|
/* Get our drawable */
|
|
|
|
drawable = gimp_drawable_get(layer_id);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-13 06:08:19 +08:00
|
|
|
gimp_tile_cache_size(ROUND4(width) * gimp_tile_height() * 3);
|
|
|
|
|
1999-07-29 08:23:51 +08:00
|
|
|
/* Initialize a pixel region for writing to the image */
|
|
|
|
gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0,
|
|
|
|
ROUND4(width), height, TRUE, FALSE);
|
|
|
|
|
|
|
|
gimp_pixel_rgn_set_rect(&pixel_rgn, (guchar *) capBytes,
|
|
|
|
0, 0, ROUND4(width), height);
|
|
|
|
|
2000-09-27 06:54:33 +08:00
|
|
|
/* HB: update data BEFORE size change */
|
1999-10-26 03:20:41 +08:00
|
|
|
gimp_drawable_flush(drawable);
|
1999-10-12 07:30:40 +08:00
|
|
|
/* Now resize the layer down to the correct size if necessary. */
|
1999-07-29 08:23:51 +08:00
|
|
|
if (width != ROUND4(width)) {
|
|
|
|
gimp_layer_resize (layer_id, width, height, 0, 0);
|
1999-10-26 03:20:41 +08:00
|
|
|
gimp_image_resize (image_id, width, height, 0, 0);
|
1999-07-29 08:23:51 +08:00
|
|
|
}
|
|
|
|
/* Finish up */
|
|
|
|
gimp_drawable_detach(drawable);
|
2000-01-15 05:38:47 +08:00
|
|
|
gimp_display_new (image_id);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
2000-01-15 05:38:47 +08:00
|
|
|
return;
|
1999-07-29 08:23:51 +08:00
|
|
|
}
|