943N/A/* Copyright (c) 1993, 2004, Oracle and/or its affiliates. All rights reserved.
830N/A *
830N/A * Permission is hereby granted, free of charge, to any person obtaining a
919N/A * copy of this software and associated documentation files (the "Software"),
919N/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:
830N/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.
830N/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.
830N/A */
830N/A
830N/A
830N/A#include <stdio.h>
830N/A#include <stdlib.h>
830N/A#include <string.h>
830N/A#include <sys/types.h>
830N/A#include <fcntl.h>
830N/A#include <netdb.h>
830N/A#ifdef SERVER_DGA
830N/A#include <X11/Xlib.h>
830N/A#else
830N/A#include <unistd.h>
830N/A#include <sys/fcntl.h>
830N/A#include <sys/mman.h>
830N/A#endif /* SERVER_DGA */
830N/A
830N/A#include "dga_incls.h"
830N/A#include "pix_grab.h"
830N/A
830N/A
830N/A
830N/A#define NDIGITS 8
830N/A#define MINSHMEMSIZE (8*1024)
830N/A#define MAXSHMEMSIZE (0x00040000)
830N/A#define MAXSHPXMEMSIZE (0x01000000)
830N/A#define SHPX_MAX_CLIENTS 64
830N/A#define SHPX_MAX_PIXMAPS 341
830N/A
830N/A
830N/A
830N/A/* Some structure definition for internal bookkeeping
830N/A * NOTE: there is only one locking window created per device for
830N/A * the use of all pixmaps on that device
830N/A*/
830N/Atypedef struct dga_pixlist {
830N/A Dga_token p_token; /* Token associated with pix */
830N/A int num_clientp;
830N/A struct dga_pixmap *dga_clientplist; /*List of client ptrs in pix */
830N/A struct dga_pixlist *next_plist; /* Next link in the dga list */
830N/A} *Dga_pixlist;
830N/A
830N/Astatic struct dga_pixlist *dga_plist = NULL;
830N/A#ifdef SERVER_DGA
830N/Aextern SHPX_CLIENT_ENTRY shpx_client_directory[];
830N/Aextern int Dga_shpx_client_count;
830N/A#else
830N/Astatic SHPX_CLIENT_ENTRY shpx_client_directory[SHPX_MAX_CLIENTS];
830N/Astatic int Dga_shpx_client_count = 0;
830N/A#endif /* SERVER_DGA */
830N/Astatic u_long pagesize;
830N/A
830N/Aextern int _dga_winlockat(u_long cookie, int **lockp, int **unlockp);
830N/Aextern int _dga_winlockdt(int *lockp, int *unlockp);
830N/Aextern void *_dga_is_X_pixmap(Pixmap pix, Display **dpyp);
830N/A
830N/A/******************************************
830N/A *
830N/A * dga_pix_grab:
830N/A *
830N/A * create shared memory file for pixmap information
830N/A * map to lock page
830N/A *
830N/A * arguments:
830N/A *
830N/A * Dga_token token; INPUT
830N/A * magic cookie supplied by the server
830N/A *
830N/A * returns a user virtual address for a dga_window structure.
830N/A * returns NULL if anything goes awry.
830N/A *
830N/A *****************************************/
830N/A
830N/ADga_pixmap
830N/Adga_pix_grab(token, pix)
830N/A Dga_token token;
830N/A Pixmap pix;
830N/A{
830N/A SHARED_PIXMAP_INFO *infop;
830N/A _Dga_pixmap clientp ;
830N/A Display *dpy;
830N/A int c_fd, i, entry_found;
830N/A u_int port;
830N/A size_t size;
830N/A SHPX_DIRECTORY *shpx_dir;
830N/A char c_fn[256];
830N/A char *dpystr;
830N/A static char path[256];
830N/A char host[MAXHOSTNAMELEN];
830N/A Dga_lockp lockp, unlockp;
830N/A
830N/A /* Remember to account for multiple clients grabbing the same pixmap
830N/A * later
830N/A */
830N/A
830N/A /* First determine if this is a X pixmap - if so, get
830N/A * the dpy and pixid
830N/A */
830N/A if (!_dga_is_X_pixmap(pix, &dpy)) {
830N/A#ifdef DEBUG
830N/A (void) fprintf(stderr, "dga_pix_grab: Unsupported pixmap type\n");
830N/A#endif
830N/A return (PIX_FAILED);
830N/A }
830N/A
830N/A if (!dga_plist) {
830N/A /* This is the first time through this code so get the
830N/A * retained path */
830N/A if (!XDgaGetRetainedPath(dpy, pix, path)) {
830N/A#ifdef DEBUG
830N/A (void) fprintf(stderr,
830N/A "dga_pix_grab: XDgaGetRetainedPath failed\n");
830N/A#endif
830N/A return (PIX_FAILED);
830N/A }
830N/A }
830N/A#ifndef SERVER_DGA
830N/A /* Now get the port number for this display */
830N/A dpystr = DisplayString(dpy);
830N/A if (dpystr[0] == ':')
830N/A (void) sscanf(dpystr, ":%u", &port);
830N/A else
830N/A (void) sscanf(dpystr, "%[^:]:%u", host, &port);
830N/A
830N/A if (Dga_shpx_client_count == 0) {
830N/A /* Now start by initializing all the per client structs -
830N/A * all 64 of them - if thie is the first time you
830N/A * are grabbing a pixmap
830N/A */
830N/A for (i = 0; i < SHPX_MAX_CLIENTS; i++) {
830N/A shpx_client_directory[i].cid = 0;
830N/A shpx_client_directory[i].shpx_directory = NULL;
830N/A shpx_client_directory[i].fd = 0;
830N/A shpx_client_directory[i].size = 0;
830N/A shpx_client_directory[i].npix = 0;
830N/A }
830N/A } else
830N/A#endif /* SERVER_DGA */
830N/A {
830N/A /* If it is not the first time, see if this client has grabbed
830N/A * a pixmap before and therefore done all the set up.
830N/A * Search through the client structures for matching token
830N/A */
830N/A i = 0;
830N/A while ((i < SHPX_MAX_CLIENTS) &&
830N/A (shpx_client_directory[i].cid != token)) {
830N/A i++;
830N/A }
830N/A if ((i == SHPX_MAX_CLIENTS) &&
830N/A (Dga_shpx_client_count == SHPX_MAX_CLIENTS)) {
830N/A return(0);
830N/A }
830N/A }
830N/A
830N/A if ((Dga_shpx_client_count > 0) && (i < SHPX_MAX_CLIENTS)) {
830N/A /* We found a match and the pixmap already has been grabbed before */
830N/A shpx_dir = shpx_client_directory[i].shpx_directory;
830N/A shpx_client_directory[i].npix++;
830N/A }
830N/A#ifndef SERVER_DGA
830N/A else {
830N/A /* This client has Never grabbed before set up the direct
830N/A * structure etc.
830N/A * Open the shared file using server command line
830N/A * -sharedretainedpath variable for file path if it is
830N/A * set, else use /tmp. This is because these files can
830N/A * be very big and there usually isn't much space in /tmp.
830N/A */
830N/A c_fn[0] = 0;
830N/A
830N/A
830N/A if ((path) && (strlen(path) > 0))
830N/A strcpy(c_fn, path);
830N/A else
830N/A strcpy(c_fn, "/tmp");
830N/A
830N/A strcat(c_fn, PIX_FILE);
830N/A size = strlen(c_fn);
830N/A sprintf(c_fn+size,"%01x.%08x", port, token);
830N/A
830N/A#ifdef SYSV
830N/A pagesize = sysconf(_SC_PAGESIZE);
830N/A#else
830N/A pagesize = getpagesize();
830N/A#endif
830N/A i = 0;
830N/A while ((i < SHPX_MAX_CLIENTS) && (shpx_client_directory[i].cid != 0))
830N/A i++;
830N/A if ((c_fd = open(c_fn,O_RDWR ,0666)) < 0)
830N/A return(0);
830N/A /* map the shpx directory for this client and map at 4 megabytes */
830N/A shpx_dir = (SHPX_DIRECTORY *)mmap(0,
830N/A MAXSHPXMEMSIZE,
830N/A PROT_READ|PROT_WRITE,
830N/A MAP_SHARED,
830N/A c_fd,
830N/A (off_t)0);
830N/A
830N/A if (shpx_dir == (SHPX_DIRECTORY *)-1) {
830N/A close(c_fd);
830N/A return(0);
830N/A }
830N/A Dga_shpx_client_count++;
830N/A shpx_client_directory[i].cid = token; /* BMAC - correct?? */
830N/A shpx_client_directory[i].shpx_directory = shpx_dir;
830N/A shpx_client_directory[i].fd = c_fd; /* no longer need to save it */
830N/A shpx_client_directory[i].size = shpx_dir[0].shpx_entry_0.s_size;
830N/A shpx_client_directory[i].npix = 1;
830N/A }
830N/A#endif /* SERVER_DGA */
830N/A
830N/A /* The first 2 entries on the file have special meaning. */
830N/A i = 2;
830N/A entry_found = 0;
830N/A while ((i < SHPX_MAX_PIXMAPS) && (!entry_found)) {
830N/A if (shpx_dir[i].shpx_entry.xid == pix)
830N/A entry_found = 1;
830N/A else
830N/A i++;
830N/A }
830N/A
830N/A if (!entry_found) {
830N/A#ifndef SERVER_DGA
830N/A close(c_fd);
830N/A#endif /* SERVER_DGA */
830N/A return(0);
830N/A }
830N/A infop = (SHARED_PIXMAP_INFO *)
830N/A (((u_char *)shpx_dir) + shpx_dir[i].shpx_entry.offset);
830N/A
830N/A if ((infop->magic != PXMPMAGIC) || (infop->version > PXMPVERS)) {
830N/A#ifndef SERVER_DGA
830N/A close(c_fd);
830N/A#endif /* SERVER_DGA */
830N/A return(0);
830N/A }
830N/A if (infop->obsolete) {
830N/A#ifndef SERVER_DGA
830N/A close(c_fd);
830N/A#endif /* SERVER_DGA */
830N/A return(0);
830N/A }
830N/A /* BMAC - Find out about the rache code - what should I do there? */
830N/A
830N/A /* Now fill out the Dga_pixmap structure */
830N/A if( (clientp = (_Dga_pixmap) malloc(sizeof(struct dga_pixmap))) == NULL )
830N/A return NULL ;
830N/A
830N/A clientp->drawable_type = DGA_DRAW_PIXMAP;
830N/A clientp->p_lockcnt = 0;
830N/A clientp->obsolete = 0;
830N/A clientp->p_modif = NULL;
830N/A clientp->p_infop = (void *)infop ;
830N/A clientp->c_chngcnt[0] = 0;
830N/A#ifdef MT
830N/A clientp->shadow_chngcnt[0] = 0;
830N/A#endif
830N/A /* This is the new location added for locking performance
830N/A * For windows it pts to the second member in the c_wm_chngcnt
830N/A * array but here I think that it just pts to the previous field
830N/A * since for pixmaps the array ctr is -1 always
830N/A */
830N/A clientp->p_chngcnt_2nd = clientp->c_chngcnt +1;
830N/A
830N/A clientp->s_chngcnt_p = &(infop->s_modified);
830N/A clientp->c_dirchngcnt = shpx_dir[1].shpx_entry_1.s_dir_seq;
830N/A clientp->s_dirchngcnt_p = &(shpx_dir[1].shpx_entry_1.s_dir_seq);
830N/A clientp->c_devinfocnt = 0;
830N/A clientp->s_devinfocnt_p = &(infop->s_devinfoseq);
830N/A clientp->c_cachecnt = 0;
830N/A clientp->s_cachecnt_p = &(infop->s_cacheseq);
830N/A clientp->c_cached = 0;
830N/A clientp->s_cached_p = &(infop->cached);
830N/A clientp->p_dir_index = i;
830N/A clientp->p_shpx_dir = (void *)shpx_dir; /*CHECK ME */
830N/A#ifdef MT
830N/A if (dgaThreaded) {
830N/A clientp->p_unlock_func = dgai_unlock;
830N/A } else {
830N/A clientp->p_unlock_func = NULL;
830N/A }
830N/A#else
830N/A clientp->p_lock_func = NULL;
830N/A clientp->p_unlock_func = NULL;
830N/A#endif
830N/A clientp->p_update_func = (int(*)())dgai_pix_update;
830N/A clientp->p_shpx_client = NULL;
830N/A clientp->p_token = token;
830N/A clientp->c_size = infop->s_size;
830N/A clientp->c_pixels = (u_char *)(infop + 1);
830N/A clientp->depth = infop->depth;
830N/A clientp->linebytes = infop->linebytes;
830N/A clientp->p_next = NULL;
830N/A clientp->p_infofd = NULL;
830N/A clientp->pix_flags = PIX_NOTICE_CLIPCHG;
830N/A clientp->p_dpy = 0;
830N/A clientp->p_id = NULL;
830N/A clientp->p_client = NULL;
830N/A clientp->changeMask = NULL;
830N/A clientp->siteChgReason = NULL;
830N/A clientp->siteNotifyFunc = NULL;
830N/A clientp->siteNotifyClientData = NULL;
830N/A
830N/A#ifdef SERVER_DGA
830N/A clientp->p_lockp = infop->p_lockp;
830N/A clientp->p_unlockp = infop->p_unlockp;
830N/A#else
830N/A lockp = NULL; /* init to NULL for check below */
830N/A unlockp = NULL;
830N/A
830N/A /* Check to see if there are already a lockp and unlockp
830N/A * for this device--if not create 'em
830N/A */
830N/A if (dga_plist) {
830N/A lockp = dga_plist->dga_clientplist->p_lockp;
830N/A unlockp = dga_plist->dga_clientplist->p_unlockp;
830N/A }
830N/A
830N/A if (!lockp) {
830N/A /* only get new lock pages if necessary */
830N/A if( _dga_winlockat(infop->p_cookie, &lockp, &unlockp) != 0 ) {
830N/A munmap((caddr_t)infop, MAXSHPXMEMSIZE);
830N/A/* REMIND Daryl: What else do we need to clean up? */
830N/A free(clientp) ;
830N/A return(NULL);
830N/A }
830N/A }
830N/A
830N/A clientp->p_lockp = lockp;
830N/A clientp->p_unlockp = unlockp;
830N/A#endif /* SERVER_DGA */
830N/A
830N/A /* add to linked list of grabbed pixmaps - for internal bookkeeping
830N/A */
830N/A if (!dga_plist) {
830N/A if ((dga_plist =
830N/A (Dga_pixlist) malloc(sizeof(struct dga_pixlist))) == NULL )
830N/A return NULL ;
830N/A dga_plist->p_token = token;
830N/A dga_plist->num_clientp = 1;
830N/A dga_plist->dga_clientplist = clientp;
830N/A dga_plist->next_plist = NULL;
830N/A } else {
830N/A struct dga_pixlist *new_plist;
830N/A
830N/A if ((new_plist =
830N/A (Dga_pixlist) malloc(sizeof(struct dga_pixlist))) == NULL )
830N/A return NULL;
830N/A new_plist->p_token = token;
830N/A new_plist->num_clientp = 1;
830N/A new_plist->dga_clientplist = clientp;
830N/A new_plist->next_plist = dga_plist;
830N/A dga_plist = new_plist;
830N/A }
830N/A#ifdef MT
830N/A if (dgaThreaded) {
830N/A clientp->mutexp = &dgaGlobalPixmapMutex;
830N/A } else {
830N/A clientp->mutexp = NULL;
830N/A }
830N/A#endif
830N/A return ((Dga_pixmap) clientp);
830N/A}
830N/A
830N/Avoid
830N/Adga_pix_ungrab(clientpi)
830N/ADga_pixmap clientpi;
830N/A{
830N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
830N/A Dga_pixlist prev_pixlist = NULL;
830N/A Dga_pixlist pixlist = dga_plist;
830N/A u_int i;
830N/A
830N/A /* Find pixmap in dga_plist */
830N/A while (pixlist) {
830N/A if (pixlist->dga_clientplist == clientp) {
830N/A#ifndef SERVER_DGA
830N/A i = 0;
830N/A while ((i < SHPX_MAX_CLIENTS) &&
830N/A (shpx_client_directory[i].cid != pixlist->p_token)) {
830N/A i++;
830N/A }
830N/A if ((i == SHPX_MAX_CLIENTS) &&
830N/A (Dga_shpx_client_count == SHPX_MAX_CLIENTS)) {
830N/A return;
830N/A }
830N/A shpx_client_directory[i].npix--;
830N/A if (!shpx_client_directory[i].npix) {
830N/A munmap((caddr_t)shpx_client_directory[i].shpx_directory,
830N/A MAXSHPXMEMSIZE);
830N/A close(shpx_client_directory[i].fd);
830N/A shpx_client_directory[i].cid = 0;
830N/A shpx_client_directory[i].shpx_directory = NULL;
830N/A shpx_client_directory[i].fd = 0;
830N/A shpx_client_directory[i].size = 0;
830N/A }
830N/A#endif /* SERVER_DGA */
830N/A
830N/A if (prev_pixlist)
830N/A prev_pixlist->next_plist = pixlist->next_plist;
830N/A else
830N/A dga_plist = pixlist->next_plist;
830N/A#ifndef SERVER_DGA
830N/A if (!dga_plist) {
830N/A _dga_winlockdt(clientp->p_lockp, clientp->p_unlockp);
830N/A }
830N/A#endif /* SERVER_DGA */
830N/A free(pixlist);
830N/A free(clientp);
830N/A if(--Dga_shpx_client_count < 0)
830N/A Dga_shpx_client_count = 0;
830N/A return;
830N/A } else {
830N/A prev_pixlist = pixlist;
830N/A pixlist = pixlist->next_plist;
830N/A }
830N/A }
830N/A}
830N/A
830N/A#ifdef COMMENT
830N/A/* TODO: Daryl what is this routine supposed to be used for??? */
830N/Aint
830N/Adga_pix_sync(clientpi)
830N/ADga_pixmap clientpi;
830N/A{
830N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
830N/A /* this checks to see if the shared pixmap info
830N/A * area has changed and if so reinits the data
830N/A */
830N/A /* This routine seems to requoire that the handle have
830N/A 1. if the pixmap is cached or not
830N/A 2. what type the pixmap is = like retained one??
830N/A 3. something called sh_rache_scr0, sh_rache_scr1;
830N/A 4. something called sh_Scr_Virt[]; virtual screen table */
830N/A}
830N/A#endif
830N/A
830N/Aint
830N/Adga_pix_cachechg(clientpi)
830N/ADga_pixmap clientpi;
830N/A{
830N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
830N/A
830N/A if (clientp->c_cachecnt != *(clientp->s_cachecnt_p)) {
830N/A /* Something changed */
830N/A clientp->c_cachecnt = *(clientp->s_cachecnt_p);
830N/A return 1;
830N/A } else
830N/A /* Nothing has changed */
830N/A return 0;
830N/A}
830N/A
830N/Aint
830N/Adga_pix_cached(clientpi)
830N/ADga_pixmap clientpi;
830N/A{
830N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
830N/A
830N/A if (clientp->c_cached != *(clientp->s_cached_p)) {
830N/A /* Something changed */
830N/A clientp->c_cached = *(clientp->s_cached_p);
830N/A return 1;
830N/A } else
830N/A /* Nothing has changed */
830N/A return 0;
830N/A}
830N/A
830N/Achar *
830N/Adga_pix_devname(clientpi)
830N/ADga_pixmap clientpi;
830N/A{
830N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
830N/A /* CHECK THIS ! */
830N/A return ((char *) PIX_INFOP(clientp)->scr_name);
830N/A}
830N/A
830N/Avoid *
830N/Adga_pix_pixels(clientpi)
830N/ADga_pixmap clientpi;
830N/A{
830N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
830N/A
830N/A return ((void*)clientp->c_pixels);
830N/A}
830N/A
830N/Aint
830N/Adga_pix_linebytes(clientpi)
830N/ADga_pixmap clientpi;
830N/A{
830N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
830N/A
830N/A return (clientp->linebytes);
830N/A}
830N/A
830N/A
830N/Au_char
830N/Adga_pix_depth(clientpi)
830N/ADga_pixmap clientpi;
830N/A{
830N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
830N/A return (clientp->depth);
830N/A}
830N/A
830N/Avoid *
830N/Adga_pix_devinfo(clientpi)
830N/ADga_pixmap clientpi;
830N/A{
830N/A _Dga_pixmap clientp = (struct dga_pixmap *)clientpi;
830N/A return (((char *)clientp->p_infop) + PIX_INFOP(clientp)->device_offset);
830N/A}
830N/A