pix_grab.c revision 830
606N/A/* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
0N/A * Use is subject to license terms.
0N/A *
0N/A * Permission is hereby granted, free of charge, to any person obtaining a
0N/A * copy of this software and associated documentation files (the
0N/A * "Software"), to deal in the Software without restriction, including
0N/A * without limitation the rights to use, copy, modify, merge, publish,
0N/A * distribute, and/or sell copies of the Software, and to permit persons
0N/A * to whom the Software is furnished to do so, provided that the above
0N/A * copyright notice(s) and this permission notice appear in all copies of
0N/A * the Software and that both the above copyright notice(s) and this
0N/A * permission notice appear in supporting documentation.
0N/A *
0N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0N/A * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0N/A * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
0N/A * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
0N/A * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
0N/A * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
0N/A * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
0N/A * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
0N/A * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0N/A *
0N/A * Except as contained in this notice, the name of a copyright holder
0N/A * shall not be used in advertising or otherwise to promote the sale, use
0N/A * or other dealings in this Software without prior written authorization
606N/A * of the copyright holder.
0N/A */
851N/A
0N/A#pragma ident "@(#)pix_grab.c 35.10 09/11/09 SMI"
606N/A
606N/A#include <stdio.h>
98N/A#include <stdlib.h>
0N/A#include <string.h>
0N/A#include <sys/types.h>
0N/A#include <fcntl.h>
0N/A#include <netdb.h>
0N/A#ifdef SERVER_DGA
0N/A#include <X11/Xlib.h>
196N/A#else
0N/A#include <unistd.h>
0N/A#include <sys/fcntl.h>
36N/A#include <sys/mman.h>
168N/A#endif /* SERVER_DGA */
0N/A
0N/A#include "dga_incls.h"
851N/A#include "pix_grab.h"
851N/A
606N/A
0N/A
639N/A#define NDIGITS 8
168N/A#define MINSHMEMSIZE (8*1024)
0N/A#define MAXSHMEMSIZE (0x00040000)
0N/A#define MAXSHPXMEMSIZE (0x01000000)
0N/A#define SHPX_MAX_CLIENTS 64
633N/A#define SHPX_MAX_PIXMAPS 341
639N/A
0N/A
0N/A
0N/A/* Some structure definition for internal bookkeeping
0N/A * NOTE: there is only one locking window created per device for
0N/A * the use of all pixmaps on that device
0N/A*/
0N/Atypedef struct dga_pixlist {
0N/A Dga_token p_token; /* Token associated with pix */
0N/A int num_clientp;
0N/A struct dga_pixmap *dga_clientplist; /*List of client ptrs in pix */
0N/A struct dga_pixlist *next_plist; /* Next link in the dga list */
0N/A} *Dga_pixlist;
0N/A
0N/Astatic struct dga_pixlist *dga_plist = NULL;
0N/A#ifdef SERVER_DGA
0N/Aextern SHPX_CLIENT_ENTRY shpx_client_directory[];
0N/Aextern int Dga_shpx_client_count;
0N/A#else
0N/Astatic SHPX_CLIENT_ENTRY shpx_client_directory[SHPX_MAX_CLIENTS];
0N/Astatic int Dga_shpx_client_count = 0;
633N/A#endif /* SERVER_DGA */
0N/Astatic u_long pagesize;
0N/A
0N/Aextern int _dga_winlockat(u_long cookie, int **lockp, int **unlockp);
0N/Aextern int _dga_winlockdt(int *lockp, int *unlockp);
0N/Aextern void *_dga_is_X_pixmap(Pixmap pix, Display **dpyp);
0N/A
0N/A/******************************************
0N/A *
0N/A * dga_pix_grab:
0N/A *
0N/A * create shared memory file for pixmap information
0N/A * map to lock page
633N/A *
633N/A * arguments:
0N/A *
0N/A * Dga_token token; INPUT
0N/A * magic cookie supplied by the server
606N/A *
0N/A * returns a user virtual address for a dga_window structure.
799N/A * returns NULL if anything goes awry.
799N/A *
0N/A *****************************************/
0N/A
0N/ADga_pixmap
0N/Adga_pix_grab(token, pix)
0N/A Dga_token token;
0N/A Pixmap pix;
0N/A{
0N/A SHARED_PIXMAP_INFO *infop;
0N/A _Dga_pixmap clientp ;
0N/A Display *dpy;
0N/A int c_fd, i, entry_found;
0N/A u_int port;
0N/A size_t size;
0N/A SHPX_DIRECTORY *shpx_dir;
0N/A char c_fn[256];
0N/A char *dpystr;
0N/A static char path[256];
0N/A char host[MAXHOSTNAMELEN];
0N/A Dga_lockp lockp, unlockp;
0N/A
0N/A /* Remember to account for multiple clients grabbing the same pixmap
0N/A * later
0N/A */
0N/A
0N/A /* First determine if this is a X pixmap - if so, get
0N/A * the dpy and pixid
0N/A */
0N/A if (!_dga_is_X_pixmap(pix, &dpy)) {
0N/A#ifdef DEBUG
0N/A (void) fprintf(stderr, "dga_pix_grab: Unsupported pixmap type\n");
0N/A#endif
0N/A return (PIX_FAILED);
0N/A }
0N/A
0N/A if (!dga_plist) {
0N/A /* This is the first time through this code so get the
0N/A * retained path */
0N/A if (!XDgaGetRetainedPath(dpy, pix, path)) {
0N/A#ifdef DEBUG
0N/A (void) fprintf(stderr,
0N/A "dga_pix_grab: XDgaGetRetainedPath failed\n");
0N/A#endif
0N/A return (PIX_FAILED);
0N/A }
0N/A }
0N/A#ifndef SERVER_DGA
0N/A /* Now get the port number for this display */
0N/A dpystr = DisplayString(dpy);
0N/A if (dpystr[0] == ':')
633N/A (void) sscanf(dpystr, ":%u", &port);
0N/A else
0N/A (void) sscanf(dpystr, "%[^:]:%u", host, &port);
0N/A
0N/A if (Dga_shpx_client_count == 0) {
0N/A /* Now start by initializing all the per client structs -
0N/A * all 64 of them - if thie is the first time you
0N/A * are grabbing a pixmap
0N/A */
606N/A for (i = 0; i < SHPX_MAX_CLIENTS; i++) {
0N/A shpx_client_directory[i].cid = 0;
0N/A shpx_client_directory[i].shpx_directory = NULL;
0N/A shpx_client_directory[i].fd = 0;
0N/A shpx_client_directory[i].size = 0;
0N/A shpx_client_directory[i].npix = 0;
0N/A }
606N/A } else
606N/A#endif /* SERVER_DGA */
0N/A {
0N/A /* If it is not the first time, see if this client has grabbed
0N/A * a pixmap before and therefore done all the set up.
0N/A * Search through the client structures for matching token
0N/A */
0N/A i = 0;
0N/A while ((i < SHPX_MAX_CLIENTS) &&
0N/A (shpx_client_directory[i].cid != token)) {
0N/A i++;
0N/A }
606N/A if ((i == SHPX_MAX_CLIENTS) &&
606N/A (Dga_shpx_client_count == SHPX_MAX_CLIENTS)) {
0N/A return(0);
0N/A }
0N/A }
0N/A
0N/A if ((Dga_shpx_client_count > 0) && (i < SHPX_MAX_CLIENTS)) {
606N/A /* We found a match and the pixmap already has been grabbed before */
0N/A shpx_dir = shpx_client_directory[i].shpx_directory;
0N/A shpx_client_directory[i].npix++;
606N/A }
0N/A#ifndef SERVER_DGA
0N/A else {
0N/A /* This client has Never grabbed before set up the direct
0N/A * structure etc.
0N/A * Open the shared file using server command line
0N/A * -sharedretainedpath variable for file path if it is
0N/A * set, else use /tmp. This is because these files can
0N/A * be very big and there usually isn't much space in /tmp.
0N/A */
0N/A c_fn[0] = 0;
0N/A
0N/A
0N/A if ((path) && (strlen(path) > 0))
0N/A strcpy(c_fn, path);
606N/A else
0N/A strcpy(c_fn, "/tmp");
0N/A
0N/A strcat(c_fn, PIX_FILE);
0N/A size = strlen(c_fn);
0N/A sprintf(c_fn+size,"%01x.%08x", port, token);
0N/A
0N/A#ifdef SYSV
0N/A pagesize = sysconf(_SC_PAGESIZE);
0N/A#else
0N/A pagesize = getpagesize();
0N/A#endif
0N/A i = 0;
0N/A while ((i < SHPX_MAX_CLIENTS) && (shpx_client_directory[i].cid != 0))
0N/A i++;
0N/A if ((c_fd = open(c_fn,O_RDWR ,0666)) < 0)
0N/A return(0);
606N/A /* map the shpx directory for this client and map at 4 megabytes */
606N/A shpx_dir = (SHPX_DIRECTORY *)mmap(0,
606N/A MAXSHPXMEMSIZE,
0N/A PROT_READ|PROT_WRITE,
0N/A MAP_SHARED,
0N/A c_fd,
0N/A (off_t)0);
0N/A
0N/A if (shpx_dir == (SHPX_DIRECTORY *)-1) {
0N/A close(c_fd);
0N/A return(0);
0N/A }
0N/A Dga_shpx_client_count++;
0N/A shpx_client_directory[i].cid = token; /* BMAC - correct?? */
0N/A shpx_client_directory[i].shpx_directory = shpx_dir;
0N/A shpx_client_directory[i].fd = c_fd; /* no longer need to save it */
0N/A shpx_client_directory[i].size = shpx_dir[0].shpx_entry_0.s_size;
0N/A shpx_client_directory[i].npix = 1;
0N/A }
0N/A#endif /* SERVER_DGA */
0N/A
0N/A /* The first 2 entries on the file have special meaning. */
0N/A i = 2;
0N/A entry_found = 0;
606N/A while ((i < SHPX_MAX_PIXMAPS) && (!entry_found)) {
0N/A if (shpx_dir[i].shpx_entry.xid == pix)
0N/A entry_found = 1;
0N/A else
606N/A i++;
0N/A }
0N/A
0N/A if (!entry_found) {
0N/A#ifndef SERVER_DGA
0N/A close(c_fd);
0N/A#endif /* SERVER_DGA */
0N/A return(0);
0N/A }
0N/A infop = (SHARED_PIXMAP_INFO *)
0N/A (((u_char *)shpx_dir) + shpx_dir[i].shpx_entry.offset);
0N/A
0N/A if ((infop->magic != PXMPMAGIC) || (infop->version > PXMPVERS)) {
0N/A#ifndef SERVER_DGA
0N/A close(c_fd);
0N/A#endif /* SERVER_DGA */
0N/A return(0);
0N/A }
0N/A if (infop->obsolete) {
0N/A#ifndef SERVER_DGA
0N/A close(c_fd);
0N/A#endif /* SERVER_DGA */
0N/A return(0);
0N/A }
0N/A /* BMAC - Find out about the rache code - what should I do there? */
0N/A
0N/A /* Now fill out the Dga_pixmap structure */
0N/A if( (clientp = (_Dga_pixmap) malloc(sizeof(struct dga_pixmap))) == NULL )
0N/A return NULL ;
0N/A
0N/A clientp->drawable_type = DGA_DRAW_PIXMAP;
0N/A clientp->p_lockcnt = 0;
0N/A clientp->obsolete = 0;
0N/A clientp->p_modif = NULL;
0N/A clientp->p_infop = (void *)infop ;
0N/A clientp->c_chngcnt[0] = 0;
0N/A#ifdef MT
0N/A clientp->shadow_chngcnt[0] = 0;
0N/A#endif
0N/A /* This is the new location added for locking performance
0N/A * For windows it pts to the second member in the c_wm_chngcnt
606N/A * array but here I think that it just pts to the previous field
0N/A * since for pixmaps the array ctr is -1 always
0N/A */
606N/A clientp->p_chngcnt_2nd = clientp->c_chngcnt +1;
0N/A
0N/A clientp->s_chngcnt_p = &(infop->s_modified);
0N/A clientp->c_dirchngcnt = shpx_dir[1].shpx_entry_1.s_dir_seq;
0N/A clientp->s_dirchngcnt_p = &(shpx_dir[1].shpx_entry_1.s_dir_seq);
0N/A clientp->c_devinfocnt = 0;
0N/A clientp->s_devinfocnt_p = &(infop->s_devinfoseq);
0N/A clientp->c_cachecnt = 0;
0N/A clientp->s_cachecnt_p = &(infop->s_cacheseq);
0N/A clientp->c_cached = 0;
0N/A clientp->s_cached_p = &(infop->cached);
0N/A clientp->p_dir_index = i;
0N/A clientp->p_shpx_dir = (void *)shpx_dir; /*CHECK ME */
0N/A#ifdef MT
0N/A if (dgaThreaded) {
0N/A clientp->p_unlock_func = dgai_unlock;
0N/A } else {
0N/A clientp->p_unlock_func = NULL;
0N/A }
0N/A#else
0N/A clientp->p_lock_func = NULL;
0N/A clientp->p_unlock_func = NULL;
0N/A#endif
0N/A clientp->p_update_func = (int(*)())dgai_pix_update;
0N/A clientp->p_shpx_client = NULL;
0N/A clientp->p_token = token;
606N/A clientp->c_size = infop->s_size;
0N/A clientp->c_pixels = (u_char *)(infop + 1);
0N/A clientp->depth = infop->depth;
0N/A clientp->linebytes = infop->linebytes;
0N/A clientp->p_next = NULL;
0N/A clientp->p_infofd = NULL;
606N/A clientp->pix_flags = PIX_NOTICE_CLIPCHG;
0N/A clientp->p_dpy = 0;
0N/A clientp->p_id = NULL;
0N/A clientp->p_client = NULL;
0N/A clientp->changeMask = NULL;
0N/A clientp->siteChgReason = NULL;
0N/A clientp->siteNotifyFunc = NULL;
606N/A clientp->siteNotifyClientData = NULL;
0N/A
0N/A#ifdef SERVER_DGA
0N/A clientp->p_lockp = infop->p_lockp;
0N/A clientp->p_unlockp = infop->p_unlockp;
0N/A#else
0N/A lockp = NULL; /* init to NULL for check below */
0N/A unlockp = NULL;
0N/A
0N/A /* Check to see if there are already a lockp and unlockp
0N/A * for this device--if not create 'em
0N/A */
0N/A if (dga_plist) {
0N/A lockp = dga_plist->dga_clientplist->p_lockp;
0N/A unlockp = dga_plist->dga_clientplist->p_unlockp;
0N/A }
0N/A
0N/A if (!lockp) {
0N/A /* only get new lock pages if necessary */
0N/A if( _dga_winlockat(infop->p_cookie, &lockp, &unlockp) != 0 ) {
0N/A munmap((caddr_t)infop, MAXSHPXMEMSIZE);
0N/A/* REMIND Daryl: What else do we need to clean up? */
0N/A free(clientp) ;
0N/A return(NULL);
0N/A }
0N/A }
0N/A
0N/A clientp->p_lockp = lockp;
0N/A clientp->p_unlockp = unlockp;
0N/A#endif /* SERVER_DGA */
0N/A
0N/A /* add to linked list of grabbed pixmaps - for internal bookkeeping
0N/A */
0N/A if (!dga_plist) {
0N/A if ((dga_plist =
0N/A (Dga_pixlist) malloc(sizeof(struct dga_pixlist))) == NULL )
633N/A return NULL ;
0N/A dga_plist->p_token = token;
0N/A dga_plist->num_clientp = 1;
851N/A dga_plist->dga_clientplist = clientp;
633N/A dga_plist->next_plist = NULL;
851N/A } else {
0N/A struct dga_pixlist *new_plist;
606N/A
0N/A if ((new_plist =
0N/A (Dga_pixlist) malloc(sizeof(struct dga_pixlist))) == NULL )
851N/A return NULL;
851N/A new_plist->p_token = token;
851N/A new_plist->num_clientp = 1;
851N/A new_plist->dga_clientplist = clientp;
851N/A new_plist->next_plist = dga_plist;
851N/A dga_plist = new_plist;
0N/A }
196N/A#ifdef MT
196N/A if (dgaThreaded) {
0N/A clientp->mutexp = &dgaGlobalPixmapMutex;
851N/A } else {
851N/A clientp->mutexp = NULL;
851N/A }
851N/A#endif
851N/A return ((Dga_pixmap) clientp);
851N/A}
851N/A
851N/Avoid
0N/Adga_pix_ungrab(clientpi)
0N/ADga_pixmap clientpi;
851N/A{
851N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
0N/A Dga_pixlist prev_pixlist = NULL;
0N/A Dga_pixlist pixlist = dga_plist;
851N/A u_int i;
851N/A
851N/A /* Find pixmap in dga_plist */
851N/A while (pixlist) {
851N/A if (pixlist->dga_clientplist == clientp) {
851N/A#ifndef SERVER_DGA
0N/A i = 0;
851N/A while ((i < SHPX_MAX_CLIENTS) &&
0N/A (shpx_client_directory[i].cid != pixlist->p_token)) {
196N/A i++;
0N/A }
196N/A if ((i == SHPX_MAX_CLIENTS) &&
196N/A (Dga_shpx_client_count == SHPX_MAX_CLIENTS)) {
196N/A return;
196N/A }
196N/A shpx_client_directory[i].npix--;
196N/A if (!shpx_client_directory[i].npix) {
196N/A munmap((caddr_t)shpx_client_directory[i].shpx_directory,
196N/A MAXSHPXMEMSIZE);
0N/A close(shpx_client_directory[i].fd);
196N/A shpx_client_directory[i].cid = 0;
196N/A shpx_client_directory[i].shpx_directory = NULL;
196N/A shpx_client_directory[i].fd = 0;
0N/A shpx_client_directory[i].size = 0;
0N/A }
0N/A#endif /* SERVER_DGA */
606N/A
633N/A if (prev_pixlist)
633N/A prev_pixlist->next_plist = pixlist->next_plist;
0N/A else
606N/A dga_plist = pixlist->next_plist;
0N/A#ifndef SERVER_DGA
0N/A if (!dga_plist) {
0N/A _dga_winlockdt(clientp->p_lockp, clientp->p_unlockp);
0N/A }
0N/A#endif /* SERVER_DGA */
0N/A free(pixlist);
0N/A free(clientp);
36N/A if(--Dga_shpx_client_count < 0)
36N/A Dga_shpx_client_count = 0;
36N/A return;
36N/A } else {
36N/A prev_pixlist = pixlist;
0N/A pixlist = pixlist->next_plist;
0N/A }
0N/A }
0N/A}
0N/A
0N/A#ifdef COMMENT
0N/A/* TODO: Daryl what is this routine supposed to be used for??? */
0N/Aint
851N/Adga_pix_sync(clientpi)
0N/ADga_pixmap clientpi;
0N/A{
0N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
633N/A /* this checks to see if the shared pixmap info
0N/A * area has changed and if so reinits the data
0N/A */
606N/A /* This routine seems to requoire that the handle have
0N/A 1. if the pixmap is cached or not
0N/A 2. what type the pixmap is = like retained one??
0N/A 3. something called sh_rache_scr0, sh_rache_scr1;
0N/A 4. something called sh_Scr_Virt[]; virtual screen table */
0N/A}
0N/A#endif
0N/A
0N/Aint
0N/Adga_pix_cachechg(clientpi)
0N/ADga_pixmap clientpi;
0N/A{
0N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
0N/A
0N/A if (clientp->c_cachecnt != *(clientp->s_cachecnt_p)) {
0N/A /* Something changed */
0N/A clientp->c_cachecnt = *(clientp->s_cachecnt_p);
0N/A return 1;
0N/A } else
0N/A /* Nothing has changed */
0N/A return 0;
0N/A}
0N/A
0N/Aint
0N/Adga_pix_cached(clientpi)
0N/ADga_pixmap clientpi;
0N/A{
0N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
0N/A
851N/A if (clientp->c_cached != *(clientp->s_cached_p)) {
0N/A /* Something changed */
0N/A clientp->c_cached = *(clientp->s_cached_p);
0N/A return 1;
0N/A } else
0N/A /* Nothing has changed */
851N/A return 0;
0N/A}
0N/A
0N/Achar *
0N/Adga_pix_devname(clientpi)
0N/ADga_pixmap clientpi;
0N/A{
0N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
0N/A /* CHECK THIS ! */
0N/A return ((char *) PIX_INFOP(clientp)->scr_name);
0N/A}
0N/A
851N/Avoid *
851N/Adga_pix_pixels(clientpi)
0N/ADga_pixmap clientpi;
0N/A{
0N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
0N/A
0N/A return ((void*)clientp->c_pixels);
0N/A}
0N/A
0N/Aint
0N/Adga_pix_linebytes(clientpi)
0N/ADga_pixmap clientpi;
0N/A{
851N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
0N/A
0N/A return (clientp->linebytes);
0N/A}
0N/A
851N/A
851N/Au_char
0N/Adga_pix_depth(clientpi)
0N/ADga_pixmap clientpi;
0N/A{
0N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
0N/A return (clientp->depth);
0N/A}
0N/A
0N/Avoid *
0N/Adga_pix_devinfo(clientpi)
0N/ADga_pixmap clientpi;
0N/A{
0N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
0N/A return (((char *)clientp->p_infop) + PIX_INFOP(clientp)->device_offset);
0N/A}
0N/A
0N/A