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