/* * Window.c -- Implementation of Window item. * * Authors : Patrick LECOANET * Creation date : Fri May 12 11:25:53 2000 */ /* * Copyright (c) 1993 - 2000 CENA, Patrick Lecoanet -- * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This code 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this code; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include "Item.h" #include "Geo.h" #include "Types.h" #include "WidgetInfo.h" static const char rcsid[] = "$Id$"; static const char compile_id[] = "$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; /* ********************************************************************************** * * Specific Window item record * ********************************************************************************** */ typedef struct _WindowItemStruct { ItemStruct header; /* Public data */ ZnPoint pos; ZnAnchor anchor; ZnAnchor connection_anchor; ZnWindow win; int width; int height; /* Private data */ ZnPoint pos_dev; int real_width; int real_height; } WindowItemStruct, *WindowItem; static ZnAttrConfig wind_attrs[] = { { ZN_CONFIG_ANCHOR, "-anchor", NULL, Tk_Offset(WindowItemStruct, anchor), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BOOL, "-composerotation", NULL, Tk_Offset(WindowItemStruct, header.flags), COMPOSE_ROTATION_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_BOOL, "-composescale", NULL, Tk_Offset(WindowItemStruct, header.flags), COMPOSE_SCALE_BIT, ZN_COORDS_FLAG, False }, { ZN_CONFIG_ITEM, "-connecteditem", NULL, Tk_Offset(WindowItemStruct, header.connected_item), 0, ZN_COORDS_FLAG|ZN_ITEM_FLAG, False }, { ZN_CONFIG_ANCHOR, "-connectionanchor", NULL, Tk_Offset(WindowItemStruct, connection_anchor), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_DIM, "-height", NULL, Tk_Offset(WindowItemStruct, height), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_POINT, "-position", NULL, Tk_Offset(WindowItemStruct, pos), 0, ZN_COORDS_FLAG, False}, { ZN_CONFIG_PRI, "-priority", NULL, Tk_Offset(WindowItemStruct, header.priority), 0, ZN_DRAW_FLAG|ZN_REPICK_FLAG, False }, { ZN_CONFIG_BOOL, "-sensitive", NULL, Tk_Offset(WindowItemStruct, header.flags), SENSITIVE_BIT, ZN_REPICK_FLAG, False }, { ZN_CONFIG_TAGS, "-tags", NULL, Tk_Offset(WindowItemStruct, header.tags), 0, 0, False }, { ZN_CONFIG_BOOL, "-visible", NULL, Tk_Offset(WindowItemStruct, header.flags), VISIBLE_BIT, ZN_DRAW_FLAG|ZN_REPICK_FLAG|ZN_VIS_FLAG, False }, { ZN_CONFIG_DIM, "-width", NULL, Tk_Offset(WindowItemStruct, width), 0, ZN_COORDS_FLAG, False }, { ZN_CONFIG_WINDOW, "-window", NULL, Tk_Offset(WindowItemStruct, win), 0, ZN_COORDS_FLAG|ZN_WINDOW_FLAG, False }, { ZN_CONFIG_END, NULL, NULL, 0, 0, 0 } }; /* ********************************************************************************** * * WindowDeleted -- * * Do the bookeeping after a managed window deletion. * ********************************************************************************** */ static void WindowDeleted(ClientData client_data, XEvent *event) { WindowItem wind = (WindowItem) client_data; if (event->type == DestroyNotify) { wind->win = NULL; } } /* ********************************************************************************** * * Window item geometry manager -- * ********************************************************************************** */ /* * A managed window changes requested dimensions. */ static void WindowItemRequest(ClientData client_data, ZnWindow win) { WindowItem wind = (WindowItem) client_data; ITEM.Invalidate((Item) wind, ZN_COORDS_FLAG); } /* * A managed window turns control over * to another geometry manager. */ static void WindowItemLostSlave(ClientData client_data, ZnWindow win) { WindowItem wind = (WindowItem) client_data; WidgetInfo *wi = ((Item) wind)->wi; Tk_DeleteEventHandler(wi->win, StructureNotifyMask, WindowDeleted, (ClientData) wind); if (wi->win != Tk_Parent(wind->win)) { Tk_UnmaintainGeometry(wind->win, wi->win); } Tk_UnmapWindow(wind->win); wind->win = NULL; } static Tk_GeomMgr wind_geom_type = { "zincwindow", /* name */ WindowItemRequest, /* requestProc */ WindowItemLostSlave, /* lostSlaveProc */ }; /* ********************************************************************************** * * Init -- * ********************************************************************************** */ static int Init(Item item, int *argc, Tcl_Obj *CONST *args[]) { WindowItem wind = (WindowItem) item; /* Init attributes */ SET(item->flags, VISIBLE_BIT); SET(item->flags, SENSITIVE_BIT); SET(item->flags, COMPOSE_ROTATION_BIT); SET(item->flags, COMPOSE_SCALE_BIT); item->priority = DEFAULT_WINDOW_PRIORITY; /* N.A */ wind->pos.x = wind->pos.y = 0.0; wind->width = wind->height = 0; wind->anchor = ZnAnchorNW; wind->connection_anchor = ZnAnchorSW; wind->win = NULL; return ZN_OK; } /* ********************************************************************************** * * Clone -- * ********************************************************************************** */ static void Clone(Item item) { WindowItem wind = (WindowItem) item; /* * The same Tk widget can't be shared by to Window items. */ wind->win = NULL; } /* ********************************************************************************** * * Destroy -- * ********************************************************************************** */ static void Destroy(Item item) { WidgetInfo *wi = item->wi; WindowItem wind = (WindowItem) item; /* * Unmanage the widget. */ if (wind->win) { Tk_DeleteEventHandler(wind->win, StructureNotifyMask, WindowDeleted, (ClientData) item); Tk_ManageGeometry(wind->win, (Tk_GeomMgr *) NULL, (ClientData) NULL); if (wi->win != Tk_Parent(wind->win)) { Tk_UnmaintainGeometry(wind->win, wi->win); } Tk_UnmapWindow(wind->win); } } /* ********************************************************************************** * * Configure -- * ********************************************************************************** */ static int Configure(Item item, int argc, Tcl_Obj *CONST argv[], int *flags) { WindowItem wind = (WindowItem) item; WidgetInfo *wi = item->wi; Item old_connected; ZnWindow old_win; old_connected = item->connected_item; old_win = wind->win; if (ITEM_P.ConfigureAttributes((char *) item, -1, argc, argv, flags) == ZN_ERROR) { return ZN_ERROR; } if (ISSET(*flags, ZN_ITEM_FLAG)) { /* * If the new connected item is not appropriate back up * to the old one. */ if ((item->connected_item == ZN_NO_ITEM) || (item->connected_item->class->has_anchors && (item->parent == item->connected_item->parent))) { ITEM.UpdateItemDependency(item, old_connected); } else { item->connected_item = old_connected; } } if (ISSET(*flags, ZN_WINDOW_FLAG)) { if (old_win != NULL) { Tk_DeleteEventHandler(old_win, StructureNotifyMask, WindowDeleted, (ClientData) item); Tk_ManageGeometry(old_win, (Tk_GeomMgr *) NULL, (ClientData) NULL); Tk_UnmaintainGeometry(old_win, wi->win); Tk_UnmapWindow(old_win); } if (wind->win != NULL) { Tk_CreateEventHandler(wind->win, StructureNotifyMask, WindowDeleted, (ClientData) item); Tk_ManageGeometry(wind->win, &wind_geom_type, (ClientData) item); } } if ((wind->win != NULL) && ISSET(*flags, ZN_VIS_FLAG) && ISCLEAR(item->flags, VISIBLE_BIT)) { Tk_UnmapWindow(wind->win); } return ZN_OK; } /* ********************************************************************************** * * Query -- * ********************************************************************************** */ static int Query(Item item, int argc, Tcl_Obj *CONST argv[]) { if (ITEM_P.QueryAttribute((char *) item, -1, argv[0]) == ZN_ERROR) { return ZN_ERROR; } return ZN_OK; } /* ********************************************************************************** * * ComputeCoordinates -- * ********************************************************************************** */ static void ComputeCoordinates(Item item, ZnBool force) { WidgetInfo *wi = item->wi; WindowItem wind = (WindowItem) item; ResetBBox(&item->item_bounding_box); if (wind->win == NULL) { return; } wind->real_width = wind->width; if (wind->real_width <= 0) { wind->real_width = Tk_ReqWidth(wind->win); if (wind->real_width <= 0) { wind->real_width = 1; } } wind->real_height = wind->height; if (wind->real_height <= 0) { wind->real_height = Tk_ReqHeight(wind->win); if (wind->real_height <= 0) { wind->real_height = 1; } } /* * The connected item support anchors, this is checked by * configure. */ if (item->connected_item != ZN_NO_ITEM) { item->connected_item->class->GetAnchor(item->connected_item, wind->connection_anchor, &wind->pos_dev); } else { ZnTransformPoint(wi->current_transfo, &wind->pos, &wind->pos_dev); } Anchor2Origin(&wind->pos_dev, wind->real_width, wind->real_height, wind->anchor, &wind->pos_dev); wind->pos_dev.x = REAL_TO_INT(wind->pos_dev.x); wind->pos_dev.y = REAL_TO_INT(wind->pos_dev.y); /* * Compute the bounding box. */ AddPointToBBox(&item->item_bounding_box, wind->pos_dev.x, wind->pos_dev.y); AddPointToBBox(&item->item_bounding_box, wind->pos_dev.x+wind->real_width, wind->pos_dev.y+wind->real_height); item->item_bounding_box.orig.x -= 1.0; item->item_bounding_box.orig.y -= 1.0; item->item_bounding_box.corner.x += 1.0; item->item_bounding_box.corner.y += 1.0; /* * Update connected items. */ SET(item->flags, UPDATE_DEPENDENT_BIT); } /* ********************************************************************************** * * ToArea -- * Tell if the object is entirely outside (-1), * entirely inside (1) or in between (0). * ********************************************************************************** */ static int ToArea(Item item, ZnBBox *area, Tk_Uid tag_uid, int enclosed, ZnBool report) { WindowItem wind = (WindowItem) item; ZnBBox box; int w=0, h=0; box.orig = wind->pos_dev; if (wind->win != NULL) { w = wind->real_width; h = wind->real_height; } box.corner.x = box.orig.x + w; box.corner.y = box.orig.y + h; return BBoxInBBox(&box, area); } /* ********************************************************************************** * * Draw -- * ********************************************************************************** */ static void Draw(Item item) { WidgetInfo *wi = item->wi; WindowItem wind = (WindowItem) item; if (wind->win == NULL) { return; } /* * If the window is outside the visible area, unmap it. */ if ((item->item_bounding_box.corner.x <= 0) || (item->item_bounding_box.corner.y <= 0) || (item->item_bounding_box.orig.x >= wi->width) || (item->item_bounding_box.orig.y >= wi->height)) { if (wi->win == Tk_Parent(wind->win)) { Tk_UnmapWindow(wind->win); } else { Tk_UnmaintainGeometry(wind->win, wi->win); } return; } /* * Position and map the window. */ if (wi->win == Tk_Parent(wind->win)) { if ((wind->pos_dev.x != Tk_X(wind->win)) || (wind->pos_dev.y != Tk_Y(wind->win)) || (wind->real_width != Tk_Width(wind->win)) || (wind->real_height != Tk_Height(wind->win))) { Tk_MoveResizeWindow(wind->win, wind->pos_dev.x, wind->pos_dev.y, wind->real_width, wind->real_height); } Tk_MapWindow(wind->win); } else { Tk_MaintainGeometry(wind->win, wi->win, wind->pos_dev.x, wind->pos_dev.y, wind->real_width, wind->real_height); } } /* ********************************************************************************** * * IsSensitive -- * ********************************************************************************** */ static ZnBool IsSensitive(Item item, int item_part) { /* * Sensitivity can't be controlled. */ return True; } /* ********************************************************************************** * * Pick -- * ********************************************************************************** */ static double Pick(Item item, ZnPoint *p, Item start_item, int aperture, Item *a_item, int *part) { WindowItem wind = (WindowItem) item; ZnBBox box; ZnReal dist = 1e40; box.orig = wind->pos_dev; if (wind->win != NULL) { box.corner.x = box.orig.x + wind->real_width; box.corner.y = box.orig.y + wind->real_height; dist = RectangleToPointDist(&box, p); if (dist <= 0.0) { dist = 0.0; } } return dist; } /* ********************************************************************************** * * PostScript -- * ********************************************************************************** */ static void PostScript(Item item, PostScriptInfo ps_info) { } /* ********************************************************************************** * * GetAnchor -- * ********************************************************************************** */ static void GetAnchor(Item item, ZnAnchor anchor, ZnPoint *p) { WindowItem wind = (WindowItem) item; if (wind->win != NULL) { Origin2Anchor(&wind->pos_dev, wind->real_width, wind->real_height, anchor, p); } else { p->x = p->y = 0.0; } } /* ********************************************************************************** * * GetClipVertices -- * Get the clipping shape. * ********************************************************************************** */ static ZnBool GetClipVertices(Item item, ZnPoly *poly) { WindowItem wind = (WindowItem) item; int w=0, h=0; ZnPoint *points; ZnListAssertSize(item->wi->work_pts, 2); if (wind->win != NULL) { w = wind->real_width; h = wind->real_height; } points = (ZnPoint *) ZnListArray(item->wi->work_pts); POLY_CONTOUR1(poly, points, 2); points[0] = wind->pos_dev; points[1].x = points[0].x + w; points[1].y = points[0].y + h; return True; } /* ********************************************************************************** * * Coords -- * Return or edit the item origin. This doesn't take care of * the possible attachment. The change will be effective at the * end of the attachment. * ********************************************************************************** */ static int Coords(Item item, int contour, int index, int cmd, ZnPoint **pts, int *num_pts) { WindowItem wind = (WindowItem) item; if ((cmd == COORDS_ADD) || (cmd == COORDS_ADD_LAST) || (cmd == COORDS_REMOVE)) { Tcl_AppendResult(item->wi->interp, " windows can't add or remove vertices", NULL); return ZN_ERROR; } else if ((cmd == COORDS_REPLACE) || (cmd == COORDS_REPLACE_ALL)) { if (*num_pts == 0) { Tcl_AppendResult(item->wi->interp, " coords command need 1 point on windows", NULL); return ZN_ERROR; } wind->pos = (*pts)[0]; ITEM.Invalidate(item, ZN_COORDS_FLAG); } else if ((cmd == COORDS_READ) || (cmd == COORDS_READ_ALL)) { *num_pts = 1; *pts = &wind->pos; } return ZN_OK; } /* ********************************************************************************** * * Exported functions struct -- * ********************************************************************************** */ static ItemClassStruct WINDOW_ITEM_CLASS = { sizeof(WindowItemStruct), False, /* has_fields */ 0, /* num_parts */ True, /* has_anchors */ "window", wind_attrs, Init, Clone, Destroy, Configure, Query, NULL, /* GetFieldSet */ GetAnchor, GetClipVertices, Coords, NULL, /* InsertChars */ NULL, /* DeleteChars */ NULL, /* Cursor */ NULL, /* Index */ NULL, /* Part */ NULL, /* Selection */ NULL, /* Contour */ ComputeCoordinates, ToArea, Draw, Draw, /* Render use the same code as Draw. */ IsSensitive, Pick, NULL, /* PickVertex */ PostScript }; ZnItemClassId ZnWind = (ZnItemClassId) &WINDOW_ITEM_CLASS;