diff --git a/doc/xschem_man/commands.html b/doc/xschem_man/commands.html index 934777d6..c189b512 100644 --- a/doc/xschem_man/commands.html +++ b/doc/xschem_man/commands.html @@ -122,6 +122,7 @@ LeftButton Double click Terminate Polygon placement - BackSpace Back to parent schematic - Delete Delete selected objects - Insert Insert element from library +- Print Scrn Grab screen area - Escape Abort, redraw, unselect ctrl Enter Confirm closing dialog boxes - Down Move down diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html index 96d3fcd1..b5c6e8f0 100644 --- a/doc/xschem_man/developer_info.html +++ b/doc/xschem_man/developer_info.html @@ -840,6 +840,8 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" Return various global variables used in the program
Go up one level (pop) in hierarchy
+ + grab root window
Do a simple hash of 'file'
'skip_path_lines' is an integer (default: 0) passed to hash_file()
@@ -860,13 +862,17 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
'inst' can be an instance name or number
Highlight net name 'net'
- +
+ blend_white|blend_black]
Apply required changes to selected images
invert: invert colors
white_transp: transform white to transparent color (alpha=0) after invert.
black_transp: transform black to transparent color (alpha=0) after invert.
transp_white: transform white to transparent color (alpha=0) after invert.
- transp_black: transform black to transparent color (alpha=0) after invert.
+ transp_black: transform black to transparent color (alpha=0) after invert.
+ blend_white: blend with white background and remove alpha
+ blend_black: blend with black background and remove alpha
+ write_back: write resulting image back into `image_data` attribute
Place a new instance of symbol 'sym_name' at position x,y,
rotation and flip set to 'rot', 'flip'
diff --git a/src/callback.c b/src/callback.c
index 33231466..c43601fb 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -1736,6 +1736,130 @@ static void end_shape_point_edit()
}
}
+#if defined(__unix__) && HAS_CAIRO==1
+static int grabscreen(const char *winpath, int event, int mx, int my, KeySym key,
+ int button, int aux, int state)
+{
+ static int grab_state = 0;
+ static int x1, y1, x2, y2;
+ int rmx, rmy, wmx, wmy;
+ unsigned int msq;
+ Window rw, cw;
+ XSetWindowAttributes winattr;
+ XGCValues gcv;
+ static GC gc = NULL;
+ static Window clientwin = 0;
+ static int first_motion = 1;
+ static int displayh = 0, displayw = 0;
+ static unsigned long white = 0;
+
+ if(grab_state == 0 && event == ButtonPress && button == Button1) {
+ unsigned long gcvm = GCFunction | GCForeground;
+
+ white = WhitePixel(display, screen_number);
+ displayh = DisplayHeight(display, screen_number);
+ displayw = DisplayWidth(display, screen_number);
+
+ XQueryPointer(display, xctx->window, &rw, &cw , &rmx, &rmy, &wmx, &wmy, &msq);
+ gcv.function = GXxor;
+ gcv.foreground = white;
+ gc = XCreateGC(display, rw, gcvm, &gcv);
+
+ winattr.override_redirect = True;
+ clientwin = XCreateWindow(display, rw, 0, 0, displayw, displayh, 0, screendepth,
+ InputOutput, visual, CWOverrideRedirect, &winattr);
+ XMapRaised(display,clientwin);
+
+ x1 = rmx;
+ y1 = rmy;
+ dbg(1, "grabscreen(): got point1: %d %d\n", x1, y1);
+ grab_state = 1;
+ }
+
+ if(grab_state == 1 && event == MotionNotify) {
+ static int xx1, xx2, yy1, yy2;
+ xx1 = x1; yy1 = y1; xx2 = x2; yy2 = y2;
+ INT_RECTORDER(xx1, yy1, xx2, yy2);
+ dbg(1, "Motion: %d %d %d %d\n", xx1, yy1, xx2, yy2);
+ if(!first_motion) {
+ XDrawRectangle(display, clientwin, gc, xx1 - 1, yy1 - 1, xx2 - xx1 + 2, yy2 - yy1 + 2);
+ }
+ first_motion = 0;
+ XQueryPointer(display, xctx->window, &rw, &cw , &rmx, &rmy, &wmx, &wmy, &msq);
+ x2 = xx2 = rmx;
+ y2 = yy2 = rmy;
+ xx1 = x1; yy1 = y1;
+ INT_RECTORDER(xx1, yy1, xx2, yy2);
+ XDrawRectangle(display, clientwin, gc, xx1 - 1, yy1 - 1, xx2 - xx1 + 2, yy2 - yy1 + 2);
+ }
+
+ if(grab_state == 1 && event == ButtonRelease) {
+ int grab_w = 0, grab_h = 0;
+ cairo_surface_t *sfc = NULL, *subsfc = NULL;
+ png_to_byte_closure_t closure;
+ char *encoded_data = NULL;
+ size_t olength;
+ char *prop = NULL;
+ grab_state = 0;
+ first_motion = 1;
+ xctx->ui_state &= ~GRABSCREEN;
+ XQueryPointer(display, xctx->window, &rw, &cw , &rmx, &rmy, &wmx, &wmy, &msq);
+ x2 = rmx;
+ y2 = rmy;
+ INT_RECTORDER(x1, y1, x2, y2);
+ tcleval("grab release [xschem get current_win_path]");
+ if(x2 - x1 > 10 && y2 -y1 > 10) {
+ grab_w = (x2 - x1 + 1);
+ grab_h = (y2 - y1 + 1);
+ dbg(1, "grabscreen(): grab area: %d %d - %d %d\n", x1, y1, x2, y2);
+ dbg(1, "grabscreen(): root w=%d, h=%d\n", displayw, displayh);
+ sfc = cairo_xlib_surface_create(display, rw, visual, displayw, displayh);
+ if(!sfc || cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS) {
+ dbg(0, "grabscreen(): failure creating sfc\n");
+ XFreeGC(display, gc);
+ XDestroyWindow(display, clientwin);
+ return 0;
+ }
+ dbg(1, "sfc: w=%d, h=%d\n",
+ cairo_xlib_surface_get_width(sfc),
+ cairo_xlib_surface_get_height(sfc));
+ subsfc = cairo_surface_create_for_rectangle(sfc, x1, y1, grab_w, grab_h);
+ if(!subsfc || cairo_surface_status(subsfc) != CAIRO_STATUS_SUCCESS) {
+ dbg(0, "grabscreen(): failure creating subsfc\n");
+ cairo_surface_destroy(sfc);
+ XFreeGC(display, gc);
+ XDestroyWindow(display, clientwin);
+ return 0;
+ }
+ closure.buffer = NULL;
+ closure.size = 0;
+ closure.pos = 0;
+ cairo_surface_write_to_png_stream(subsfc, png_writer, &closure);
+ cairo_surface_destroy(subsfc);
+ cairo_surface_destroy(sfc);
+ closure.size = closure.pos;
+ dbg(1, "closure.size = %ld\n", closure.size);
+ encoded_data = base64_encode((unsigned char *)closure.buffer, closure.size, &olength, 0);
+ dbg(1, "olength = %ld\n", olength);
+ my_free(_ALLOC_ID_, &closure.buffer);
+ my_mstrcat(_ALLOC_ID_, &prop, "flags=image,unscaled\nalpha=0.8\nimage_data=", encoded_data, NULL);
+ my_free(_ALLOC_ID_, &encoded_data);
+ storeobject(-1, xctx->mousex_snap, xctx->mousey_snap, xctx->mousex_snap + grab_w, xctx->mousey_snap + grab_h,
+ xRECT, GRIDLAYER, SELECTED, prop);
+ my_free(_ALLOC_ID_, &prop);
+ xctx->need_reb_sel_arr=1;
+ rebuild_selected_array();
+ move_objects(START,0,0,0);
+ xctx->ui_state |= START_SYMPIN;
+ }
+ XFreeGC(display, gc);
+ XDestroyWindow(display, clientwin);
+ }
+ return 1;
+}
+#endif
+
+
/* main window callback */
/* mx and my are set to the mouse coord. relative to window */
/* winpath: set to .drw or sub windows .x1.drw, .x2.drw, ... */
@@ -1854,6 +1978,12 @@ int rstate; /* (reduced state, without ShiftMask) */
}
dbg(1, "key=%d EQUAL_MODMASK=%d, SET_MODMASK=%d\n", key, SET_MODMASK, EQUAL_MODMASK);
+
+ #if defined(__unix__) && HAS_CAIRO==1
+ if(xctx->ui_state & GRABSCREEN) {
+ grabscreen(winpath, event, mx, my, key, button, aux, state);
+ } else
+ #endif
switch(event)
{
@@ -2708,6 +2838,13 @@ int rstate; /* (reduced state, without ShiftMask) */
}
break;
}
+ #if defined(__unix__) && HAS_CAIRO==1
+ if(key == XK_Print) {
+ xctx->ui_state |= GRABSCREEN;
+ tcleval("grab set -global [xschem get current_win_path]");
+ break;
+ }
+ #endif
if(key=='Q' && rstate == 0) /* edit attributes in editor */
{
if(xctx->semaphore >= 2) break;
diff --git a/src/draw.c b/src/draw.c
index 85cd3446..cd241517 100644
--- a/src/draw.c
+++ b/src/draw.c
@@ -4049,7 +4049,7 @@ static cairo_surface_t *get_surface_from_file(const char *filename, const char *
}
filesize = (size_t)buf.st_size;
if(filesize > 0) {
- fd = fopen(filename, "r");
+ fd = fopen(filename, fopen_read_mode);
if(fd) {
size_t bytes_read;
filedata = my_malloc(_ALLOC_ID_, filesize);
diff --git a/src/keys.help b/src/keys.help
index 77447c51..e0a1c3b8 100644
--- a/src/keys.help
+++ b/src/keys.help
@@ -63,6 +63,7 @@ LeftButton Double click Terminate Polygon placement
- BackSpace Back to parent schematic
- Delete Delete selected objects
- Insert Insert element from library
+- Print Scrn Grab screen area
- Escape Abort, redraw, unselect
ctrl Enter Confirm closing dialog boxes
- Down Move down
diff --git a/src/scheduler.c b/src/scheduler.c
index 8cbb8634..a49d3883 100644
--- a/src/scheduler.c
+++ b/src/scheduler.c
@@ -1907,6 +1907,18 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
if((xctx->semaphore == 0)) go_back(1);
Tcl_ResetResult(interp);
}
+
+ /* grabscreen
+ * grab root window */
+ else if(!strcmp(argv[1], "grabscreen"))
+ {
+ if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
+ #if defined(__unix__) && HAS_CAIRO==1
+ xctx->ui_state |= GRABSCREEN;
+ tcleval("grab set -global [xschem get current_win_path]");
+ #endif
+ Tcl_ResetResult(interp);
+ }
else { cmd_found = 0;}
break;
case 'h': /*----------------------------------------------*/
@@ -5397,7 +5409,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
else if(argc > 2 && atoi(argv[2]) == 2) {
Tcl_ResetResult(interp);
}
- else if(argc > 3 && atoi(argv[2]) == 3) {
+ else if(argc > 2 && atoi(argv[2]) == 3) {
Tcl_ResetResult(interp);
}
}
diff --git a/src/xinit.c b/src/xinit.c
index 739ab82c..4715c352 100644
--- a/src/xinit.c
+++ b/src/xinit.c
@@ -2551,6 +2551,7 @@ int Tcl_AppInit(Tcl_Interp *inter)
tcleval(name);
}
}
+ if(debug_var==-10) debug_var=0;
/* */
/* EXECUTE xschem.tcl */
/* */
@@ -2594,7 +2595,6 @@ int Tcl_AppInit(Tcl_Interp *inter)
cadlayers=tclgetintvar("cadlayers");
fix_broken_tiled_fill = tclgetboolvar("fix_broken_tiled_fill");
fix_mouse_coord = tclgetboolvar("fix_mouse_coord");
- if(debug_var==-10) debug_var=0;
my_snprintf(tmp, S(tmp), "%.16g",CADGRID);
tclvareval("set_ne cadgrid ", tmp, NULL);
my_snprintf(tmp, S(tmp), "%.16g",CADSNAP);
diff --git a/src/xschem.h b/src/xschem.h
index 76ce8f0d..3ce176fe 100644
--- a/src/xschem.h
+++ b/src/xschem.h
@@ -229,6 +229,7 @@ extern char win_temp_dir[PATH_MAX];
#define START_SYMPIN 16384U
#define GRAPHPAN 32768U /* bit 15 */
#define MENUSTART 65536U /* bit 16 */
+#define GRABSCREEN 131072 /* bit 17 */
#define SELECTED 1U /* used in the .sel field for selected objs. */
#define SELECTED1 2U /* first point selected... */
@@ -349,6 +350,13 @@ extern char win_temp_dir[PATH_MAX];
if(y2 < y1) {xxtmp = y1; y1 = y2; y2 = xxtmp;} \
}
+#define INT_RECTORDER(x1,y1,x2,y2) { \
+ int xxtmp; \
+ if(x2 < x1) {xxtmp = x1; x1 = x2; x2 = xxtmp;} \
+ if(y2 < y1) {xxtmp = y1; y1 = y2; y2 = xxtmp;} \
+}
+
+
#define LINE_OUTSIDE(xa,ya,xb,yb,x1,y1,x2,y2) \
(xa>=x2 || xb<=x1 || ( (ya=y2 || yb<=y1) : (yb>=y2 || ya<=y1) ) )
diff --git a/src/xschem.tcl b/src/xschem.tcl
index 0a67720c..4b920a10 100644
--- a/src/xschem.tcl
+++ b/src/xschem.tcl
@@ -7736,6 +7736,8 @@ proc build_widgets { {topwin {} } } {
$topwin.menubar.tools.menu add command -label "Insert circle" -command "xschem circle" -accelerator Ctrl+Shift+C
toolbar_add ToolInsertCircle "xschem circle" "Insert Circle" $topwin
$topwin.menubar.tools.menu add command -label "Insert JPG/PNG image" -command "xschem add_image"
+ $topwin.menubar.tools.menu add command -label "Grab screen area" -command "xschem grabscreen" \
+ -accelerator {Print Scrn}
$topwin.menubar.tools.menu add command -label "Search" -accelerator Ctrl+F -command property_search
toolbar_add ToolSearch property_search "Search" $topwin
$topwin.menubar.tools.menu add command -label "Align to Grid" -accelerator Alt+U -command "xschem align"