diff options
author | alanh <alanh> | 2002-10-22 13:22:42 +0000 |
---|---|---|
committer | alanh <alanh> | 2002-10-22 13:22:42 +0000 |
commit | d9adac36dc5c47304f8b98458bab48c0394dd5b2 (patch) | |
tree | af642c159aeabdbd8ac6e58ccc4bea054ef784dd | |
parent | a10dd7bf6ed1ec9e9810710a71f9238061369e15 (diff) |
Initial revision
87 files changed, 23420 insertions, 0 deletions
diff --git a/xc/programs/Xserver/fb/fbtrap.c b/xc/programs/Xserver/fb/fbtrap.c new file mode 100644 index 000000000..3a44d53ef --- /dev/null +++ b/xc/programs/Xserver/fb/fbtrap.c @@ -0,0 +1,1382 @@ +/* + * $XFree86: xc/programs/Xserver/fb/fbtrap.c,v 1.10 2002/09/27 00:31:24 keithp Exp $ + * + * Copyright © 2000 University of Southern California + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of University + * of Southern California not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. University of Southern California makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * University of Southern California DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE BE LIABLE FOR + * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Author: Carl Worth, USC, Information Sciences Institute */ + +#include "fb.h" + +#ifdef RENDER + +#include "picturestr.h" +#include "mipict.h" +#include "fbpict.h" + +#ifdef DEBUG +#include <stdio.h> +#include <assert.h> + +#define ASSERT(e) assert(e) + +#endif + +#ifndef ASSERT +#define ASSERT(e) +#endif + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define MAX_AREA 0x80000000 + +/* + * A RationalPoint is an exact position along one of the trapezoid + * edges represented by an approximate position (x,y) and two error + * terms (ex_dy, ey_dx). The error in X is multiplied by the Y + * dimension of the line while the error in Y is multiplied by the + * X dimension of the line, allowing an exact measurement of the + * distance from (x,y) to the line. + * + * Generally, while walking an edge, one of ex_dy/ey_dx will be zero + * indicating that the position error is held in the other. + */ +typedef struct { + xFixed x; + xFixed ex_dy; + xFixed y; + xFixed ey_dx; +} RationalPoint; + +/* + * Edges are walked both horizontally and vertically + * They are walked vertically to get to a particular row + * of pixels, and then walked horizontally within that row + * to compute pixel coverage. + * + * Edges are always walked from top to bottom and from + * left to right. This means that for lines moving leftwards + * from top to bottom, the left to right walking actually moves + * backwards along the line with respect to the top to bottom + * walking. + */ + +/* + * A RationalRow represents the two positions where + * an edge intersects a row of pixels. This is used + * to walk an edge vertically + */ + +typedef struct { + RationalPoint top; /* intersection at top of row */ + RationalPoint bottom; /* intersection at bottom of row */ + RationalPoint pixel_top; /* intersection at top of pixel */ +} RationalRow; + +/* + * A RationalCol represents the two positions where + * an edge intersects a column of pixels + */ + +typedef struct { + RationalPoint left; /* intersection at left of column */ + RationalPoint right; /* intersection at right of column */ +} RationalCol; + +/* + Here are some thoughts on line walking: + + Conditions: c2.x - c1.x = 1 + r2.y - r1.y = 1 + + A B C D E F G H + c1\ c1 c2 /c2 +r1 r1 |\ \ r1 r1 / r1/| r1 r1 +\-+---+ \-+---+ +-\-+ +\--+ +--/+ +-/-+ +---+-/ +---+-/ + \| | `.c1 | |r1\| | \ | | / | |/ | | .' | |/ +c1\ | |`-.|c2 | \c2 | | | | | | c1/ | c1|,_/|c2 | /c2 + |\ | | `. | |\ | \ | | / | /| | ./ | | /| + +-\-+ +---+-\ +---+-\ +--\+ +/--+ /-+---+ /-+---+ +-/-+ + r2\| r2 r2 r2\ /r2 r2 r2 |/r2 + \c2 c2 c1 c1/ + + Bottom Right Right Bottom Top Top Right Right + +State transitions: + +A -> C, D E -> E, F +B -> A, B F -> G, H +C -> A, B G -> G, H +D -> C, D H -> E, F + +*/ + +/* + * Values for PixelWalk.depart. Top and Bottom can have the same value + * as only one mode is possible given a line of either positive or + * negative slope. These mark the departure edge while walking + * rightwards across columns. + */ + +typedef enum _departure { + DepartTop = 0, /* edge exits top of pixel */ + DepartBottom = 0, /* edge exits bottom of pixel */ + DepartRight = 1 /* edge exits right edge of pixel */ +} Departure; + +/* + * PixelWalk + * + * This structure holds state to walk a single edge down the trapezoid. + * + * The edge is walked twice -- once by rows and once by columns. + * The two intersections of the pixel by the edge are then set + * from either the row or column position, depending on which edge + * is intersected. + * + * Note that for lines moving left, walking by rows moves down the + * line (increasing y) while walking by columns moves up the line + * (decreasing y). + */ +typedef struct { + xFixed dx; + xFixed ey_thresh; + xFixed dy; + xFixed ex_thresh; + + Departure depart; + + /* slope */ + xFixed m; + xFixed em_dx; + xFixed y_correct; + xFixed ey_correct; + + /* Inverse slope. Does this have a standard symbol? */ + xFixed p; + xFixed ep_dy; + xFixed x_correct; + xFixed ex_correct; + + /* Trapezoid bottom, used to limit walking to the last row */ + xFixed bottom; + + /* + * Current edge positions along pixel rows and columns + */ + RationalRow row; + RationalCol col; + + /* + * The three pixel intersection points, copied from the appropriate + * row or column position above + */ + RationalPoint p_pixel_top; + RationalPoint p_trap_top; + RationalPoint p_trap_bottom; +} PixelWalk; + +#if 0 +#ifdef GCC +#define INLINE inline +#endif +#endif + +#ifndef INLINE +#define INLINE +#endif + +/* + * Step 'pt' vertically to 'newy'. + */ +static INLINE void +pixelWalkMovePointToRow (PixelWalk *pw, RationalPoint *pt, xFixed newy) +{ + xFixed_32_32 oex; + xFixed xoff; + + /* X error of old X position and new Y position */ + oex = (xFixed_32_32) pw->dx * (newy - pt->y) - pt->ey_dx + pt->ex_dy; + + /* amount to step X by */ + xoff = oex / pw->dy; + + /* step X */ + pt->x = pt->x + xoff; + + /* set new X error value for new X position and new Y positition */ + pt->ex_dy = oex - (xFixed_32_32) pw->dy * xoff; + + /* set new Y position, set Y error to zero */ + pt->y = newy; + pt->ey_dx = 0; +} + +/* + * Step 'pt' horizontally to 'newx' + */ +static INLINE void +pixelWalkMovePointToCol (PixelWalk *pw, RationalPoint *pt, xFixed newx) +{ + xFixed_32_32 oey; + xFixed yoff; + + /* Special case vertical lines to arbitrary y */ + if (pw->dx == 0) + { + pt->x = newx; + pt->ex_dy = 0; + pt->y = 0; + pt->ey_dx = 0; + } + else + { + /* Y error of old Y position and new X position */ + oey = (xFixed_32_32) pw->dy * (newx - pt->x) - pt->ex_dy + pt->ey_dx; + + /* amount to step Y by */ + yoff = oey / pw->dx; + + /* step Y */ + pt->y = pt->y + yoff; + + /* set new Y error value for new Y position and new X position */ + pt->ey_dx = oey - (xFixed_32_32) pw->dx * yoff; + + /* set new X position, set X error to zero */ + pt->x = newx; + pt->ex_dy = 0; + } +} + +/* + * Step the 'row' element of 'pw' vertically + * (increasing y) by one whole pixel + */ +static INLINE void +pixelWalkStepRow (PixelWalk *pw) +{ + xFixed y_next = xFixedFloor (pw->row.bottom.y) + xFixed1; + + if (y_next > pw->bottom) + y_next = pw->bottom; + + /* pw.row.top.y < pw.row.bottom.y */ + pw->row.top = pw->row.bottom; + + if (y_next - pw->row.bottom.y == xFixed1) + { + pw->row.pixel_top = pw->row.bottom; + pw->row.bottom.y += xFixed1; + pw->row.bottom.x += pw->p; + pw->row.bottom.ex_dy += pw->ep_dy; + if (abs (pw->row.bottom.ex_dy) > pw->ex_thresh) + { + pw->row.bottom.x += pw->x_correct; + pw->row.bottom.ex_dy += pw->ex_correct; + } + } + else + { + pixelWalkMovePointToRow (pw, &pw->row.pixel_top, + xFixedCeil (y_next) - xFixed1); + pixelWalkMovePointToRow (pw, &pw->row.bottom, y_next); + } +} + +/* + * Step the 'col' element of 'pw' horizontally + * (increasing x) by one whole pixel + */ +static INLINE void +pixelWalkStepCol (PixelWalk *pw) +{ + /* pw.col.p1.x < pw.col.p2.x */ + /* + * Copy the current right point into the left point + */ + pw->col.left = pw->col.right; + + /* + * Now incrementally walk across the pixel + */ + pw->col.right.x += xFixed1; + pw->col.right.y += pw->m; + pw->col.right.ey_dx += pw->em_dx; + if (pw->col.right.ey_dx > pw->ey_thresh) + { + pw->col.right.y += pw->y_correct; + pw->col.right.ey_dx += pw->ey_correct; + } +} +/* + * Walk to the nearest edge of the next pixel, filling in both p1 and + * p2 as necessary from either the row or col intersections. + * + * The "next" pixel is defined to be the next pixel intersected by the + * line with pixels visited in raster scan order, (for the benefit of + * cache performance). For lines with positive slope it is easy to + * achieve raster scan order by simply calling StepCol for each pixel + * in a given scanline, then calling StepRow once at the end of each + * scanline. + * + * However, for lines of negative slope where the magnitude of dx is + * greater than dy, a little more work needs to be done. The pixels of + * a particular scanline will be visited by succesive calls to StepCol + * as before. This will effectively step "up" the line as we scan from + * left to right. But, the call to StepRow at the end of the scan line + * will step "down" the line and the column information will be + * invalid at that point. + * + * For now, I fix up the column of all negative slope lines by calling + * MovePointToCol at the end of each scanline. However, this is an + * extremely expensive operation since it involves a 64-bit multiply + * and a 64-bit divide. It would be much better, (at least as long as + * abs(dx) is not much greater than dy), to instead step the col + * backwards as many times as necessary. Or even better, we could + * simply restore col to the position it began at when we started the + * scanline, then simply step it backwards once. That would give a + * performance benefit for lines with slope of any magnitude. + */ + +static INLINE void +pixelWalkNextPixel (PixelWalk *pw) +{ + if (pw->dx < 0) + { + /* + * left moving lines + * + * Check which pixel edge we're departing from + * + * Remember that in this case (dx < 0), the 'row' element of 'pw' + * walks down the line while 'col' walks up + */ + if (pw->depart == DepartTop) + { + /* + * The edge departs the row at this pixel, the + * next time it gets used will be for the next row + * + * Step down one row and then recompute the + * column values to start the next row of + * pixels + */ + pixelWalkStepRow(pw); + /* + * Set column exit pixel + */ + pixelWalkMovePointToCol(pw, &pw->col.right, xFixedFloor(pw->row.bottom.x)); + /* + * This moves the exit pixel to the entry pixel + * and computes the next exit pixel + */ + pixelWalkStepCol(pw); + /* + * The first pixel on the next row will always + * be entered from below, set the lower + * intersection of this edge with that pixel + */ + pw->p_trap_bottom = pw->row.bottom; + } + else /* pw->depart == DepartRight */ + { + /* + * easy case -- just move right one pixel + */ + pixelWalkStepCol(pw); + /* + * Set the lower intersection of the edge with the + * pixel -- that's just where the edge entered + * the pixel from the left + */ + pw->p_trap_bottom = pw->col.left; + } + /* + * Now compute which edge the pixel + * is departing from + */ + if (pw->row.top.x <= pw->col.right.x) + { + /* + * row intersection is left of column intersection, + * that means the edge hits the top of the pixel + * before it hits the right edge + */ + pw->p_trap_top = pw->row.top; + pw->depart = DepartTop; + /* + * Further check to see whether the edge + * leaves the right or top edge of the + * whole pixel + */ + if (pw->row.pixel_top.x <= pw->col.right.x) + pw->p_pixel_top = pw->row.pixel_top; + else + pw->p_pixel_top = pw->col.right; + } + else + { + /* + * Row intersection is right of colum intersection, + * that means the edge hits the right edge of the + * pixel first + */ + pw->p_trap_top = pw->col.right; + pw->p_pixel_top = pw->col.right; + pw->depart = DepartRight; + } + } + else + { + /* + * right moving lines + * + * Check which edge we're departing from + * + * In the dx >= 0 case, the row and col elements both + * walk downwards + */ + if (pw->depart == DepartBottom) + { + /* + * The edge departs the row at this pixel, + * the next time it gets used will be for the + * next row + * + * Step down one row and (maybe) over one + * column to prepare for the next row + */ + if (pw->row.bottom.x == pw->col.right.x) + { + /* + * right through the corner of the pixel, + * adjust the column + */ + pixelWalkStepCol(pw); + } + pixelWalkStepRow(pw); + /* + * Set the upper intersection of the edge with + * the pixel, the first pixel on the next + * row is always entered from the top + */ + pw->p_trap_top = pw->row.top; + pw->p_pixel_top = pw->row.pixel_top; + } + else /* pw->depart == DepartRight */ + { + /* + * Easy case -- move right one + * pixel + */ + pixelWalkStepCol(pw); + /* + * Set the upper intersection of the edge + * with the pixel, that's along the left + * edge of the pixel + */ + pw->p_trap_top = pw->col.left; + pw->p_pixel_top = pw->col.left; + } + /* + * Now compute the exit edge and the + * lower intersection of the edge with the pixel + */ + if (pw->row.bottom.x <= pw->col.right.x) + { + /* + * Hit the place where the edge leaves + * the pixel, the lower intersection is + * where the edge hits the bottom + */ + pw->p_trap_bottom = pw->row.bottom; + pw->depart = DepartBottom; + } + else + { + /* + * The edge goes through the + * next pixel on the row, + * the lower intersection is where the + * edge hits the right side of the pixel + */ + pw->p_trap_bottom = pw->col.right; + pw->depart = DepartRight; + } + } +} + +/* + * Compute the first pixel intersection points + * and the departure type from that pixel + */ +static void +pixelWalkFirstPixel (PixelWalk *pw) +{ + if (pw->dx < 0) + { + if (pw->row.top.x <= pw->col.right.x) + { + /* + * leaving through the top. + * upper position is the upper point of + * the 'row' element + */ + pw->depart = DepartTop; + pw->p_trap_top = pw->row.top; + /* + * further check for pixel top + */ + if (pw->row.pixel_top.x <= pw->col.right.x) + pw->p_pixel_top = pw->row.pixel_top; + else + pw->p_pixel_top = pw->col.right; + } + else + { + /* + * leaving through the right side + * upper position is the right point of + * the 'col' element + */ + pw->depart = DepartRight; + pw->p_trap_top = pw->col.right; + pw->p_pixel_top = pw->col.right; + } + /* + * Now find the lower pixel intersection point + */ + if (pw->row.bottom.x >= pw->col.left.x) + /* + * entering through bottom, + * lower position is the bottom point of + * the 'row' element + */ + pw->p_trap_bottom = pw->row.bottom; + else + /* + * entering through left side, + * lower position is the left point of + * the 'col' element + */ + pw->p_trap_bottom = pw->col.left; + } + else + { + if (pw->row.bottom.x <= pw->col.right.x) + { + /* + * leaving through the bottom (or corner). + * lower position is the lower point of + * the 'row' element + */ + pw->depart = DepartBottom; + pw->p_trap_bottom = pw->row.bottom; + } + else + { + /* + * leaving through the right side + * lower position is the right point of + * the 'col' element + */ + pw->depart = DepartRight; + pw->p_trap_bottom = pw->col.right; + } + /* + * Now find the upper pixel intersection point + */ + if (pw->row.top.x >= pw->col.left.x) + { + /* + * entering through the top (or corner), + * upper position is the top point + * of the 'row' element + */ + pw->p_trap_top = pw->row.top; + /* + * further check for pixel entry + */ + if (pw->row.pixel_top.x >= pw->col.left.x) + pw->p_pixel_top = pw->row.pixel_top; + else + pw->p_pixel_top = pw->col.left; + } + else + { + /* + * entering through the left side, + * upper position is the left point of + * the 'col' element + */ + pw->p_trap_top = pw->col.left; + pw->p_pixel_top = pw->col.left; + } + } +} + +static void +pixelWalkInit (PixelWalk *pw, xLineFixed *line, xFixed top_y, xFixed bottom_y) +{ + xFixed_32_32 dy_inc, dx_inc; + xFixed next_y; + xFixed left_x; + xPointFixed *top, *bot; + + next_y = xFixedFloor (top_y) + xFixed1; + if (next_y > bottom_y) + next_y = bottom_y; + + /* + * Orient lines top down + */ + if (line->p1.y < line->p2.y) + { + top = &line->p1; + bot = &line->p2; + } + else + { + top = &line->p2; + bot = &line->p1; + } + + pw->dx = bot->x - top->x; + pw->ey_thresh = abs(pw->dx >> 1); + pw->dy = bot->y - top->y; + pw->ex_thresh = pw->dy >> 1; + + /* + * Set step values for walking lines + */ + if (pw->dx < 0) + { + pw->x_correct = -1; + pw->ex_correct = pw->dy; + pw->y_correct = -1; + pw->ey_correct = pw->dx; + } + else + { + pw->x_correct = 1; + pw->ex_correct = -pw->dy; + pw->y_correct = 1; + pw->ey_correct = -pw->dx; + } + + pw->bottom = bottom_y; + + /* + * Compute Bresenham values for walking edges incrementally + */ + dy_inc = (xFixed_32_32) xFixed1 * pw->dy; /* > 0 */ + if (pw->dx != 0) + { + pw->m = dy_inc / pw->dx; /* sign(dx) */ + pw->em_dx = dy_inc - (xFixed_32_32) pw->m * pw->dx; /* > 0 */ + } + else + { + /* Vertical line. Setting these to zero prevents us from + having to put any conditions in pixelWalkStepCol. */ + pw->m = 0; + pw->em_dx = 0; + } + + dx_inc = (xFixed_32_32) xFixed1 * (xFixed_32_32) pw->dx; /* sign(dx) */ + pw->p = dx_inc / pw->dy; /* sign(dx) */ + pw->ep_dy = dx_inc - (xFixed_32_32) pw->p * pw->dy; /* sign(dx) */ + + /* + * Initialize 'row' for walking down rows + */ + pw->row.bottom.x = top->x; + pw->row.bottom.ex_dy = 0; + pw->row.bottom.y = top->y; + pw->row.bottom.ey_dx = 0; + + /* + * Initialize 'pixel_top' to be on the line for + * the first step + */ + pw->row.pixel_top = pw->row.bottom; + /* + * Move to the pixel above the 'top_y' coordinate, + * first setting 'bottom' and then using StepRow + * which moves that to 'top' and computes the next 'bottom' + */ + pixelWalkMovePointToRow(pw, &pw->row.bottom, top_y); + pixelWalkStepRow(pw); + + /* + * Initialize 'col' for walking across columns + */ + pw->col.right.x = top->x; + pw->col.right.ex_dy = 0; + pw->col.right.y = top->y; + pw->col.right.ey_dx = 0; + + /* + * First set the column to the left most + * pixel hit by the row + */ + if (pw->dx < 0) + left_x = pw->row.bottom.x; + else + left_x = pw->row.top.x; + + pixelWalkMovePointToCol(pw, &pw->col.right, xFixedFloor (left_x)); + pixelWalkStepCol(pw); + + /* + * Compute first pixel intersections and the + * first departure state + */ + pixelWalkFirstPixel (pw); +} + +#define RoundShift(a,b) (((a) + (1 << ((b) - 1))) >> (b)) +#define MaxAlpha(depth) ((1 << (depth)) - 1) + +#define AreaAlpha(area, depth) (RoundShift (RoundShift (area, depth) * \ + MaxAlpha (depth), \ + (31 - depth))) + +/* + Pixel coverage from the upper-left corner bounded by one horizontal + bottom line (bottom) and one line defined by two points, (x1,y1) and + (x2,y2), which intersect the pixel. y1 must be less than y2. There + are 8 cases yielding the following area calculations: + + A B C D E F G H ++---+ +---+ +-1-+ +1--+ +--1+ +-1-+ +---+ +---+ +| | 1 | | \| | \ | | / | |/ | | 1 | | +1 | |`-.| | 2 | | | | | | 2 | |,_/| | 1 +|\ | | 2 | | | \ | | / | | | 2 | | /| ++-2-+ +---+ +---+ +--2+ +2--+ +---+ +---+ +-2-+ + +A: (1/2 * x2 * (y2 - y1)) +B: (1/2 * x2 * (y2 - y1)) + (bottom - y2) * x2 +C: (1/2 * (x1 + x2) * y2 ) + (bottom - y2) * x2 +D: (1/2 * (x1 + x2) * y2 ) +E: (1/2 * (x1 + x2) * y2 ) +F: (1/2 * x1 * y2 ) +G: (1/2 * x1 * (y2 - y1)) + x1 * y1 +H: (1/2 * (x1 + x2) * (y2 - y1)) + x1 * y1 + +The union of these calculations is valid for all cases. Namely: + + (1/2 * (x1 + x2) * (y2 - y1)) + (bottom - y2) * x2 + x1 * y1 + +An exercise for later would perhaps be to optimize the calculations +for some of the cases above. Specifically, it's possible to eliminate +multiplications by zero in several cases, leaving a maximum of two +multiplies per pixel calculation. (This is even more promising now +that the higher level code actually computes the exact same 8 cases +as part of its pixel walking). + +But, for now, I just want to get something working correctly even if +slower. So, we'll use the non-optimized general equation. + +*/ + +/* 1.16 * 1.16 -> 1.31 */ +#define AREA_MULT(w, h) ( (xFixed_1_31) (((((xFixed_1_16)w)*((xFixed_1_16)h) + 1) >> 1) | (((xFixed_1_16)w)&((xFixed_1_16)h)&0x10000) << 15)) + +/* (1.16 + 1.16) / 2 -> 1.16 */ +#define WIDTH_AVG(x1,x2) (((x1) + (x2) + 1) >> 1) + +#define SubPixelArea(x1, y1, x2, y2, bottom) \ +(xFixed_1_31) ( \ + AREA_MULT((x1), (y1)) \ + + AREA_MULT(WIDTH_AVG((x1), (x2)), (y2) - (y1))\ + + AREA_MULT((x2), (bottom) - (y2)) \ +) + +/* +static xFixed_1_31 +SubPixelArea (xFixed_1_16 x1, + xFixed_1_16 y1, + xFixed_1_16 x2, + xFixed_1_16 y2, + xFixed_1_16 bottom) +{ + xFixed_1_16 x_trap; + xFixed_1_16 h_top, h_trap, h_bot; + xFixed_1_31 area; + + x_trap = WIDTH_AVG(x1,x2); + h_top = y1; + h_trap = (y2 - y1); + h_bot = (bottom - y2); + + area = AREA_MULT(x1, h_top) + + AREA_MULT(x_trap, h_trap) + + AREA_MULT(x2, h_bot); + + return area; +} +*/ + +#define SubPixelAlpha(x1, y1, x2, y2, bottom, depth) \ +( \ + AreaAlpha( \ + SubPixelArea((x1), (y1), (x2), (y2), (bottom)), \ + (depth) \ + ) \ +) + +/* +static int +SubPixelAlpha (xFixed_1_16 x1, + xFixed_1_16 y1, + xFixed_1_16 x2, + xFixed_1_16 y2, + xFixed_1_16 bottom, + int depth) +{ + xFixed_1_31 area; + + area = SubPixelArea(x1, y1, x2, y2, bottom); + + return AreaAlpha(area, depth); +} +*/ + +/* Alpha of a pixel above a given horizontal line */ +#define AlphaAbove(pixel_y, line_y, depth) \ +( \ + AreaAlpha(AREA_MULT((line_y) - (pixel_y), xFixed1), depth) \ +) + +static int +RectAlpha(xFixed pixel_y, xFixed top, xFixed bottom, int depth) +{ + if (depth == 1) + return top == pixel_y ? 1 : 0; + else + return (AlphaAbove (pixel_y, bottom, depth) - + AlphaAbove (pixel_y, top, depth)); +} + + +/* + * Pixel coverage from the left edge bounded by one horizontal lines, + * (top and bottom), as well as one PixelWalk line. + */ +static int +AlphaAboveLeft(RationalPoint *upper, + RationalPoint *lower, + xFixed bottom, + xFixed pixel_x, + xFixed pixel_y, + int depth) +{ + return SubPixelAlpha(upper->x - pixel_x, + upper->y - pixel_y, + lower->x - pixel_x, + lower->y - pixel_y, + bottom - pixel_y, + depth); +} + +/* + Pixel coverage from the left edge bounded by two horizontal lines, + (top and bottom), as well as one line two points, p1 and p2, which + intersect the pixel. The following condition must be true: + + p2.y > p1.y +*/ + +/* + lr + |\ + +--|-\-------+ + | a| b\ | + =======|===\========== top + | c| d \ | + =======|=====\======== bot + | | \ | + +--|-------\-+ + + alpha(d) = alpha(cd) - alpha(c) = alpha(abcd) - alpha(ab) - (alpha(ac) - alpha(c)) + + alpha(d) = pixelalpha(top, bot, right) - pixelalpha(top, bot, left) + + pixelalpha(top, bot, line) = subpixelalpha(bot, line) - subpixelalpha(top, line) +*/ + +static int +PixelAlpha(xFixed pixel_x, + xFixed pixel_y, + xFixed top, + xFixed bottom, + PixelWalk *pw, + int depth) +{ + int alpha; + +#ifdef DEBUG + fprintf(stderr, "alpha (%f, %f) - (%f, %f) = ", + (double) pw->p1.x / (1 << 16), + (double) pw->p1.y / (1 << 16), + (double) pw->p2.x / (1 << 16), + (double) pw->p2.y / (1 << 16)); + fflush(stderr); +#endif + + /* + * Sharp polygons are different, alpha is 1 if the + * area includes the pixel origin, else zero, in + * the above figure, only 'a' has alpha 1 + */ + if (depth == 1) + { + alpha = 0; + if (top == pixel_y && pw->p_pixel_top.x != pixel_x) + alpha = 1; + } + else + { + alpha = (AlphaAboveLeft(&pw->p_pixel_top, &pw->p_trap_bottom, + bottom, pixel_x, pixel_y, depth) + - AlphaAboveLeft(&pw->p_pixel_top, &pw->p_trap_top, + top, pixel_x, pixel_y, depth)); + } + +#ifdef DEBUG + fprintf(stderr, "0x%x => %f\n", + alpha, + (double) alpha / ((1 << depth) -1 )); + fflush(stderr); +#endif + + return alpha; +} + +#define INCREMENT_X_AND_PIXEL \ +{ \ + pixel_x += xFixed1; \ + (*mask.over) (&mask); \ +} + +/* XXX: What do we really want this prototype to look like? Do we want + separate versions for 1, 4, 8, and 16-bit alpha? */ + +#define saturateAdd(t, a, b) (((t) = (a) + (b)), \ + ((CARD8) ((t) | (0 - ((t) >> 8))))) + +#define addAlpha(mask, depth, alpha, temp) (\ + (*(mask)->store) ((mask), (alpha == (1 << depth) - 1) ? \ + 0xff000000 : \ + (saturateAdd (temp, \ + alpha << (8 - depth), \ + (*(mask)->fetch) (mask) >> 24) << 24)) \ +) + +void +fbRasterizeTrapezoid (PicturePtr pMask, + xTrapezoid *pTrap, + int x_off, + int y_off) +{ + xTrapezoid trap = *pTrap; + int alpha, temp; + + FbCompositeOperand mask; + + int depth = pMask->pDrawable->depth; + int max_alpha = (1 << depth) - 1; + int buf_width = pMask->pDrawable->width; + + xFixed x_off_fixed = IntToxFixed(x_off); + xFixed y_off_fixed = IntToxFixed(y_off); + xFixed buf_width_fixed = IntToxFixed(buf_width); + + PixelWalk left, right; + xFixed pixel_x, pixel_y; + xFixed first_right_x; + xFixed y, y_next; + + /* trap.left and trap.right must be non-horizontal */ + if (trap.left.p1.y == trap.left.p2.y + || trap.right.p1.y == trap.right.p2.y) { + return; + } + + trap.top += y_off_fixed; + trap.bottom += y_off_fixed; + trap.left.p1.x += x_off_fixed; + trap.left.p1.y += y_off_fixed; + trap.left.p2.x += x_off_fixed; + trap.left.p2.y += y_off_fixed; + trap.right.p1.x += x_off_fixed; + trap.right.p1.y += y_off_fixed; + trap.right.p2.x += x_off_fixed; + trap.right.p2.y += y_off_fixed; + +#ifdef DEBUG + fprintf(stderr, "(top, bottom) = (%f, %f)\n", + (double) trap.top / (1 << 16), + (double) trap.bottom / (1 << 16)); +#endif + + pixelWalkInit(&left, &trap.left, trap.top, trap.bottom); + pixelWalkInit(&right, &trap.right, trap.top, trap.bottom); + + /* XXX: I'd still like to optimize this loop for top and + bottom. Only the first row intersects top and only the last + row, (which could also be the first row), intersects bottom. So + we could eliminate some unnecessary calculations from all other + rows. Unfortunately, I haven't found an easy way to do it + without bloating the text, (eg. unrolling a couple iterations + of the loop). So, for sake of maintenance, I'm putting off this + optimization at least until this code is more stable.. */ + + if (!fbBuildCompositeOperand (pMask, &mask, 0, xFixedToInt (trap.top), FALSE, FALSE)) + return; + + for (y = trap.top; y < trap.bottom; y = y_next) + { + pixel_y = xFixedFloor (y); + y_next = pixel_y + xFixed1; + if (y_next > trap.bottom) + y_next = trap.bottom; + + ASSERT (left.row.top.y == y); + ASSERT (left.row.bottom.y == y_next); + ASSERT (right.row.top.y == y); + ASSERT (right.row.bottom.y == y_next); + + pixel_x = xFixedFloor(left.col.left.x); + + /* + * Walk pixels on this row that are left of the + * first possibly lit pixel + * + * pixelWalkNextPixel will change .row.top.y + * when the last pixel covered by the edge + * is passed + */ + + first_right_x = xFixedFloor(right.col.left.x); + while (right.row.top.y == y && first_right_x < pixel_x) + { + /* these are empty */ + pixelWalkNextPixel (&right); + /* step over */ + first_right_x += xFixed1; + } + + (*mask.set) (&mask, xFixedToInt (pixel_x), xFixedToInt (y)); + + /* + * Walk pixels on this row intersected by only trap.left + * + */ + while (left.row.top.y == y && pixel_x < first_right_x) + { + alpha = (RectAlpha (pixel_y, y, y_next, depth) + - PixelAlpha(pixel_x, pixel_y, y, y_next, &left, depth)); + + if (alpha > 0) + { + if (0 <= pixel_x && pixel_x < buf_width_fixed) + addAlpha (&mask, depth, alpha, temp); + } + + /* + * Step right + */ + pixelWalkNextPixel(&left); + INCREMENT_X_AND_PIXEL; + } + + /* + * Either pixels are covered by both edges or + * there are fully covered pixels on this row + */ + if (pixel_x == first_right_x) + { + /* + * Now walk the pixels on this row intersected + * by both edges + */ + while (left.row.top.y == y && right.row.top.y == y) + { + alpha = (PixelAlpha(pixel_x, pixel_y, y, y_next, &right, depth) + - PixelAlpha(pixel_x, pixel_y, y, y_next, &left, depth)); + if (alpha > 0) + { + ASSERT (0 <= alpha && alpha <= max_alpha); + if (0 <= pixel_x && pixel_x < buf_width_fixed) + addAlpha (&mask, depth, alpha, temp); + } + pixelWalkNextPixel(&left); + pixelWalkNextPixel(&right); + INCREMENT_X_AND_PIXEL; + } + /* + * If the right edge is now left of the left edge, + * the left edge will end up only partially walked, + * walk it the rest of the way + */ + while (left.row.top.y == y) + pixelWalkNextPixel(&left); + } + else + { + /* + * Fully covered pixels simply saturate + */ + alpha = RectAlpha (pixel_y, y, y_next, depth); + if (alpha == max_alpha) + { + while (pixel_x < first_right_x) + { + if (0 <= pixel_x && pixel_x < buf_width_fixed) + (*mask.store) (&mask, 0xff000000); + INCREMENT_X_AND_PIXEL; + } + } + else + { + while (pixel_x < first_right_x) + { + ASSERT (0 <= alpha && alpha <= max_alpha); + if (0 <= pixel_x && pixel_x < buf_width_fixed) + addAlpha (&mask, depth, alpha, temp); + INCREMENT_X_AND_PIXEL; + } + } + } + + /* + * Finally, pixels intersected only by trap.right + */ + while (right.row.top.y == y) + { + alpha = PixelAlpha(pixel_x, pixel_y, y, y_next, &right, depth); + if (alpha > 0) + { + if (0 <= pixel_x && pixel_x < buf_width_fixed) + addAlpha (&mask, depth, alpha, temp); + } + pixelWalkNextPixel(&right); + INCREMENT_X_AND_PIXEL; + } + } +} + +/* Some notes on walking while keeping track of errors in both dimensions: + +That's really pretty easy. Your bresenham should be walking sub-pixel +coordinates rather than pixel coordinates. Now you can calculate the +sub-pixel Y coordinate for any arbitrary sub-pixel X coordinate (or vice +versa). + + ey: y error term (distance from current Y sub-pixel to line) * dx + ex: x error term (distance from current X sub-pixel to line) * dy + dx: difference of X coordinates for line endpoints + dy: difference of Y coordinates for line endpoints + x: current fixed-point X coordinate + y: current fixed-point Y coordinate + +One of ey or ex will always be zero, depending on whether the distance to +the line was measured horizontally or vertically. + +In moving from x, y to x1, y1: + + (x1 + e1x/dy) - (x + ex/dy) dx + --------------------------- = -- + (y1 + e1y/dx) - (y + ey/dx) dy + + (x1dy + e1x) - (xdy + ex) = (y1dx + e1y) - (ydx + ey) + + dy(x1 - x) + (e1x - ex) = dx(y1-y) + (e1y - ey) + +So, if you know y1 and want to know x1: + + Set e1y to zero and compute the error from x: + + oex = dx(y1 - y) - ey + ex + + Compute the number of whole pixels to get close to the line: + + wx = oex / dy + + Set x1: + + Now compute the e1x: + + e1x = oex - wx * dy + +A similar operation moves to a known y1. Note that this computation (in +general) requires 64 bit arithmetic. I suggest just using the available +64 bit datatype for now, we can optimize the common cases with a few +conditionals. There's some cpp code in fb/fb.h that selects a 64 bit type +for machines that XFree86 builds on; there aren't any machines missing a +64 bit datatype that I know of. +*/ + +/* Here's a large-step Bresenham for jogging my memory. + +void large_bresenham_x_major(x1, y1, x2, y2, x_inc) +{ + int x, y, dx, dy, m; + int em_dx, ey_dx; + + dx = x2 - x1; + dy = y2 - y1; + + m = (x_inc * dy) / dx; + em_dx = (x_inc * dy) - m * dx; + + x = x1; + y = y1; + ey = 0; + + set(x,y); + + while (x < x2) { + x += x_inc; + y += m; + ey_dx += em_dx; + if (ey_dx > dx_2) { + y++; + ey_dx -= dx; + } + set(x,y); + } +} + +*/ + +/* Here are the latest, simplified equations for computing trapezoid + coverage of a pixel: + + alpha_from_area(A) = round(2**depth-1 * A) + + alpha(o) = 2**depth-1 + + alpha(a) = alpha_from_area(area(a)) + + alpha(ab) = alpha_from_area(area(ab)) + + alpha(b) = alpha(ab) - alpha (a) + + alpha(abc) = alpha_from_area(area(abc)) + + alpha(c) = alpha(abc) - alpha(ab) + + alpha(ad) = alpha_from_area(area(ad)) + + alpha (d) = alpha(ad) - alpha (a) + + alpha (abde) = alpha_from_area(area(abde)) + + alpha (de) = alpha (abde) - alpha (ab) + + alpha (e) = alpha (de) - alpha (d) + + alpha (abcdef) = alpha_from_area(area(abcdef)) + + alpha (def) = alpha (abcdef) - alpha (abc) + + alpha (f) = alpha (def) - alpha (de) + + alpha (adg) = alpha_from_area(area(adg)) + + alpha (g) = alpha (adg) - alpha (ad) + + alpha (abdegh) = alpha_from_area(area(abdegh)) + + alpha (gh) = alpha (abdegh) - alpha (abde) + + alpha (h) = alpha (gh) - alpha (g) + + alpha (abcdefghi) = alpha_from_area(area(abcdefghi)) = + alpha_from_area(area(o)) = alpha_from_area(1) = alpha(o) + + alpha (ghi) = alpha (abcdefghi) - alpha (abcdef) + + alpha (i) = alpha (ghi) - alpha (gh) +*/ + +/* Latest thoughts from Keith on implementing area/alpha computations: + +*** 1.16 * 1.16 -> 1.31 *** +#define AREA_MULT(w,h) ((w)&(h) == 0x10000 ? 0x80000000 : (((w)*(h) + 1) >> 1) + +*** (1.16 + 1.16) / 2 -> 1.16 *** +#define WIDTH_AVG(x1,x2) (((x1) + (x2) + 1) >> 1) + +xFixed_1_31 +SubpixelArea (xFixed_1_16 x1, + xFixed_1_16 x2, + xFixed_1_16 y1, + xFixed_1_16 y2, + xFixed_1_16 bottom) + { + xFixed_1_16 x_trap; + xFixed_1_16 h_top, h_trap, h_bot; + xFixed_1_31 area; + + x_trap = WIDTH_AVG(x1,x2); + h_top = y1; + h_trap = (y2 - y1); + h_bot = (bottom - y2); + + area = AREA_MULT(x1, h_top) + + AREA_MULT(x_trap, h_trap) + + AREA_MULT(x2, h_bot); + + return area; + } + +To convert this xFixed_1_31 value to alpha using 32 bit arithmetic: + +int +AreaAlpha (xFixed_1_31 area, int depth) + { + return ((area >> bits) * ((1 << depth) - 1)) >> (31 - depth); + } + +Avoiding the branch bubble in the AREA_MULT could be done with either: + +area = (w * h + 1) >> 1; +area |= ((area - 1) & 0x80000000); + +or + #define AREA_MULT(w,h) ((((w)*(h) + 1) >> 1) | ((w)&(h)&0x10000) << 15) + +depending on your preference, the first takes one less operation but +can't be expressed as a macro; the second takes a large constant which may +require an additional instruction on some processors. The differences +will be swamped by the cost of the multiply. + +*/ + +#endif /* RENDER */ diff --git a/xc/programs/Xserver/fb/module/Imakefile b/xc/programs/Xserver/fb/module/Imakefile new file mode 100644 index 000000000..8ad64ec73 --- /dev/null +++ b/xc/programs/Xserver/fb/module/Imakefile @@ -0,0 +1,6 @@ +XCOMM $XFree86: xc/programs/Xserver/fb/module/Imakefile,v 1.1 2002/05/31 16:12:17 dawes Exp $ + +#define IHaveModules +#define LinkDirectory .. + +#include "../Imakefile" diff --git a/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Credits.rtf b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Credits.rtf new file mode 100644 index 000000000..cbf13779f --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Credits.rtf @@ -0,0 +1,139 @@ +{\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;\f2\fswiss\fcharset77 Helvetica-Oblique; +} +{\colortbl;\red255\green255\blue255;} +\vieww5340\viewh4520\viewkind0 +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\qc + +\f0\b\fs24 \cf0 Contribuidores do XonX ao XFree86 4.2.99.x: +\f1\b0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural +\cf0 Fabr\'92cio Luis de Castro +\f0\b \ + +\f2\i\b0 Localiza\'8d\'8bo para o Portugu\'90s\ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural + +\f0\i0\b \cf0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\qc +\cf0 Contribuidores do XonX ao XFree86 4.2: +\f1\b0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural +\cf0 Rob Braun\ + +\f2\i Suporte para o Darwin x86\ + +\f1\i0 Pablo Di Noto\ + +\f2\i Localiza\'8d\'8bo para o Espanhol +\f1\i0 \ +Paul Edens\ + +\f2\i Localiza\'8d\'8bo para o Holand\'90s +\f1\i0 \ +Kyunghwan Kim\ + +\f2\i Localiza\'8d\'8bo para o Coreano +\f1\i0 \ +Mario Klebsch\ + +\f2\i Suporte para teclados Non-US +\f1\i0 \ +Torrey T. Lyons\ + +\f2\i L\'92der de Projeto +\f1\i0 \ +Andreas Monitzer\ + +\f2\i Localiza\'8d\'8bo para o Alem\'8bo +\f1\i0 \ +Patrik Montgomery\ + +\f2\i Localiza\'8d\'8bo para o Sueco +\f1\i0 \ +Greg Parker\ + +\f2\i Suporte ao modo Compartilhado (Rootless) +\f1\i0 \ +Toshimitsu Tanaka\ + +\f2\i Localiza\'8d\'8bo para o Japon\'90s +\f1\i0 \ +Olivier Verdier\ + +\f2\i Localiza\'8d\'8bo para o Fran\'8d\'90s +\f1\i0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural + +\f0\b \cf0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\qc +\cf0 Agradecimentos Especiais: +\f1\b0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural +\cf0 Devin Poolman and Zero G Software, Inc.\ + +\f2\i Instalador +\f1\i0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural + +\f0\b \cf0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\qc +\cf0 Membros do Time XonX\ +Contribuindo com o XFree86 4.1: +\f1\b0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural +\cf0 Rob Braun\ + +\f2\i Suporte ao Darwin x86\ + +\f1\i0 Torrey T. Lyons\ + +\f2\i L\'92der de Projeto +\f1\i0 \ +Andreas Monitzer\ + +\f2\i Vers\'8bo Cocoa da interface XDarwin +\f1\i0 \ +Greg Parker\ + +\f2\i Implementa\'8d\'8bo Original +\f1\i0 +\f2\i ao Quartz \ + +\f1\i0 Christoph Pfisterer\ + +\f2\i Bibliotecas Din\'89micas Compartilhadas +\f1\i0 \ +Toshimitsu Tanaka\ + +\f2\i Localiza\'8d\'8bo para o Japon\'90s +\f1\i0 \ +\ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\qc + +\f0\b \cf0 Agradecimento Especial: +\f1\b0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural +\cf0 Tiago Ribeiro\ + +\f2\i \'eacone do XDarwin +\f1\i0 \ +\ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\qc + +\f0\b \cf0 Hist\'97rico: +\f1\b0 \ +\pard\tx1440\tx2880\tx4320\tx5760\tx7200\ql\qnatural +\cf0 John Carmack\ + +\f2\i Suporte Original do XFree86 no Mac OS X Server +\f1\i0 \ +Dave Zarzycki\ + +\f2\i Suporte ao +\f1\i0 +\f2\i XFree86 4.0 no Darwin 1.0 +\f1\i0 \ +Torrey T. Lyons\ + +\f2\i Integra\'8d\'8bo dentro do Projeto XFree86 na vers\'8bo 4.0.2}
\ No newline at end of file diff --git a/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Imakefile b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Imakefile new file mode 100644 index 000000000..89a73d682 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Imakefile @@ -0,0 +1,25 @@ +XCOMM $XFree86: xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Imakefile,v 1.2 2002/07/17 01:24:58 torrey Exp $ + +#include <Server.tmpl> + +LinkSourceFile(InfoPlist.strings.cpp,../English.lproj) + +INCLUDES = -I$(SERVERSRC)/include + +VERS = XFree86VersionString +DATE = XFree86DateString +XF86_DEFS = $(INCLUDES) -DXF86_VERSION=$(VERS) -DXF86_REL_DATE=$(DATE) + +AllTarget(XDarwinHelp.html) +CppFileTarget(XDarwinHelp.html,XDarwinHelp.html.cpp,$(XF86_DEFS), \ + NullParameter) + +AllTarget(InfoPlist.strings) +InfoPlist.strings: InfoPlist.strings.cpp + RemoveFile($@) + ClearmakeOSName \ + $(CPP) CppNoLineInfoOption $(XF86_DEFS) <InfoPlist.strings.cpp | \ + CppSedMagic | sed 's/__quote__/"/g' >$@ + +clean:: + RemoveFiles(InfoPlist.strings) diff --git a/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Localizable.strings b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Localizable.strings Binary files differnew file mode 100644 index 000000000..b3edbb41d --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/Localizable.strings diff --git a/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/MainMenu.nib/classes.nib b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/MainMenu.nib/classes.nib new file mode 100644 index 000000000..ba1e3a206 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,64 @@ +{ + IBClasses = ( + { + ACTIONS = {showHelp = id; }; + CLASS = FirstResponder; + LANGUAGE = ObjC; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {close = id; pickFile = id; saveChanges = id; setKey = id; }; + CLASS = Preferences; + LANGUAGE = ObjC; + OUTLETS = { + addToPathButton = id; + addToPathField = id; + button2ModifiersMatrix = id; + button3ModifiersMatrix = id; + depthButton = id; + displayField = id; + dockSwitchButton = id; + fakeButton = id; + keymapFileField = id; + modeMatrix = id; + modeWindowButton = id; + mouseAccelChangeButton = id; + startupHelpButton = id; + switchKeyButton = id; + systemBeepButton = id; + useDefaultShellMatrix = id; + useOtherShellField = id; + useXineramaButton = id; + window = id; + }; + SUPERCLASS = NSObject; + }, + { + CLASS = XApplication; + LANGUAGE = ObjC; + OUTLETS = {preferences = id; xserver = id; }; + SUPERCLASS = NSApplication; + }, + { + ACTIONS = { + closeHelpAndShow = id; + showAction = id; + startFullScreen = id; + startRootless = id; + }; + CLASS = XServer; + LANGUAGE = ObjC; + OUTLETS = { + helpWindow = NSWindow; + modeWindow = NSWindow; + startFullScreenButton = NSButton; + startRootlessButton = NSButton; + startupHelpButton = NSButton; + startupModeButton = NSButton; + switchWindow = NSPanel; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +}
\ No newline at end of file diff --git a/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/MainMenu.nib/objects.nib b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/MainMenu.nib/objects.nib Binary files differnew file mode 100644 index 000000000..4b7736a12 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/MainMenu.nib/objects.nib diff --git a/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/XDarwinHelp.html.cpp b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/XDarwinHelp.html.cpp new file mode 100644 index 000000000..37502eac6 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/XDarwinHelp.html.cpp @@ -0,0 +1,216 @@ +<!-- $XFree86: xc/programs/Xserver/hw/darwin/bundle/Portuguese.lproj/XDarwinHelp.html.cpp,v 1.1 2002/01/25 06:46:46 torrey Exp $ --><html><body> + +#include "xf86Version.h" +#ifndef PRE_RELEASE +#define PRE_RELEASE XF86_VERSION_SNAP +#endif + + +<head> +<title>XFree86 para Mac OS X</title> +</head> + +<center> + + <h1>XFree86 para Darwin e Mac OS X</h1> + XFree86 XF86_VERSION<br> + Release Date: XF86_REL_DATE +</center> +<h2>Índice</h2> +<ol> + <li><A HREF="#notice">Notas importantes</A></li> + <li><A HREF="#usage">Uso</A></li> + <li><A HREF="#path">Ajustando seu Path</A></li> + + <li><A HREF="#prefs">Preferências do usuário</A></li> + <li><A HREF="#license">Licença</A></li> +</ol> +<center> + <h2><a NAME="notice">Notas importantes</a></h2> +</center> +<blockquote> #if PRE_RELEASE Essa é uma versão pré-lancamento + do XFree86, e ela não é suportada de nenhuma forma. Bugs podem + ser reportados e correções podem ser enviadas para <A HREF="http://sourceforge.net/projects/xonx/">Página + do projeto XonX</A> no SourceForge. Antes de informar bugs em versões + pré-lancamento, por favor verifique a þltima versão em <A HREF="http://sourceforge.net/projects/xonx/">XonX</A> + or no <A HREF="http://www.XFree86.Org/cvs">Repositório CVS do XFree86</A>. + #else Se o servidor é mais velho que 6-12 semanas, ou seu hardware é + mais novo que a data acima, procure por uma nova versão antes de informar + problemas. Bugs podem ser reportados e correções podem ser enviadas + para a <A HREF="http://sourceforge.net/projects/xonx/">Página do projeto + XonX</A> na SourceForge. #endif </blockquote> +<blockquote> Este software é distribuído sob os termos da <a href="#license">licença + MIT X11 / X Consortium</a> e é provido, sem nenhuma garantia. Por favor + leia a <a href="#license">Licença</a> antes de começar a usar + o programa.</blockquote> + +<h2><a NAME="usage">Uso</a></h2> +<p>O XFree86 é uma aplicação "open-source" livremente + redistribuída do <a HREF +="http://www.x.org/">Sistema X Window</a> produzido pelo <a HREF="http://www.XFree86.Org/">XFree86 + Project, Inc.</a> O servidor X window para o Darwin e Mac OS X provido pelo + XFree86 é chamado XDarwin. XDarwin roda sobre Mac OS X no modo Tela Cheia + ou no modo Compartilhado.</p> +<p>No modo Tela Cheia, quando o sistema X window está ativo, ele ocupa + a tela toda. Você pode voltar ao desktop do Mac OS X clicando Command-Option-A. + Essa combinação de teclas pode ser mudada nas preferências. + Pelo desktop Mac OS X, clique no ícone XDarwin no Dock para voltar ao + sistema X window. (Você pode mudar esse comportamento nas preferências + daí você deverá clicar no ícone XDarwin na janela + flutuante que aparecerá.)</p> +<p>No modo Compartilhado, o sistema X window e Aqua dividem a mesma tela. A janela + raiz da tela X11 está do tamanho da tela (monitor) e contém todas + as outras janelas. A janela raiz do X11 no modo compartilhado não é + mostrada pois o Aqua controla o fundo de tela.</p> +<h3>Emulação de Mouse Multi-Botões</h3> +<p>Muitas aplicações X11 insistem em usar um mouse de 3 botões. + Você pode emular um mouse de 3 botões com um simples botão, + mantendo pressionando teclas modificadoras enquanto você clica no botão + do mouse. Isto é controlado pela configuração da "Emulação + de Mouse Multi-Botões" da preferência "Geral". Por + padrão, a emulação está habilitada e mantendo pressionada + a tecla Command e clicando no botão do mouse ele simulará o clique + no segundo botão do mouse. Mantendo pressionada a tecla Option e clicando + no botão do mouse ele simulará o terceiro botão. Você + pode mudar a combinação de teclas modificadoras para emular os + botões dois e três nas preferências. Nota, se a tecla modificadora + foi mapeada para alguma outra tecla no xmodmap, você ainda terá + que usar a tecla atual especificada nas preferências para a emulação + do mouse multi-botões.</p> +<h2><a NAME="path">Ajustando seu Path</a></h2> +<p>Seu path é a lista de diretórios a serem procurados por arquivos + executáveis. O comando X11 está localizado em <code>/usr/X11R6/bin</code>, + que precisa ser adicionado ao seu path. XDarwin faz isso para você por + padrão e pode-se também adicionar diretórios onde você + instalou aplicações de linha de comando.</p> +<p>Usuários experientes já terão configurado corretamente + seu path usando arquivos de inicialização de seu shell. Neste + caso, você pode informar o XDarwin para não modificar seu path + nas preferências. O XDarwin inicia o cliente inicial X11 no shell padrão + do usuário corrente. (Um shell alternativo pode ser também expecificado + nas preferências.) O modo para ajustar o path depende do shell que você + está usando. Isto é descrito na man page do seu shell.</p> +<p>Você pode também querer adicionar as man pages do XFree86 para + a lista de páginas a serem procuradas quando você está procurando + por documentação. As man pages do X11 estão localizadas + em <code>/usr/X11R6/man</code> e a variável de ambiente <code>MANPATH</code> + contém a lista de diretórios a buscar.</p> +<h2><a NAME="prefs">Preferências do Usuário</a></h2> +<p>Várias opções podem ser ajustadas nas preferências + do usuário, acessível pelo item "Preferências..." + no menu "XDarwin". As opções listadas como opções + de inicialização, não terão efeito até você + reiniciar o XDarwin. Todas as outras opções terão efeito + imediatamente. Várias das opções estão descritas + abaixo:</p> +<h3>Geral</h3> +<ul> + <li><b>Usar o Beep do Sistema para o X11: </b>Quando habilitado som de alerta + padrão do Mac OS X será usado como alerta no X11. Quando desabilitado + (padrão) um tom simples será usado.</li> + <li><b>Permitir o X11 mudar a aceleração do mouse: </b>Por implementação + padrão no sistema X window, o gerenciador de janelas pode mudar a aceleração + do mouse. Isso pode gerar uma confusão pois a aceleração + do mouse pode ser ajustada diferentemente nas preferências do Mac OS + X e nas preferências do X window. Por padrão, o X11 não + está habilitado a mudar a aceleração do mouse para evitar + este problema.</li> + <li><b>Emulação de Mouse de Multi-Botões: </b>Esta opção + está escrita acima em <a href="#usage">Uso</a>. Quando a emulação + está habilitada as teclas modificadoras selecionadas tem que estar + pressionadas quando o botão do mouse for pressionado, para emular o + segundo e terceiro botões.</li> +</ul> +<h3>Inicial</h3> +<ul> + <li><b>Modo Padrão: </b>Se o usuário não indicar qual modo + de exibição quer usar (Tela Cheia ou Compartilhado) o modo especificado + aqui será usado .</li> + <li><b>Mostrar o painel de escolha na inicialização: </b> Por + padrão, uma painel é mostrado quando o XDarwin é + iniciado para permitir que o usuário escolha ente o modo tela cheia + ou modo compartilhado. Se esta opção estiver desligada, o modo + padrão será inicializado automaticamente.</li> + <li><b>Número do Monitor X11: </b>O X11 permite ser administrado em multiplos + monitores por servidores X separados num mesmo computador. O usuário + pode indicar o número do monitor para o XDarwin usar se mais de um + servidor X se estiver rodando simultaneamente.</li> + <li><b>Habilitar suporte a múltiplos monitores pelo Xinerama: </b>o XDarwin + suporta múltiplos monitores com o Xinerama, que trata todos os monitores + como parte de uma grande e retangular tela. Você pode desabilitar o + Xinerama com está opção, mas normalmente o XDarwin não + controla múltiplos monitores corretamente sem está opção. + Se você só tiver um monotor, Xinerama é automaticamente + desabilitado. </li> + <li><b>Arquivo de Mapa de Teclado: </b> O mapa de teclado é lido na inicialização + e traduzido para um mapa de teclado X11. Arquivos de mapa de teclado, estão + disponíveis numa grande variedade de línguas e são encontradas + em <code>/System/Library/Keyboards</code>.</li> + <li><b>Iniciando Clientes X11 primeiro: </b>Quando o XDrawin é inicializado + pelo Finder, ele irá rodar o <code>xinit</code> para abrir o controlador + X window e outros clientes X. (Veja o manual "<code>man xinit</code>" para + mais informações.) Antes do XDarwin rodar o <code>xinit</code> + ele irá adicionar específicos diretórios a seu path. + Por padrão somente o <code>/usr/X11R6/bin</code> é adicionado. + separado por um ponto-e-vírgula. Os clientes X são inicializados + no shell padrão do usuário e os arquivos de inicialização + do shell serão lidos. Se desejado, um shell alternativo pode ser especificado.</li> +</ul> +<h3>Tela Cheia</h3> +<ul> + <li><b>Botão de Combinação de Teclas: </b> Clique no botão + e pressione qualquer quantidade de teclas modificadoras seguidas por uma tecla + padrão para modificar a combinação quando se quer mudar + entre o Aqua e X11.</li> + <li><b>Clique no Ícone no Dock para mudar para o X11: </b>Habilitando + esta opção você irá ativar a mudança para + o X11 clicando no ícone do XDarwin no Dock. Em algumas versões + do Mac OS X, mudando pelo clique no Dock pode causar o desaparecimento do + cursor quando retornar ao Aqua.</li> + <li><b>Mostrar a Ajuda na inicialização: </b>Isto irá mostrar + uma tela introdutória quando o XDarwin for inicializado no modo Tela + Cheia. </li> + <li><b>Profundidade de Cores em bits: </b> No modo Tela Cheia, a tela do X11 + pode usar uma profundiadde de cor diferente da usada no Aqua. Se a opção + "Atual" está especificada, a profundidade usada pelo Aqua + quando o XDarwin iniciar será a mesma. Além das opções + 8, 15 ou 24 bits que podem ser especificadas.</li> +</ul> + +<h2><a NAME="license">Licença</a></h2> +<p>O projeto XFree86 é designado a prover e a ser livremente redistribuído + as versões binárias e souce (código-fonte). A licença + principal nós usamos uma baseada na licença tradicional MIT X11 + / X Consortium, que não impõe nenhuma condição sobre + modificações ou redistribuição do código-fonte + ou dos binários desde que o copyright/licença sejam mantidos intactos. + Para mais informações e notícias adicionais de copyright/licensing + em algumas seção do código, por favor visite a <a href="http://www.xfree86.org/legal/licence.html">página + de licenças do XFree86</a>.</p> +<H3><A NAME="3"></A>Licença do X Consortium</H3> +<p>Copyright (C) 1996 X Consortium</p> +<p>Permissões são em virtude garantidas, livre de mudanças, + para qualquer pessoa que possua uma cópia deste software e aos arquivos + de documentação associada (o "Software"), para lidar + com o software sem restrições, incluindo limitações + dos direitos de uso, cópia, modificação, inclusão, + publicação, distribuição, sub licença, e/ou + venda de cópias deste Software, e permitir pessoas to whom o Software + é fornecido para ser desta forma, verifique as seguintes condições:</p> +<p>O nota de copyright abaixo e a permissão deverão ser incluídas + em todas as cópias ou substanciais porções do Software.</p> +<p>O SOFTWARE 'E PROVIDO "COMO TAL", SEM GARANTIAS DE NENHUM TIPO, EXPLICITA + OU IMPLICITA, INCLUINDO MAS NÃO LIMITADO NOS AVISOS DE COMÉRCIO, + TAMANHO OU PARA PROPOSTAS PARTICULARES E NÃO INFRAÇÃO. + EM NENHUM ACONTECIMENTO O X CONSORTIUM SERÁ RESPONSAVÉL POR NENHUMA + RECLAMAÇÃO, DANOS OU OUTRAS RESPONSABILIDADES, SE NUMA AÇÃO + DE CONTRATO, OU OUTRA COISA, SURGINDO DE, FORA DE OU EM CONEXÃO COM O + SOFTWARE OU O USO OU OUTRO MODO DE LIDAR COM O SOFTWARE.</p> +<p>Exceto o contido nesta nota, o nome do X Consortium não pode ser usado + em propagandas ou outra forma de promoção de vendas, uso ou outro + modo de lidar com este Software sem ter recebido uma autorização + escrita pelo X Consortium.</p> +<p>O Sistema X Window é marca registrada do X Consortium, Inc.</p> +</body> +</html> + diff --git a/xc/programs/Xserver/hw/darwin/darwinEvents.c b/xc/programs/Xserver/hw/darwin/darwinEvents.c new file mode 100644 index 000000000..d0cd7880b --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/darwinEvents.c @@ -0,0 +1,418 @@ +/* + * Darwin event queue and event handling + */ +/* +Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + +This file is based on mieq.c by Keith Packard, +which contains the following copyright: +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + */ + +#define NEED_EVENTS +#include "X.h" +#include "Xmd.h" +#include "Xproto.h" +#include "misc.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "inputstr.h" +#include "mi.h" +#include "scrnintstr.h" +#include "mipointer.h" + +#include "darwin.h" +#include "quartz/quartz.h" + +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +#include <IOKit/hidsystem/IOLLEvent.h> + +/* Fake button press/release for scroll wheel move. */ +#define SCROLLWHEELUPFAKE 4 +#define SCROLLWHEELDOWNFAKE 5 + +#define QUEUE_SIZE 256 + +typedef struct _Event { + xEvent event; + ScreenPtr pScreen; +} EventRec, *EventPtr; + +typedef struct _EventQueue { + HWEventQueueType head, tail; /* long for SetInputCheck */ + CARD32 lastEventTime; /* to avoid time running backwards */ + Bool lastMotion; + EventRec events[QUEUE_SIZE]; /* static allocation for signals */ + DevicePtr pKbd, pPtr; /* device pointer, to get funcs */ + ScreenPtr pEnqueueScreen; /* screen events are being delivered to */ + ScreenPtr pDequeueScreen; /* screen events are being dispatched to */ +} EventQueueRec, *EventQueuePtr; + +static EventQueueRec darwinEventQueue; + + +/* + * DarwinPressModifierMask + * Press or release the given modifier key, specified by its mask. + */ +static void DarwinPressModifierMask( + xEvent *xe, // must already have type, time and mouse location + int mask) // one of NX_*MASK constants +{ + int key = DarwinModifierNXMaskToNXKey(mask); + + if (key != -1) { + int keycode = DarwinModifierNXKeyToNXKeycode(key, 0); + if (keycode != 0) { + xe->u.u.detail = keycode + MIN_KEYCODE; + (*darwinEventQueue.pKbd->processInputProc)(xe, + (DeviceIntPtr)darwinEventQueue.pKbd, 1); + } + } +} + + +/* + * DarwinUpdateModifiers + * Send events to update the modifier state. + */ +static void DarwinUpdateModifiers( + xEvent *xe, // event template with time and mouse position set + int pressed, // KeyPress or KeyRelease + int flags ) // modifier flags that have changed +{ + xe->u.u.type = pressed; + if (flags & NX_ALPHASHIFTMASK) { + DarwinPressModifierMask(xe, NX_ALPHASHIFTMASK); + } + if (flags & NX_COMMANDMASK) { + DarwinPressModifierMask(xe, NX_COMMANDMASK); + } + if (flags & NX_CONTROLMASK) { + DarwinPressModifierMask(xe, NX_CONTROLMASK); + } + if (flags & NX_ALTERNATEMASK) { + DarwinPressModifierMask(xe, NX_ALTERNATEMASK); + } + if (flags & NX_SHIFTMASK) { + DarwinPressModifierMask(xe, NX_SHIFTMASK); + } + if (flags & NX_SECONDARYFNMASK) { + DarwinPressModifierMask(xe, NX_SECONDARYFNMASK); + } +} + + +/* + * DarwinSimulateMouseClick + * Send a mouse click to X when multiple mouse buttons are simulated + * with modifier-clicks, such as command-click for button 2. The dix + * layer is told that the previously pressed modifier key(s) are + * released, the simulated click event is sent. After the mouse button + * is released, the modifier keys are reverted to their actual state, + * which may or may not be pressed at that point. This is usually + * closest to what the user wants. Ie. the user typically wants to + * simulate a button 2 press instead of Command-button 2. + */ +static void DarwinSimulateMouseClick( + xEvent *xe, // event template with time and + // mouse position filled in + int whichButton, // mouse button to be pressed + int modifierMask) // modifiers used for the fake click +{ + // first fool X into forgetting about the keys + DarwinUpdateModifiers(xe, KeyRelease, modifierMask); + + // push the mouse button + xe->u.u.type = ButtonPress; + xe->u.u.detail = whichButton; + (*darwinEventQueue.pPtr->processInputProc) + (xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); +} + + +Bool +DarwinEQInit( + DevicePtr pKbd, + DevicePtr pPtr) +{ + darwinEventQueue.head = darwinEventQueue.tail = 0; + darwinEventQueue.lastEventTime = GetTimeInMillis (); + darwinEventQueue.pKbd = pKbd; + darwinEventQueue.pPtr = pPtr; + darwinEventQueue.pEnqueueScreen = screenInfo.screens[0]; + darwinEventQueue.pDequeueScreen = darwinEventQueue.pEnqueueScreen; + SetInputCheck (&darwinEventQueue.head, &darwinEventQueue.tail); + return TRUE; +} + + +/* + * DarwinEQEnqueue + * Must be thread safe with ProcessInputEvents. + * DarwinEQEnqueue - called from event gathering thread + * ProcessInputEvents - called from X server thread + * DarwinEQEnqueue should never be called from more than one thread. + */ +void +DarwinEQEnqueue( + const xEvent *e) +{ + HWEventQueueType oldtail, newtail; + + oldtail = darwinEventQueue.tail; + + // mieqEnqueue() collapses successive motion events into one event. + // This is difficult to do in a thread-safe way and rarely useful. + + newtail = oldtail + 1; + if (newtail == QUEUE_SIZE) + newtail = 0; + /* Toss events which come in late */ + if (newtail == darwinEventQueue.head) + return; + + darwinEventQueue.events[oldtail].event = *e; + /* + * Make sure that event times don't go backwards - this + * is "unnecessary", but very useful + */ + if (e->u.keyButtonPointer.time < darwinEventQueue.lastEventTime && + darwinEventQueue.lastEventTime - e->u.keyButtonPointer.time < 10000) + { + darwinEventQueue.events[oldtail].event.u.keyButtonPointer.time = + darwinEventQueue.lastEventTime; + } + darwinEventQueue.events[oldtail].pScreen = darwinEventQueue.pEnqueueScreen; + + // Update the tail after the event is prepared + darwinEventQueue.tail = newtail; +} + + +void +DarwinEQSwitchScreen( + ScreenPtr pScreen, + Bool fromDIX) +{ + darwinEventQueue.pEnqueueScreen = pScreen; + if (fromDIX) + darwinEventQueue.pDequeueScreen = pScreen; +} + + +/* + * ProcessInputEvents + * Read and process events from the event queue until it is empty. + */ +void ProcessInputEvents(void) +{ + EventRec *e; + int x, y; + xEvent xe; + static int old_flags = 0; // last known modifier state + // button number and modifier mask of currently pressed fake button + static int darwinFakeMouseButtonDown = 0; + static int darwinFakeMouseButtonMask = 0; + + // Empty the signaling pipe + x = sizeof(xe); + while (x == sizeof(xe)) { + x = read(darwinEventFD, &xe, sizeof(xe)); + } + + while (darwinEventQueue.head != darwinEventQueue.tail) + { + if (screenIsSaved == SCREEN_SAVER_ON) + SaveScreens (SCREEN_SAVER_OFF, ScreenSaverReset); + + e = &darwinEventQueue.events[darwinEventQueue.head]; + xe = e->event; + + // Shift from global screen coordinates to coordinates relative to + // the origin of the current screen. + xe.u.keyButtonPointer.rootX -= darwinMainScreenX + + dixScreenOrigins[miPointerCurrentScreen()->myNum].x; + xe.u.keyButtonPointer.rootY -= darwinMainScreenY + + dixScreenOrigins[miPointerCurrentScreen()->myNum].y; + + /* + * Assumption - screen switching can only occur on motion events + */ + if (e->pScreen != darwinEventQueue.pDequeueScreen) + { + darwinEventQueue.pDequeueScreen = e->pScreen; + x = xe.u.keyButtonPointer.rootX; + y = xe.u.keyButtonPointer.rootY; + if (darwinEventQueue.head == QUEUE_SIZE - 1) + darwinEventQueue.head = 0; + else + ++darwinEventQueue.head; + NewCurrentScreen (darwinEventQueue.pDequeueScreen, x, y); + } + else + { + if (darwinEventQueue.head == QUEUE_SIZE - 1) + darwinEventQueue.head = 0; + else + ++darwinEventQueue.head; + switch (xe.u.u.type) + { + case KeyPress: + case KeyRelease: + xe.u.u.detail += MIN_KEYCODE; + (*darwinEventQueue.pKbd->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pKbd, 1); + break; + + case ButtonPress: + if (darwinFakeButtons && xe.u.u.detail == 1) { + // Mimic multi-button mouse with modifier-clicks + // If both sets of modifiers are pressed, + // button 2 is clicked. + if ((old_flags & darwinFakeMouse2Mask) == + darwinFakeMouse2Mask) + { + DarwinSimulateMouseClick(&xe, 2, darwinFakeMouse2Mask); + darwinFakeMouseButtonDown = 2; + darwinFakeMouseButtonMask = darwinFakeMouse2Mask; + break; + } + else if ((old_flags & darwinFakeMouse3Mask) == + darwinFakeMouse3Mask) + { + DarwinSimulateMouseClick(&xe, 3, darwinFakeMouse3Mask); + darwinFakeMouseButtonDown = 3; + darwinFakeMouseButtonMask = darwinFakeMouse3Mask; + break; + } + } + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + break; + + case ButtonRelease: + if (darwinFakeButtons && xe.u.u.detail == 1 && + darwinFakeMouseButtonDown) + { + // If last mousedown was a fake click, don't check for + // mouse modifiers here. The user may have released the + // modifiers before the mouse button. + xe.u.u.detail = darwinFakeMouseButtonDown; + darwinFakeMouseButtonDown = 0; + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + + // Bring modifiers back up to date + DarwinUpdateModifiers(&xe, KeyPress, + darwinFakeMouseButtonMask & old_flags); + darwinFakeMouseButtonMask = 0; + } else { + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + } + break; + + case MotionNotify: + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + break; + + case kXDarwinUpdateModifiers: + { + // Update modifier state. + // Any amount of modifiers may have changed. + int flags = xe.u.clientMessage.u.l.longs0; + DarwinUpdateModifiers(&xe, KeyRelease, + old_flags & ~flags); + DarwinUpdateModifiers(&xe, KeyPress, + ~old_flags & flags); + old_flags = flags; + break; + } + + case kXDarwinUpdateButtons: + { + long hwDelta = xe.u.clientMessage.u.l.longs0; + long hwButtons = xe.u.clientMessage.u.l.longs1; + int i; + + for (i = 1; i < 5; i++) { + if (hwDelta & (1 << i)) { + // IOKit and X have different numbering for the + // middle and right mouse buttons. + if (i == 1) { + xe.u.u.detail = 3; + } else if (i == 2) { + xe.u.u.detail = 2; + } else { + xe.u.u.detail = i + 1; + } + if (hwButtons & (1 << i)) { + xe.u.u.type = ButtonPress; + } else { + xe.u.u.type = ButtonRelease; + } + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + } + } + break; + } + + case kXDarwinScrollWheel: + { + short count = xe.u.clientMessage.u.s.shorts0; + + if (count > 0) { + xe.u.u.detail = SCROLLWHEELUPFAKE; + } else { + xe.u.u.detail = SCROLLWHEELDOWNFAKE; + count = -count; + } + + for (; count; --count) { + xe.u.u.type = ButtonPress; + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + xe.u.u.type = ButtonRelease; + (*darwinEventQueue.pPtr->processInputProc) + (&xe, (DeviceIntPtr)darwinEventQueue.pPtr, 1); + } + break; + } + + default: + if (quartz) { + QuartzProcessEvent(&xe); + } else { + ErrorF("Unknown X event caught: %d\n", xe.u.u.type); + } + } + } + } + + miPointerUpdate(); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/Imakefile b/xc/programs/Xserver/hw/darwin/quartz/Imakefile new file mode 100644 index 000000000..d547fe97c --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/Imakefile @@ -0,0 +1,102 @@ +XCOMM $XFree86: xc/programs/Xserver/hw/darwin/quartz/Imakefile,v 1.4 2002/07/24 05:58:33 torrey Exp $ + +#include <Server.tmpl> + +SRCS = Preferences.m \ + XApplication.m \ + XServer.m \ + XView.m \ + aquaPicture.c \ + aquaWindow.c \ + fullscreen.c \ + quartz.c \ + quartzAudio.c \ + quartzCocoa.m \ + quartzCursor.c \ + quartzPasteboard.c \ + rootlessAquaGlue.c \ + rootlessAquaImp.m \ + rootlessCommon.c \ + rootlessGC.c \ + rootlessScreen.c \ + rootlessValTree.c \ + rootlessWindow.c \ + pseudoramiX.c + +OBJS = Preferences.o \ + XApplication.o \ + XServer.o \ + XView.o \ + aquaPicture.o \ + aquaWindow.o \ + fullscreen.o \ + quartz.o \ + quartzAudio.o \ + quartzCocoa.o \ + quartzCursor.o \ + quartzPasteboard.o \ + rootlessAquaGlue.o \ + rootlessAquaImp.o \ + rootlessCommon.o \ + rootlessGC.o \ + rootlessScreen.o \ + rootlessValTree.o \ + rootlessWindow.o \ + pseudoramiX.o + +INCLUDES = -I. -I$(SERVERSRC)/fb -I$(SERVERSRC)/mi -I$(SERVERSRC)/include \ + -I$(XINCLUDESRC) -I$(FONTINCSRC) -I$(SERVERSRC)/render \ + -I$(EXTINCSRC) -I.. -I$(SERVERSRC)/Xext + +#if defined(XFree86CustomVersion) +CUSTOMVERSION = XFree86CustomVersion +CUSTOMVERDEF = -DXF86_CUSTOM_VERSION='$(CUSTOMVERSION)' +#endif +#if HasCGMachPort +QUARTZDEFINES = -DHAS_CG_MACH_PORT +#endif + +#if XFree86Devel +PBXBUILDSTYLE = -buildstyle Development +DEBUGDEFINES = -DROOTLESSDEBUG +#else +PBXBUILDSTYLE = -buildstyle Deployment +#endif + +DEFINES = $(CUSTOMVERDEF) -DXBINDIR=$(BINDIR) -DXINITDIR=$(XINITDIR) \ + $(QUARTZDEFINES) $(DEBUGDEFINES) +EXTRAMANDEFS = -D__XBinDir__=$(BINDIR) +#if NothingOutsideProjectRoot +XDARWINROOT = $(BINDIR) +#else +XDARWINROOT = /Applications +#endif + +NormalLibraryObjectRule() +NormalLibraryTarget(XQuartz,$(OBJS)) + +AllTarget(quartzStartup.o) + +AllTarget(XDarwinStartup) +NormalProgramTarget(XDarwinStartup,XDarwinStartup.o, \ + NullParameter,NullParameter, \ + -framework CoreFoundation -framework ApplicationServices) +InstallProgram(XDarwinStartup,$(BINDIR)) +install:: + -(cd $(DESTDIR)$(BINDIR); $(RM) X; $(LN) XDarwinStartup X) + +AllTarget(XDarwin) +XDarwin: + pbxbuild -target XDarwin $(PBXBUILDSTYLE) + +install:: + pbxbuild install -target XDarwin $(PBXBUILDSTYLE) \ + DSTROOT=$(DESTDIR)$(XDARWINROOT) + +InstallManPage(XDarwinStartup,$(MANDIR)) + +clean:: + pbxbuild "clean" -target XDarwin $(PBXBUILDSTYLE) + +DependTarget() + diff --git a/xc/programs/Xserver/hw/darwin/quartz/Preferences.h b/xc/programs/Xserver/hw/darwin/quartz/Preferences.h new file mode 100644 index 000000000..6a84bbd01 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/Preferences.h @@ -0,0 +1,105 @@ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/Preferences.h,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +#import <Cocoa/Cocoa.h> + +@interface Preferences : NSObject +{ + IBOutlet NSPanel *window; + IBOutlet id displayField; + IBOutlet id dockSwitchButton; + IBOutlet id fakeButton; + IBOutlet id button2ModifiersMatrix; + IBOutlet id button3ModifiersMatrix; + IBOutlet id switchKeyButton; + IBOutlet id keymapFileField; + IBOutlet id modeMatrix; + IBOutlet id modeWindowButton; + IBOutlet id startupHelpButton; + IBOutlet id systemBeepButton; + IBOutlet id mouseAccelChangeButton; + IBOutlet id useXineramaButton; + IBOutlet id addToPathButton; + IBOutlet id addToPathField; + IBOutlet id useDefaultShellMatrix; + IBOutlet id useOtherShellField; + IBOutlet id depthButton; + + BOOL isGettingKeyCode; + int keyCode; + int modifiers; + NSMutableString *switchString; +} + +- (IBAction)close:(id)sender; +- (IBAction)pickFile:(id)sender; +- (IBAction)saveChanges:(id)sender; +- (IBAction)setKey:(id)sender; + +- (BOOL)sendEvent:(NSEvent*)anEvent; + +- (void)awakeFromNib; +- (void)windowWillClose:(NSNotification *)aNotification; + ++ (void)setUseKeymapFile:(BOOL)newUseKeymapFile; ++ (void)setKeymapFile:(NSString*)newFile; ++ (void)setSwitchString:(NSString*)newString; ++ (void)setKeyCode:(int)newKeyCode; ++ (void)setModifiers:(int)newModifiers; ++ (void)setDisplay:(int)newDisplay; ++ (void)setDockSwitch:(BOOL)newDockSwitch; ++ (void)setFakeButtons:(BOOL)newFakeButtons; ++ (void)setButton2Mask:(int)newFakeMask; ++ (void)setButton3Mask:(int)newFakeMask; ++ (void)setMouseAccelChange:(BOOL)newMouseAccelChange; ++ (void)setUseQDCursor:(int)newUseQDCursor; ++ (void)setRootless:(BOOL)newRootless; ++ (void)setModeWindow:(BOOL)newModeWindow; ++ (void)setStartupHelp:(BOOL)newStartupHelp; ++ (void)setSystemBeep:(BOOL)newSystemBeep; ++ (void)setXinerama:(BOOL)newXinerama; ++ (void)setAddToPath:(BOOL)newAddToPath; ++ (void)setAddToPathString:(NSString*)newAddToPathString; ++ (void)setUseDefaultShell:(BOOL)newUseDefaultShell; ++ (void)setShellString:(NSString*)newShellString; ++ (void)setDepth:(int)newDepth; ++ (void)saveToDisk; + ++ (BOOL)useKeymapFile; ++ (NSString*)keymapFile; ++ (NSString*)switchString; ++ (unsigned int)keyCode; ++ (unsigned int)modifiers; ++ (int)display; ++ (BOOL)dockSwitch; ++ (BOOL)fakeButtons; ++ (int)button2Mask; ++ (int)button3Mask; ++ (BOOL)mouseAccelChange; ++ (int)useQDCursor; ++ (BOOL)rootless; ++ (BOOL)modeWindow; ++ (BOOL)startupHelp; ++ (BOOL)systemBeep; ++ (BOOL)xinerama; ++ (BOOL)addToPath; ++ (NSString*)addToPathString; ++ (BOOL)useDefaultShell; ++ (NSString*)shellString; ++ (int)depth; + +@end + +// Possible settings for useQDCursor +enum { + qdCursor_Never, // never use QuickDraw cursor + qdCursor_Not8Bit, // don't try to use QuickDraw with 8-bit depth + qdCursor_Always // always try to use QuickDraw cursor +}; + +// Possible settings for depth +enum { + depth_Current, + depth_8Bit, + depth_15Bit, + depth_24Bit +}; diff --git a/xc/programs/Xserver/hw/darwin/quartz/Preferences.m b/xc/programs/Xserver/hw/darwin/quartz/Preferences.m new file mode 100644 index 000000000..c17c997ea --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/Preferences.m @@ -0,0 +1,517 @@ +// +// Preferences.m +// +// This class keeps track of the user preferences. +// +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/Preferences.m,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +#import "Preferences.h" +#import "quartzCommon.h" +#include <IOKit/hidsystem/IOLLEvent.h> // for modifier masks + +// Macros to build the path name +#ifndef XBINDIR +#define XBINDIR /usr/X11R6/bin +#endif +#define STR(s) #s +#define XSTRPATH(s) STR(s) + + +@implementation Preferences + ++ (void)initialize +{ + // Provide user defaults if needed + NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt:0], @"Display", + @"YES", @"FakeButtons", + [NSNumber numberWithInt:NX_COMMANDMASK], @"Button2Mask", + [NSNumber numberWithInt:NX_ALTERNATEMASK], @"Button3Mask", + NSLocalizedString(@"USA.keymapping",@""), @"KeymappingFile", + @"YES", @"UseKeymappingFile", + NSLocalizedString(@"Cmd-Opt-a",@""), @"SwitchString", + @"NO", @"UseRootlessMode", + @"YES", @"ShowModePickWindow", + @"YES", @"ShowStartupHelp", + [NSNumber numberWithInt:0], @"SwitchKeyCode", + [NSNumber numberWithInt:(NSCommandKeyMask | NSAlternateKeyMask)], + @"SwitchModifiers", @"NO", @"UseSystemBeep", + @"YES", @"DockSwitch", + @"NO", @"AllowMouseAccelChange", + [NSNumber numberWithInt:qdCursor_Not8Bit], @"UseQDCursor", + @"YES", @"Xinerama", + @"YES", @"AddToPath", + [NSString stringWithCString:XSTRPATH(XBINDIR)], @"AddToPathString", + @"YES", @"UseDefaultShell", + @"/bin/tcsh", @"Shell", + [NSNumber numberWithInt:depth_Current], @"Depth", nil]; + + [super initialize]; + [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults]; +} + +// Initialize internal state info of switch key button +- (void)initSwitchKey +{ + keyCode = [Preferences keyCode]; + modifiers = [Preferences modifiers]; + [switchString setString:[Preferences switchString]]; +} + +- (id)init +{ + self = [super init]; + + isGettingKeyCode=NO; + switchString=[[NSMutableString alloc] init]; + [self initSwitchKey]; + + return self; +} + +// Set a modifiers checkbox matrix to match a modifier mask +- (void)resetMatrix:(NSMatrix *)aMatrix withMask:(int)aMask +{ + [aMatrix setState:(aMask & NX_SHIFTMASK) atRow:0 column:0]; + [aMatrix setState:(aMask & NX_CONTROLMASK) atRow:1 column:0]; + [aMatrix setState:(aMask & NX_COMMANDMASK) atRow:2 column:0]; + [aMatrix setState:(aMask & NX_ALTERNATEMASK) atRow:3 column:0]; + [aMatrix setState:(aMask & NX_SECONDARYFNMASK) atRow:4 column:0]; +} + +// Generate a modifiers mask from a modifiers checkbox matrix +- (int)getMaskFromMatrix:(NSMatrix *)aMatrix +{ + int theMask = 0; + + if ([[aMatrix cellAtRow:0 column:0] state]) + theMask |= NX_SHIFTMASK; + if ([[aMatrix cellAtRow:1 column:0] state]) + theMask |= NX_CONTROLMASK; + if ([[aMatrix cellAtRow:2 column:0] state]) + theMask |= NX_COMMANDMASK; + if ([[aMatrix cellAtRow:3 column:0] state]) + theMask |= NX_ALTERNATEMASK; + if ([[aMatrix cellAtRow:4 column:0] state]) + theMask |= NX_SECONDARYFNMASK; + + return theMask; +} + +// Set the window controls to the state in user defaults +- (void)resetWindow +{ + if ([Preferences keymapFile] == nil) + [keymapFileField setStringValue:@" "]; + else + [keymapFileField setStringValue:[Preferences keymapFile]]; + + if ([Preferences switchString] == nil) + [switchKeyButton setTitle:@"--"]; + else + [switchKeyButton setTitle:[Preferences switchString]]; + + [displayField setIntValue:[Preferences display]]; + [dockSwitchButton setIntValue:[Preferences dockSwitch]]; + [fakeButton setIntValue:[Preferences fakeButtons]]; + [self resetMatrix:button2ModifiersMatrix + withMask:[Preferences button2Mask]]; + [self resetMatrix:button3ModifiersMatrix + withMask:[Preferences button3Mask]]; + [modeMatrix setState:[Preferences rootless] atRow:0 column:1]; + [startupHelpButton setIntValue:[Preferences startupHelp]]; + [modeWindowButton setIntValue:[Preferences modeWindow]]; + [systemBeepButton setIntValue:[Preferences systemBeep]]; + [mouseAccelChangeButton setIntValue:[Preferences mouseAccelChange]]; + [useXineramaButton setIntValue:[Preferences xinerama]]; + [addToPathButton setIntValue:[Preferences addToPath]]; + [addToPathField setStringValue:[Preferences addToPathString]]; + [useDefaultShellMatrix setState:![Preferences useDefaultShell] + atRow:1 column:0]; + [useOtherShellField setStringValue:[Preferences shellString]]; + [depthButton selectItemAtIndex:[Preferences depth]]; +} + +- (void)awakeFromNib +{ + [self resetWindow]; +} + +// Preference window delegate +- (void)windowWillClose:(NSNotification *)aNotification +{ + [self resetWindow]; + [self initSwitchKey]; +} + +// User cancelled the changes +- (IBAction)close:(id)sender +{ + [window orderOut:nil]; + [self resetWindow]; // reset window controls + [self initSwitchKey]; // reset switch key state +} + +// Pick keymapping file +- (IBAction)pickFile:(id)sender +{ + int result; + NSArray *fileTypes = [NSArray arrayWithObject:@"keymapping"]; + NSOpenPanel *oPanel = [NSOpenPanel openPanel]; + + [oPanel setAllowsMultipleSelection:NO]; + result = [oPanel runModalForDirectory:@"/System/Library/Keyboards" + file:nil types:fileTypes]; + if (result == NSOKButton) { + [keymapFileField setStringValue:[oPanel filename]]; + } +} + +// User saved changes +- (IBAction)saveChanges:(id)sender +{ + [Preferences setKeyCode:keyCode]; + [Preferences setModifiers:modifiers]; + [Preferences setSwitchString:switchString]; + [Preferences setKeymapFile:[keymapFileField stringValue]]; + [Preferences setUseKeymapFile:YES]; + [Preferences setDisplay:[displayField intValue]]; + [Preferences setDockSwitch:[dockSwitchButton intValue]]; + [Preferences setFakeButtons:[fakeButton intValue]]; + [Preferences setButton2Mask: + [self getMaskFromMatrix:button2ModifiersMatrix]]; + [Preferences setButton3Mask: + [self getMaskFromMatrix:button3ModifiersMatrix]]; + [Preferences setRootless:[[modeMatrix cellAtRow:0 column:1] state]]; + [Preferences setModeWindow:[modeWindowButton intValue]]; + [Preferences setStartupHelp:[startupHelpButton intValue]]; + [Preferences setSystemBeep:[systemBeepButton intValue]]; + [Preferences setMouseAccelChange:[mouseAccelChangeButton intValue]]; + [Preferences setXinerama:[useXineramaButton intValue]]; + [Preferences setAddToPath:[addToPathButton intValue]]; + [Preferences setAddToPathString:[addToPathField stringValue]]; + [Preferences setUseDefaultShell: + [[useDefaultShellMatrix cellAtRow:0 column:0] state]]; + [Preferences setShellString:[useOtherShellField stringValue]]; + [Preferences setDepth:[depthButton indexOfSelectedItem]]; + [Preferences saveToDisk]; + + [window orderOut:nil]; +} + +- (IBAction)setKey:(id)sender +{ + [switchKeyButton setTitle:NSLocalizedString(@"Press key",@"")]; + isGettingKeyCode=YES; + [switchString setString:@""]; +} + +- (BOOL)sendEvent:(NSEvent*)anEvent +{ + if(isGettingKeyCode) { + if([anEvent type]==NSKeyDown) // wait for keyup + return YES; + if([anEvent type]!=NSKeyUp) + return NO; + + if([anEvent modifierFlags] & NSCommandKeyMask) + [switchString appendString:@"Cmd-"]; + if([anEvent modifierFlags] & NSControlKeyMask) + [switchString appendString:@"Ctrl-"]; + if([anEvent modifierFlags] & NSAlternateKeyMask) + [switchString appendString:@"Opt-"]; + if([anEvent modifierFlags] & NSNumericPadKeyMask) // doesn't work + [switchString appendString:@"Num-"]; + if([anEvent modifierFlags] & NSHelpKeyMask) + [switchString appendString:@"Help-"]; + if([anEvent modifierFlags] & NSFunctionKeyMask) // powerbooks only + [switchString appendString:@"Fn-"]; + + [switchString appendString:[anEvent charactersIgnoringModifiers]]; + [switchKeyButton setTitle:switchString]; + + keyCode = [anEvent keyCode]; + modifiers = [anEvent modifierFlags]; + isGettingKeyCode=NO; + + return YES; + } + return NO; +} + ++ (void)setKeymapFile:(NSString*)newFile +{ + [[NSUserDefaults standardUserDefaults] setObject:newFile + forKey:@"KeymappingFile"]; +} + ++ (void)setUseKeymapFile:(BOOL)newUseKeymapFile +{ + [[NSUserDefaults standardUserDefaults] setBool:newUseKeymapFile + forKey:@"UseKeymappingFile"]; +} + ++ (void)setSwitchString:(NSString*)newString +{ + [[NSUserDefaults standardUserDefaults] setObject:newString + forKey:@"SwitchString"]; +} + ++ (void)setKeyCode:(int)newKeyCode +{ + [[NSUserDefaults standardUserDefaults] setInteger:newKeyCode + forKey:@"SwitchKeyCode"]; +} + ++ (void)setModifiers:(int)newModifiers +{ + [[NSUserDefaults standardUserDefaults] setInteger:newModifiers + forKey:@"SwitchModifiers"]; +} + ++ (void)setDisplay:(int)newDisplay +{ + [[NSUserDefaults standardUserDefaults] setInteger:newDisplay + forKey:@"Display"]; +} + ++ (void)setDockSwitch:(BOOL)newDockSwitch +{ + [[NSUserDefaults standardUserDefaults] setBool:newDockSwitch + forKey:@"DockSwitch"]; +} + ++ (void)setFakeButtons:(BOOL)newFakeButtons +{ + [[NSUserDefaults standardUserDefaults] setBool:newFakeButtons + forKey:@"FakeButtons"]; + // Update the setting used by the X server thread + darwinFakeButtons = newFakeButtons; +} + ++ (void)setButton2Mask:(int)newFakeMask +{ + [[NSUserDefaults standardUserDefaults] setInteger:newFakeMask + forKey:@"Button2Mask"]; + // Update the setting used by the X server thread + darwinFakeMouse2Mask = newFakeMask; +} + ++ (void)setButton3Mask:(int)newFakeMask +{ + [[NSUserDefaults standardUserDefaults] setInteger:newFakeMask + forKey:@"Button3Mask"]; + // Update the setting used by the X server thread + darwinFakeMouse3Mask = newFakeMask; +} + ++ (void)setMouseAccelChange:(BOOL)newMouseAccelChange +{ + [[NSUserDefaults standardUserDefaults] setBool:newMouseAccelChange + forKey:@"AllowMouseAccelChange"]; + // Update the setting used by the X server thread + quartzMouseAccelChange = newMouseAccelChange; +} + ++ (void)setUseQDCursor:(int)newUseQDCursor +{ + [[NSUserDefaults standardUserDefaults] setInteger:newUseQDCursor + forKey:@"UseQDCursor"]; +} + ++ (void)setModeWindow:(BOOL)newModeWindow +{ + [[NSUserDefaults standardUserDefaults] setBool:newModeWindow + forKey:@"ShowModePickWindow"]; +} + ++ (void)setRootless:(BOOL)newRootless +{ + [[NSUserDefaults standardUserDefaults] setBool:newRootless + forKey:@"UseRootlessMode"]; +} + ++ (void)setStartupHelp:(BOOL)newStartupHelp +{ + [[NSUserDefaults standardUserDefaults] setBool:newStartupHelp + forKey:@"ShowStartupHelp"]; +} + ++ (void)setSystemBeep:(BOOL)newSystemBeep +{ + [[NSUserDefaults standardUserDefaults] setBool:newSystemBeep + forKey:@"UseSystemBeep"]; + // Update the setting used by the X server thread + quartzUseSysBeep = newSystemBeep; +} + ++ (void)setXinerama:(BOOL)newXinerama +{ + [[NSUserDefaults standardUserDefaults] setBool:newXinerama + forKey:@"Xinerama"]; +} + ++ (void)setAddToPath:(BOOL)newAddToPath +{ + [[NSUserDefaults standardUserDefaults] setBool:newAddToPath + forKey:@"AddToPath"]; +} + ++ (void)setAddToPathString:(NSString*)newAddToPathString +{ + [[NSUserDefaults standardUserDefaults] setObject:newAddToPathString + forKey:@"AddToPathString"]; +} + ++ (void)setUseDefaultShell:(BOOL)newUseDefaultShell +{ + [[NSUserDefaults standardUserDefaults] setBool:newUseDefaultShell + forKey:@"UseDefaultShell"]; +} + ++ (void)setShellString:(NSString*)newShellString +{ + [[NSUserDefaults standardUserDefaults] setObject:newShellString + forKey:@"Shell"]; +} + ++ (void)setDepth:(int)newDepth +{ + [[NSUserDefaults standardUserDefaults] setInteger:newDepth + forKey:@"Depth"]; +} + ++ (void)saveToDisk +{ + [[NSUserDefaults standardUserDefaults] synchronize]; +} + ++ (BOOL)useKeymapFile +{ + return [[NSUserDefaults standardUserDefaults] + boolForKey:@"UseKeymappingFile"]; +} + ++ (NSString*)keymapFile +{ + return [[NSUserDefaults standardUserDefaults] + stringForKey:@"KeymappingFile"]; +} + ++ (NSString*)switchString +{ + return [[NSUserDefaults standardUserDefaults] + stringForKey:@"SwitchString"]; +} + ++ (unsigned int)keyCode +{ + return [[NSUserDefaults standardUserDefaults] + integerForKey:@"SwitchKeyCode"]; +} + ++ (unsigned int)modifiers +{ + return [[NSUserDefaults standardUserDefaults] + integerForKey:@"SwitchModifiers"]; +} + ++ (int)display +{ + return [[NSUserDefaults standardUserDefaults] + integerForKey:@"Display"]; +} + ++ (BOOL)dockSwitch +{ + return [[NSUserDefaults standardUserDefaults] boolForKey:@"DockSwitch"]; +} + ++ (BOOL)fakeButtons +{ + return [[NSUserDefaults standardUserDefaults] boolForKey:@"FakeButtons"]; +} + ++ (int)button2Mask +{ + return [[NSUserDefaults standardUserDefaults] + integerForKey:@"Button2Mask"]; +} + ++ (int)button3Mask +{ + return [[NSUserDefaults standardUserDefaults] + integerForKey:@"Button3Mask"]; +} + ++ (BOOL)mouseAccelChange +{ + return [[NSUserDefaults standardUserDefaults] + boolForKey:@"AllowMouseAccelChange"]; +} + ++ (int)useQDCursor +{ + return [[NSUserDefaults standardUserDefaults] + integerForKey:@"UseQDCursor"]; +} + ++ (BOOL)rootless +{ + return [[NSUserDefaults standardUserDefaults] + boolForKey:@"UseRootlessMode"]; +} + ++ (BOOL)modeWindow +{ + return [[NSUserDefaults standardUserDefaults] + boolForKey:@"ShowModePickWindow"]; +} + ++ (BOOL)startupHelp +{ + return [[NSUserDefaults standardUserDefaults] + boolForKey:@"ShowStartupHelp"]; +} + ++ (BOOL)systemBeep +{ + return [[NSUserDefaults standardUserDefaults] boolForKey:@"UseSystemBeep"]; +} + ++ (BOOL)xinerama +{ + return [[NSUserDefaults standardUserDefaults] boolForKey:@"Xinerama"]; +} + ++ (BOOL)addToPath +{ + return [[NSUserDefaults standardUserDefaults] boolForKey:@"AddToPath"]; +} + ++ (NSString*)addToPathString +{ + return [[NSUserDefaults standardUserDefaults] + stringForKey:@"AddToPathString"]; +} + ++ (BOOL)useDefaultShell +{ + return [[NSUserDefaults standardUserDefaults] + boolForKey:@"UseDefaultShell"]; +} + ++ (NSString*)shellString +{ + return [[NSUserDefaults standardUserDefaults] + stringForKey:@"Shell"]; +} + ++ (int)depth +{ + return [[NSUserDefaults standardUserDefaults] + integerForKey:@"Depth"]; +} + + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz/XApplication.h b/xc/programs/Xserver/hw/darwin/quartz/XApplication.h new file mode 100644 index 000000000..3d3e96dab --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XApplication.h @@ -0,0 +1,47 @@ +// +// XApplication.h +// +// Created by Andreas Monitzer on January 6, 2001. +// +/* + * Copyright (c) 2001 Andreas Monitzer. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XApplication.h,v 1.2 2002/10/12 00:32:45 torrey Exp $ */ + +#import <Cocoa/Cocoa.h> + +#import "XServer.h" +#import "Preferences.h" + +@interface XApplication : NSApplication { + IBOutlet XServer *xserver; + IBOutlet Preferences *preferences; +} + +- (void)sendEvent:(NSEvent *)anEvent; + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz/XApplication.m b/xc/programs/Xserver/hw/darwin/quartz/XApplication.m new file mode 100644 index 000000000..9b81bbee0 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XApplication.m @@ -0,0 +1,47 @@ +// +// XApplication.m +// +// Created by Andreas Monitzer on January 6, 2001. +// +/* + * Copyright (c) 2001 Andreas Monitzer. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XApplication.m,v 1.2 2002/10/12 00:32:45 torrey Exp $ */ + +#import "XApplication.h" + + +@implementation XApplication + +- (void)sendEvent:(NSEvent *)anEvent { + if (![xserver translateEvent:anEvent]) { + if (![preferences sendEvent:anEvent]) + [super sendEvent:anEvent]; + } +} + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz/XCarbonWindow.h b/xc/programs/Xserver/hw/darwin/quartz/XCarbonWindow.h new file mode 100644 index 000000000..3ffc16c9c --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XCarbonWindow.h @@ -0,0 +1,41 @@ +/* + * XCarbonWindow category for Mac OS X rootless X server + * + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XCarbonWindow.h,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +#import <AppKit/NSWindow.h> + +@interface NSCarbonWindow : NSWindow + +@end + + +@interface NSCarbonWindow(XCarbonWindow) + +- (void)display; + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz/XCarbonWindow.m b/xc/programs/Xserver/hw/darwin/quartz/XCarbonWindow.m new file mode 100644 index 000000000..167297b2e --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XCarbonWindow.m @@ -0,0 +1,45 @@ +/* + * XCarbonWindow category for Mac OS X rootless X server + * + * This category extends/replaces the functionality of NSCarbonWindow. + * + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XCarbonWindow.m,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +#import "XCarbonWindow.h" + + +@implementation NSCarbonWindow(XCarbonWindow) + +// Unfortunately, NSCarbonWindow does not always respect autoDisplay:NO. +// NSCarbonWindow's display method erases the window content, +// so we override it. +- (void)display +{ + // Don't do anything here. +} + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz/XDarwin.pbproj/project.pbxproj b/xc/programs/Xserver/hw/darwin/quartz/XDarwin.pbproj/project.pbxproj new file mode 100644 index 000000000..30b591fd5 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XDarwin.pbproj/project.pbxproj @@ -0,0 +1,1376 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 38; + objects = { + 01279092000747AA0A000002 = { + isa = PBXFileReference; + path = XServer.m; + refType = 4; + }; + 0127909600074AF60A000002 = { + isa = PBXFileReference; + path = XApplication.m; + refType = 4; + }; + 0127909800074B1A0A000002 = { + isa = PBXFileReference; + path = XApplication.h; + refType = 4; + }; + 014C68ED00ED6A9D7F000001 = { + isa = PBXFileReference; + path = XView.h; + refType = 4; + }; + 014C68EE00ED6A9D7F000001 = { + isa = PBXFileReference; + path = XView.m; + refType = 4; + }; + 014C68F200ED7AD67F000001 = { + isa = PBXFileReference; + path = fakeBoxRec.h; + refType = 4; + }; + 014C68F300EE5AB97F000001 = { + isa = PBXFileReference; + path = rootlessCommon.c; + refType = 4; + }; + 014C68F400EE5AB97F000001 = { + isa = PBXFileReference; + path = rootlessCommon.h; + refType = 4; + }; + 014C68F700EE678F7F000001 = { + isa = PBXFileReference; + path = rootlessWindow.c; + refType = 4; + }; + 014C68F800EE678F7F000001 = { + isa = PBXFileReference; + path = rootlessWindow.h; + refType = 4; + }; + 015698ED003DF345CE6F79C2 = { + isa = PBXFileReference; + path = XDarwin.icns; + refType = 4; + }; + 0157A37D002CF6D7CE6F79C2 = { + children = ( + F533214601A4B45401000001, + 0157A37E002CF6D7CE6F79C2, + F58D65DF018F79B101000001, + F533213D0193CBE001000001, + 43B962E200617B93416877C2, + F5ACD263C5BE031F01000001, + F51BF62E02026E3501000001, + F5ACD25CC5B5E96601000001, + F587E16401924C6901000001, + ); + isa = PBXVariantGroup; + name = Credits.rtf; + path = ""; + refType = 4; + }; + 0157A37E002CF6D7CE6F79C2 = { + isa = PBXFileReference; + name = English; + path = English.lproj/Credits.rtf; + refType = 4; + }; + 015EDCEA004203A8CE6F79C2 = { + isa = PBXFrameworkReference; + name = IOKit.framework; + path = /System/Library/Frameworks/IOKit.framework; + refType = 0; + }; + 017D6F4400E861FB7F000001 = { + isa = PBXFileReference; + path = rootlessGC.c; + refType = 4; + }; + 017D6F4500E861FB7F000001 = { + isa = PBXFileReference; + path = rootlessScreen.c; + refType = 4; + }; + 018F40F2003E1902CE6F79C2 = { + children = ( + 018F40F3003E1916CE6F79C2, + 021D6BA9003E1BACCE6F79C2, + 3E74E03600863F047F000001, + F5A94EF10314BAC70100011B, + 018F40F6003E1974CE6F79C2, + ); + isa = PBXGroup; + name = "X Server"; + path = ..; + refType = 4; + }; + 018F40F3003E1916CE6F79C2 = { + isa = PBXFileReference; + path = darwin.c; + refType = 4; + }; + 018F40F6003E1974CE6F79C2 = { + isa = PBXFileReference; + path = darwinKeyboard.c; + refType = 4; + }; + 018F40F8003E1979CE6F79C2 = { + isa = PBXFileReference; + path = quartz.c; + refType = 4; + }; + 018F40FA003E197ECE6F79C2 = { + isa = PBXFileReference; + path = quartz.h; + refType = 4; + }; + 018F40FC003E1983CE6F79C2 = { + isa = PBXFileReference; + path = xfIOKit.c; + refType = 4; + }; + 018F40FE003E1988CE6F79C2 = { + isa = PBXFileReference; + path = xfIOKit.h; + refType = 4; + }; + 018F4100003E19E4CE6F79C2 = { + isa = PBXFileReference; + path = xfIOKitCursor.c; + refType = 4; + }; +//010 +//011 +//012 +//013 +//014 +//020 +//021 +//022 +//023 +//024 + 021D6BA9003E1BACCE6F79C2 = { + isa = PBXFileReference; + path = darwin.h; + refType = 4; + }; + 02A1FEA6006D34BE416877C2 = { + isa = PBXFileReference; + path = xfIOKitStartup.c; + refType = 4; + }; + 02A1FEA8006D38F0416877C2 = { + isa = PBXFileReference; + path = quartzStartup.c; + refType = 4; + }; + 02E03CA000348209CE6F79C2 = { + children = ( + F533214701A4B48301000001, + 02E03CA100348209CE6F79C2, + F58D65E0018F79C001000001, + F533213E0193CBF401000001, + 43B962E300617B93416877C2, + F5ACD268C5BE046401000001, + F51BF62F02026E5C01000001, + F5ACD261C5B5EA2001000001, + F587E16501924C7401000001, + ); + isa = PBXVariantGroup; + name = XDarwinHelp.html; + path = ""; + refType = 4; + }; + 02E03CA100348209CE6F79C2 = { + isa = PBXFileReference; + name = English; + path = English.lproj/XDarwinHelp.html; + refType = 4; + }; +//020 +//021 +//022 +//023 +//024 +//030 +//031 +//032 +//033 +//034 + 0338412F0083BFE57F000001 = { + isa = PBXFileReference; + path = quartzCursor.h; + refType = 4; + }; +//030 +//031 +//032 +//033 +//034 +//040 +//041 +//042 +//043 +//044 + 04329610000763920A000002 = { + isa = PBXFileReference; + path = Preferences.m; + refType = 4; + }; + 04329611000763920A000002 = { + isa = PBXFileReference; + path = Preferences.h; + refType = 4; + }; +//040 +//041 +//042 +//043 +//044 +//060 +//061 +//062 +//063 +//064 + 06EB6C3B004099E7CE6F79C2 = { + isa = PBXFileReference; + path = quartzShared.h; + refType = 4; + }; +//060 +//061 +//062 +//063 +//064 +//080 +//081 +//082 +//083 +//084 + 080E96DDFE201D6D7F000001 = { + children = ( + 04329610000763920A000002, + 04329611000763920A000002, + 0127909600074AF60A000002, + 0127909800074B1A0A000002, + 01279092000747AA0A000002, + 1C4A3109004D8F24CE6F79C2, + 014C68EE00ED6A9D7F000001, + 014C68ED00ED6A9D7F000001, + ); + isa = PBXGroup; + name = Classes; + refType = 4; + }; + 089C165CFE840E0CC02AAC07 = { + children = ( + F533214301A4B3F001000001, + 089C165DFE840E0CC02AAC07, + F58D65DD018F798F01000001, + F533213A0193CBA201000001, + 43B962E100617B49416877C2, + F5ACD269C5BE049301000001, + F51BF62B02026DDA01000001, + F5ACD262C5B5EA4D01000001, + F587E16101924C2F01000001, + ); + isa = PBXVariantGroup; + name = InfoPlist.strings; + refType = 4; + }; + 089C165DFE840E0CC02AAC07 = { + isa = PBXFileReference; + name = English; + path = English.lproj/InfoPlist.strings; + refType = 4; + }; +//080 +//081 +//082 +//083 +//084 +//0A0 +//0A1 +//0A2 +//0A3 +//0A4 + 0A79E19E004499A1CE6F79C2 = { + isa = PBXApplicationReference; + path = XDarwin.app; + refType = 3; + }; + 0A79E19F004499A1CE6F79C2 = { + buildPhases = ( + 0A79E1A0004499A1CE6F79C2, + 0A79E1A1004499A1CE6F79C2, + 0A79E1A2004499A1CE6F79C2, + 0A79E1A3004499A1CE6F79C2, + 0A79E1A4004499A1CE6F79C2, + ); + buildSettings = { + INSTALL_PATH = /; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = XDarwin; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + WRAPPER_EXTENSION = app; + }; + dependencies = ( + ); + isa = PBXApplicationTarget; + name = XDarwin; + productInstallPath = /; + productName = XDarwin; + productReference = 0A79E19E004499A1CE6F79C2; + productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> +<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"> +<plist version=\"1.0\"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>XDarwin</string> + <key>CFBundleGetInfoString</key> + <string>XDarwin 1.2a2, ©2001-2002 XFree86 Project, Inc.</string> + <key>CFBundleIconFile</key> + <string>XDarwin.icns</string> + <key>CFBundleIdentifier</key> + <string>org.xfree86.XDarwin</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>XDarwin</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>XDarwin 1.2a2</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string></string> + <key>NSHelpFile</key> + <string>XDarwinHelp.html</string> + <key>NSMainNibFile</key> + <string>MainMenu</string> + <key>NSPrincipalClass</key> + <string>XApplication</string> +</dict> +</plist> +"; + shouldUseHeadermap = 0; + }; + 0A79E1A0004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXHeadersBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 0A79E1A1004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + 0A79E1A600449EB2CE6F79C2, + 0A79E1A700449EB2CE6F79C2, + 0A79E1A800449EB2CE6F79C2, + 0A79E1A900449EB2CE6F79C2, + 0A79E1AA00449EB2CE6F79C2, + 1220774500712D2D416877C2, + F54BF6ED017D506E01000001, + ); + isa = PBXResourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 0A79E1A2004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXSourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 0A79E1A3004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXFrameworksBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 0A79E1A4004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXRezBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 0A79E1A600449EB2CE6F79C2 = { + fileRef = 29B97318FDCFA39411CA2CEA; + isa = PBXBuildFile; + settings = { + }; + }; + 0A79E1A700449EB2CE6F79C2 = { + fileRef = 089C165CFE840E0CC02AAC07; + isa = PBXBuildFile; + settings = { + }; + }; + 0A79E1A800449EB2CE6F79C2 = { + fileRef = 0157A37D002CF6D7CE6F79C2; + isa = PBXBuildFile; + settings = { + }; + }; + 0A79E1A900449EB2CE6F79C2 = { + fileRef = 02E03CA000348209CE6F79C2; + isa = PBXBuildFile; + settings = { + }; + }; + 0A79E1AA00449EB2CE6F79C2 = { + fileRef = 015698ED003DF345CE6F79C2; + isa = PBXBuildFile; + settings = { + }; + }; +//0A0 +//0A1 +//0A2 +//0A3 +//0A4 +//100 +//101 +//102 +//103 +//104 + 1058C7A0FEA54F0111CA2CBB = { + children = ( + F53321400193CCF001000001, + 1BE4F84D0006C9890A000002, + 1058C7A1FEA54F0111CA2CBB, + F53321410193CCF001000001, + 015EDCEA004203A8CE6F79C2, + ); + isa = PBXGroup; + name = "Linked Frameworks"; + refType = 4; + }; + 1058C7A1FEA54F0111CA2CBB = { + isa = PBXFrameworkReference; + name = Cocoa.framework; + path = /System/Library/Frameworks/Cocoa.framework; + refType = 0; + }; + 1058C7A2FEA54F0111CA2CBB = { + children = ( + 29B97325FDCFA39411CA2CEA, + 29B97324FDCFA39411CA2CEA, + ); + isa = PBXGroup; + name = "Other Frameworks"; + refType = 4; + }; +//100 +//101 +//102 +//103 +//104 +//120 +//121 +//122 +//123 +//124 + 1220774300712D2D416877C2 = { + children = ( + F533214501A4B42501000001, + 1220774400712D2D416877C2, + F58D65DE018F79A001000001, + F533213C0193CBC901000001, + 1220774600712D75416877C2, + F5ACD266C5BE03C501000001, + F51BF62D02026E1C01000001, + F5ACD25FC5B5E9AA01000001, + F587E16301924C5E01000001, + ); + isa = PBXVariantGroup; + name = Localizable.strings; + path = ""; + refType = 4; + }; + 1220774400712D2D416877C2 = { + isa = PBXFileReference; + name = English; + path = English.lproj/Localizable.strings; + refType = 4; + }; + 1220774500712D2D416877C2 = { + fileRef = 1220774300712D2D416877C2; + isa = PBXBuildFile; + settings = { + }; + }; + 1220774600712D75416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/Localizable.strings; + refType = 4; + }; +//120 +//121 +//122 +//123 +//124 +//170 +//171 +//172 +//173 +//174 + 170DFAFF00729A35416877C2 = { + isa = PBXFileReference; + path = XDarwinStartup.c; + refType = 4; + }; + 170DFB0000729C86416877C2 = { + children = ( + 018F40FC003E1983CE6F79C2, + 018F40FE003E1988CE6F79C2, + 018F4100003E19E4CE6F79C2, + 02A1FEA6006D34BE416877C2, + ); + isa = PBXGroup; + name = IOKit; + path = ..; + refType = 4; + }; +//170 +//171 +//172 +//173 +//174 +//190 +//191 +//192 +//193 +//194 + 19C28FACFE9D520D11CA2CBB = { + children = ( + 0A79E19E004499A1CE6F79C2, + ); + isa = PBXGroup; + name = Products; + refType = 4; + }; +//190 +//191 +//192 +//193 +//194 +//1B0 +//1B1 +//1B2 +//1B3 +//1B4 + 1BD8DE4200B8A3567F000001 = { + children = ( + F533214401A4B40F01000001, + 1BD8DE4300B8A3567F000001, + F58D65DC018F794D01000001, + F533213B0193CBB401000001, + 1BD8DE4700B8A3C77F000001, + F5ACD264C5BE035B01000001, + F51BF62C02026E0601000001, + F5ACD25DC5B5E97701000001, + F587E16201924C5301000001, + ); + isa = PBXVariantGroup; + name = InfoPlist.strings.cpp; + path = ""; + refType = 4; + }; + 1BD8DE4300B8A3567F000001 = { + isa = PBXFileReference; + name = English; + path = English.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + 1BD8DE4400B8A38E7F000001 = { + children = ( + F533214801A4B4D701000001, + 1BD8DE4500B8A38E7F000001, + F58D65E1018F79E001000001, + F533213F0193CC2501000001, + 1BD8DE4800B8A4167F000001, + F5ACD267C5BE03FC01000001, + F51BF63002026E8D01000001, + F5ACD260C5B5E9DF01000001, + F587E16601924C9D01000001, + ); + isa = PBXVariantGroup; + name = XDarwinHelp.html.cpp; + path = ""; + refType = 4; + }; + 1BD8DE4500B8A38E7F000001 = { + isa = PBXFileReference; + name = English; + path = English.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + 1BD8DE4700B8A3C77F000001 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + 1BD8DE4800B8A4167F000001 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + 1BE4F84D0006C9890A000002 = { + isa = PBXFrameworkReference; + name = Carbon.framework; + path = /System/Library/Frameworks/Carbon.framework; + refType = 0; + }; +//1B0 +//1B1 +//1B2 +//1B3 +//1B4 +//1C0 +//1C1 +//1C2 +//1C3 +//1C4 + 1C4A3109004D8F24CE6F79C2 = { + isa = PBXFileReference; + path = XServer.h; + refType = 4; + }; +//1C0 +//1C1 +//1C2 +//1C3 +//1C4 +//230 +//231 +//232 +//233 +//234 + 237A34C10076E37E7F000001 = { + isa = PBXFileReference; + path = quartzAudio.c; + refType = 4; + }; + 237A34C20076E37E7F000001 = { + buildRules = ( + ); + buildSettings = { + COPY_PHASE_STRIP = NO; + OPTIMIZATION_CFLAGS = "-O0"; + }; + isa = PBXBuildStyle; + name = Development; + }; + 237A34C30076E37E7F000001 = { + buildRules = ( + ); + buildSettings = { + COPY_PHASE_STRIP = YES; + }; + isa = PBXBuildStyle; + name = Deployment; + }; + 237A34C40076F4F07F000001 = { + isa = PBXFileReference; + path = quartzAudio.h; + refType = 4; + }; +//230 +//231 +//232 +//233 +//234 +//290 +//291 +//292 +//293 +//294 + 29B97313FDCFA39411CA2CEA = { + buildStyles = ( + 237A34C20076E37E7F000001, + 237A34C30076E37E7F000001, + ); + isa = PBXProject; + knownRegions = ( + English, + Japanese, + French, + German, + Swedish, + Dutch, + Spanish, + ko, + Portuguese, + ); + mainGroup = 29B97314FDCFA39411CA2CEA; + projectDirPath = ""; + targets = ( + 0A79E19F004499A1CE6F79C2, + ); + }; + 29B97314FDCFA39411CA2CEA = { + children = ( + 080E96DDFE201D6D7F000001, + 018F40F2003E1902CE6F79C2, + 170DFB0000729C86416877C2, + 43B962CE00617089416877C2, + F5614B3D025112D901000114, + 32FEE13C00E07C3E7F000001, + 29B97315FDCFA39411CA2CEA, + 29B97317FDCFA39411CA2CEA, + 29B97323FDCFA39411CA2CEA, + 19C28FACFE9D520D11CA2CBB, + ); + isa = PBXGroup; + name = "Xmaster-Cocoa"; + path = ""; + refType = 4; + }; + 29B97315FDCFA39411CA2CEA = { + children = ( + 170DFAFF00729A35416877C2, + ); + isa = PBXGroup; + name = "Other Sources"; + path = ""; + refType = 2; + }; + 29B97317FDCFA39411CA2CEA = { + children = ( + 29B97318FDCFA39411CA2CEA, + 089C165CFE840E0CC02AAC07, + 1BD8DE4200B8A3567F000001, + 1220774300712D2D416877C2, + 0157A37D002CF6D7CE6F79C2, + 02E03CA000348209CE6F79C2, + 1BD8DE4400B8A38E7F000001, + 015698ED003DF345CE6F79C2, + F54BF6EA017D500901000001, + F54BF6EC017D506E01000001, + ); + isa = PBXGroup; + name = Resources; + path = ../bundle; + refType = 4; + }; + 29B97318FDCFA39411CA2CEA = { + children = ( + F533214201A4B3CE01000001, + 29B97319FDCFA39411CA2CEA, + F58D65DB018F793801000001, + F53321390193CB6A01000001, + 43B962E000617B49416877C2, + F5ACD265C5BE038601000001, + F51BF62A02026DAF01000001, + F5ACD25EC5B5E98D01000001, + F587E16001924C1D01000001, + ); + isa = PBXVariantGroup; + name = MainMenu.nib; + path = ""; + refType = 4; + }; + 29B97319FDCFA39411CA2CEA = { + isa = PBXFileReference; + name = English; + path = English.lproj/MainMenu.nib; + refType = 4; + }; + 29B97323FDCFA39411CA2CEA = { + children = ( + 1058C7A0FEA54F0111CA2CBB, + 1058C7A2FEA54F0111CA2CBB, + ); + isa = PBXGroup; + name = Frameworks; + path = ""; + refType = 4; + }; + 29B97324FDCFA39411CA2CEA = { + isa = PBXFrameworkReference; + name = AppKit.framework; + path = /System/Library/Frameworks/AppKit.framework; + refType = 0; + }; + 29B97325FDCFA39411CA2CEA = { + isa = PBXFrameworkReference; + name = Foundation.framework; + path = /System/Library/Frameworks/Foundation.framework; + refType = 0; + }; +//290 +//291 +//292 +//293 +//294 +//320 +//321 +//322 +//323 +//324 + 32FEE13C00E07C3E7F000001 = { + children = ( + F56CBD0D02EB84A801129B8A, + F56CBD0E02EB84A801129B8A, + F56CBD0F02EBDCFC01129B8A, + 014C68F200ED7AD67F000001, + F5269C2D01D5BC3501000001, + F5269C2E01D5BC3501000001, + 32FEE13E00E07CBE7F000001, + 32FEE13F00E07CBE7F000001, + 32FEE14000E07CBE7F000001, + 32FEE14100E07CBE7F000001, + 32FEE14200E07CBE7F000001, + 014C68F300EE5AB97F000001, + 014C68F400EE5AB97F000001, + 017D6F4400E861FB7F000001, + 017D6F4500E861FB7F000001, + 014C68F700EE678F7F000001, + 014C68F800EE678F7F000001, + 32FEE14900E07D317F000001, + ); + isa = PBXGroup; + name = Rootless; + path = ""; + refType = 4; + }; + 32FEE13E00E07CBE7F000001 = { + isa = PBXFileReference; + path = rootless.h; + refType = 4; + }; + 32FEE13F00E07CBE7F000001 = { + isa = PBXFileReference; + path = rootlessAqua.h; + refType = 4; + }; + 32FEE14000E07CBE7F000001 = { + isa = PBXFileReference; + path = rootlessAquaGlue.c; + refType = 4; + }; + 32FEE14100E07CBE7F000001 = { + isa = PBXFileReference; + path = rootlessAquaImp.h; + refType = 4; + }; + 32FEE14200E07CBE7F000001 = { + isa = PBXFileReference; + path = rootlessAquaImp.m; + refType = 4; + }; + 32FEE14900E07D317F000001 = { + isa = PBXFileReference; + path = rootlessValTree.c; + refType = 4; + }; +//320 +//321 +//322 +//323 +//324 +//350 +//351 +//352 +//353 +//354 + 3576829A0077B8F17F000001 = { + isa = PBXFileReference; + path = quartzCursor.c; + refType = 4; + }; +//350 +//351 +//352 +//353 +//354 +//3E0 +//3E1 +//3E2 +//3E3 +//3E4 + 3E74E03600863F047F000001 = { + isa = PBXFileReference; + path = darwinClut8.h; + refType = 4; + }; +//3E0 +//3E1 +//3E2 +//3E3 +//3E4 +//430 +//431 +//432 +//433 +//434 + 43B962CE00617089416877C2 = { + children = ( + 018F40F8003E1979CE6F79C2, + 018F40FA003E197ECE6F79C2, + 237A34C10076E37E7F000001, + 237A34C40076F4F07F000001, + 3576829A0077B8F17F000001, + 0338412F0083BFE57F000001, + 43B962D000617089416877C2, + 43B962D100617089416877C2, + 43B962CF00617089416877C2, + F5582948015DAD3B01000001, + 06EB6C3B004099E7CE6F79C2, + 02A1FEA8006D38F0416877C2, + ); + isa = PBXGroup; + name = Quartz; + path = ""; + refType = 4; + }; + 43B962CF00617089416877C2 = { + isa = PBXFileReference; + path = quartzCocoa.m; + refType = 4; + }; + 43B962D000617089416877C2 = { + isa = PBXFileReference; + path = quartzPasteboard.c; + refType = 4; + }; + 43B962D100617089416877C2 = { + isa = PBXFileReference; + path = quartzPasteboard.h; + refType = 4; + }; + 43B962E000617B49416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/MainMenu.nib; + refType = 4; + }; + 43B962E100617B49416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/InfoPlist.strings; + refType = 4; + }; + 43B962E200617B93416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/Credits.rtf; + refType = 4; + }; + 43B962E300617B93416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/XDarwinHelp.html; + refType = 4; + }; +//430 +//431 +//432 +//433 +//434 +//F50 +//F51 +//F52 +//F53 +//F54 + F51BF62A02026DAF01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/MainMenu.nib; + refType = 4; + }; + F51BF62B02026DDA01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/InfoPlist.strings; + refType = 4; + }; + F51BF62C02026E0601000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F51BF62D02026E1C01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/Localizable.strings; + refType = 4; + }; + F51BF62E02026E3501000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/Credits.rtf; + refType = 4; + }; + F51BF62F02026E5C01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/XDarwinHelp.html; + refType = 4; + }; + F51BF63002026E8D01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F5269C2D01D5BC3501000001 = { + isa = PBXFileReference; + path = pseudoramiX.c; + refType = 4; + }; + F5269C2E01D5BC3501000001 = { + isa = PBXFileReference; + path = pseudoramiX.h; + refType = 4; + }; + F53321390193CB6A01000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/MainMenu.nib; + refType = 4; + }; + F533213A0193CBA201000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/InfoPlist.strings; + refType = 4; + }; + F533213B0193CBB401000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F533213C0193CBC901000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/Localizable.strings; + refType = 4; + }; + F533213D0193CBE001000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/Credits.rtf; + refType = 4; + }; + F533213E0193CBF401000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/XDarwinHelp.html; + refType = 4; + }; + F533213F0193CC2501000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F53321400193CCF001000001 = { + isa = PBXFrameworkReference; + name = ApplicationServices.framework; + path = /System/Library/Frameworks/ApplicationServices.framework; + refType = 0; + }; + F53321410193CCF001000001 = { + isa = PBXFrameworkReference; + name = CoreAudio.framework; + path = /System/Library/Frameworks/CoreAudio.framework; + refType = 0; + }; + F533214201A4B3CE01000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/MainMenu.nib; + refType = 4; + }; + F533214301A4B3F001000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/InfoPlist.strings; + refType = 4; + }; + F533214401A4B40F01000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F533214501A4B42501000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/Localizable.strings; + refType = 4; + }; + F533214601A4B45401000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/Credits.rtf; + refType = 4; + }; + F533214701A4B48301000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/XDarwinHelp.html; + refType = 4; + }; + F533214801A4B4D701000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F54BF6EA017D500901000001 = { + isa = PBXFileReference; + path = startXClients.cpp; + refType = 4; + }; + F54BF6EC017D506E01000001 = { + isa = PBXFileReference; + path = startXClients; + refType = 4; + }; + F54BF6ED017D506E01000001 = { + fileRef = F54BF6EC017D506E01000001; + isa = PBXBuildFile; + settings = { + }; + }; + F5582948015DAD3B01000001 = { + isa = PBXFileReference; + path = quartzCommon.h; + refType = 4; + }; + F5614B3B0251124C01000114 = { + isa = PBXFileReference; + path = fullscreen.c; + refType = 4; + }; + F5614B3C0251124C01000114 = { + isa = PBXFileReference; + path = fullscreen.h; + refType = 4; + }; + F5614B3D025112D901000114 = { + children = ( + F5614B3B0251124C01000114, + F5614B3C0251124C01000114, + ); + isa = PBXGroup; + name = "Full Screen"; + path = ""; + refType = 4; + }; + F56CBD0D02EB84A801129B8A = { + isa = PBXFileReference; + path = aqua.h; + refType = 4; + }; + F56CBD0E02EB84A801129B8A = { + isa = PBXFileReference; + path = aquaPicture.c; + refType = 4; + }; + F56CBD0F02EBDCFC01129B8A = { + isa = PBXFileReference; + path = aquaWindow.c; + refType = 4; + }; + F587E16001924C1D01000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/MainMenu.nib; + refType = 4; + }; + F587E16101924C2F01000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/InfoPlist.strings; + refType = 4; + }; + F587E16201924C5301000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F587E16301924C5E01000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/Localizable.strings; + refType = 4; + }; + F587E16401924C6901000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/Credits.rtf; + refType = 4; + }; + F587E16501924C7401000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/XDarwinHelp.html; + refType = 4; + }; + F587E16601924C9D01000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F58D65DB018F793801000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/MainMenu.nib; + refType = 4; + }; + F58D65DC018F794D01000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F58D65DD018F798F01000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/InfoPlist.strings; + refType = 4; + }; + F58D65DE018F79A001000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/Localizable.strings; + refType = 4; + }; + F58D65DF018F79B101000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/Credits.rtf; + refType = 4; + }; + F58D65E0018F79C001000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/XDarwinHelp.html; + refType = 4; + }; + F58D65E1018F79E001000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F5A94EF10314BAC70100011B = { + isa = PBXFileReference; + path = darwinEvents.c; + refType = 4; + }; + F5ACD25CC5B5E96601000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/Credits.rtf; + refType = 4; + }; + F5ACD25DC5B5E97701000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F5ACD25EC5B5E98D01000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/MainMenu.nib; + refType = 4; + }; + F5ACD25FC5B5E9AA01000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/Localizable.strings; + refType = 4; + }; + F5ACD260C5B5E9DF01000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F5ACD261C5B5EA2001000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/XDarwinHelp.html; + refType = 4; + }; + F5ACD262C5B5EA4D01000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/InfoPlist.strings; + refType = 4; + }; + F5ACD263C5BE031F01000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/Credits.rtf; + refType = 4; + }; + F5ACD264C5BE035B01000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F5ACD265C5BE038601000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/MainMenu.nib; + refType = 4; + }; + F5ACD266C5BE03C501000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/Localizable.strings; + refType = 4; + }; + F5ACD267C5BE03FC01000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F5ACD268C5BE046401000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/XDarwinHelp.html; + refType = 4; + }; + F5ACD269C5BE049301000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/InfoPlist.strings; + refType = 4; + }; + }; + rootObject = 29B97313FDCFA39411CA2CEA; +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/XDarwinStartup.c b/xc/programs/Xserver/hw/darwin/quartz/XDarwinStartup.c new file mode 100644 index 000000000..53343aa1e --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XDarwinStartup.c @@ -0,0 +1,165 @@ +/************************************************************** + * + * Startup program for Darwin X servers + * + * This program selects the appropriate X server to launch: + * XDarwin IOKit X server (default) + * XDarwinQuartz A soft link to the Quartz X server + * executable (-quartz etc. option) + * + * If told to idle, the program will simply pause and not + * launch any X server. This is to support startx being + * run by XDarwin.app. + * + **************************************************************/ +/* + * Copyright (c) 2001-2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * TORREY T. LYONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Torrey T. Lyons shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in this Software without prior written authorization from + * Torrey T. Lyons. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XDarwinStartup.c,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/syslimits.h> +#include <ApplicationServices/ApplicationServices.h> + +extern int errno; + +// Macros to build the path name +#ifndef XBINDIR +#define XBINDIR /usr/X11R6/bin +#endif +#define STR(s) #s +#define XSTRPATH(s) STR(s) "/" +#define XPATH(file) XSTRPATH(XBINDIR) STR(file) + +int main( + int argc, + char *argv[] ) +{ + int i, j, quartzMode = -1; + char **newargv; + + // Check if we are going to run in Quartz mode or idle + // to support startx from the Quartz server. The last + // parameter in the list is the one used. + for (i = argc-1; i; i--) { + if (!strcmp(argv[i], "-idle")) { + pause(); + return 0; + + } else if (!strcmp(argv[i], "-quartz") || + !strcmp(argv[i], "-rootless") || + !strcmp(argv[i], "-fullscreen")) + { + quartzMode = 1; + break; + + } else if (!strcmp(argv[i], "-iokit")) { + quartzMode = 0; + break; + } + } + + if (quartzMode == -1) { +#ifdef HAS_CG_MACH_PORT + // Check if the CoreGraphics window server is running. + // Mike Paquette says this is the fastest way to determine if it is running. + CFMachPortRef cgMachPortRef = CGWindowServerCFMachPort(); + if (cgMachPortRef == NULL) + quartzMode = 0; + else + quartzMode = 1; +#else + // On older systems we assume IOKit mode. + quartzMode = 0; +#endif + } + + if (quartzMode) { + // Launch the X server for the quartz modes + + char quartzPath[PATH_MAX+1]; + int pathLength; + OSStatus theStatus; + CFURLRef appURL; + CFStringRef appPath; + Boolean success; + + // Build the new argument list + newargv = (char **) malloc((argc+2) * sizeof(char *)); + for (j = argc; j; j--) + newargv[j] = argv[j]; + newargv[argc] = "-nostartx"; + newargv[argc+1] = NULL; + + // Use the XDarwinQuartz soft link if it is valid + pathLength = readlink(XPATH(XDarwinQuartz), quartzPath, PATH_MAX); + if (pathLength != -1) { + quartzPath[pathLength] = '\0'; + newargv[0] = quartzPath; + execv(newargv[0], newargv); + } + + // Otherwise query LaunchServices for the location of the XDarwin application + theStatus = LSFindApplicationForInfo(kLSUnknownCreator, + CFSTR("org.xfree86.XDarwin"), + NULL, NULL, &appURL); + if (theStatus) { + fprintf(stderr, "Could not find the XDarwin application. (Error = 0x%lx)\n", theStatus); + fprintf(stderr, "Launch XDarwin once from the Finder.\n"); + return theStatus; + } + + appPath = CFURLCopyFileSystemPath (appURL, kCFURLPOSIXPathStyle); + success = CFStringGetCString(appPath, quartzPath, PATH_MAX, CFStringGetSystemEncoding()); + if (! success) { + fprintf(stderr, "Could not find path to XDarwin application.\n"); + return success; + } + + // Launch the XDarwin application + strncat(quartzPath, "/Contents/MacOS/XDarwin", PATH_MAX); + newargv[0] = quartzPath; + execv(newargv[0], newargv); + fprintf(stderr, "Could not start XDarwin application at %s.\n", newargv[0]); + return errno; + + } else { + + // Build the new argument list + newargv = (char **) malloc((argc+1) * sizeof(char *)); + for (j = argc; j; j--) + newargv[j] = argv[j]; + newargv[0] = "XDarwin"; + newargv[argc] = NULL; + + // Launch the IOKit X server + execvp(newargv[0], newargv); + fprintf(stderr, "Could not start XDarwin IOKit X server.\n"); + return errno; + } +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/XDarwinStartup.man b/xc/programs/Xserver/hw/darwin/quartz/XDarwinStartup.man new file mode 100644 index 000000000..312f4b88b --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XDarwinStartup.man @@ -0,0 +1,75 @@ +.\" $XFree86: xc/programs/Xserver/hw/darwin/quartz/XDarwinStartup.man,v 1.1 2002/03/28 02:21:18 torrey Exp $ +.TH XDarwinStartup 1 +.SH NAME +XDarwinStartup - Startup program for the XDarwin X window server +.SH SYNOPSIS +.B XDarwinStartup +[\fI-iokit\fP] +[\fI-fullscreen\fP] +[\fI-rootless\fP] +[\fI-quartz\fP] +[\fI-idle\fP] +[\fIoptions\fP] +.SH DESCRIPTION +The \fIXDarwin(1)\fP X window server can be run in a variety of different +modes and is actually two different executables. The IOKit X server, +XDarwin, is used when running from the console. It is most commonly +located in __XBinDir__. The Quartz X server, for running in parallel with +Aqua, is a full-fledged Mac OS X application that can be started from +the Finder. Its application bundle is XDarwin.app, which is typically +located in /Applications. +.I XDarwinStartup +allows easy switching between these X servers and auto-detection of the +appropriate one to use when launching from the command line. +When run without any arguments, +.I XDarwinStartup +will start the Quartz X server if the Core Graphics window server +is currently running. Otherwise it will start the IOKit X server. +.PP +To locate the Quartz X server, +.I XDarwinStartup +will try to read the soft link at __XBinDir__/XDarwinQuartz. +This is typically a soft link to the executable of the XDarwin.app +application. If this fails, +.I XDarwinStartup +will call Launch Services to locate XDarwin.app. +.PP +To start the IOKit X server, +.I XDarwinStartup +will run the XDarwin execuatable, which should be present in the +user's path. +.SH OPTIONS +.I XDarwinStartup +accepts and passes on all options to the X server it +launches. In addition the following options have specific effects: +.TP 8 +.B \-iokit +Launch the IOKit X server. +.TP 8 +.B \-fullscreen +Launch the Quartz X server to run in full screen mode. +.TP 8 +.B \-rootless +Launch the Quartz X server to run in rootless mode. +.TP 8 +.B \-quartz +Launch the Quartz X server. +.TP 8 +.B \-idle +Pause and do nothing. This option is used by XDarwin.app when it is +started from the Finder. +.SH FILES +.TP 30 +__XBinDir__/XDarwin +IOKit mode X server +.TP 30 +/Applications/XDarwin.app +Quartz mode X server +.TP 30 +__XBinDir__/XDarwinQuartz +Soft link to Quartz mode X server executable +.SH SEE ALSO +XDarwin(1) +.SH BUGS +The path to XDarwinQuartz should not be hard coded. + diff --git a/xc/programs/Xserver/hw/darwin/quartz/XServer.h b/xc/programs/Xserver/hw/darwin/quartz/XServer.h new file mode 100644 index 000000000..b9fe410b6 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XServer.h @@ -0,0 +1,100 @@ +// +// XServer.h +// +/* + * Copyright (c) 2001 Andreas Monitzer. All Rights Reserved. + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XServer.h,v 1.4 2002/10/12 00:32:45 torrey Exp $ */ + +#define BOOL xBOOL +#include "Xproto.h" +#undef BOOL + +#import <Cocoa/Cocoa.h> + +@interface XServer : NSObject { + // server state + NSRecursiveLock *serverLock; + BOOL serverVisible; + BOOL rootlessMenuBarVisible; + BOOL appQuitting; + UInt32 mouseState; + Class windowClass; + + // server event queue + BOOL sendServerEvents; + int eventWriteFD; + + // Aqua interface + IBOutlet NSWindow *modeWindow; + IBOutlet NSButton *startupModeButton; + IBOutlet NSButton *startFullScreenButton; + IBOutlet NSButton *startRootlessButton; + IBOutlet NSWindow *helpWindow; + IBOutlet NSButton *startupHelpButton; + IBOutlet NSPanel *switchWindow; +} + +- (id)init; + +- (BOOL)translateEvent:(NSEvent *)anEvent; +- (BOOL)getMousePosition:(xEvent *)xe; + ++ (void)append:(NSString *)value toEnv:(NSString *)name; + +- (void)startX; +- (BOOL)startXClients; +- (void)run; +- (void)toggle; +- (void)show; +- (void)hide; +- (void)killServer; +- (void)readPasteboard; +- (void)writePasteboard; +- (void)sendXEvent:(xEvent *)xe; +- (void)sendShowHide:(BOOL)show; +- (void)clientProcessDone:(int)clientStatus; + +// Aqua interface actions +- (IBAction)startFullScreen:(id)sender; +- (IBAction)startRootless:(id)sender; +- (IBAction)closeHelpAndShow:(id)sender; +- (IBAction)showAction:(id)sender; + +// NSApplication delegate +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification; +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag; +- (void)applicationWillResignActive:(NSNotification *)aNotification; +- (void)applicationWillBecomeActive:(NSNotification *)aNotification; + +// NSPort delegate +- (void)handlePortMessage:(NSPortMessage *)portMessage; + +@end + diff --git a/xc/programs/Xserver/hw/darwin/quartz/XServer.m b/xc/programs/Xserver/hw/darwin/quartz/XServer.m new file mode 100644 index 000000000..4b7af53e6 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XServer.m @@ -0,0 +1,916 @@ +// +// XServer.m +// +// This class handles the interaction between the Cocoa front-end +// and the Darwin X server thread. +// +// Created by Andreas Monitzer on January 6, 2001. +// +/* + * Copyright (c) 2001 Andreas Monitzer. All Rights Reserved. + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XServer.m,v 1.4 2002/10/12 00:32:45 torrey Exp $ */ + +#include "quartzCommon.h" + +#define BOOL xBOOL +#include "X.h" +#include "Xproto.h" +#include "os.h" +#include "darwin.h" +#undef BOOL + +#import "XServer.h" +#import "Preferences.h" + +#include <unistd.h> +#include <stdio.h> +#include <sys/syslimits.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <pwd.h> +#include <signal.h> +#include <fcntl.h> + +#define ENQUEUE(xe) \ +{ \ + char byte = 0; \ + DarwinEQEnqueue(xe); \ + /* signal there is an event ready to handle */ \ + write(eventWriteFD, &byte, 1); \ +} + +// Types of shells +enum { + shell_Unknown, + shell_Bourne, + shell_C +}; + +typedef struct { + char *name; + int type; +} shellList_t; + +static shellList_t const shellList[] = { + { "csh", shell_C }, // standard C shell + { "tcsh", shell_C }, // ... needs no introduction + { "sh", shell_Bourne }, // standard Bourne shell + { "zsh", shell_Bourne }, // Z shell + { "bash", shell_Bourne }, // GNU Bourne again shell + { NULL, shell_Unknown } +}; + +extern int argcGlobal; +extern char **argvGlobal; +extern char **envpGlobal; +extern int main(int argc, char *argv[], char *envp[]); +extern void HideMenuBar(void); +extern void ShowMenuBar(void); +static void childDone(int sig); + +static NSPort *signalPort; +static NSPort *returnPort; +static NSPortMessage *signalMessage; +static pid_t clientPID; +static XServer *oneXServer; +static NSRect aquaMenuBarBox; + + +@implementation XServer + +- (id)init +{ + self = [super init]; + oneXServer = self; + + serverLock = [[NSRecursiveLock alloc] init]; + clientPID = 0; + sendServerEvents = NO; + serverVisible = NO; + rootlessMenuBarVisible = YES; + appQuitting = NO; + mouseState = 0; + eventWriteFD = quartzEventWriteFD; + windowClass = [NSWindow class]; + + // set up a port to safely send messages to main thread from server thread + signalPort = [[NSPort port] retain]; + returnPort = [[NSPort port] retain]; + signalMessage = [[NSPortMessage alloc] initWithSendPort:signalPort + receivePort:returnPort components:nil]; + + // set up receiving end + [signalPort setDelegate:self]; + [[NSRunLoop currentRunLoop] addPort:signalPort + forMode:NSDefaultRunLoopMode]; + [[NSRunLoop currentRunLoop] addPort:signalPort + forMode:NSModalPanelRunLoopMode]; + + return self; +} + +- (NSApplicationTerminateReply) + applicationShouldTerminate:(NSApplication *)sender +{ + // Quit if the X server is not running + if ([serverLock tryLock]) { + appQuitting = YES; + if (clientPID != 0) + kill(clientPID, SIGINT); + return NSTerminateNow; + } + + if (clientPID != 0 || !quartzStartClients) { + int but; + + // Hide the X server and stop sending it events + [self hide]; + sendServerEvents = NO; + + but = NSRunAlertPanel(NSLocalizedString(@"Quit X server?",@""), + NSLocalizedString(@"Quitting the X server will terminate any running X Window System programs.",@""), + NSLocalizedString(@"Quit",@""), + NSLocalizedString(@"Cancel",@""), + nil); + + switch (but) { + case NSAlertDefaultReturn: // quit + break; + case NSAlertAlternateReturn: // cancel + sendServerEvents = YES; + return NSTerminateCancel; + } + } + + appQuitting = YES; + if (clientPID != 0) + kill(clientPID, SIGINT); + [self killServer]; + return NSTerminateNow; +} + +// Ensure that everything has quit cleanly +- (void)applicationWillTerminate:(NSNotification *)aNotification +{ + // Make sure the client process has finished + if (clientPID != 0) { + NSLog(@"Waiting on client process..."); + sleep(2); + + // If the client process hasn't finished yet, kill it off + if (clientPID != 0) { + int clientStatus; + NSLog(@"Killing client process..."); + killpg(clientPID, SIGKILL); + waitpid(clientPID, &clientStatus, 0); + } + } + + // Wait until the X server thread quits + [serverLock lock]; +} + +// returns YES when event was handled +- (BOOL)translateEvent:(NSEvent *)anEvent +{ + xEvent xe; + static BOOL mouse1Pressed = NO; + BOOL onScreen; + NSEventType type; + unsigned int flags; + + if (!sendServerEvents) { + return NO; + } + + type = [anEvent type]; + flags = [anEvent modifierFlags]; + + if (!quartzRootless) { + // Check for switch keypress + if ((type == NSKeyDown) && (![anEvent isARepeat]) && + ([anEvent keyCode] == [Preferences keyCode])) + { + unsigned int switchFlags = [Preferences modifiers]; + + // Switch if all the switch modifiers are pressed, while none are + // pressed that should not be, except for caps lock. + if (((flags & switchFlags) == switchFlags) && + ((flags & ~(switchFlags | NSAlphaShiftKeyMask)) == 0)) + { + [self toggle]; + return YES; + } + } + + if (!serverVisible) + return NO; + } + + memset(&xe, 0, sizeof(xe)); + + // If the mouse is not on the valid X display area, + // we don't send the X server key events. + onScreen = [self getMousePosition:&xe]; + + switch (type) { + case NSLeftMouseUp: + if (quartzRootless && !mouse1Pressed) { + // MouseUp after MouseDown in menu - ignore + return NO; + } + mouse1Pressed = NO; + xe.u.u.type = ButtonRelease; + xe.u.u.detail = 1; + break; + case NSLeftMouseDown: + if (quartzRootless && + ! ([anEvent window] && + [[anEvent window] isKindOfClass:windowClass])) { + // Click in non X window - ignore + return NO; + } + mouse1Pressed = YES; + xe.u.u.type = ButtonPress; + xe.u.u.detail = 1; + break; + case NSMouseMoved: + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: + xe.u.u.type = MotionNotify; + break; + case NSSystemDefined: + { + long hwButtons = [anEvent data2]; + + if (![anEvent subtype]==7) + return NO; // we only use multibutton mouse events + if (mouseState == hwButtons) + return NO; // ignore double events + mouseState = hwButtons; + + xe.u.u.type = kXDarwinUpdateButtons; + xe.u.clientMessage.u.l.longs0 = [anEvent data1]; + xe.u.clientMessage.u.l.longs1 =[anEvent data2]; + break; + } + case NSScrollWheel: + xe.u.u.type = kXDarwinScrollWheel; + xe.u.clientMessage.u.s.shorts0 = [anEvent deltaY]; + break; + case NSKeyDown: + case NSKeyUp: + if (!onScreen) + return NO; + if (type == NSKeyDown) + xe.u.u.type = KeyPress; + else + xe.u.u.type = KeyRelease; + xe.u.u.detail = [anEvent keyCode]; + break; + case NSFlagsChanged: + xe.u.u.type = kXDarwinUpdateModifiers; + xe.u.clientMessage.u.l.longs0 = flags; + break; + case NSOtherMouseDown: // undocumented MouseDown + case NSOtherMouseUp: // undocumented MouseUp + // Hide these from AppKit to avoid its log messages + return YES; + default: + return NO; + } + + [self sendXEvent:&xe]; + + // Rootless: Send first NSLeftMouseDown to windows and views so window + // ordering can be suppressed. + // Don't pass further events - they (incorrectly?) bring the window + // forward no matter what. + if (quartzRootless && + (type == NSLeftMouseDown || type == NSLeftMouseUp) && + [anEvent clickCount] == 1 && + [[anEvent window] isKindOfClass:windowClass]) + { + return NO; + } + + return YES; +} + +// Return mouse coordinates, inverting y coordinate. +// For rootless mode, the menu bar is treated as not part of the usable +// X display area and the cursor position is adjusted accordingly. +// Returns YES if the cursor is not in the menu bar. +- (BOOL)getMousePosition:(xEvent *)xe +{ + NSPoint pt = [NSEvent mouseLocation]; + + xe->u.keyButtonPointer.rootX = (int)(pt.x); + + if (quartzRootless && NSMouseInRect(pt, aquaMenuBarBox, NO)) { + // mouse in menu bar - tell X11 that it's just below instead + xe->u.keyButtonPointer.rootY = aquaMenuBarHeight; + return NO; + } else { + xe->u.keyButtonPointer.rootY = + NSHeight([[NSScreen mainScreen] frame]) - (int)(pt.y); + return YES; + } +} + +// Append a string to the given enviroment variable ++ (void)append:(NSString*)value toEnv:(NSString*)name +{ + setenv([name cString], + [[[NSString stringWithCString:getenv([name cString])] + stringByAppendingString:value] cString],1); +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + // Block SIGPIPE + // SIGPIPE repeatably killed the (rootless) server when closing a + // dozen xterms in rapid succession. Those SIGPIPEs should have been + // sent to the X server thread, which ignores them, but somehow they + // ended up in this thread instead. + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGPIPE); + // pthread_sigmask not implemented yet + // pthread_sigmask(SIG_BLOCK, &set, NULL); + sigprocmask(SIG_BLOCK, &set, NULL); + } + + if (quartzRootless == -1) { + // The display mode was not set from the command line. + // Show mode pick panel? + if ([Preferences modeWindow]) { + if ([Preferences rootless]) + [startRootlessButton setKeyEquivalent:@"\r"]; + else + [startFullScreenButton setKeyEquivalent:@"\r"]; + [modeWindow makeKeyAndOrderFront:nil]; + } else { + // Otherwise use default mode + quartzRootless = [Preferences rootless]; + [self startX]; + } + } else { + [self startX]; + } +} + +// Start the X server thread and the client process +- (void)startX +{ + NSDictionary *appDictionary; + NSString *appVersion; + + [modeWindow close]; + + // Calculate the height of the menu bar so rootless mode can avoid it + if (quartzRootless) { + aquaMenuBarHeight = NSHeight([[NSScreen mainScreen] frame]) - + NSMaxY([[NSScreen mainScreen] visibleFrame]) - 1; + aquaMenuBarBox = + NSMakeRect(0, NSMaxY([[NSScreen mainScreen] visibleFrame]) + 1, + NSWidth([[NSScreen mainScreen] frame]), + aquaMenuBarHeight); + } + + // Write the XDarwin version to the console log + appDictionary = [[NSBundle mainBundle] infoDictionary]; + appVersion = [appDictionary objectForKey:@"CFBundleShortVersionString"]; + if (appVersion) + NSLog(@"\n%@", appVersion); + else + NSLog(@"No version"); + + // Start the X server thread + [NSThread detachNewThreadSelector:@selector(run) toTarget:self + withObject:nil]; + sendServerEvents = YES; + + // Start the X clients if started from GUI + if (quartzStartClients) { + [self startXClients]; + } + + if (quartzRootless) { + // There is no help window for rootless; just start + [helpWindow close]; + helpWindow = nil; + if ([NSApp isActive]) + [self sendShowHide:YES]; + else + [self sendShowHide:NO]; + } else { + // Show the X switch window if not using dock icon switching + if (![Preferences dockSwitch]) + [switchWindow orderFront:nil]; + + if ([Preferences startupHelp]) { + // display the full screen mode help + [self sendShowHide:NO]; + [helpWindow makeKeyAndOrderFront:nil]; + } else { + // start running full screen and make sure X is visible + ShowMenuBar(); + [self closeHelpAndShow:nil]; + } + } +} + +// Start the first X clients in a separate process +- (BOOL)startXClients +{ + struct passwd *passwdUser; + NSString *shellPath, *dashShellName, *commandStr, *startXPath; + NSMutableString *safeStartXPath; + NSRange aRange; + NSBundle *thisBundle; + const char *shellPathStr, *newargv[3], *shellNameStr; + int fd[2], outFD, length, shellType, i; + + // Register to catch the signal when the client processs finishes + signal(SIGCHLD, childDone); + + // Get user's password database entry + passwdUser = getpwuid(getuid()); + + // Find the shell to use + if ([Preferences useDefaultShell]) + shellPath = [NSString stringWithCString:passwdUser->pw_shell]; + else + shellPath = [Preferences shellString]; + + dashShellName = [NSString stringWithFormat:@"-%@", + [shellPath lastPathComponent]]; + shellPathStr = [shellPath cString]; + shellNameStr = [[shellPath lastPathComponent] cString]; + + if (access(shellPathStr, X_OK)) { + NSLog(@"Shell %s is not valid!", shellPathStr); + return NO; + } + + // Find the type of shell + for (i = 0; shellList[i].name; i++) { + if (!strcmp(shellNameStr, shellList[i].name)) + break; + } + shellType = shellList[i].type; + + newargv[0] = [dashShellName cString]; + if (shellType == shell_Bourne) { + // Bourne shells need to be told they are interactive to make + // sure they read all their initialization files. + newargv[1] = "-i"; + newargv[2] = NULL; + } else { + newargv[1] = NULL; + } + + // Create a pipe to communicate with the X client process + NSAssert(pipe(fd) == 0, @"Could not create new pipe."); + + // Open a file descriptor for writing to stdout and stderr + outFD = open("/dev/console", O_WRONLY, 0); + if (outFD == -1) { + outFD = open("/dev/null", O_WRONLY, 0); + NSAssert(outFD != -1, @"Could not open shell output."); + } + + // Fork process to start X clients in user's default shell + // Sadly we can't use NSTask because we need to start a login shell. + // Login shells are started by passing "-" as the first character of + // argument 0. NSTask forces argument 0 to be the shell's name. + clientPID = vfork(); + if (clientPID == 0) { + + // Inside the new process: + if (fd[0] != STDIN_FILENO) { + dup2(fd[0], STDIN_FILENO); // Take stdin from pipe + close(fd[0]); + } + close(fd[1]); // Close write end of pipe + if (outFD == STDOUT_FILENO) { // Setup stdout and stderr + dup2(outFD, STDERR_FILENO); + } else if (outFD == STDERR_FILENO) { + dup2(outFD, STDOUT_FILENO); + } else { + dup2(outFD, STDERR_FILENO); + dup2(outFD, STDOUT_FILENO); + close(outFD); + } + + // Setup environment + setenv("HOME", passwdUser->pw_dir, 1); + setenv("SHELL", shellPathStr, 1); + setenv("LOGNAME", passwdUser->pw_name, 1); + setenv("USER", passwdUser->pw_name, 1); + setenv("TERM", "unknown", 1); + if (chdir(passwdUser->pw_dir)) // Change to user's home dir + NSLog(@"Could not change to user's home directory."); + + execv(shellPathStr, (char * const *)newargv); // Start user's shell + + NSLog(@"Could not start X client process with errno = %i.", errno); + _exit(127); + } + + // In parent process: + close(fd[0]); // Close read end of pipe + close(outFD); // Close output file descriptor + + thisBundle = [NSBundle bundleForClass:[self class]]; + startXPath = [thisBundle pathForResource:@"startXClients" ofType:nil]; + if (!startXPath) { + NSLog(@"Could not find startXClients in application bundle!"); + return NO; + } + + // We will run the startXClients script with the path in single quotes + // in case there are problematic characters in the path. We still have + // to worry about there being single quotes in the path. So, replace + // all instances of the ' character in startXPath with '\''. + safeStartXPath = [NSMutableString stringWithString:startXPath]; + aRange = NSMakeRange(0, [safeStartXPath length]); + while (aRange.length) { + aRange = [safeStartXPath rangeOfString:@"'" options:0 range:aRange]; + if (!aRange.length) + break; + [safeStartXPath replaceCharactersInRange:aRange + withString:@"\'\\'\'"]; + aRange.location += 4; + aRange.length = [safeStartXPath length] - aRange.location; + } + + if ([Preferences addToPath]) { + commandStr = [NSString stringWithFormat:@"'%@' :%d %@\n", + safeStartXPath, [Preferences display], + [Preferences addToPathString]]; + } else { + commandStr = [NSString stringWithFormat:@"'%@' :%d\n", + safeStartXPath, [Preferences display]]; + } + + length = [commandStr cStringLength]; + if (write(fd[1], [commandStr cString], length) != length) { + NSLog(@"Write to X client process failed."); + return NO; + } + + // Close the pipe so that shell will terminate when xinit quits + close(fd[1]); + + return YES; +} + +// Run the X server thread +- (void)run +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [serverLock lock]; + main(argcGlobal, argvGlobal, envpGlobal); + serverVisible = NO; + [pool release]; + [serverLock unlock]; + QuartzMessageMainThread(kQuartzServerDied, nil, 0); +} + +// Full screen mode was picked in the mode pick panel +- (IBAction)startFullScreen:(id)sender +{ + [Preferences setModeWindow:[startupModeButton intValue]]; + [Preferences saveToDisk]; + quartzRootless = FALSE; + [self startX]; +} + +// Rootless mode was picked in the mode pick panel +- (IBAction)startRootless:(id)sender +{ + [Preferences setModeWindow:[startupModeButton intValue]]; + [Preferences saveToDisk]; + quartzRootless = TRUE; + [self startX]; +} + +// Close the help splash screen and show the X server +- (IBAction)closeHelpAndShow:(id)sender +{ + if (sender) { + int helpVal = [startupHelpButton intValue]; + [Preferences setStartupHelp:helpVal]; + [Preferences saveToDisk]; + } + [helpWindow close]; + helpWindow = nil; + + serverVisible = YES; + [self sendShowHide:YES]; + [NSApp activateIgnoringOtherApps:YES]; +} + +// Show the X server when sent message from GUI +- (IBAction)showAction:(id)sender +{ + if (sendServerEvents) + [self sendShowHide:YES]; +} + +// Show or hide the X server or menu bar in rootless mode +- (void)toggle +{ + if (quartzRootless) { +#if 0 + // FIXME: Remove or add option to not dodge menubar + if (rootlessMenuBarVisible) + HideMenuBar(); + else + ShowMenuBar(); + rootlessMenuBarVisible = !rootlessMenuBarVisible; +#endif + } else { + if (serverVisible) + [self hide]; + else + [self show]; + } +} + +// Show the X server on screen +- (void)show +{ + if (!serverVisible && sendServerEvents) { + [self sendShowHide:YES]; + } +} + +// Hide the X server from the screen +- (void)hide +{ + if (serverVisible && sendServerEvents) { + [self sendShowHide:NO]; + } +} + +// Kill the X server thread +- (void)killServer +{ + xEvent xe; + + if (serverVisible) + [self hide]; + + xe.u.u.type = kXDarwinQuit; + [self sendXEvent:&xe]; +} + +// Tell the X server to show or hide itself. +// This ignores the current X server visible state. +// +// In full screen mode, the order we do things is important and must be +// preserved between the threads. X drawing operations have to be performed +// in the X server thread. It appears that we have the additional +// constraint that we must hide and show the menu bar in the main thread. +// +// To show the X server: +// 1. Capture the displays. (Main thread) +// 2. Hide the menu bar. (Must be in main thread) +// 3. Send event to X server thread to redraw X screen. +// 4. Redraw the X screen. (Must be in X server thread) +// +// To hide the X server: +// 1. Send event to X server thread to stop drawing. +// 2. Stop drawing to the X screen. (Must be in X server thread) +// 3. Message main thread that drawing is stopped. +// 4. If main thread still wants X server hidden: +// a. Release the displays. (Main thread) +// b. Unhide the menu bar. (Must be in main thread) +// Otherwise we have already queued an event to start drawing again. +// +- (void)sendShowHide:(BOOL)show +{ + xEvent xe; + + [self getMousePosition:&xe]; + + if (show) { + if (!quartzRootless) { + QuartzFSCapture(); + HideMenuBar(); + } + xe.u.u.type = kXDarwinShow; + [self sendXEvent:&xe]; + + // the mouse location will have moved; track it + xe.u.u.type = MotionNotify; + [self sendXEvent:&xe]; + + // inform the X server of the current modifier state + xe.u.u.type = kXDarwinUpdateModifiers; + xe.u.clientMessage.u.l.longs0 = [[NSApp currentEvent] modifierFlags]; + [self sendXEvent:&xe]; + + // put the pasteboard into the X cut buffer + [self readPasteboard]; + } else { + // put the X cut buffer on the pasteboard + [self writePasteboard]; + + xe.u.u.type = kXDarwinHide; + [self sendXEvent:&xe]; + } + + serverVisible = show; +} + +// Tell the X server to read from the pasteboard into the X cut buffer +- (void)readPasteboard +{ + xEvent xe; + + xe.u.u.type = kXDarwinReadPasteboard; + [self sendXEvent:&xe]; +} + +// Tell the X server to write the X cut buffer into the pasteboard +- (void)writePasteboard +{ + xEvent xe; + + xe.u.u.type = kXDarwinWritePasteboard; + [self sendXEvent:&xe]; +} + +- (void)sendXEvent:(xEvent *)xe +{ + // This field should be filled in for every event + xe->u.keyButtonPointer.time = GetTimeInMillis(); + +#if 0 + // FIXME: Really? + if (quartzRootless && + (ev->type == NSLeftMouseDown || ev->type == NSLeftMouseUp || + (ev->type == NSSystemDefined && ev->data.compound.subType == 7))) + { + // mouse button event - send mouseMoved to this position too + // X gets confused if it gets a click that isn't at the last + // reported mouse position. + xEvent moveEvent = *ev; + xe.u.u.type = NSMouseMoved; + [self sendXEvent:&moveEvent]; + } +#endif + + ENQUEUE(xe); +} + +// Handle messages from the X server thread +- (void)handlePortMessage:(NSPortMessage *)portMessage +{ + unsigned msg = [portMessage msgid]; + + switch(msg) { + case kQuartzServerHidden: + // Make sure the X server wasn't queued to be shown again while + // the hide was pending. + if (!quartzRootless && !serverVisible) { + QuartzFSRelease(); + ShowMenuBar(); + } + + // FIXME: This hack is necessary (but not completely effective) + // since Mac OS X 10.0.2 + [NSCursor unhide]; + break; + + case kQuartzServerDied: + sendServerEvents = NO; + if (!appQuitting) { + [NSApp terminate:nil]; // quit if we aren't already + } + break; + + case kQuartzPostEvent: + { + const xEvent *xe = [[[portMessage components] lastObject] bytes]; + ENQUEUE(xe); + break; + } + + default: + NSLog(@"Unknown message from server thread."); + } +} + +// Quit the X server when the X client process finishes +- (void)clientProcessDone:(int)clientStatus +{ + if (WIFEXITED(clientStatus)) { + int exitStatus = WEXITSTATUS(clientStatus); + if (exitStatus != 0) + NSLog(@"X client process terminated with status %i.", exitStatus); + } else { + NSLog(@"X client process terminated abnormally."); + } + + if (!appQuitting) { + [NSApp terminate:nil]; // quit if we aren't already + } +} + +// Called when the user clicks the application icon, +// but not when Cmd-Tab is used. +// Rootless: Don't switch until applicationWillBecomeActive. +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication + hasVisibleWindows:(BOOL)flag +{ + if ([Preferences dockSwitch] && !quartzRootless) { + [self show]; + } + return NO; +} + +- (void)applicationWillResignActive:(NSNotification *)aNotification +{ + [self hide]; +} + +- (void)applicationWillBecomeActive:(NSNotification *)aNotification +{ + if (quartzRootless) + [self show]; +} + +@end + + +// Send a message to the main thread, which calls handlePortMessage in +// response. Must only be called from the X server thread because +// NSPort is not thread safe. +void QuartzMessageMainThread(unsigned msg, void *data, unsigned length) +{ + if (msg == kQuartzPostEvent) { + NSData *eventData = [NSData dataWithBytes:data length:length]; + NSArray *eventArray = [NSArray arrayWithObject:eventData]; + NSPortMessage *newMessage = + [[NSPortMessage alloc] + initWithSendPort:signalPort + receivePort:returnPort components:eventArray]; + [newMessage setMsgid:msg]; + [newMessage sendBeforeDate:[NSDate distantPast]]; + [newMessage release]; + } else { + [signalMessage setMsgid:msg]; + [signalMessage sendBeforeDate:[NSDate distantPast]]; + } +} + +// Handle SIGCHLD signals +static void childDone(int sig) +{ + int clientStatus; + + if (clientPID == 0) + return; + + // Make sure it was the client task that finished + if (waitpid(clientPID, &clientStatus, WNOHANG) == clientPID) { + if (WIFSTOPPED(clientStatus)) + return; + clientPID = 0; + [oneXServer clientProcessDone:clientStatus]; + } +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/XView.h b/xc/programs/Xserver/hw/darwin/quartz/XView.h new file mode 100644 index 000000000..01f5b04b4 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XView.h @@ -0,0 +1,42 @@ +/* + * NSView subclass for Mac OS X rootless X server + * + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XView.h,v 1.2 2002/07/15 19:58:31 torrey Exp $ */ + +#import <Cocoa/Cocoa.h> + +@interface XView : NSQuickDrawView + +- (BOOL)isFlipped; +- (BOOL)isOpaque; +- (BOOL)acceptsFirstResponder; +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent; +- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent; + +- (void)mouseDown:(NSEvent *)anEvent; + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz/XView.m b/xc/programs/Xserver/hw/darwin/quartz/XView.m new file mode 100644 index 000000000..5146ff185 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/XView.m @@ -0,0 +1,76 @@ +/* + * NSView subclass for Mac OS X rootless X server + * + * Each rootless window contains an instance of this class. + * This class handles events while drawing is handled by Carbon + * code in the rootless Aqua implementation. + * + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/XView.m,v 1.2 2002/07/15 19:58:31 torrey Exp $ */ + +#import "XView.h" + + +@implementation XView + +- (BOOL)isFlipped +{ + return NO; +} + +- (BOOL)isOpaque +{ + return YES; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent +{ + return YES; +} + +- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent +{ + return YES; +} + +- (void)mouseDown:(NSEvent *)anEvent +{ + // Only X is allowed to restack windows. + [NSApp preventWindowOrdering]; + if (! [NSApp isActive]) { + [NSApp activateIgnoringOtherApps:YES]; + // FIXME: Interleaving with other apps would be nice, but has issues. + [NSApp arrangeInFront:nil]; + } + [[self nextResponder] mouseDown:anEvent]; +} + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz/aqua.h b/xc/programs/Xserver/hw/darwin/quartz/aqua.h new file mode 100644 index 000000000..35adf2256 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/aqua.h @@ -0,0 +1,53 @@ +/* + * Rootless implementation for the Mac OS X Aqua environment + */ +/* + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/aqua.h,v 1.2 2002/07/24 05:58:33 torrey Exp $ */ + +#ifndef _AQUA_H +#define _AQUA_H + +#include "picturestr.h" + +void AquaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what); + +#ifdef RENDER +void +AquaComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); +#endif /* RENDER */ + + +/* + * AquaAlphaMask + * Bit mask for alpha channel with a particular number of bits per pixel (bpp) + */ +#define AquaAlphaMask(bpp) ((((Pixel) 1 << (bpp >> 2))-1) << \ + (bpp - (bpp >> 2))) + +#endif /* _AQUA_H */ diff --git a/xc/programs/Xserver/hw/darwin/quartz/aquaCommon.h b/xc/programs/Xserver/hw/darwin/quartz/aquaCommon.h new file mode 100644 index 000000000..a6618197a --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/aquaCommon.h @@ -0,0 +1,56 @@ +/* + * Common internal definitions and code of the rootless implementation + * for the Mac OS X Aqua environment + */ +/* + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ + +#ifndef _AQUACOMMON_H +#define _AQUACOMMON_H + +#include "quartzCommon.h" + +#ifdef __OBJC__ +#undef BOOL +#import <Cocoa/Cocoa.h> +#import "XView.h" +#else +typedef struct OpaqueNSWindow NSWindow; +typedef struct OpaqueXView XView; +#endif + + +typedef struct { + NSWindow *window; + XView *view; + GrafPtr port; + CGContextRef context; + GWorldPtr rootGWorld; +} AquaWindowRec; + +#define AQUA_WINREC(rw) ((AquaWindowRec *)rw) + +#endif /* _AQUACOMMON_H */
\ No newline at end of file diff --git a/xc/programs/Xserver/hw/darwin/quartz/aquaPicture.c b/xc/programs/Xserver/hw/darwin/quartz/aquaPicture.c new file mode 100644 index 000000000..1d5fa7d44 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/aquaPicture.c @@ -0,0 +1,268 @@ +/* + * Support for RENDER extension with rootless Aqua + */ +/* + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* This file is largely based on fbcompose.c and fbpict.c, which contain + * the following copyright: + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + */ + /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/aquaPicture.c,v 1.3 2002/09/28 00:00:03 torrey Exp $ */ + +#ifdef RENDER + +#include "fb.h" +#include "picturestr.h" +#include "mipict.h" +#include "fbpict.h" +#include "aqua.h" + +# define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b)) + + +// Replacement for fbStore_x8r8g8b8 that sets the Aqua alpha channel +void +AquaStore_x8r8g8b8 (FbCompositeOperand *op, CARD32 value) +{ + FbBits *line = op->u.drawable.line; CARD32 offset = op->u.drawable.offset; + ((CARD32 *)line)[offset >> 5] = (value & 0xffffff) | 0xff000000; +} + + +// Defined in fbcompose.c +extern FbCombineFunc fbCombineFuncU[]; +extern FbCombineFunc fbCombineFuncC[]; + +void +AquaCompositeGeneral( + CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + FbCompositeOperand src[4],msk[4],dst[4],*pmsk; + FbCompositeOperand *srcPict, *srcAlpha; + FbCompositeOperand *dstPict, *dstAlpha; + FbCompositeOperand *mskPict = 0, *mskAlpha = 0; + FbCombineFunc f; + int w; + + if (!fbBuildCompositeOperand (pSrc, src, xSrc, ySrc, TRUE, TRUE)) + return; + if (!fbBuildCompositeOperand (pDst, dst, xDst, yDst, FALSE, TRUE)) + return; + + // Use Aqua operands for on screen picture formats + if (pDst->format == PICT_x8r8g8b8) { + dst[0].store = AquaStore_x8r8g8b8; + } + + if (pSrc->alphaMap) + { + srcPict = &src[1]; + srcAlpha = &src[2]; + } + else + { + srcPict = &src[0]; + srcAlpha = 0; + } + if (pDst->alphaMap) + { + dstPict = &dst[1]; + dstAlpha = &dst[2]; + } + else + { + dstPict = &dst[0]; + dstAlpha = 0; + } + f = fbCombineFuncU[op]; + if (pMask) + { + if (!fbBuildCompositeOperand (pMask, msk, xMask, yMask, TRUE, TRUE)) + return; + pmsk = msk; + if (pMask->componentAlpha) + f = fbCombineFuncC[op]; + if (pMask->alphaMap) + { + mskPict = &msk[1]; + mskAlpha = &msk[2]; + } + else + { + mskPict = &msk[0]; + mskAlpha = 0; + } + } + else + pmsk = 0; + while (height--) + { + w = width; + + while (w--) + { + (*f) (src, pmsk, dst); + (*src->over) (src); + (*dst->over) (dst); + if (pmsk) + (*pmsk->over) (pmsk); + } + (*src->down) (src); + (*dst->down) (dst); + if (pmsk) + (*pmsk->down) (pmsk); + } +} + + +void +AquaComposite( + CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + RegionRec region; + int n; + BoxPtr pbox; + CompositeFunc func; + Bool srcRepeat = pSrc->repeat; + Bool maskRepeat = FALSE; + Bool maskAlphaMap = FALSE; + int x_msk, y_msk, x_src, y_src, x_dst, y_dst; + int w, h, w_this, h_this; + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + if (pMask) + { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + maskRepeat = pMask->repeat; + maskAlphaMap = pMask->alphaMap != 0; + } + + if (!miComputeCompositeRegion (®ion, + pSrc, + pMask, + pDst, + xSrc, + ySrc, + xMask, + yMask, + xDst, + yDst, + width, + height)) + return; + + // To preserve the alpha channel we only use a special, + // non-optimzied compositor. + func = AquaCompositeGeneral; + + n = REGION_NUM_RECTS (®ion); + pbox = REGION_RECTS (®ion); + while (n--) + { + h = pbox->y2 - pbox->y1; + y_src = pbox->y1 - yDst + ySrc; + y_msk = pbox->y1 - yDst + yMask; + y_dst = pbox->y1; + while (h) + { + h_this = h; + w = pbox->x2 - pbox->x1; + x_src = pbox->x1 - xDst + xSrc; + x_msk = pbox->x1 - xDst + xMask; + x_dst = pbox->x1; + if (maskRepeat) + { + y_msk = mod (y_msk, pMask->pDrawable->height); + if (h_this > pMask->pDrawable->height - y_msk) + h_this = pMask->pDrawable->height - y_msk; + } + if (srcRepeat) + { + y_src = mod (y_src, pSrc->pDrawable->height); + if (h_this > pSrc->pDrawable->height - y_src) + h_this = pSrc->pDrawable->height - y_src; + } + while (w) + { + w_this = w; + if (maskRepeat) + { + x_msk = mod (x_msk, pMask->pDrawable->width); + if (w_this > pMask->pDrawable->width - x_msk) + w_this = pMask->pDrawable->width - x_msk; + } + if (srcRepeat) + { + x_src = mod (x_src, pSrc->pDrawable->width); + if (w_this > pSrc->pDrawable->width - x_src) + w_this = pSrc->pDrawable->width - x_src; + } + (*func) (op, pSrc, pMask, pDst, + x_src, y_src, x_msk, y_msk, x_dst, y_dst, + w_this, h_this); + w -= w_this; + x_src += w_this; + x_msk += w_this; + x_dst += w_this; + } + h -= h_this; + y_src += h_this; + y_msk += h_this; + y_dst += h_this; + } + pbox++; + } + REGION_UNINIT (pDst->pDrawable->pScreen, ®ion); +} + +#endif /* RENDER */ diff --git a/xc/programs/Xserver/hw/darwin/quartz/aquaWindow.c b/xc/programs/Xserver/hw/darwin/quartz/aquaWindow.c new file mode 100644 index 000000000..8addd5e1b --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/aquaWindow.c @@ -0,0 +1,171 @@ +/* + * Specialized window functions for rootless Aqua + */ +/* + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* Portions of this file are based on fbwindow.c, which contains the + * following copyright: + * + * Copyright © 1998 Keith Packard + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/aquaWindow.c,v 1.1 2002/07/24 05:58:33 torrey Exp $ */ + +#include "fb.h" +#include "aqua.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +/* + * AquaFillRegionTiled + * Fill using a tile while leaving the alpha channel untouched. + * Based on fbfillRegionTiled. + */ +void +AquaFillRegionTiled( + DrawablePtr pDrawable, + RegionPtr pRegion, + PixmapPtr pTile) +{ + FbBits *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + FbBits *tile; + FbStride tileStride; + int tileBpp; + int tileXoff, tileYoff; /* XXX assumed to be zero */ + int tileWidth, tileHeight; + int n = REGION_NUM_RECTS(pRegion); + BoxPtr pbox = REGION_RECTS(pRegion); + int xRot = pDrawable->x; + int yRot = pDrawable->y; + FbBits planeMask; + +#ifdef PANORAMIX + if(!noPanoramiXExtension) + { + int index = pDrawable->pScreen->myNum; + if(&WindowTable[index]->drawable == pDrawable) + { + xRot -= panoramiXdataPtr[index].x; + yRot -= panoramiXdataPtr[index].y; + } + } +#endif + fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + fbGetDrawable (&pTile->drawable, tile, tileStride, tileBpp, + tileXoff, tileYoff); + tileWidth = pTile->drawable.width; + tileHeight = pTile->drawable.height; + planeMask = FB_ALLONES & ~AquaAlphaMask(dstBpp); + + while (n--) + { + fbTile (dst + (pbox->y1 + dstYoff) * dstStride, + dstStride, + (pbox->x1 + dstXoff) * dstBpp, + (pbox->x2 - pbox->x1) * dstBpp, + pbox->y2 - pbox->y1, + tile, + tileStride, + tileWidth * dstBpp, + tileHeight, + GXcopy, + planeMask, + dstBpp, + xRot * dstBpp, + yRot - pbox->y1); + pbox++; + } +} + + +/* + * AquaPaintWindow + * Paint the window while filling in the alpha channel with all on. + * We can't use fbPaintWindow because it zeros the alpha channel. + */ +void +AquaPaintWindow( + WindowPtr pWin, + RegionPtr pRegion, + int what) +{ + switch (what) { + case PW_BACKGROUND: + + switch (pWin->backgroundState) { + case None: + break; + case ParentRelative: + do { + pWin = pWin->parent; + } while (pWin->backgroundState == ParentRelative); + (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion, + what); + break; + case BackgroundPixmap: + AquaFillRegionTiled (&pWin->drawable, + pRegion, + pWin->background.pixmap); + break; + case BackgroundPixel: + { + Pixel pixel = pWin->background.pixel | + AquaAlphaMask(pWin->drawable.bitsPerPixel); + fbFillRegionSolid (&pWin->drawable, pRegion, 0, + fbReplicatePixel (pixel, + pWin->drawable.bitsPerPixel)); + break; + } + } + break; + case PW_BORDER: + if (pWin->borderIsPixel) + { + Pixel pixel = pWin->border.pixel | + AquaAlphaMask(pWin->drawable.bitsPerPixel); + fbFillRegionSolid (&pWin->drawable, pRegion, 0, + fbReplicatePixel (pixel, + pWin->drawable.bitsPerPixel)); + } + else + { + WindowPtr pBgWin; + for (pBgWin = pWin; pBgWin->backgroundState == ParentRelative; + pBgWin = pBgWin->parent); + + AquaFillRegionTiled (&pBgWin->drawable, + pRegion, + pWin->border.pixmap); + } + break; + } + fbValidateDrawable (&pWin->drawable); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/fakeBoxRec.h b/xc/programs/Xserver/hw/darwin/quartz/fakeBoxRec.h new file mode 100644 index 000000000..1629cce4e --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/fakeBoxRec.h @@ -0,0 +1,15 @@ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/fakeBoxRec.h,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +#ifndef FAKEBOXREC_H +#define FAKEBOXREC_H + +// This struct is byte-compatible with X11's BoxRec, for use in +// code that can't include X headers. +typedef struct _fakeBox { + short x1; + short y1; + short x2; + short y2; +} fakeBoxRec; + +#endif diff --git a/xc/programs/Xserver/hw/darwin/quartz/fullscreen.c b/xc/programs/Xserver/hw/darwin/quartz/fullscreen.c new file mode 100644 index 000000000..46b562794 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/fullscreen.c @@ -0,0 +1,444 @@ +/* + * Screen routines for full screen Quartz mode + * + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * TORREY T. LYONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Torrey T. Lyons shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in this Software without prior written authorization from + * Torrey T. Lyons. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/fullscreen.c,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +#include "quartzCommon.h" +#include "darwin.h" +#include "colormapst.h" +#include "scrnintstr.h" +#include "micmap.h" + +// Full screen specific per screen storage structure +typedef struct { + CGDirectDisplayID displayID; + CFDictionaryRef xDisplayMode; + CFDictionaryRef aquaDisplayMode; + CGDirectPaletteRef xPalette; + CGDirectPaletteRef aquaPalette; +} QuartzFSScreenRec, *QuartzFSScreenPtr; + +#define FULLSCREEN_PRIV(pScreen) \ + ((QuartzFSScreenPtr)pScreen->devPrivates[quartzFSScreenIndex].ptr) + +static int quartzFSScreenIndex; +static CGDirectDisplayID *quartzDisplayList = NULL; +static int quartzNumScreens = 0; +static QuartzFSScreenPtr quartzScreens[MAXSCREENS]; + +static int darwinCmapPrivateIndex = -1; +static unsigned long darwinCmapGeneration = 0; + +#define CMAP_PRIV(pCmap) \ + ((CGDirectPaletteRef) (pCmap)->devPrivates[darwinCmapPrivateIndex].ptr) + +/* + ============================================================================= + + Colormap handling + + ============================================================================= +*/ + +/* + * QuartzFSInitCmapPrivates + * Colormap privates may be allocated after the default colormap has + * already been created for some screens. This initialization procedure + * is called for each default colormap that is found. + */ +static Bool +QuartzFSInitCmapPrivates( + ColormapPtr pCmap) +{ + return TRUE; +} + + +/* + * QuartzFSCreateColormap + * This is a callback from X after a new colormap is created. + * We allocate a new CoreGraphics pallete for each colormap. + */ +Bool +QuartzFSCreateColormap( + ColormapPtr pCmap) +{ + CGDirectPaletteRef pallete; + + // Allocate private storage for the hardware dependent colormap info. + if (darwinCmapGeneration != serverGeneration) { + if ((darwinCmapPrivateIndex = + AllocateColormapPrivateIndex(QuartzFSInitCmapPrivates)) < 0) + { + return FALSE; + } + darwinCmapGeneration = serverGeneration; + } + + pallete = CGPaletteCreateDefaultColorPalette(); + if (!pallete) return FALSE; + + CMAP_PRIV(pCmap) = pallete; + return TRUE; +} + + +/* + * QuartzFSDestroyColormap + * This is called by DIX FreeColormap after it has uninstalled a colormap + * and notified all interested parties. We deallocated the corresponding + * CoreGraphics pallete. + */ +void +QuartzFSDestroyColormap( + ColormapPtr pCmap) +{ + CGPaletteRelease( CMAP_PRIV(pCmap) ); +} + + +/* + * QuartzFSInstallColormap + * Set the current CoreGraphics pallete to the pallete corresponding + * to the provided colormap. + */ +void +QuartzFSInstallColormap( + ColormapPtr pCmap) +{ + CGDirectPaletteRef palette = CMAP_PRIV(pCmap); + ScreenPtr pScreen = pCmap->pScreen; + QuartzFSScreenPtr fsDisplayInfo = FULLSCREEN_PRIV(pScreen); + + // Inform all interested parties that the map is being changed. + miInstallColormap(pCmap); + + if (quartzServerVisible) + CGDisplaySetPalette(fsDisplayInfo->displayID, palette); + + fsDisplayInfo->xPalette = palette; +} + + +/* + * QuartzFSStoreColors + * This is a callback from X to change the hardware colormap + * when using PsuedoColor in full screen mode. + */ +static void +QuartzFSStoreColors( + ColormapPtr pCmap, + int numEntries, + xColorItem *pdefs) +{ + CGDirectPaletteRef palette = CMAP_PRIV(pCmap); + ScreenPtr pScreen = pCmap->pScreen; + QuartzFSScreenPtr fsDisplayInfo = FULLSCREEN_PRIV(pScreen); + CGDeviceColor color; + int i; + + if (! palette) + return; + + for (i = 0; i < numEntries; i++) { + color.red = pdefs[i].red / 65535.0; + color.green = pdefs[i].green / 65535.0; + color.blue = pdefs[i].blue / 65535.0; + CGPaletteSetColorAtIndex(palette, color, pdefs[i].pixel); + } + + // Update hardware colormap + if (quartzServerVisible) + CGDisplaySetPalette(fsDisplayInfo->displayID, palette); +} + + +/* + ============================================================================= + + Screen initialization + + ============================================================================= +*/ + +/* + * QuartzFSDisplayInit + * Full screen specific initialization called from InitOutput. + */ +void QuartzFSDisplayInit(void) +{ + static unsigned long generation = 0; + CGDisplayCount quartzDisplayCount = 0; + + // Allocate private storage for each screen's mode specific info + if (generation != serverGeneration) { + quartzFSScreenIndex = AllocateScreenPrivateIndex(); + generation = serverGeneration; + } + + // Find all the CoreGraphics displays + CGGetActiveDisplayList(0, NULL, &quartzDisplayCount); + quartzDisplayList = xalloc(quartzDisplayCount * sizeof(CGDirectDisplayID)); + CGGetActiveDisplayList(quartzDisplayCount, quartzDisplayList, + &quartzDisplayCount); + + darwinScreensFound = quartzDisplayCount; + atexit(QuartzFSRelease); +} + + +/* + * QuartzFSFindDisplayMode + * Find the appropriate display mode to use in full screen mode. + * If display mode is not the same as the current Aqua mode, switch + * to the new mode. + */ +static Bool QuartzFSFindDisplayMode( + QuartzFSScreenPtr fsDisplayInfo) +{ + CGDirectDisplayID cgID = fsDisplayInfo->displayID; + size_t height, width, bpp; + boolean_t exactMatch; + + fsDisplayInfo->aquaDisplayMode = CGDisplayCurrentMode(cgID); + + // If no user options, use current display mode + if (darwinDesiredWidth == 0 && darwinDesiredDepth == -1 && + darwinDesiredRefresh == -1) + { + fsDisplayInfo->xDisplayMode = fsDisplayInfo->aquaDisplayMode; + return TRUE; + } + + // If the user has no choice for size, use current + if (darwinDesiredWidth == 0) { + width = CGDisplayPixelsWide(cgID); + height = CGDisplayPixelsHigh(cgID); + } else { + width = darwinDesiredWidth; + height = darwinDesiredHeight; + } + + switch (darwinDesiredDepth) { + case 0: + bpp = 8; + break; + case 1: + bpp = 16; + break; + case 2: + bpp = 32; + break; + default: + bpp = CGDisplayBitsPerPixel(cgID); + } + + if (darwinDesiredRefresh == -1) { + fsDisplayInfo->xDisplayMode = + CGDisplayBestModeForParameters(cgID, bpp, width, height, + &exactMatch); + } else { + fsDisplayInfo->xDisplayMode = + CGDisplayBestModeForParametersAndRefreshRate(cgID, bpp, + width, height, darwinDesiredRefresh, &exactMatch); + } + if (!exactMatch) { + fsDisplayInfo->xDisplayMode = fsDisplayInfo->aquaDisplayMode; + return FALSE; + } + + // Switch to the new display mode + CGDisplaySwitchToMode(cgID, fsDisplayInfo->xDisplayMode); + return TRUE; +} + + +/* + * QuartzFSAddScreen + * Do initialization of each screen for Quartz in full screen mode. + */ +Bool QuartzFSAddScreen( + int index, + ScreenPtr pScreen) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + QuartzScreenPtr displayInfo = QUARTZ_PRIV(pScreen); + CGDirectDisplayID cgID = quartzDisplayList[index]; + CGRect bounds; + QuartzFSScreenPtr fsDisplayInfo; + + // Allocate space for private per screen fullscreen specific storage. + fsDisplayInfo = xalloc(sizeof(QuartzFSScreenRec)); + FULLSCREEN_PRIV(pScreen) = fsDisplayInfo; + + displayInfo->displayCount = 1; + displayInfo->displayIDs = xrealloc(displayInfo->displayIDs, + 1 * sizeof(CGDirectDisplayID)); + displayInfo->displayIDs[0] = cgID; + + fsDisplayInfo->displayID = cgID; + fsDisplayInfo->xDisplayMode = 0; + fsDisplayInfo->aquaDisplayMode = 0; + fsDisplayInfo->xPalette = 0; + fsDisplayInfo->aquaPalette = 0; + + // Capture full screen because X doesn't like read-only framebuffer. + // We need to do this before we (potentially) switch the display mode. + CGDisplayCapture(cgID); + + if (! QuartzFSFindDisplayMode(fsDisplayInfo)) { + ErrorF("Could not support specified display mode on screen %i.\n", + index); + xfree(fsDisplayInfo); + return FALSE; + } + + // Don't need to flip y-coordinate as CoreGraphics treats (0, 0) + // as the top left of main screen. + bounds = CGDisplayBounds(cgID); + dfb->x = bounds.origin.x; + dfb->y = bounds.origin.y; + dfb->width = bounds.size.width; + dfb->height = bounds.size.height; + dfb->pitch = CGDisplayBytesPerRow(cgID); + dfb->bitsPerPixel = CGDisplayBitsPerPixel(cgID); + dfb->pixelInfo.componentCount = CGDisplaySamplesPerPixel(cgID); + + if (dfb->bitsPerPixel == 8) { + if (CGDisplayCanSetPalette(cgID)) { + dfb->pixelInfo.pixelType = kIOCLUTPixels; + } else { + dfb->pixelInfo.pixelType = kIOFixedCLUTPixels; + } + dfb->pixelInfo.bitsPerComponent = 8; + dfb->colorBitsPerPixel = 8; + } else { + dfb->pixelInfo.pixelType = kIORGBDirectPixels; + dfb->pixelInfo.bitsPerComponent = CGDisplayBitsPerSample(cgID); + dfb->colorBitsPerPixel = (dfb->pixelInfo.componentCount * + dfb->pixelInfo.bitsPerComponent); + } + + dfb->framebuffer = CGDisplayBaseAddress(cgID); + + return TRUE; +} + + +/* + * QuartzFSSetupScreen + * Finalize full screen specific setup of each screen. + */ +Bool QuartzFSSetupScreen( + int index, + ScreenPtr pScreen) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + QuartzFSScreenPtr fsDisplayInfo = FULLSCREEN_PRIV(pScreen); + CGDirectDisplayID cgID = fsDisplayInfo->displayID; + + if (dfb->pixelInfo.pixelType == kIOCLUTPixels) { + // Initialize colormap handling + size_t aquaBpp; + + // If Aqua is using 8 bits we need to keep track of its pallete. + CFNumberGetValue(CFDictionaryGetValue(fsDisplayInfo->aquaDisplayMode, + kCGDisplayBitsPerPixel), kCFNumberLongType, &aquaBpp); + if (aquaBpp <= 8) + fsDisplayInfo->aquaPalette = CGPaletteCreateWithDisplay(cgID); + + pScreen->CreateColormap = QuartzFSCreateColormap; + pScreen->DestroyColormap = QuartzFSDestroyColormap; + pScreen->InstallColormap = QuartzFSInstallColormap; + pScreen->StoreColors = QuartzFSStoreColors; + + } + + quartzScreens[quartzNumScreens++] = fsDisplayInfo; + return TRUE; +} + + +/* + ============================================================================= + + Switching between Aqua and X + + ============================================================================= +*/ + +/* + * QuartzFSCapture + * Capture the screen so we can draw. Called directly from the main thread + * to synchronize with hiding the menubar. + */ +void QuartzFSCapture(void) +{ + int i; + + if (quartzRootless) return; + + for (i = 0; i < quartzNumScreens; i++) { + QuartzFSScreenPtr fsDisplayInfo = quartzScreens[i]; + CGDirectDisplayID cgID = fsDisplayInfo->displayID; + + if (!CGDisplayIsCaptured(cgID)) { + CGDisplayCapture(cgID); + fsDisplayInfo->aquaDisplayMode = CGDisplayCurrentMode(cgID); + if (fsDisplayInfo->xDisplayMode != fsDisplayInfo->aquaDisplayMode) + CGDisplaySwitchToMode(cgID, fsDisplayInfo->xDisplayMode); + if (fsDisplayInfo->xPalette) + CGDisplaySetPalette(cgID, fsDisplayInfo->xPalette); + } + } +} + + +/* + * QuartzFSRelease + * Release the screen so others can draw. + */ +void QuartzFSRelease(void) +{ + int i; + + if (quartzRootless) return; + + for (i = 0; i < quartzNumScreens; i++) { + QuartzFSScreenPtr fsDisplayInfo = quartzScreens[i]; + CGDirectDisplayID cgID = fsDisplayInfo->displayID; + + if (CGDisplayIsCaptured(cgID)) { + if (fsDisplayInfo->xDisplayMode != fsDisplayInfo->aquaDisplayMode) + CGDisplaySwitchToMode(cgID, fsDisplayInfo->aquaDisplayMode); + if (fsDisplayInfo->aquaPalette) + CGDisplaySetPalette(cgID, fsDisplayInfo->aquaPalette); + CGDisplayRelease(cgID); + } + } +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/fullscreen.h b/xc/programs/Xserver/hw/darwin/quartz/fullscreen.h new file mode 100644 index 000000000..7cfacbae3 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/fullscreen.h @@ -0,0 +1,33 @@ +/* + * External interface for full screen Quartz mode + * + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * TORREY T. LYONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Torrey T. Lyons shall not + * be used in advertising or otherwise to promote the sale, use or other + * dealings in this Software without prior written authorization from + * Torrey T. Lyons. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/fullscreen.h,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +void QuartzFSDisplayInit(void); +Bool QuartzFSAddScreen(int index, ScreenPtr pScreen); +Bool QuartzFSSetupScreen(int index, ScreenPtr pScreen); diff --git a/xc/programs/Xserver/hw/darwin/quartz/pseudoramiX.c b/xc/programs/Xserver/hw/darwin/quartz/pseudoramiX.c new file mode 100644 index 000000000..e55aabd6f --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/pseudoramiX.c @@ -0,0 +1,420 @@ +/* + * Minimal implementation of PanoramiX/Xinerama + * + * This is used in rootless mode where the underlying window server + * already provides an abstracted view of multiple screens as one + * large screen area. + * + * This code is largely based on panoramiX.c, which contains the + * following copyright notice: + */ +/***************************************************************** +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. +******************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/pseudoramiX.c,v 1.2 2002/10/16 21:13:33 dawes Exp $ */ + +#include "pseudoramiX.h" + +#include "extnsionst.h" +#include "dixstruct.h" +#include "window.h" +#include "panoramiXproto.h" +#include "globals.h" + +extern int ProcPanoramiXQueryVersion (ClientPtr client); + +static void PseudoramiXResetProc(ExtensionEntry *extEntry); + +static int ProcPseudoramiXQueryVersion(ClientPtr client); +static int ProcPseudoramiXGetState(ClientPtr client); +static int ProcPseudoramiXGetScreenCount(ClientPtr client); +static int ProcPseudoramiXGetScreenSize(ClientPtr client); +static int ProcPseudoramiXIsActive(ClientPtr client); +static int ProcPseudoramiXQueryScreens(ClientPtr client); +static int ProcPseudoramiXDispatch(ClientPtr client); + +static int SProcPseudoramiXQueryVersion(ClientPtr client); +static int SProcPseudoramiXGetState(ClientPtr client); +static int SProcPseudoramiXGetScreenCount(ClientPtr client); +static int SProcPseudoramiXGetScreenSize(ClientPtr client); +static int SProcPseudoramiXIsActive(ClientPtr client); +static int SProcPseudoramiXQueryScreens(ClientPtr client); +static int SProcPseudoramiXDispatch(ClientPtr client); + + +typedef struct { + int x; + int y; + int w; + int h; +} PseudoramiXScreenRec; + +static PseudoramiXScreenRec *pseudoramiXScreens = NULL; +static int pseudoramiXScreensAllocated = 0; +static int pseudoramiXNumScreens = 0; +static unsigned long pseudoramiXGeneration = 0; + + +// Add a PseudoramiX screen. +// The rest of the X server will know nothing about this screen. +// Can be called before or after extension init. +// Screens must be re-added once per generation. +void +PseudoramiXAddScreen(int x, int y, int w, int h) +{ + PseudoramiXScreenRec *s; + + if (noPseudoramiXExtension) return; + + if (pseudoramiXNumScreens == pseudoramiXScreensAllocated) { + pseudoramiXScreensAllocated += pseudoramiXScreensAllocated + 1; + pseudoramiXScreens = xrealloc(pseudoramiXScreens, + pseudoramiXScreensAllocated * + sizeof(PseudoramiXScreenRec)); + } + + s = &pseudoramiXScreens[pseudoramiXNumScreens++]; + s->x = x; + s->y = y; + s->w = w; + s->h = h; +} + + +// Initialize PseudoramiX. +// Copied from PanoramiXExtensionInit +void PseudoramiXExtensionInit(int argc, char *argv[]) +{ + Bool success = FALSE; + ExtensionEntry *extEntry; + + if (noPseudoramiXExtension) return; + + if (pseudoramiXNumScreens == 1 || aquaNumScreens == 1) { + // Only one screen - disable Xinerama extension. + noPseudoramiXExtension = TRUE; + return; + } + + // The server must not run the PanoramiX operations. + noPanoramiXExtension = TRUE; + + if (pseudoramiXGeneration != serverGeneration) { + extEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0, 0, + ProcPseudoramiXDispatch, + SProcPseudoramiXDispatch, + PseudoramiXResetProc, + StandardMinorOpcode); + if (!extEntry) { + ErrorF("PseudoramiXExtensionInit(): AddExtension failed\n"); + } else { + pseudoramiXGeneration = serverGeneration; + success = TRUE; + } + } + + if (!success) { + ErrorF("%s Extension (PseudoramiX) failed to initialize\n", + PANORAMIX_PROTOCOL_NAME); + return; + } +} + + +static void PseudoramiXResetProc(ExtensionEntry *extEntry) +{ + pseudoramiXNumScreens = 0; +} + + +// was PanoramiX +static int ProcPseudoramiXQueryVersion(ClientPtr client) +{ + return ProcPanoramiXQueryVersion(client); +} + + +// was PanoramiX +static int ProcPseudoramiXGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + WindowPtr pWin; + xPanoramiXGetStateReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + pWin = LookupWindow (stuff->window, client); + if (!pWin) + return BadWindow; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = !noPseudoramiXExtension; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swaps (&rep.state, n); + } + WriteToClient (client, sizeof (xPanoramiXGetStateReply), (char *) &rep); + return client->noClientException; +} + + +// was PanoramiX +static int ProcPseudoramiXGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + WindowPtr pWin; + xPanoramiXGetScreenCountReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + pWin = LookupWindow (stuff->window, client); + if (!pWin) + return BadWindow; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.ScreenCount = pseudoramiXNumScreens; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swaps (&rep.ScreenCount, n); + } + WriteToClient (client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); + return client->noClientException; +} + + +// was PanoramiX +static int ProcPseudoramiXGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + WindowPtr pWin; + xPanoramiXGetScreenSizeReply rep; + register int n; + + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + pWin = LookupWindow (stuff->window, client); + if (!pWin) + return BadWindow; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + /* screen dimensions */ + rep.width = pseudoramiXScreens[stuff->screen].w; + // was panoramiXdataPtr[stuff->screen].width; + rep.height = pseudoramiXScreens[stuff->screen].h; + // was panoramiXdataPtr[stuff->screen].height; + if (client->swapped) { + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swaps (&rep.width, n); + swaps (&rep.height, n); + } + WriteToClient (client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); + return client->noClientException; +} + + +// was Xinerama +static int ProcPseudoramiXIsActive(ClientPtr client) +{ + /* REQUEST(xXineramaIsActiveReq); */ + xXineramaIsActiveReply rep; + + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.state = !noPseudoramiXExtension; + if (client->swapped) { + register int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.state, n); + } + WriteToClient (client, sizeof (xXineramaIsActiveReply), (char *) &rep); + return client->noClientException; +} + + +// was Xinerama +static int ProcPseudoramiXQueryScreens(ClientPtr client) +{ + /* REQUEST(xXineramaQueryScreensReq); */ + xXineramaQueryScreensReply rep; + + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.number = noPseudoramiXExtension ? 0 : pseudoramiXNumScreens; + rep.length = rep.number * sz_XineramaScreenInfo >> 2; + if (client->swapped) { + register int n; + swaps (&rep.sequenceNumber, n); + swapl (&rep.length, n); + swapl (&rep.number, n); + } + WriteToClient (client, sizeof (xXineramaQueryScreensReply), (char *) &rep); + + if (!noPseudoramiXExtension) { + xXineramaScreenInfo scratch; + int i; + + for(i = 0; i < pseudoramiXNumScreens; i++) { + scratch.x_org = pseudoramiXScreens[i].x; + scratch.y_org = pseudoramiXScreens[i].y; + scratch.width = pseudoramiXScreens[i].w; + scratch.height = pseudoramiXScreens[i].h; + + if(client->swapped) { + register int n; + swaps (&scratch.x_org, n); + swaps (&scratch.y_org, n); + swaps (&scratch.width, n); + swaps (&scratch.height, n); + } + WriteToClient (client, sz_XineramaScreenInfo, (char *) &scratch); + } + } + + return client->noClientException; +} + + +// was PanoramiX +static int ProcPseudoramiXDispatch (ClientPtr client) +{ REQUEST(xReq); + switch (stuff->data) + { + case X_PanoramiXQueryVersion: + return ProcPseudoramiXQueryVersion(client); + case X_PanoramiXGetState: + return ProcPseudoramiXGetState(client); + case X_PanoramiXGetScreenCount: + return ProcPseudoramiXGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return ProcPseudoramiXGetScreenSize(client); + case X_XineramaIsActive: + return ProcPseudoramiXIsActive(client); + case X_XineramaQueryScreens: + return ProcPseudoramiXQueryScreens(client); + } + return BadRequest; +} + + + +static int +SProcPseudoramiXQueryVersion (ClientPtr client) +{ + REQUEST(xPanoramiXQueryVersionReq); + register int n; + + swaps(&stuff->length,n); + REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); + return ProcPseudoramiXQueryVersion(client); +} + +static int +SProcPseudoramiXGetState(ClientPtr client) +{ + REQUEST(xPanoramiXGetStateReq); + register int n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); + return ProcPseudoramiXGetState(client); +} + +static int +SProcPseudoramiXGetScreenCount(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenCountReq); + register int n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); + return ProcPseudoramiXGetScreenCount(client); +} + +static int +SProcPseudoramiXGetScreenSize(ClientPtr client) +{ + REQUEST(xPanoramiXGetScreenSizeReq); + register int n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); + return ProcPseudoramiXGetScreenSize(client); +} + + +static int +SProcPseudoramiXIsActive(ClientPtr client) +{ + REQUEST(xXineramaIsActiveReq); + register int n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaIsActiveReq); + return ProcPseudoramiXIsActive(client); +} + + +static int +SProcPseudoramiXQueryScreens(ClientPtr client) +{ + REQUEST(xXineramaQueryScreensReq); + register int n; + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); + return ProcPseudoramiXQueryScreens(client); +} + + +static int +SProcPseudoramiXDispatch (ClientPtr client) +{ REQUEST(xReq); + switch (stuff->data) + { + case X_PanoramiXQueryVersion: + return SProcPseudoramiXQueryVersion(client); + case X_PanoramiXGetState: + return SProcPseudoramiXGetState(client); + case X_PanoramiXGetScreenCount: + return SProcPseudoramiXGetScreenCount(client); + case X_PanoramiXGetScreenSize: + return SProcPseudoramiXGetScreenSize(client); + case X_XineramaIsActive: + return SProcPseudoramiXIsActive(client); + case X_XineramaQueryScreens: + return SProcPseudoramiXQueryScreens(client); + } + return BadRequest; +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/pseudoramiX.h b/xc/programs/Xserver/hw/darwin/quartz/pseudoramiX.h new file mode 100644 index 000000000..d0d596686 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/pseudoramiX.h @@ -0,0 +1,10 @@ +/* + * Minimal implementation of PanoramiX/Xinerama + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/pseudoramiX.h,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +extern int noPseudoramiXExtension; +extern int aquaNumScreens; + +void PseudoramiXAddScreen(int x, int y, int w, int h); +void PseudoramiXExtensionInit(int argc, char *argv[]); diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartz.c b/xc/programs/Xserver/hw/darwin/quartz/quartz.c new file mode 100644 index 000000000..5f24ad93c --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartz.c @@ -0,0 +1,288 @@ +/************************************************************** + * + * Quartz-specific support for the Darwin X Server + * + **************************************************************/ +/* + * Copyright (c) 2001 Greg Parker and Torrey T. Lyons. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartz.c,v 1.2 2002/10/12 00:32:45 torrey Exp $ */ + +#include "quartzCommon.h" +#include "quartz.h" +#include "darwin.h" +#include "quartzAudio.h" +#include "quartzCursor.h" +#include "fullscreen.h" +#include "rootlessAqua.h" +#include "pseudoramiX.h" + +// X headers +#include "scrnintstr.h" +#include "colormapst.h" + +// System headers +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <IOKit/pwr_mgt/IOPMLib.h> + +// Shared global variables for Quartz modes +int quartzEventWriteFD = -1; +int quartzStartClients = 1; +int quartzRootless = -1; +int quartzUseSysBeep = 0; +int quartzServerVisible = TRUE; +int quartzScreenIndex = 0; +int aquaMenuBarHeight = 0; +int noPseudoramiXExtension = TRUE; +int aquaNumScreens = 0; + + +/* +=========================================================================== + + Screen functions + +=========================================================================== +*/ + +/* + * QuartzPMThread + * Handle power state notifications, FIXME + */ +#if 0 +static void *QuartzPMThread(void *arg) +{ + for (;;) { + mach_msg_return_t kr; + mach_msg_empty_rcv_t msg; + + kr = mach_msg((mach_msg_header_t*) &msg, MACH_RCV_MSG, 0, + sizeof(msg), pmNotificationPort, 0, MACH_PORT_NULL); + kern_assert(kr); + + // computer just woke up + if (msg.header.msgh_id == 1) { + if (quartzServerVisible) { + int i; + + for (i = 0; i < screenInfo.numScreens; i++) { + if (screenInfo.screens[i]) + xf86SetRootClip(screenInfo.screens[i], true); + } + } + } + } + return NULL; +} +#endif + + +/* + * QuartzAddScreen + * Do mode dependent initialization of each screen for Quartz. + */ +Bool QuartzAddScreen( + int index, + ScreenPtr pScreen) +{ + // allocate space for private per screen Quartz specific storage + QuartzScreenPtr displayInfo = xcalloc(sizeof(QuartzScreenRec), 1); + QUARTZ_PRIV(pScreen) = displayInfo; + + // do full screen or rootless specific initialization + if (quartzRootless) { + return AquaAddScreen(index, pScreen); + } else { + return QuartzFSAddScreen(index, pScreen); + } +} + + +/* + * QuartzSetupScreen + * Finalize mode specific setup of each screen. + */ +Bool QuartzSetupScreen( + int index, + ScreenPtr pScreen) +{ + // do full screen or rootless specific setup + if (quartzRootless) { + if (! AquaSetupScreen(index, pScreen)) + return FALSE; + } else { + if (! QuartzFSSetupScreen(index, pScreen)) + return FALSE; + } + + // setup cursor support + if (! QuartzInitCursor(pScreen)) + return FALSE; + + return TRUE; +} + + +/* + * QuartzInitOutput + * Quartz display initialization. + */ +void QuartzInitOutput( + int argc, + char **argv ) +{ + static unsigned long generation = 0; + + // Allocate private storage for each screen's Quartz specific info + if (generation != serverGeneration) { + quartzScreenIndex = AllocateScreenPrivateIndex(); + generation = serverGeneration; + } + + if (serverGeneration == 0) { + QuartzAudioInit(); + } + + if (quartzRootless) { + ErrorF("Display mode: Rootless Quartz\n"); + AquaDisplayInit(); + } else { + ErrorF("Display mode: Full screen Quartz\n"); + QuartzFSDisplayInit(); + } + + // Init PseudoramiX implementation of Xinerama. + // This should be in InitExtensions, but that causes link errors + // for servers that don't link in pseudoramiX.c. + if (!noPseudoramiXExtension) { + PseudoramiXExtensionInit(argc, argv); + } +} + + +/* + * QuartzShow + * Show the X server on screen. Does nothing if already shown. + * Restore the X clip regions the X server cursor state. + */ +void QuartzShow( + int x, // cursor location + int y ) +{ + int i; + + if (!quartzServerVisible) { + quartzServerVisible = TRUE; + for (i = 0; i < screenInfo.numScreens; i++) { + if (screenInfo.screens[i]) { + QuartzResumeXCursor(screenInfo.screens[i], x, y); + if (!quartzRootless) + xf86SetRootClip(screenInfo.screens[i], TRUE); + } + } + } +} + + +/* + * QuartzHide + * Remove the X server display from the screen. Does nothing if already + * hidden. Set X clip regions to prevent drawing, and restore the Aqua + * cursor. + */ +void QuartzHide(void) +{ + int i; + + if (quartzServerVisible) { + for (i = 0; i < screenInfo.numScreens; i++) { + if (screenInfo.screens[i]) { + QuartzSuspendXCursor(screenInfo.screens[i]); + if (!quartzRootless) + xf86SetRootClip(screenInfo.screens[i], FALSE); + } + } + } + quartzServerVisible = FALSE; + QuartzMessageMainThread(kQuartzServerHidden, NULL, 0); +} + + +/* + * QuartzProcessEvent + * Process Quartz specific events. + */ +void QuartzProcessEvent( + xEvent *xe) +{ + switch (xe->u.u.type) { + + case kXDarwinShow: + QuartzShow(xe->u.keyButtonPointer.rootX, + xe->u.keyButtonPointer.rootY); + break; + + case kXDarwinHide: + QuartzHide(); + break; + + case kXDarwinQuit: + GiveUp(0); + break; + + case kXDarwinReadPasteboard: + QuartzReadPasteboard(); + break; + + case kXDarwinWritePasteboard: + QuartzWritePasteboard(); + break; + + default: + ErrorF("Unknown application defined event.\n"); + } +} + + +/* + * QuartzGiveUp + * Cleanup before X server shutdown + * Release the screen and restore the Aqua cursor. + */ +void QuartzGiveUp(void) +{ + int i; + + for (i = 0; i < screenInfo.numScreens; i++) { + if (screenInfo.screens[i]) { + QuartzSuspendXCursor(screenInfo.screens[i]); + } + } + if (!quartzRootless) + QuartzFSRelease(); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartz.h b/xc/programs/Xserver/hw/darwin/quartz/quartz.h new file mode 100644 index 000000000..e304591a4 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartz.h @@ -0,0 +1,51 @@ +/* + * quartz.h + * + * External interface of the Quartz modes seen by the generic, mode + * independent parts of the Darwin X server. + */ +/* + * Copyright (c) 2001 Greg Parker and Torrey T. Lyons. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartz.h,v 1.2 2002/10/12 00:32:45 torrey Exp $ */ + +#ifndef _QUARTZ_H +#define _QUARTZ_H + +#include "screenint.h" +#include "Xproto.h" +#include "quartzPasteboard.h" + +int QuartzProcessArgument(int argc, char *argv[], int i); +void QuartzInitOutput(int argc, char **argv); +Bool QuartzAddScreen(int index, ScreenPtr pScreen); +Bool QuartzSetupScreen(int index, ScreenPtr pScreen); +void QuartzGiveUp(void); +void QuartzHide(void); +void QuartzShow(int x, int y); +void QuartzProcessEvent(xEvent *xe); + +#endif diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzAudio.c b/xc/programs/Xserver/hw/darwin/quartz/quartzAudio.c new file mode 100644 index 000000000..2dfb313b7 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzAudio.c @@ -0,0 +1,342 @@ +// +// QuartzAudio.m +// +// X Window bell support using CoreAudio or AppKit. +// Greg Parker gparker@cs.stanford.edu 19 Feb 2001 +// +// Info about sine wave sound playback: +// CoreAudio code derived from macosx-dev posting by Tim Wood +// http://www.omnigroup.com/mailman/archive/macosx-dev/2000-May/002004.html +// Smoothing transitions between sounds +// http://www.wam.umd.edu/~mphoenix/dss/dss.html +// +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzAudio.c,v 1.1 2002/03/28 02:21:18 torrey Exp $ */ + +#include "quartzCommon.h" +#include "quartzAudio.h" + +#include <CoreAudio/CoreAudio.h> +#include <pthread.h> + +#include "inputstr.h" +#include "extensions/XI.h" + +void NSBeep(); + +typedef struct QuartzAudioRec { + double frequency; + double amplitude; + + UInt32 curFrame; + UInt32 remainingFrames; + UInt32 totalFrames; + UInt32 bytesPerFrame; + double sampleRate; + UInt32 fadeLength; + + UInt32 bufferByteCount; + Boolean playing; + pthread_mutex_t lock; + + // used to fade out interrupted sound and avoid 'pop' + double prevFrequency; + double prevAmplitude; + UInt32 prevFrame; +} QuartzAudioRec; + +static AudioDeviceID quartzAudioDevice = kAudioDeviceUnknown; +static QuartzAudioRec data; + + +/* + * QuartzAudioEnvelope + * Fade sound in and out to avoid pop. + * Sounds with shorter duration will never reach full amplitude. Deal. + */ +static double QuartzAudioEnvelope( + UInt32 curFrame, + UInt32 totalFrames, + UInt32 fadeLength ) +{ + double fadeFrames = min(fadeLength, totalFrames / 2); + if (fadeFrames < 1) return 0; + + if (curFrame < fadeFrames) { + return curFrame / fadeFrames; + } else if (curFrame > totalFrames - fadeFrames) { + return (totalFrames-curFrame) / fadeFrames; + } else { + return 1.0; + } +} + + +/* + * QuartzFillBuffer + * Fill this buffer with data and update the data position. + * FIXME: this is ugly + */ +static void QuartzFillBuffer( + AudioBuffer *audiobuffer, + QuartzAudioRec *data ) +{ + float *buffer, *b; + unsigned int frame, frameCount; + unsigned int bufferFrameCount; + float multiplier, v; + int i; + + buffer = (float *)audiobuffer->mData; + bufferFrameCount = audiobuffer->mDataByteSize / data->bytesPerFrame; + + frameCount = min(bufferFrameCount, data->remainingFrames); + + // Fade out previous sine wave, if any. + b = buffer; + if (data->prevFrame) { + multiplier = 2*M_PI*(data->prevFrequency/data->sampleRate); + for (frame = 0; frame < data->fadeLength; frame++) { + v = data->prevAmplitude * + QuartzAudioEnvelope(frame+data->fadeLength, + 2*data->fadeLength, + data->fadeLength) * + sin(multiplier * (data->prevFrame+frame)); + for (i = 0; i < audiobuffer->mNumberChannels; i++) { + *b++ = v; + } + } + // no more prev fade + data->prevFrame = 0; + + // adjust for space eaten by prev fade + buffer += audiobuffer->mNumberChannels*frame; + bufferFrameCount -= frame; + frameCount = min(bufferFrameCount, data->remainingFrames); + } + + // Write a sine wave with the specified frequency and amplitude + multiplier = 2*M_PI*(data->frequency/data->sampleRate); + for (frame = 0; frame < frameCount; frame++) { + v = data->amplitude * + QuartzAudioEnvelope(data->curFrame+frame, data->totalFrames, + data->fadeLength) * + sin(multiplier * (data->curFrame+frame)); + for (i = 0; i < audiobuffer->mNumberChannels; i++) { + *b++ = v; + } + } + + // Zero out the rest of the buffer, if any + memset(b, 0, sizeof(float) * audiobuffer->mNumberChannels * + (bufferFrameCount-frame)); + + data->curFrame += frameCount; + data->remainingFrames -= frameCount; + if (data->remainingFrames == 0) { + data->playing = FALSE; + data->curFrame = 0; + } +} + + +/* + * QuartzAudioIOProc + * Callback function for audio playback. + * FIXME: use inOutputTime to correct for skipping + */ +static OSStatus +QuartzAudioIOProc( + AudioDeviceID inDevice, + const AudioTimeStamp *inNow, + const AudioBufferList *inInputData, + const AudioTimeStamp *inInputTime, + AudioBufferList *outOutputData, + const AudioTimeStamp *inOutputTime, + void *inClientData ) +{ + QuartzAudioRec *data = (QuartzAudioRec *)inClientData; + int i; + Boolean wasPlaying; + + pthread_mutex_lock(&data->lock); + wasPlaying = data->playing; + for (i = 0; i < outOutputData->mNumberBuffers; i++) { + if (data->playing) { + QuartzFillBuffer(outOutputData->mBuffers+i, data); + } + else { + memset(outOutputData->mBuffers[i].mData, 0, + outOutputData->mBuffers[i].mDataByteSize); + } + } + if (wasPlaying && !data->playing) { + OSStatus err; + err = AudioDeviceStop(inDevice, QuartzAudioIOProc); + } + pthread_mutex_unlock(&data->lock); + return 0; +} + + +/* + * QuartzCoreAudioBell + * Play a tone using the CoreAudio API + */ +static void QuartzCoreAudioBell( + int volume, // volume is % of max + int pitch, // pitch is Hz + int duration ) // duration is milliseconds +{ + if (quartzAudioDevice == kAudioDeviceUnknown) return; + + pthread_mutex_lock(&data.lock); + + // fade previous sound, if any + data.prevFrequency = data.frequency; + data.prevAmplitude = data.amplitude; + data.prevFrame = data.curFrame; + + // set new sound + data.frequency = pitch; + data.amplitude = volume / 100.0; + data.curFrame = 0; + data.totalFrames = (int)(data.sampleRate * duration / 1000.0); + data.remainingFrames = data.totalFrames; + + if (! data.playing) { + OSStatus status; + status = AudioDeviceStart(quartzAudioDevice, QuartzAudioIOProc); + if (status) { + ErrorF("QuartzAudioBell: AudioDeviceStart returned %d\n", status); + } else { + data.playing = TRUE; + } + } + pthread_mutex_unlock(&data.lock); +} + + +/* + * QuartzBell + * Ring the bell + */ +void QuartzBell( + int volume, // volume in percent of max + DeviceIntPtr pDevice, + pointer ctrl, + int class ) +{ + int pitch; // pitch in Hz + int duration; // duration in milliseconds + + if (class == BellFeedbackClass) { + pitch = ((BellCtrl*)ctrl)->pitch; + duration = ((BellCtrl*)ctrl)->duration; + } else if (class == KbdFeedbackClass) { + pitch = ((KeybdCtrl*)ctrl)->bell_pitch; + duration = ((KeybdCtrl*)ctrl)->bell_duration; + } else { + ErrorF("QuartzBell: bad bell class %d\n", class); + return; + } + + if (quartzUseSysBeep) { + if (volume) + NSBeep(); + } else { + QuartzCoreAudioBell(volume, pitch, duration); + } +} + + +/* + * QuartzAudioInit + * Prepare to play the bell with the CoreAudio API + */ +void QuartzAudioInit(void) +{ + UInt32 propertySize; + OSStatus status; + AudioDeviceID outputDevice; + AudioStreamBasicDescription outputStreamDescription; + double sampleRate; + + // Get the default output device + propertySize = sizeof(outputDevice); + status = AudioHardwareGetProperty( + kAudioHardwarePropertyDefaultOutputDevice, + &propertySize, &outputDevice); + if (status) { + ErrorF("QuartzAudioInit: AudioHardwareGetProperty returned %d\n", + status); + return; + } + if (outputDevice == kAudioDeviceUnknown) { + ErrorF("QuartzAudioInit: No audio output devices available.\n"); + return; + } + + // Get the basic device description + propertySize = sizeof(outputStreamDescription); + status = AudioDeviceGetProperty(outputDevice, 0, FALSE, + kAudioDevicePropertyStreamFormat, + &propertySize, &outputStreamDescription); + if (status) { + ErrorF("QuartzAudioInit: GetProperty(stream format) returned %d\n", + status); + return; + } + sampleRate = outputStreamDescription.mSampleRate; + + // Fill in the playback data + data.frequency = 0; + data.amplitude = 0; + data.curFrame = 0; + data.remainingFrames = 0; + data.bytesPerFrame = outputStreamDescription.mBytesPerFrame; + data.sampleRate = sampleRate; + // data.bufferByteCount = bufferByteCount; + data.playing = FALSE; + data.prevAmplitude = 0; + data.prevFrame = 0; + data.prevFrequency = 0; + data.fadeLength = data.sampleRate / 200; + pthread_mutex_init(&data.lock, NULL); // fixme error check + + // fixme assert fadeLength<framesPerBuffer + + // Prepare for playback + status = AudioDeviceAddIOProc(outputDevice, QuartzAudioIOProc, &data); + if (status) { + ErrorF("QuartzAudioInit: AddIOProc returned %d\n", status); + return; + } + + // success! + quartzAudioDevice = outputDevice; +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzAudio.h b/xc/programs/Xserver/hw/darwin/quartz/quartzAudio.h new file mode 100644 index 000000000..1d213e36a --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzAudio.h @@ -0,0 +1,41 @@ +// +// QuartzAudio.h +// +// X Window bell support using CoreAudio or AppKit. +// Greg Parker gparker@cs.stanford.edu 19 Feb 2001 +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzAudio.h,v 1.1 2002/03/28 02:21:19 torrey Exp $ */ + +#ifndef _QUARTZAUDIO_H +#define _QUARTZAUDIO_H + +#include "input.h" + +void QuartzAudioInit(void); +void QuartzBell(int volume, DeviceIntPtr pDevice, pointer ctrl, int class); + +#endif diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzCocoa.m b/xc/programs/Xserver/hw/darwin/quartz/quartzCocoa.m new file mode 100644 index 000000000..b24739184 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzCocoa.m @@ -0,0 +1,148 @@ +/************************************************************** + * + * Quartz-specific support for the Darwin X Server + * that requires Cocoa and Objective-C. + * + * This file is separate from the parts of Quartz support + * that use X include files to avoid symbol collisions. + * + **************************************************************/ +/* + * Copyright (c) 2001 Torrey T. Lyons and Greg Parker. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzCocoa.m,v 1.1 2002/03/28 02:21:19 torrey Exp $ */ + +#include <Cocoa/Cocoa.h> + +#import "Preferences.h" +#include "quartzCommon.h" +#include "pseudoramiX.h" + +extern void FatalError(const char *, ...); +extern char *display; +extern int noPanoramiXExtension; + +// Read the user preferences from the Cocoa front end +void QuartzReadPreferences(void) +{ + char *fileString; + + darwinFakeButtons = [Preferences fakeButtons]; + darwinFakeMouse2Mask = [Preferences button2Mask]; + darwinFakeMouse3Mask = [Preferences button3Mask]; + quartzMouseAccelChange = [Preferences mouseAccelChange]; + quartzUseSysBeep = [Preferences systemBeep]; + + // Rootless: use PseudoramiX not Xinerama (quartzRootless already set) + if (quartzRootless) { + noPanoramiXExtension = TRUE; + noPseudoramiXExtension = ![Preferences xinerama]; + } else { + noPanoramiXExtension = ![Preferences xinerama]; + noPseudoramiXExtension = TRUE; + } + + if ([Preferences useKeymapFile]) { + fileString = (char *) [[Preferences keymapFile] lossyCString]; + darwinKeymapFile = (char *) malloc(strlen(fileString)+1); + if (! darwinKeymapFile) + FatalError("malloc failed in QuartzReadPreferences()!\n"); + strcpy(darwinKeymapFile, fileString); + } + + display = (char *) malloc(8); + if (! display) + FatalError("malloc failed in QuartzReadPreferences()!\n"); + snprintf(display, 8, "%i", [Preferences display]); + + darwinDesiredDepth = [Preferences depth] - 1; +} + +// Write text to the Mac OS X pasteboard. +void QuartzWriteCocoaPasteboard( + char *text) +{ + NSPasteboard *pasteboard; + NSArray *pasteboardTypes; + NSString *string; + + if (! text) return; + pasteboard = [NSPasteboard generalPasteboard]; + if (! pasteboard) return; + string = [NSString stringWithCString:text]; + if (! string) return; + pasteboardTypes = [NSArray arrayWithObject:NSStringPboardType]; + + // nil owner because we don't provide type translations + [pasteboard declareTypes:pasteboardTypes owner:nil]; + [pasteboard setString:string forType:NSStringPboardType]; +} + +// Read text from the Mac OS X pasteboard and return it as a heap string. +// The caller must free the string. +char *QuartzReadCocoaPasteboard(void) +{ + NSPasteboard *pasteboard; + NSArray *pasteboardTypes; + NSString *existingType; + char *text = NULL; + + pasteboardTypes = [NSArray arrayWithObject:NSStringPboardType]; + pasteboard = [NSPasteboard generalPasteboard]; + if (! pasteboard) return NULL; + + existingType = [pasteboard availableTypeFromArray:pasteboardTypes]; + if (existingType) { + NSString *string = [pasteboard stringForType:existingType]; + char *buffer; + + if (! string) return NULL; + buffer = (char *) [string lossyCString]; + text = (char *) malloc(strlen(buffer)+1); + if (text) + strcpy(text, buffer); + } + + return text; +} + +// Return whether the screen should use a QuickDraw cursor +int QuartzFSUseQDCursor( + int depth) // screen depth +{ + switch ([Preferences useQDCursor]) { + case qdCursor_Always: + return TRUE; + case qdCursor_Never: + return FALSE; + case qdCursor_Not8Bit: + if (depth > 8) + return TRUE; + else + return FALSE; + } + return TRUE; +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzCommon.h b/xc/programs/Xserver/hw/darwin/quartz/quartzCommon.h new file mode 100644 index 000000000..dce37e001 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzCommon.h @@ -0,0 +1,92 @@ +/* + * quartzCommon.h + * + * Common definitions used internally by all Quartz modes + * + * This file should be included before any X11 or IOKit headers + * so that it can avoid symbol conflicts. + * + * Copyright (c) 2001 Torrey T. Lyons and Greg Parker. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzCommon.h,v 1.4 2002/10/12 00:32:45 torrey Exp $ */ + +#ifndef _QUARTZCOMMON_H +#define _QUARTZCOMMON_H + +// QuickDraw in ApplicationServices has the following conflicts with +// the basic X server headers. Use QD_<name> to use the QuickDraw +// definition of any of these symbols, or the normal name for the +// X11 definition. +#define Cursor QD_Cursor +#define WindowPtr QD_WindowPtr +#define Picture QD_Picture +#include <ApplicationServices/ApplicationServices.h> +#undef Cursor +#undef WindowPtr +#undef Picture + +#include "quartzShared.h" + +// Quartz specific per screen storage structure +typedef struct { + // List of CoreGraphics displays that this X11 screen covers. + // This is more than one CG display for video mirroring and + // rootless PseudoramiX mode. + // No CG display will be covered by more than one X11 screen. + int displayCount; + CGDirectDisplayID *displayIDs; +} QuartzScreenRec, *QuartzScreenPtr; + +#define QUARTZ_PRIV(pScreen) \ + ((QuartzScreenPtr)pScreen->devPrivates[quartzScreenIndex].ptr) + +// Data stored at startup for Cocoa front end +extern int quartzEventWriteFD; +extern int quartzStartClients; + +// User preferences used by Quartz modes +extern int quartzRootless; +extern int quartzUseSysBeep; + +// Other shared data +extern int quartzServerVisible; +extern int quartzScreenIndex; +extern int aquaMenuBarHeight; + +void QuartzReadPreferences(void); +void QuartzMessageMainThread(unsigned msg, void *data, unsigned length); +void QuartzFSCapture(void); +void QuartzFSRelease(void); +int QuartzFSUseQDCursor(int depth); + +// Messages that can be sent to the main thread. +enum { + kQuartzServerHidden, + kQuartzServerDied, + kQuartzPostEvent +}; + +#endif /* _QUARTZCOMMON_H */ diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzCursor.c b/xc/programs/Xserver/hw/darwin/quartz/quartzCursor.c new file mode 100644 index 000000000..ddc2fb0ef --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzCursor.c @@ -0,0 +1,620 @@ +/************************************************************** + * + * Support for using the Quartz Window Manager cursor + * + **************************************************************/ +/* + * Copyright (c) 2001-2002 Torrey T. Lyons and Greg Parker. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzCursor.c,v 1.3 2002/10/16 17:39:18 torrey Exp $ */ + +#include "quartzCommon.h" +#include "quartzCursor.h" +#include "darwin.h" + +#include "mi.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "mipointrst.h" +#include "globals.h" + +// Size of the QuickDraw cursor +#define CURSORWIDTH 16 +#define CURSORHEIGHT 16 + +typedef struct { + int qdCursorMode; + int qdCursorVisible; + int useQDCursor; + QueryBestSizeProcPtr QueryBestSize; + miPointerSpriteFuncPtr spriteFuncs; +} QuartzCursorScreenRec, *QuartzCursorScreenPtr; + +static int darwinCursorScreenIndex = -1; +static unsigned long darwinCursorGeneration = 0; +static CursorPtr quartzLatentCursor = NULL; +static QD_Cursor gQDArrow; // QuickDraw arrow cursor + +#define CURSOR_PRIV(pScreen) \ + ((QuartzCursorScreenPtr)pScreen->devPrivates[darwinCursorScreenIndex].ptr) + +#define HIDE_QD_CURSOR(pScreen, visible) \ + if (visible) { \ + int ix; \ + for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) { \ + CGDisplayHideCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]); \ + } \ + visible = FALSE; \ + } ((void)0) + +#define SHOW_QD_CURSOR(pScreen, visible) \ + { \ + int ix; \ + for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) { \ + CGDisplayShowCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]); \ + } \ + visible = TRUE; \ + } ((void)0) + + +/* + * MakeQDCursor helpers: CTAB_ENTER, interleave + */ + +// Add a color entry to a ctab +#define CTAB_ENTER(ctab, index, r, g, b) \ + ctab->ctTable[index].value = index; \ + ctab->ctTable[index].rgb.red = r; \ + ctab->ctTable[index].rgb.green = g; \ + ctab->ctTable[index].rgb.blue = b + +// Make an unsigned short by interleaving the bits of bytes c1 and c2. +// High bit of c1 is first; low bit of c2 is last. +// Interleave is a built-in INTERCAL operator. +static unsigned short +interleave( + unsigned char c1, + unsigned char c2 ) +{ + return + ((c1 & 0x80) << 8) | ((c2 & 0x80) << 7) | + ((c1 & 0x40) << 7) | ((c2 & 0x40) << 6) | + ((c1 & 0x20) << 6) | ((c2 & 0x20) << 5) | + ((c1 & 0x10) << 5) | ((c2 & 0x10) << 4) | + ((c1 & 0x08) << 4) | ((c2 & 0x08) << 3) | + ((c1 & 0x04) << 3) | ((c2 & 0x04) << 2) | + ((c1 & 0x02) << 2) | ((c2 & 0x02) << 1) | + ((c1 & 0x01) << 1) | ((c2 & 0x01) << 0) ; +} + +/* + * MakeQDCursor + * Make a QuickDraw color cursor from the given X11 cursor. + * Warning: This code is nasty. Color cursors were meant to be read + * from resources; constructing the structures programmatically is messy. + */ +/* + QuickDraw cursor representation: + Our color cursor is a 2 bit per pixel pixmap. + Each pixel's bits are (source<<1 | mask) from the original X cursor pixel. + The cursor's color table maps the colors like this: + (2-bit value | X result | colortable | Mac result) + 00 | transparent | white | transparent (white outside mask) + 01 | back color | back color | back color + 10 | undefined | black | invert background (just for fun) + 11 | fore color | fore color | fore color +*/ +static CCrsrHandle +MakeQDCursor( + CursorPtr pCursor ) +{ + CCrsrHandle result; + CCrsrPtr curs; + int i, w, h; + unsigned short rowMask; + PixMap *pix; + ColorTable *ctab; + unsigned short *image; + + result = (CCrsrHandle) NewHandleClear(sizeof(CCrsr)); + if (!result) return NULL; + HLock((Handle)result); + curs = *result; + + // Initialize CCrsr + curs->crsrType = 0x8001; // 0x8000 = b&w, 0x8001 = color + curs->crsrMap = (PixMapHandle) NewHandleClear(sizeof(PixMap)); + if (!curs->crsrMap) goto pixAllocFailed; + HLock((Handle)curs->crsrMap); + pix = *curs->crsrMap; + curs->crsrData = NULL; // raw cursor image data (set below) + curs->crsrXData = NULL; // QD's processed data + curs->crsrXValid = 0; // zero means QD must re-process cursor data + curs->crsrXHandle = NULL; // reserved + memset(curs->crsr1Data, 0, CURSORWIDTH*CURSORHEIGHT/8); // b&w data + memset(curs->crsrMask, 0, CURSORWIDTH*CURSORHEIGHT/8); // b&w & color mask + curs->crsrHotSpot.h = min(CURSORWIDTH, pCursor->bits->xhot); // hot spot + curs->crsrHotSpot.v = min(CURSORHEIGHT, pCursor->bits->yhot); // hot spot + curs->crsrXTable = 0; // reserved + curs->crsrID = GetCTSeed(); // unique ID from Color Manager + + // Set the b&w data and mask + w = min(pCursor->bits->width, CURSORWIDTH); + h = min(pCursor->bits->height, CURSORHEIGHT); + rowMask = ~((1 << (CURSORWIDTH - w)) - 1); + for (i = 0; i < h; i++) { + curs->crsr1Data[i] = rowMask & + ((pCursor->bits->source[i*4]<<8) | pCursor->bits->source[i*4+1]); + curs->crsrMask[i] = rowMask & + ((pCursor->bits->mask[i*4]<<8) | pCursor->bits->mask[i*4+1]); + } + + // Set the color data and mask + // crsrMap: defines bit depth and size and colortable only + pix->rowBytes = (CURSORWIDTH * 2 / 8) | 0x8000; // last bit on means PixMap + SetRect(&pix->bounds, 0, 0, CURSORWIDTH, CURSORHEIGHT); // see TN 1020 + pix->pixelSize = 2; + pix->cmpCount = 1; + pix->cmpSize = 2; + // pix->pmTable set below + + // crsrData is the pixel data. crsrMap's baseAddr is not used. + curs->crsrData = NewHandleClear(CURSORWIDTH*CURSORHEIGHT * 2 / 8); + if (!curs->crsrData) goto imageAllocFailed; + HLock((Handle)curs->crsrData); + image = (unsigned short *) *curs->crsrData; + // Pixel data is just 1-bit data and mask interleaved (see above) + for (i = 0; i < h; i++) { + unsigned char s, m; + s = pCursor->bits->source[i*4] & (rowMask >> 8); + m = pCursor->bits->mask[i*4] & (rowMask >> 8); + image[2*i] = interleave(s, m); + s = pCursor->bits->source[i*4+1] & (rowMask & 0x00ff); + m = pCursor->bits->mask[i*4+1] & (rowMask & 0x00ff); + image[2*i+1] = interleave(s, m); + } + + // Build the color table (entries described above) + // NewPixMap allocates a color table handle. + pix->pmTable = (CTabHandle) NewHandleClear(sizeof(ColorTable) + 3 + * sizeof(ColorSpec)); + if (!pix->pmTable) goto ctabAllocFailed; + HLock((Handle)pix->pmTable); + ctab = *pix->pmTable; + ctab->ctSeed = GetCTSeed(); + ctab->ctFlags = 0; + ctab->ctSize = 3; // color count - 1 + CTAB_ENTER(ctab, 0, 0xffff, 0xffff, 0xffff); + CTAB_ENTER(ctab, 1, pCursor->backRed, pCursor->backGreen, + pCursor->backBlue); + CTAB_ENTER(ctab, 2, 0x0000, 0x0000, 0x0000); + CTAB_ENTER(ctab, 3, pCursor->foreRed, pCursor->foreGreen, + pCursor->foreBlue); + + HUnlock((Handle)pix->pmTable); // ctab + HUnlock((Handle)curs->crsrData); // image data + HUnlock((Handle)curs->crsrMap); // pix + HUnlock((Handle)result); // cursor + + return result; + + // "What we have here is a failure to allocate" +ctabAllocFailed: + HUnlock((Handle)curs->crsrData); + DisposeHandle((Handle)curs->crsrData); +imageAllocFailed: + HUnlock((Handle)curs->crsrMap); + DisposeHandle((Handle)curs->crsrMap); +pixAllocFailed: + HUnlock((Handle)result); + DisposeHandle((Handle)result); + return NULL; +} + + +/* + * FreeQDCursor + * Destroy a QuickDraw color cursor created with MakeQDCursor(). + * The cursor must not currently be on screen. + */ +static void FreeQDCursor(CCrsrHandle cursHandle) +{ + CCrsrPtr curs; + PixMap *pix; + + HLock((Handle)cursHandle); + curs = *cursHandle; + HLock((Handle)curs->crsrMap); + pix = *curs->crsrMap; + DisposeHandle((Handle)pix->pmTable); + HUnlock((Handle)curs->crsrMap); + DisposeHandle((Handle)curs->crsrMap); + DisposeHandle((Handle)curs->crsrData); + HUnlock((Handle)cursHandle); + DisposeHandle((Handle)cursHandle); +} + + +/* +=========================================================================== + + Pointer sprite functions + +=========================================================================== +*/ + +/* + * QuartzRealizeCursor + * Convert the X cursor representation to QuickDraw format if possible. + */ +Bool +QuartzRealizeCursor( + ScreenPtr pScreen, + CursorPtr pCursor ) +{ + CCrsrHandle qdCursor; + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if(!pCursor || !pCursor->bits) + return FALSE; + + // if the cursor is too big we use a software cursor + if ((pCursor->bits->height > CURSORHEIGHT) || + (pCursor->bits->width > CURSORWIDTH) || !ScreenPriv->useQDCursor) + { + if (quartzRootless) { + // rootless can't use a software cursor + return TRUE; + } else { + return (*ScreenPriv->spriteFuncs->RealizeCursor) + (pScreen, pCursor); + } + } + + // make new cursor image + qdCursor = MakeQDCursor(pCursor); + if (!qdCursor) return FALSE; + + // save the result + pCursor->devPriv[pScreen->myNum] = (pointer) qdCursor; + + return TRUE; +} + + +/* + * QuartzUnrealizeCursor + * Free the storage space associated with a realized cursor. + */ +Bool +QuartzUnrealizeCursor( + ScreenPtr pScreen, + CursorPtr pCursor ) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if ((pCursor->bits->height > CURSORHEIGHT) || + (pCursor->bits->width > CURSORWIDTH) || !ScreenPriv->useQDCursor) + { + if (quartzRootless) { + return TRUE; + } else { + return (*ScreenPriv->spriteFuncs->UnrealizeCursor) + (pScreen, pCursor); + } + } else { + FreeQDCursor((CCrsrHandle) pCursor->devPriv[pScreen->myNum]); + pCursor->devPriv[pScreen->myNum] = NULL; + return TRUE; + } +} + + +/* + * QuartzSetCursor + * Set the cursor sprite and position. + * Use QuickDraw cursor if possible. + */ +static void +QuartzSetCursor( + ScreenPtr pScreen, + CursorPtr pCursor, + int x, + int y) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + quartzLatentCursor = pCursor; + + // Don't touch Mac OS cursor if X is hidden! + if (!quartzServerVisible) + return; + + if (!pCursor) { + // Remove the cursor completely. + HIDE_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); + if (! ScreenPriv->qdCursorMode) + (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y); + } + else if ((pCursor->bits->height <= CURSORHEIGHT) && + (pCursor->bits->width <= CURSORWIDTH) && ScreenPriv->useQDCursor) + { + // Cursor is small enough to use QuickDraw directly. + CCrsrHandle curs; + + if (! ScreenPriv->qdCursorMode) // remove the X cursor + (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y); + ScreenPriv->qdCursorMode = TRUE; + + curs = (CCrsrHandle) pCursor->devPriv[pScreen->myNum]; + SetCCursor(curs); + SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); + } + else if (quartzRootless) { + // Rootless can't use a software cursor, so we just use Mac OS arrow. + SetCursor(&gQDArrow); + SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); + } + else { + // Cursor is too big for QuickDraw. Use X software cursor. + HIDE_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); + ScreenPriv->qdCursorMode = FALSE; + (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, pCursor, x, y); + } +} + + +/* + * QuartzMoveCursor + * Move the cursor. This is a noop for QuickDraw. + */ +static void +QuartzMoveCursor( + ScreenPtr pScreen, + int x, + int y) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + // only the X cursor needs to be explicitly moved + if (!ScreenPriv->qdCursorMode) + (*ScreenPriv->spriteFuncs->MoveCursor)(pScreen, x, y); +} + + +static miPointerSpriteFuncRec quartzSpriteFuncsRec = { + QuartzRealizeCursor, + QuartzUnrealizeCursor, + QuartzSetCursor, + QuartzMoveCursor +}; + +/* +=========================================================================== + + Pointer screen functions + +=========================================================================== +*/ + +/* + * QuartzCursorOffScreen + */ +static Bool QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y) +{ + return FALSE; +} + + +/* + * QuartzCrossScreen + */ +static void QuartzCrossScreen(ScreenPtr pScreen, Bool entering) +{ + return; +} + + +/* + * QuartzWarpCursor + * Change the cursor position without generating an event or motion history. + * The input coordinates (x,y) are in pScreen-local X11 coordinates. + * + */ +static void +QuartzWarpCursor( + ScreenPtr pScreen, + int x, + int y) +{ + static int neverMoved = TRUE; + + if (neverMoved) { + // Don't move the cursor the first time. This is the jump-to-center + // initialization, and it's annoying because we may still be in MacOS. + neverMoved = FALSE; + return; + } + + if (quartzServerVisible) { + CGDisplayErr cgErr; + CGPoint cgPoint; + // Only need to do this for one display. Any display will do. + CGDirectDisplayID cgID = QUARTZ_PRIV(pScreen)->displayIDs[0]; + CGRect cgRect = CGDisplayBounds(cgID); + + // Convert (x,y) to CoreGraphics screen-local CG coordinates. + // This is necessary because the X11 screen and CG screen may not + // coincide. (e.g. X11 screen may be moved to dodge the menu bar) + + // Make point in X11 global coordinates + cgPoint = CGPointMake(x + dixScreenOrigins[pScreen->myNum].x, + y + dixScreenOrigins[pScreen->myNum].y); + // Shift to CoreGraphics global screen coordinates + cgPoint.x += darwinMainScreenX; + cgPoint.y += darwinMainScreenY; + // Shift to CoreGraphics screen-local coordinates + cgPoint.x -= cgRect.origin.x; + cgPoint.y -= cgRect.origin.y; + + cgErr = CGDisplayMoveCursorToPoint(cgID, cgPoint); + if (cgErr != CGDisplayNoErr) { + ErrorF("Could not set cursor position with error code 0x%x.\n", + cgErr); + } + } + + miPointerWarpCursor(pScreen, x, y); +} + + +/* + * QuartzEnqueueEvent + * Enqueue an event from the X server thread. Most events are posted with + * DarwinEQEnqueue() by the main thread, but any events generated by the + * X server thread must be posted with this routine. + */ +static void QuartzEnqueueEvent( + xEvent *xe) +{ + // Convert back to global screen coordinates + xe->u.keyButtonPointer.rootX += darwinMainScreenX + + dixScreenOrigins[miPointerCurrentScreen()->myNum].x; + xe->u.keyButtonPointer.rootY += darwinMainScreenY + + dixScreenOrigins[miPointerCurrentScreen()->myNum].y; + + QuartzMessageMainThread(kQuartzPostEvent, xe, sizeof(xEvent)); +} + + +static miPointerScreenFuncRec quartzScreenFuncsRec = { + QuartzCursorOffScreen, + QuartzCrossScreen, + QuartzWarpCursor, + QuartzEnqueueEvent, + DarwinEQSwitchScreen +}; + +/* +=========================================================================== + + Other screen functions + +=========================================================================== +*/ + +/* + * QuartzCursorQueryBestSize + * Handle queries for best cursor size + */ +static void +QuartzCursorQueryBestSize( + int class, + unsigned short *width, + unsigned short *height, + ScreenPtr pScreen) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if (class == CursorShape) { + *width = CURSORWIDTH; + *height = CURSORHEIGHT; + } else { + (*ScreenPriv->QueryBestSize)(class, width, height, pScreen); + } +} + + +/* + * QuartzInitCursor + * Initialize cursor support + */ +Bool +QuartzInitCursor( + ScreenPtr pScreen ) +{ + QuartzCursorScreenPtr ScreenPriv; + miPointerScreenPtr PointPriv; + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + + // initialize software cursor handling (always needed as backup) + if (!miDCInitialize(pScreen, &quartzScreenFuncsRec)) { + return FALSE; + } + + // allocate private storage for this screen's QuickDraw cursor info + if (darwinCursorGeneration != serverGeneration) { + if ((darwinCursorScreenIndex = AllocateScreenPrivateIndex()) < 0) + return FALSE; + darwinCursorGeneration = serverGeneration; + } + + ScreenPriv = xcalloc( 1, sizeof(QuartzCursorScreenRec) ); + if (!ScreenPriv) return FALSE; + + CURSOR_PRIV(pScreen) = ScreenPriv; + + // override some screen procedures + ScreenPriv->QueryBestSize = pScreen->QueryBestSize; + pScreen->QueryBestSize = QuartzCursorQueryBestSize; + + // initialize QuickDraw cursor handling + GetQDGlobalsArrow(&gQDArrow); + PointPriv = (miPointerScreenPtr) + pScreen->devPrivates[miPointerScreenIndex].ptr; + + ScreenPriv->spriteFuncs = PointPriv->spriteFuncs; + PointPriv->spriteFuncs = &quartzSpriteFuncsRec; + + if (!quartzRootless) + ScreenPriv->useQDCursor = QuartzFSUseQDCursor(dfb->colorBitsPerPixel); + else + ScreenPriv->useQDCursor = TRUE; + ScreenPriv->qdCursorMode = TRUE; + ScreenPriv->qdCursorVisible = TRUE; + return TRUE; +} + + +// X server is hiding. Restore the Aqua cursor. +void QuartzSuspendXCursor( + ScreenPtr pScreen ) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + SetCursor(&gQDArrow); + SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); +} + + +// X server is showing. Restore the X cursor. +void QuartzResumeXCursor( + ScreenPtr pScreen, + int x, + int y ) +{ + QuartzSetCursor(pScreen, quartzLatentCursor, x, y); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzCursor.h b/xc/programs/Xserver/hw/darwin/quartz/quartzCursor.h new file mode 100644 index 000000000..9710d4be2 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzCursor.h @@ -0,0 +1,43 @@ +/* + * quartzCursor.h + * + * External interface for Quartz hardware cursor + */ +/* + * Copyright (c) 2001 Torrey T. Lyons and Greg Parker. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzCursor.h,v 1.1 2002/03/28 02:21:19 torrey Exp $ */ + +#ifndef QUARTZCURSOR_H +#define QUARTZCURSOR_H + +#include "screenint.h" + +Bool QuartzInitCursor(ScreenPtr pScreen); +void QuartzSuspendXCursor(ScreenPtr pScreen); +void QuartzResumeXCursor(ScreenPtr pScreen, int x, int y); + +#endif diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzPasteboard.c b/xc/programs/Xserver/hw/darwin/quartz/quartzPasteboard.c new file mode 100644 index 000000000..658832aa1 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzPasteboard.c @@ -0,0 +1,150 @@ +/************************************************************** + * quartzPasteboard.c + * + * Aqua pasteboard <-> X cut buffer + * Greg Parker gparker@cs.stanford.edu March 8, 2001 + **************************************************************/ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzPasteboard.c,v 1.1 2002/03/28 02:21:19 torrey Exp $ */ + +#include "quartzPasteboard.h" + +#include "Xatom.h" +#include "windowstr.h" +#include "propertyst.h" +#include "scrnintstr.h" +#include "selection.h" +#include "globals.h" + +extern Selection *CurrentSelections; +extern int NumCurrentSelections; + + +// Helper function to read the X11 cut buffer +// FIXME: What about multiple screens? Currently, this reads the first +// CUT_BUFFER0 from the first screen where the buffer content is a string. +// Returns a string on the heap that the caller must free. +// Returns NULL if there is no cut text or there is not enough memory. +static char * QuartzReadCutBuffer(void) +{ + int i; + char *text = NULL; + + for (i = 0; i < screenInfo.numScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + PropertyPtr pProp; + + pProp = wUserProps (WindowTable[pScreen->myNum]); + while (pProp && pProp->propertyName != XA_CUT_BUFFER0) { + pProp = pProp->next; + } + if (! pProp) continue; + if (pProp->type != XA_STRING) continue; + if (pProp->format != 8) continue; + + text = xalloc(1 + pProp->size); + if (! text) continue; + memcpy(text, pProp->data, pProp->size); + text[pProp->size] = '\0'; + return text; + } + + // didn't find any text + return NULL; +} + +// Write X cut buffer to Mac OS X pasteboard +// Called by ProcessInputEvents() in response to request from X server thread. +void QuartzWritePasteboard(void) +{ + char *text; + text = QuartzReadCutBuffer(); + if (text) { + QuartzWriteCocoaPasteboard(text); + free(text); + } +} + +#define strequal(a, b) (0 == strcmp((a), (b))) + +// Read Mac OS X pasteboard into X cut buffer +// Called by ProcessInputEvents() in response to request from X server thread. +void QuartzReadPasteboard(void) +{ + char *oldText = QuartzReadCutBuffer(); + char *text = QuartzReadCocoaPasteboard(); + + // Compare text with current cut buffer contents. + // Change the buffer if both exist and are different + // OR if there is new text but no old text. + // Otherwise, don't clear the selection unnecessarily. + + if ((text && oldText && !strequal(text, oldText)) || + (text && !oldText)) { + int scrn, sel; + + for (scrn = 0; scrn < screenInfo.numScreens; scrn++) { + ScreenPtr pScreen = screenInfo.screens[scrn]; + // Set the cut buffers on each screen + // fixme really on each screen? + ChangeWindowProperty(WindowTable[pScreen->myNum], XA_CUT_BUFFER0, + XA_STRING, 8, PropModeReplace, + strlen(text), (pointer)text, TRUE); + } + + // Undo any current X selection (similar to code in dispatch.c) + // FIXME: what about secondary selection? + // FIXME: only touch first XA_PRIMARY selection? + sel = 0; + while ((sel < NumCurrentSelections) && + CurrentSelections[sel].selection != XA_PRIMARY) + sel++; + if (sel < NumCurrentSelections) { + // Notify client if necessary + if (CurrentSelections[sel].client) { + xEvent event; + + event.u.u.type = SelectionClear; + event.u.selectionClear.time = GetTimeInMillis(); + event.u.selectionClear.window = CurrentSelections[sel].window; + event.u.selectionClear.atom = CurrentSelections[sel].selection; + TryClientEvents(CurrentSelections[sel].client, &event, 1, + NoEventMask, NoEventMask /*CantBeFiltered*/, + NullGrab); + } + + // Erase it + // FIXME: need to erase .selection too? dispatch.c doesn't + CurrentSelections[sel].pWin = NullWindow; + CurrentSelections[sel].window = None; + CurrentSelections[sel].client = NullClient; + } + } + + if (text) free(text); + if (oldText) free(oldText); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzPasteboard.h b/xc/programs/Xserver/hw/darwin/quartz/quartzPasteboard.h new file mode 100644 index 000000000..fef375493 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzPasteboard.h @@ -0,0 +1,45 @@ +/* + QuartzPasteboard.h + + Mac OS X pasteboard <-> X cut buffer + Greg Parker gparker@cs.stanford.edu March 8, 2001 +*/ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzPasteboard.h,v 1.1 2002/03/28 02:21:19 torrey Exp $ */ + +#ifndef _QUARTZPASTEBOARD_H +#define _QUARTZPASTEBOARD_H + +// Aqua->X +void QuartzReadPasteboard(); +char * QuartzReadCocoaPasteboard(void); // caller must free string + +// X->Aqua +void QuartzWritePasteboard(); +void QuartzWriteCocoaPasteboard(char *text); + +#endif /* _QUARTZPASTEBOARD_H */
\ No newline at end of file diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzShared.h b/xc/programs/Xserver/hw/darwin/quartz/quartzShared.h new file mode 100644 index 000000000..94c7417ee --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzShared.h @@ -0,0 +1,57 @@ +/* + * quartzShared.h + * + * Shared definitions between the Darwin X Server and the Cocoa front end + * + * This file is included in all parts of the Darwin X Server and must not + * include any types defined in X11 or Mac OS X specific headers. + * Definitions that are internal to the Quartz modes or use Mac OS X + * specific types should be in quartzCommon.h instead of here. + */ +/* + * Copyright (c) 2001 Torrey T. Lyons and Greg Parker. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzShared.h,v 1.2 2002/10/12 00:32:45 torrey Exp $ */ + +#ifndef _QUARTZSHARED_H +#define _QUARTZSHARED_H + +// User preferences used by generic Darwin X server code +extern int quartzMouseAccelChange; +extern int darwinFakeButtons; +extern int darwinFakeMouse2Mask; +extern int darwinFakeMouse3Mask; +extern char *darwinKeymapFile; +extern unsigned int darwinDesiredWidth, darwinDesiredHeight; +extern int darwinDesiredDepth; +extern int darwinDesiredRefresh; + +// location of X11's (0,0) point in global screen coordinates +extern int darwinMainScreenX; +extern int darwinMainScreenY; + +#endif /* _QUARTZSHARED_H */ + diff --git a/xc/programs/Xserver/hw/darwin/quartz/quartzStartup.c b/xc/programs/Xserver/hw/darwin/quartz/quartzStartup.c new file mode 100644 index 000000000..9b210ac6e --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/quartzStartup.c @@ -0,0 +1,139 @@ +/************************************************************** + * + * Startup code for the Quartz Darwin X Server + * + **************************************************************/ +/* + * Copyright (c) 2001 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/quartzStartup.c,v 1.1 2002/03/28 02:21:19 torrey Exp $ */ + +#include <fcntl.h> +#include "quartzCommon.h" +#include "darwin.h" +#include "opaque.h" + +int NSApplicationMain(int argc, char *argv[]); + +char **envpGlobal; // argcGlobal and argvGlobal + // are from dix/globals.c + +/* + * DarwinHandleGUI + * This function is called first from main(). The first time + * it is called we start the Mac OS X front end. The front end + * will call main() again from another thread to run the X + * server. On the second call this function loads the user + * preferences set by the Mac OS X front end. + */ +void DarwinHandleGUI( + int argc, + char *argv[], + char *envp[] ) +{ + static Bool been_here = FALSE; + int main_exit, i; + int fd[2]; + + if (been_here) { + QuartzReadPreferences(); + return; + } + been_here = TRUE; + + // Make a pipe to pass events + assert( pipe(fd) == 0 ); + darwinEventFD = fd[0]; + quartzEventWriteFD = fd[1]; + fcntl(darwinEventFD, F_SETFL, O_NONBLOCK); + + // Store command line arguments to pass back to main() + argcGlobal = argc; + argvGlobal = argv; + envpGlobal = envp; + + // Determine if we need to start X clients + // and what display mode to use + quartzStartClients = 1; + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-nostartx")) { + quartzStartClients = 0; + } else if (!strcmp( argv[i], "-fullscreen")) { + quartzRootless = 0; + } else if (!strcmp( argv[i], "-rootless")) { + quartzRootless = 1; + } + } + + quartz = TRUE; + main_exit = NSApplicationMain(argc, argv); + exit(main_exit); +} + +int QuartzProcessArgument( int argc, char *argv[], int i ) +{ + // fullscreen: CoreGraphics full-screen mode + // rootless: Cocoa rootless mode + // quartz: Default, either fullscreen or rootless + + if ( !strcmp( argv[i], "-fullscreen" ) ) { + ErrorF( "Running full screen in parallel with Mac OS X Quartz window server.\n" ); +#ifdef QUARTZ_SAFETY_DELAY + ErrorF( "Quitting in %d seconds if no controller is found.\n", + QUARTZ_SAFETY_DELAY ); +#endif + return 1; + } + + if ( !strcmp( argv[i], "-rootless" ) ) { + ErrorF( "Running rootless inside Mac OS X window server.\n" ); +#ifdef QUARTZ_SAFETY_DELAY + ErrorF( "Quitting in %d seconds if no controller is found.\n", + QUARTZ_SAFETY_DELAY ); +#endif + return 1; + } + + if ( !strcmp( argv[i], "-quartz" ) ) { + ErrorF( "Running in parallel with Mac OS X Quartz window server.\n" ); +#ifdef QUARTZ_SAFETY_DELAY + ErrorF( "Quitting in %d seconds if no controller is found.\n", + QUARTZ_SAFETY_DELAY ); +#endif + return 1; + } + + // The Mac OS X front end uses this argument, which we just ignore here. + if ( !strcmp( argv[i], "-nostartx" ) ) { + return 1; + } + + // This command line arg is passed when launched from the Aqua GUI. + if ( !strncmp( argv[i], "-psn_", 5 ) ) { + return 1; + } + + return 0; +}
\ No newline at end of file diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootless.h b/xc/programs/Xserver/hw/darwin/quartz/rootless.h new file mode 100644 index 000000000..e2aad5a4c --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootless.h @@ -0,0 +1,136 @@ +/* + * External interface to generic rootless mode + * + * Greg Parker gparker@cs.stanford.edu March 3, 2001 + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootless.h,v 1.2 2002/08/28 06:41:26 torrey Exp $ */ + +#ifndef _ROOTLESS_H +#define _ROOTLESS_H + +#include "mi.h" +#include "gcstruct.h" + +// RootlessFrameRec +// Describes a single rootless window (aka frame). +// The rootless mode keeps track of window position, and the +// rootless implementation is responsible for the pixmap. +// Multiple screens: all coordinates are SCREEN-LOCAL, not global. + + +typedef struct RootlessFrameRec { + /* Data maintained by rootless mode */ + /* position and size, including window border, in screen coordinates */ + int x; + int y; + unsigned int w; + unsigned int h; + WindowPtr win; /* the top-level window drawn in this frame */ + int isRoot; /* TRUE if this is the root window */ + + /* Data maintained by rootless implementation */ + char *pixelData; + int depth; // color bits per pixel; depth <= bitsPerPixel + int bitsPerPixel; + int bytesPerRow; + + void *devPrivate; /* for caller's use */ +} RootlessFrameRec, *RootlessFramePtr; + + +// Create a new frame. +// pUpper is the window above the new frame, or NULL if the new +// frame will be on top. +// pFrame is completely initialized. devPrivate is NULL +// The pixmap must be valid when this is done. +typedef void (*RootlessCreateFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, RootlessFramePtr pUpper); + +// Destroy a frame. Caller must free any private data and the pixmap. +// All drawing is stopped and all updates are flushed before this is called. +typedef void (*RootlessDestroyFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame); + +// Move a frame on screen. +// The frame changes position and nothing else. +// pFrame and pFrame->win already contain the information about the +// new position. oldX and oldY are the old position. +// All updates are flushed before this is called. +// The pixmap may change during this function. +typedef void (*RootlessMoveFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, int oldX, int oldY); + +// Change frame ordering (aka stacking, layering) +// pFrame->win already has its new siblings. +// pOldNext is the window that was below this one, or NULL if this was +// at the bottom. +// pNewNext is the window that is now below this one, or NULL if this is +// now at the bottom. +typedef void (*RootlessRestackFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, + RootlessFramePtr pOldNext, RootlessFramePtr pNewNext); + +// Change the frame's shape. +// pNewShape is in frame-local coordinates. +// Everything outside pNewShape is no longer part of the frame. +// pNewShape is {0, 0, width, height} for a plain-shaped frame. +typedef void (*RootlessReshapeFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, RegionPtr pNewShape); + +// Flush drawing updates to the screen. +// pDamage contains all changed pixels. +// pDamage is in frame-local coordinates. +// pDamage is clipped to the frame bounds and the frame shape. +typedef void (*RootlessUpdateRegionProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, RegionPtr pDamage); + +// Prepare a window for direct access to its backing buffer. +typedef void (*RootlessStartDrawingProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame); + +// Stop access to a window's backing buffer. +typedef void (*RootlessStopDrawingProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame); + +// Frame is about to resize. +// The frame has its new position and size already. +// postconditions: +// The pixmap MUST point to a pixmap with the new size. +// The pixmap data is undefined. +// The old pixmap may be destroyed here. +typedef void (*RootlessStartResizeFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY, unsigned int oldW, unsigned int oldH); + +// Frame is done resizing. +// Destroy the old pixmap if you haven't already. +typedef void (*RootlessFinishResizeFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY, unsigned int oldW, unsigned int oldH); + + +// The callback function list. +// Any of these may be NULL. +typedef struct RootlessFrameProcs { + RootlessCreateFrameProc CreateFrame; + RootlessDestroyFrameProc DestroyFrame; + + RootlessMoveFrameProc MoveFrame; + RootlessStartResizeFrameProc StartResizeFrame; + RootlessFinishResizeFrameProc FinishResizeFrame; + RootlessRestackFrameProc RestackFrame; + RootlessReshapeFrameProc ReshapeFrame; + + RootlessUpdateRegionProc UpdateRegion; + + RootlessStartDrawingProc StartDrawing; + RootlessStopDrawingProc StopDrawing; +} RootlessFrameProcs; + +// Initialize rootless mode on the given screen. +Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcs *procs); + +// Return the rootless frame for the given window or NULL if it's not framed +RootlessFramePtr RootlessFrameForWindow(WindowPtr pWin); + +#endif /* _ROOTLESS_H */ diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessAqua.h b/xc/programs/Xserver/hw/darwin/quartz/rootlessAqua.h new file mode 100644 index 000000000..c64005325 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessAqua.h @@ -0,0 +1,15 @@ +/* + * Rootless setup for Aqua + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessAqua.h,v 1.1 2002/03/28 02:21:19 torrey Exp $ */ + +#ifndef _ROOTLESSAQUA_H +#define _ROOTLESSAQUA_H + +Bool AquaAddScreen(int index, ScreenPtr pScreen); +Bool AquaSetupScreen(int index, ScreenPtr pScreen); +void AquaDisplayInit(void); + +#endif /* _ROOTLESSAQUA_H */ diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaGlue.c b/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaGlue.c new file mode 100644 index 000000000..bebfb411b --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaGlue.c @@ -0,0 +1,242 @@ +/* + * Generic rootless to Aqua specific glue code + * + * This code acts as a glue between the generic rootless X server code + * and the Aqua specific implementation, which includes definitions that + * conflict with stardard X types. + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessAquaGlue.c,v 1.4 2002/07/24 05:58:33 torrey Exp $ */ + +#include "quartzCommon.h" +#include "darwin.h" +#include "rootlessAqua.h" +#include "rootlessAquaImp.h" +#include "rootless.h" +#include "aqua.h" + +#include "regionstr.h" +#include "scrnintstr.h" +#include "picturestr.h" +#include "globals.h" // dixScreenOrigins[] + + +///////////////////////////////////////// +// Rootless mode callback glue + +static void +AquaGlueCreateFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + RootlessFramePtr pUpper) +{ + int sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + int sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + pFrame->devPrivate = AquaNewWindow(pUpper ? pUpper->devPrivate : NULL, + pFrame->x + sx, pFrame->y + sy, + pFrame->w, pFrame->h, + pFrame->isRoot); +} + + +static void +AquaGlueDestroyFrame(ScreenPtr pScreen, RootlessFramePtr pFrame) +{ + AquaDestroyWindow(pFrame->devPrivate); +} + + +static void +AquaGlueMoveFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY) +{ + int sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + int sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + AquaMoveWindow(pFrame->devPrivate, pFrame->x + sx, pFrame->y + sy); +} + + +static void +AquaGlueStartResizeFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY, + unsigned int oldW, unsigned int oldH) +{ + int sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + int sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + AquaStartResizeWindow(pFrame->devPrivate, + pFrame->x + sx, pFrame->y + sy, pFrame->w, pFrame->h); +} + +static void +AquaGlueFinishResizeFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY, + unsigned int oldW, unsigned int oldH) +{ + int sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + int sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + AquaFinishResizeWindow(pFrame->devPrivate, + pFrame->x + sx, pFrame->y + sy, + pFrame->w, pFrame->h); +} + + +static void +AquaGlueRestackFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + RootlessFramePtr pOldPrev, + RootlessFramePtr pNewPrev) +{ + AquaRestackWindow(pFrame->devPrivate, + pNewPrev ? pNewPrev->devPrivate : NULL); +} + + +static void +AquaGlueReshapeFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + RegionPtr pNewShape) +{ + BoxRec shapeBox = {0, 0, pFrame->w, pFrame->h}; + + // Don't correct for dixScreenOrigins here. + // pNewShape is in window-local coordinates. + + if (pFrame->isRoot) return; // shouldn't happen; mi or dix covers this + + REGION_INVERSE(pScreen, pNewShape, pNewShape, &shapeBox); + AquaReshapeWindow(pFrame->devPrivate, + (fakeBoxRec *) REGION_RECTS(pNewShape), + REGION_NUM_RECTS(pNewShape)); +} + + +static void +AquaGlueUpdateRegion(ScreenPtr pScreen, RootlessFramePtr pFrame, + RegionPtr pDamage) +{ + AquaUpdateRects(pFrame->devPrivate, + (fakeBoxRec *) REGION_RECTS(pDamage), + REGION_NUM_RECTS(pDamage)); +} + + +static void +AquaGlueStartDrawing(ScreenPtr pScreen, RootlessFramePtr pFrame) +{ + AquaStartDrawing(pFrame->devPrivate, &pFrame->pixelData, + &pFrame->bytesPerRow, &pFrame->depth, + &pFrame->bitsPerPixel); +} + +static void +AquaGlueStopDrawing(ScreenPtr pScreen, RootlessFramePtr pFrame) +{ + AquaStopDrawing(pFrame->devPrivate); +} + + +static RootlessFrameProcs aquaRootlessProcs = { + AquaGlueCreateFrame, + AquaGlueDestroyFrame, + AquaGlueMoveFrame, + AquaGlueStartResizeFrame, + AquaGlueFinishResizeFrame, + AquaGlueRestackFrame, + AquaGlueReshapeFrame, + AquaGlueUpdateRegion, + AquaGlueStartDrawing, + AquaGlueStopDrawing +}; + + +/////////////////////////////////////// +// Rootless mode initialization. +// Exported by rootlessAqua.h + +/* + * AquaDisplayInit + * Find all Aqua screens. + */ +void +AquaDisplayInit(void) +{ + darwinScreensFound = AquaDisplayCount(); +} + + +/* + * AquaAddScreen + * Init the framebuffer and record pixmap parameters for the screen. + */ +Bool +AquaAddScreen(int index, ScreenPtr pScreen) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + QuartzScreenPtr displayInfo = QUARTZ_PRIV(pScreen); + CGRect cgRect; + CGDisplayCount numDisplays; + CGDisplayCount allocatedDisplays = 0; + CGDirectDisplayID *displays = NULL; + CGDisplayErr cgErr; + + dfb->pixelInfo.pixelType = kIORGBDirectPixels; + AquaScreenInit(index, &dfb->x, &dfb->y, &dfb->width, &dfb->height, + &dfb->pitch, &dfb->pixelInfo.bitsPerComponent, + &dfb->pixelInfo.componentCount, &dfb->bitsPerPixel); + dfb->colorBitsPerPixel = dfb->pixelInfo.bitsPerComponent * + dfb->pixelInfo.componentCount; + + // No frame buffer - it's all in window pixmaps. + dfb->framebuffer = NULL; // malloc(dfb.pitch * dfb.height); + + // Get all CoreGraphics displays covered by this X11 display. + cgRect = CGRectMake(dfb->x, dfb->y, dfb->width, dfb->height); + do { + cgErr = CGGetDisplaysWithRect(cgRect, 0, NULL, &numDisplays); + if (cgErr) break; + allocatedDisplays = numDisplays; + displays = xrealloc(displays, + numDisplays * sizeof(CGDirectDisplayID)); + cgErr = CGGetDisplaysWithRect(cgRect, allocatedDisplays, displays, + &numDisplays); + if (cgErr != CGDisplayNoErr) break; + } while (numDisplays > allocatedDisplays); + + if (cgErr != CGDisplayNoErr || numDisplays == 0) { + ErrorF("Could not find CGDirectDisplayID(s) for X11 screen %d: %dx%d @ %d,%d.\n", + index, dfb->width, dfb->height, dfb->x, dfb->y); + return FALSE; + } + + // This X11 screen covers all CoreGraphics displays we just found. + // If there's more than one CG display, then video mirroring is on + // or PseudoramiX is on. + displayInfo->displayCount = allocatedDisplays; + displayInfo->displayIDs = displays; + + return TRUE; +} + + +/* + * AquaSetupScreen + * Setup the screen for rootless access. + */ +Bool +AquaSetupScreen(int index, ScreenPtr pScreen) +{ + // Add Aqua specific replacements for fb screen functions + pScreen->PaintWindowBackground = AquaPaintWindow; + pScreen->PaintWindowBorder = AquaPaintWindow; + +#ifdef RENDER + { + PictureScreenPtr ps = GetPictureScreen(pScreen); + ps->Composite = AquaComposite; + } +#endif /* RENDER */ + + // Initialize generic rootless code + return RootlessInit(pScreen, &aquaRootlessProcs); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.h b/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.h new file mode 100644 index 000000000..ded22d40b --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.h @@ -0,0 +1,40 @@ +/* + * Rootless implementation for Mac OS X Aqua environment + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.h,v 1.1 2002/03/28 02:21:19 torrey Exp $ */ + +#ifndef _ROOTLESSAQUAIMP_H +#define _ROOTLESSAQUAIMP_H + +#include "fakeBoxRec.h" + +int AquaDisplayCount(); + +void AquaScreenInit(int index, int *x, int *y, int *width, int *height, + int *rowBytes, unsigned long *bps, unsigned long *spp, + int *bpp); + +void *AquaNewWindow(void *upperw, int x, int y, int w, int h, int isRoot); + +void AquaDestroyWindow(void *rw); + +void AquaMoveWindow(void *rw, int x, int y); + +void AquaStartResizeWindow(void *rw, int x, int y, int w, int h); + +void AquaFinishResizeWindow(void *rw, int x, int y, int w, int h); + +void AquaUpdateRects(void *rw, fakeBoxRec *rects, int count); + +void AquaRestackWindow(void *rw, void *lowerw); + +void AquaReshapeWindow(void *rw, fakeBoxRec *rects, int count); + +void AquaStartDrawing(void *rw, char **bits, + int *rowBytes, int *depth, int *bpp); + +void AquaStopDrawing(void *rw); + +#endif /* _ROOTLESSAQUAIMP_H */ diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.m b/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.m new file mode 100644 index 000000000..3a67b3693 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.m @@ -0,0 +1,427 @@ +/* + * Rootless implementation for Mac OS X Aqua environment + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.m,v 1.3 2002/08/28 06:41:26 torrey Exp $ */ + +#include "rootlessAquaImp.h" +#include "fakeBoxRec.h" +#include "quartzCommon.h" +#include "aquaCommon.h" +#include "pseudoramiX.h" +#import <Cocoa/Cocoa.h> +#include <ApplicationServices/ApplicationServices.h> +#import "XView.h" + +extern void ErrorF(const char *, ...); + + +/* + * AquaDisplayCount + * Return the number of displays. + * Multihead note: When rootless mode uses PseudoramiX, the + * X server only sees one screen; only PseudoramiX itself knows + * about all of the screens. + */ +int AquaDisplayCount() +{ + aquaNumScreens = [[NSScreen screens] count]; + + if (noPseudoramiXExtension) { + return aquaNumScreens; + } else { + return 1; // only PseudoramiX knows about the rest + } +} + + +void AquaScreenInit(int index, int *x, int *y, int *width, int *height, + int *rowBytes, unsigned long *bps, unsigned long *spp, + int *bpp) +{ + *bps = 8; + *spp = 3; + *bpp = 32; + + if (noPseudoramiXExtension) { + NSScreen *screen = [[NSScreen screens] objectAtIndex:index]; + NSRect frame = [screen frame]; + + // set x, y so (0,0) is top left of main screen + *x = NSMinX(frame); + *y = NSHeight([[NSScreen mainScreen] frame]) - NSHeight(frame) - + NSMinY(frame); + + *width = NSWidth(frame); + *height = NSHeight(frame); + *rowBytes = (*width) * (*bpp) / 8; + + // Shift the usable part of main screen down to avoid the menu bar. + if (NSEqualRects(frame, [[NSScreen mainScreen] frame])) { + *y += aquaMenuBarHeight; + *height -= aquaMenuBarHeight; + } + + } else { + int i; + NSRect unionRect = NSMakeRect(0, 0, 0, 0); + NSArray *screens = [NSScreen screens]; + + // Get the union of all screens (minus the menu bar on main screen) + for (i = 0; i < [screens count]; i++) { + NSScreen *screen = [screens objectAtIndex:i]; + NSRect frame = [screen frame]; + frame.origin.y = [[NSScreen mainScreen] frame].size.height - + frame.size.height - frame.origin.y; + if (NSEqualRects([screen frame], [[NSScreen mainScreen] frame])) { + frame.origin.y += aquaMenuBarHeight; + frame.size.height -= aquaMenuBarHeight; + } + unionRect = NSUnionRect(unionRect, frame); + } + + // Use unionRect as the screen size for the X server. + *x = unionRect.origin.x; + *y = unionRect.origin.y; + *width = unionRect.size.width; + *height = unionRect.size.height; + *rowBytes = (*width) * (*bpp) / 8; + + // Tell PseudoramiX about the real screens. + // InitOutput() will move the big screen to (0,0), + // so compensate for that here. + for (i = 0; i < [screens count]; i++) { + NSScreen *screen = [screens objectAtIndex:i]; + NSRect frame = [screen frame]; + int j; + + // Skip this screen if it's a mirrored copy of an earlier screen. + for (j = 0; j < i; j++) { + if (NSEqualRects(frame, [[screens objectAtIndex:j] frame])) { + ErrorF("PseudoramiX screen %d is a mirror of screen %d.\n", + i, j); + break; + } + } + if (j < i) continue; // this screen is a mirrored copy + + frame.origin.y = [[NSScreen mainScreen] frame].size.height - + frame.size.height - frame.origin.y; + + if (NSEqualRects([screen frame], [[NSScreen mainScreen] frame])) { + frame.origin.y += aquaMenuBarHeight; + frame.size.height -= aquaMenuBarHeight; + } + + ErrorF("PseudoramiX screen %d added: %dx%d @ (%d,%d).\n", i, + (int)frame.size.width, (int)frame.size.height, + (int)frame.origin.x, (int)frame.origin.y); + + frame.origin.x -= unionRect.origin.x; + frame.origin.y -= unionRect.origin.y; + + ErrorF("PseudoramiX screen %d placed at X11 coordinate (%d,%d).\n", + i, (int)frame.origin.x, (int)frame.origin.y); + + PseudoramiXAddScreen(frame.origin.x, frame.origin.y, + frame.size.width, frame.size.height); + } + } +} + + +/* + * AquaNewWindow + * Create a new on-screen window. + * Rootless windows must not autodisplay! Autodisplay can cause a deadlock. + * Event thread - autodisplay: locks view hierarchy, then window + * X Server thread - window resize: locks window, then view hierarchy + * Deadlock occurs if each thread gets one lock and waits for the other. + * Autodisplay can also cause NSCarbonWindows to lose their contents. +*/ +void *AquaNewWindow(void *upperw, int x, int y, int w, int h, int isRoot) +{ + AquaWindowRec *winRec = (AquaWindowRec *)malloc(sizeof(AquaWindowRec)); + NSRect frame = NSMakeRect(x, NSHeight([[NSScreen mainScreen] frame]) - + y - h, w, h); + NSWindow *theWindow; + XView *theView; + + // Create an NSWindow for the new X11 window + theWindow = [[NSWindow alloc] initWithContentRect:frame + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:YES]; + if (!theWindow) return NULL; + + [theWindow setBackgroundColor:[NSColor clearColor]]; // erase transparent + [theWindow setAlphaValue:1.0]; // draw opaque + [theWindow setOpaque:YES]; // changed when window is shaped + + [theWindow useOptimizedDrawing:YES]; // Has no overlapping sub-views + [theWindow setAutodisplay:NO]; // See comment above + [theWindow disableFlushWindow]; // We do all the flushing manually + [theWindow setHasShadow:!isRoot]; // All windows have shadows except root + [theWindow setReleasedWhenClosed:YES]; // Default, but we want to be sure + + theView = [[XView alloc] initWithFrame:frame]; + [theWindow setContentView:theView]; + [theWindow setInitialFirstResponder:theView]; + + if (upperw) { + AquaWindowRec *upperRec = AQUA_WINREC(upperw); + int uppernum = [upperRec->window windowNumber]; + [theWindow orderWindow:NSWindowBelow relativeTo:uppernum]; + } else { + if (!isRoot) { + [theWindow orderFront:nil]; + winRec->port = NULL; + } + } + + [theWindow setAcceptsMouseMovedEvents:YES]; + + winRec->window = theWindow; + winRec->view = theView; + + if (!isRoot) { + winRec->rootGWorld = NULL; + [theView lockFocus]; + // Fill the window with white to make sure alpha channel is set + NSEraseRect(frame); + winRec->port = [theView qdPort]; + winRec->context = [[NSGraphicsContext currentContext] graphicsPort]; + // CreateCGContextForPort(winRec->port, &winRec->context); + [theView unlockFocus]; + } else { + // Allocate the offscreen graphics world for root window drawing + GWorldPtr rootGWorld; + Rect globalRect; + + SetRect(&globalRect, x, y, x+w, y+h); + if (NewGWorld(&rootGWorld, 0, &globalRect, NULL, NULL, 0)) + return NULL; + winRec->rootGWorld = rootGWorld; + } + + return winRec; +} + + +void AquaDestroyWindow(void *rw) +{ + AquaWindowRec *winRec = AQUA_WINREC(rw); + + [winRec->window orderOut:nil]; + [winRec->window close]; + [winRec->view release]; + if (winRec->rootGWorld) { + DisposeGWorld(winRec->rootGWorld); + } + free(rw); +} + + +void AquaMoveWindow(void *rw, int x, int y) +{ + AquaWindowRec *winRec = AQUA_WINREC(rw); + NSPoint topLeft = NSMakePoint(x, NSHeight([[NSScreen mainScreen] frame]) - + y); + + [winRec->window setFrameTopLeftPoint:topLeft]; +} + + +/* + * AquaStartResizeWindow + * Undo any shape and resize the on screen window. + */ +void AquaStartResizeWindow(void *rw, int x, int y, int w, int h) +{ + AquaWindowRec *winRec = AQUA_WINREC(rw); + NSRect frame = NSMakeRect(x, NSHeight([[NSScreen mainScreen] frame]) - + y - h, w, h); + + [winRec->window setFrame:frame display:NO]; +} + + +void AquaFinishResizeWindow(void *rw, int x, int y, int w, int h) +{ + // refresh everything? fixme yes for testing + fakeBoxRec box = {0, 0, w, h}; + AquaUpdateRects(rw, &box, 1); +} + + +/* + * AquaUpdateRects + * Flush rectangular regions from a window's backing buffer + * (or PixMap for the root window) to the screen. + */ +void AquaUpdateRects(void *rw, fakeBoxRec *fakeRects, int count) +{ + AquaWindowRec *winRec = AQUA_WINREC(rw); + fakeBoxRec *rects, *end; + static RgnHandle rgn = NULL; + static RgnHandle box = NULL; + + if (!rgn) rgn = NewRgn(); + if (!box) box = NewRgn(); + + if (winRec->rootGWorld) { + // FIXME: Draw from the root PixMap to the normally + // invisible root window. + } else { + for (rects = fakeRects, end = fakeRects+count; rects < end; rects++) { + Rect qdrect; + qdrect.left = rects->x1; + qdrect.top = rects->y1; + qdrect.right = rects->x2; + qdrect.bottom = rects->y2; + + RectRgn(box, &qdrect); + UnionRgn(rgn, box, rgn); + } + + QDFlushPortBuffer(winRec->port, rgn); + } + + SetEmptyRgn(rgn); + SetEmptyRgn(box); +} + + +/* + * AquaRestackWindow + * Change the window order. Put the window behind upperw or on top if + * upperw is NULL. + */ +void AquaRestackWindow(void *rw, void *upperw) +{ + AquaWindowRec *winRec = AQUA_WINREC(rw); + + if (upperw) { + AquaWindowRec *upperRec = AQUA_WINREC(upperw); + int uppernum = [upperRec->window windowNumber]; + [winRec->window orderWindow:NSWindowBelow relativeTo:uppernum]; + } else { + [winRec->window makeKeyAndOrderFront:nil]; + } +} + + +/* + * AquaReshapeWindow + * Set the shape of a window. The rectangles are the areas that are + * not part of the new shape. + */ +void AquaReshapeWindow(void *rw, fakeBoxRec *fakeRects, int count) +{ + AquaWindowRec *winRec = AQUA_WINREC(rw); + NSRect frame = [winRec->view frame]; + int winHeight = NSHeight(frame); + + if (count > 0) { + fakeBoxRec *rects, *end; + + // Make transparent if window is now shaped. + [winRec->window setOpaque:NO]; + + // Clear the areas outside the window shape + [winRec->view lockFocus]; + [[NSColor clearColor] set]; + for (rects = fakeRects, end = fakeRects+count; rects < end; rects++) { + int rectHeight = rects->y2 - rects->y1; + NSRectFill( NSMakeRect(rects->x1, + winHeight - rects->y1 - rectHeight, + rects->x2 - rects->x1, rectHeight) ); + } + [[NSGraphicsContext currentContext] flushGraphics]; + [winRec->view unlockFocus]; + + // force update of window shadow + [winRec->window setHasShadow:NO]; + [winRec->window setHasShadow:YES]; + + } else { + fakeBoxRec bounds = {0, 0, NSWidth(frame), winHeight}; + + [winRec->window setOpaque:YES]; + AquaUpdateRects(rw, &bounds, 1); + } +} + + +/* AquaStartDrawing + * When a window's buffer is not being drawn to, the CoreGraphics + * window server may compress or move it. Call this routine + * to lock down the buffer during direct drawing. It returns + * a pointer to the backing buffer and its depth, etc. + */ +void AquaStartDrawing(void *rw, char **bits, + int *rowBytes, int *depth, int *bpp) +{ + AquaWindowRec *winRec = AQUA_WINREC(rw); + PixMapHandle pix; + + if (! winRec->rootGWorld) { + [winRec->view lockFocus]; + winRec->port = [winRec->view qdPort]; + LockPortBits(winRec->port); + [winRec->view unlockFocus]; + pix = GetPortPixMap(winRec->port); + } else { + pix = GetGWorldPixMap(winRec->rootGWorld); + LockPixels(pix); + } + + *bits = GetPixBaseAddr(pix); + *rowBytes = GetPixRowBytes(pix) & 0x3fff; // fixme is mask needed? + *depth = (**pix).cmpCount * (**pix).cmpSize; // fixme use GetPixDepth(pix)? + *bpp = (**pix).pixelSize; +} + + +/* + * AquaStopDrawing + * When direct access to a window's buffer is no longer needed, this + * routine should be called to allow CoreGraphics to compress or + * move it. + */ +void AquaStopDrawing(void *rw) +{ + AquaWindowRec *winRec = AQUA_WINREC(rw); + + if (! winRec->rootGWorld) { + UnlockPortBits(winRec->port); + } else { + PixMapHandle pix = GetGWorldPixMap(winRec->rootGWorld); + UnlockPixels(pix); + } +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessCommon.c b/xc/programs/Xserver/hw/darwin/quartz/rootlessCommon.c new file mode 100644 index 000000000..2018fa84f --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessCommon.c @@ -0,0 +1,360 @@ +/* + * Common rootless definitions and code + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessCommon.c,v 1.6 2002/07/15 19:58:31 torrey Exp $ */ + +#include "rootlessCommon.h" + + +RegionRec rootlessHugeRoot = {{-32767, -32767, 32767, 32767}, NULL}; + + +/* + * TopLevelParent + * Returns the top-level parent of pWindow. + * The root is the top-level parent of itself, even though the root is + * not otherwise considered to be a top-level window. + */ +WindowPtr TopLevelParent(WindowPtr pWindow) +{ + WindowPtr top = pWindow; + + if (IsRoot(pWindow)) return pWindow; // root is top-level parent of itself + while (top && ! IsTopLevel(top)) top = top->parent; + return top; +} + + +/* + * IsFramedWindow + * Returns TRUE if this window is visible inside a frame + * (e.g. it is visible and has a top-level or root parent) + */ +Bool IsFramedWindow(WindowPtr pWin) +{ + WindowPtr top; + + if (! pWin->realized) return FALSE; + top = TopLevelParent(pWin); + return (top && WINREC(top)); +} + + +/* + * RootlessStartDrawing + * Prepare a window for direct access to its backing buffer. + * Each top-level parent has a Pixmap representing its backing buffer, + * which all of its children inherit. + */ +void RootlessStartDrawing(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + WindowPtr top = TopLevelParent(pWindow); + RootlessWindowRec *winRec; + + if (!top) return; + winRec = WINREC(top); + if (!winRec) return; + + // Make sure the window's top-level parent is prepared for drawing. + if (!winRec->drawing) { + int bw = wBorderWidth(top); + + CallFrameProc(pScreen, StartDrawing, (pScreen, &winRec->frame)); + winRec->pixmap = + GetScratchPixmapHeader(pScreen, winRec->frame.w, winRec->frame.h, + winRec->frame.depth, + winRec->frame.bitsPerPixel, + winRec->frame.bytesPerRow, + winRec->frame.pixelData); + SetPixmapBaseToScreen(winRec->pixmap, + top->drawable.x - bw, top->drawable.y - bw); + winRec->drawing = TRUE; + } + + winRec->oldPixmap = pScreen->GetWindowPixmap(pWindow); + pScreen->SetWindowPixmap(pWindow, winRec->pixmap); +} + + +/* + * RootlessStopDrawing + * Stop drawing to a window's backing buffer. + */ +void RootlessStopDrawing(WindowPtr pWindow) +{ + WindowPtr top = TopLevelParent(pWindow); + RootlessWindowRec *winRec; + + if (!top) return; + winRec = WINREC(top); + if (!winRec) return; + + if (winRec->drawing) { + ScreenPtr pScreen = pWindow->drawable.pScreen; + CallFrameProc(pScreen, StopDrawing, (pScreen, &winRec->frame)); + FreeScratchPixmapHeader(winRec->pixmap); + pScreen->SetWindowPixmap(pWindow, winRec->oldPixmap); + winRec->pixmap = NULL; + winRec->drawing = FALSE; + } +} + +#if 0 +// NSCarbonWindow Note: Windows no longer need a backing pixmap +// other than the one provided by the implementation. +// This routine is obsolete. + +// Update pWindow's pixmap. +// This needs to be called every time a window moves relative to +// its top-level parent, or the parent's pixmap data is reallocated. +// Three cases: +// * window is top-level with no existing pixmap: make one +// * window is top-level with existing pixmap: update it in place +// * window is descendant of top-level: point to top-level's pixmap +void UpdatePixmap(WindowPtr pWindow) +{ + WindowPtr top = TopLevelParent(pWindow); + RootlessWindowRec *winRec; + ScreenPtr pScreen = pWindow->drawable.pScreen; + PixmapPtr pix; + + RL_DEBUG_MSG("update pixmap (win 0x%x)", pWindow); + + // Don't use IsFramedWindow(); window is unrealized during RealizeWindow(). + + if (! top) { + RL_DEBUG_MSG("no parent\n"); + return; + } + winRec = WINREC(top); + if (!winRec) { + RL_DEBUG_MSG("not framed\n"); + return; + } + + if (pWindow == top) { + // This is the top window. Update its pixmap. + int bw = wBorderWidth(pWindow); + + if (winRec->pixmap == NULL) { + // Allocate a new pixmap. + pix = GetScratchPixmapHeader(pScreen, + winRec->frame.w, winRec->frame.h, + winRec->frame.depth, + winRec->frame.bitsPerPixel, + winRec->frame.bytesPerRow, + winRec->frame.pixelData); + SetPixmapBaseToScreen(pix, pWindow->drawable.x - bw, + pWindow->drawable.y - bw); + pScreen->SetWindowPixmap(pWindow, pix); + winRec->pixmap = pix; + } else { + // Update existing pixmap. Update in place so we don't have to + // change the children's pixmaps. + int bw = wBorderWidth(top); + + pix = winRec->pixmap; + pScreen->ModifyPixmapHeader(pix, + winRec->frame.w, winRec->frame.h, + winRec->frame.depth, + winRec->frame.bitsPerPixel, + winRec->frame.bytesPerRow, + winRec->frame.pixelData); + SetPixmapBaseToScreen(pix, top->drawable.x - bw, + top->drawable.y - bw); + } + } else { + // This is not the top window. Point to the parent's pixmap. + pix = winRec->pixmap; + pScreen->SetWindowPixmap(pWindow, pix); + } + + RL_DEBUG_MSG("done\n"); +} +#endif + +#ifdef SHAPE + +// boundingShape = outside border (like borderClip) +// clipShape = inside border (like clipList) +// Both are in window-local coordinates +// We only care about boundingShape (fixme true?) + +// RootlessReallySetShape is used in several places other than SetShape. +// Most importantly, SetShape is often called on unmapped windows, so we +// have to wait until the window is mapped to reshape the frame. +static void RootlessReallySetShape(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec newShape; + + if (IsRoot(pWin)) return; + if (!IsTopLevel(pWin)) return; + if (!winRec) return; + + RootlessStopDrawing(pWin); + + if (wBoundingShape(pWin)) { + // wBoundingShape is relative to *inner* origin of window. + // Translate by borderWidth to get the outside-relative position. + REGION_INIT(pScreen, &newShape, NullBox, 0); + REGION_COPY(pScreen, &newShape, wBoundingShape(pWin)); + REGION_TRANSLATE(pScreen, &newShape, pWin->borderWidth, + pWin->borderWidth); + } else { + newShape.data = NULL; + newShape.extents.x1 = 0; + newShape.extents.y1 = 0; + newShape.extents.x2 = winRec->frame.w; + newShape.extents.y2 = winRec->frame.h; + } + RL_DEBUG_MSG("reshaping..."); + RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ", + REGION_NUM_RECTS(&newShape), + newShape.extents.x1, newShape.extents.y1, + newShape.extents.x2, newShape.extents.y2); + CallFrameProc(pScreen, ReshapeFrame, (pScreen, &winRec->frame, &newShape)); + REGION_UNINIT(pScreen, &newShape); +} + +#endif // SHAPE + + +// pRegion is GLOBAL +void +RootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion) +{ + RL_DEBUG_MSG("Damaged win 0x%x ", pWindow); + pWindow = TopLevelParent(pWindow); + RL_DEBUG_MSG("parent 0x%x:\n", pWindow); + if (!pWindow) { + RL_DEBUG_MSG("RootlessDamageRegion: window is not framed\n"); + } else if (!WINREC(pWindow)) { + RL_DEBUG_MSG("RootlessDamageRegion: top-level window not a frame\n"); + } else { + REGION_UNION((pWindow)->drawable.pScreen, &WINREC(pWindow)->damage, + &WINREC(pWindow)->damage, (pRegion)); + } + +#ifdef ROOTLESSDEBUG + { + BoxRec *box = REGION_RECTS(pRegion), *end; + int numBox = REGION_NUM_RECTS(pRegion); + + for (end = box+numBox; box < end; box++) { + RL_DEBUG_MSG("Damage rect: %i, %i, %i, %i\n", + box->x1, box->x2, box->y1, box->y2); + } + } +#endif +} + + +// pBox is GLOBAL +void +RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox) +{ + RegionRec region; + + REGION_INIT(pWindow->drawable.pScreen, ®ion, pBox, 1); + RootlessDamageRegion(pWindow, ®ion); +} + + +// (x, y, w, h) is in window-local coordinates. +void +RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h) +{ + BoxRec box; + RegionRec region; + + x += pWindow->drawable.x; + y += pWindow->drawable.y; + box.x1 = x; + box.x2 = x + w; + box.y1 = y; + box.y2 = y + h; + REGION_INIT(pWindow->drawable.pScreen, ®ion, &box, 1); + RootlessDamageRegion(pWindow, ®ion); +} + +#ifdef SHAPE + +void +RootlessDamageShape(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + + // We only care about the shape of top-level framed windows. + if (IsRoot(pWin)) return; + if (!IsTopLevel(pWin)) return; + if (!winRec) return; + + winRec->shapeDamage = TRUE; +} + +#endif // SHAPE + +/* + * RootlessRedisplay + * Stop drawing and redisplay the damaged region of a window. + */ +void +RootlessRedisplay(WindowPtr pWindow) +{ + RootlessWindowRec *winRec = WINREC(pWindow); + ScreenPtr pScreen = pWindow->drawable.pScreen; + +#ifdef SHAPE + if (winRec->shapeDamage) { + // Reshape the window. This will also update the entire window. + RootlessReallySetShape(pWindow); + REGION_EMPTY(pScreen, &winRec->damage); + winRec->shapeDamage = FALSE; + } else +#endif // SHAPE + { + RootlessStopDrawing(pWindow); + if (REGION_NOTEMPTY(pScreen, &winRec->damage)) { + RL_DEBUG_MSG("Redisplay Win 0x%x, %i x %i @ (%i, %i)\n", + pWindow, winRec->frame.w, winRec->frame.h, + winRec->frame.x, winRec->frame.y); + + REGION_INTERSECT(pScreen, &winRec->damage, &winRec->damage, + &pWindow->borderSize); + + // move region to window local coords + REGION_TRANSLATE(pScreen, &winRec->damage, + -winRec->frame.x, -winRec->frame.y); + CallFrameProc(pScreen, UpdateRegion, + (pScreen, &winRec->frame, &winRec->damage)); + REGION_EMPTY(pScreen, &winRec->damage); + } + } +} + + +/* + * RootlessRedisplayScreen + * Walk every window on a screen and redisplay the damaged regions. + */ +void +RootlessRedisplayScreen(ScreenPtr pScreen) +{ + WindowPtr root = WindowTable[pScreen->myNum]; + + if (root) { + WindowPtr win; + + RootlessRedisplay(root); + for (win = root->firstChild; win; win = win->nextSib) { + if (WINREC(win)) { + RootlessRedisplay(win); + } + } + } +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessCommon.h b/xc/programs/Xserver/hw/darwin/quartz/rootlessCommon.h new file mode 100644 index 000000000..43a74e106 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessCommon.h @@ -0,0 +1,228 @@ +/* + * Common internal rootless definitions and code + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessCommon.h,v 1.6 2002/07/24 05:58:33 torrey Exp $ */ + +#ifndef _ROOTLESSCOMMON_H +#define _ROOTLESSCOMMON_H + +#include "rootless.h" + +#include "pixmapstr.h" +#include "windowstr.h" + +#ifdef RENDER +#include "picturestr.h" +#endif + + +// Debug output, or not. +#ifdef ROOTLESSDEBUG +#define RL_DEBUG_MSG ErrorF +#else +#define RL_DEBUG_MSG(a, ...) +#endif + + +// Global variables +extern int rootlessGCPrivateIndex; +extern int rootlessScreenPrivateIndex; +extern int rootlessWindowPrivateIndex; + + +// RootlessGCRec: private per-gc data +typedef struct { + GCFuncs *originalFuncs; + GCOps *originalOps; +} RootlessGCRec; + + +// RootlessWindowRec: private per-window data +typedef struct RootlessWindowRec { + RootlessFrameRec frame; + RegionRec damage; + unsigned int borderWidth; // needed for MoveWindow(VTOther) (%$#@!!!) + PixmapPtr pixmap; + PixmapPtr oldPixmap; + BOOL drawing; // TRUE if currently drawing +#ifdef SHAPE + BOOL shapeDamage; // TRUE if shape has changed +#endif +} RootlessWindowRec; + + +// RootlessScreenRec: per-screen private data +typedef struct { + ScreenPtr pScreen; + RootlessFrameProcs frameProcs; + + CloseScreenProcPtr CloseScreen; + + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + MoveWindowProcPtr MoveWindow; + ResizeWindowProcPtr ResizeWindow; + RestackWindowProcPtr RestackWindow; + ChangeBorderWidthProcPtr ChangeBorderWidth; + PositionWindowProcPtr PositionWindow; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + + CreateGCProcPtr CreateGC; + PaintWindowBackgroundProcPtr PaintWindowBackground; + PaintWindowBorderProcPtr PaintWindowBorder; + CopyWindowProcPtr CopyWindow; + GetImageProcPtr GetImage; + SourceValidateProcPtr SourceValidate; + + MarkOverlappedWindowsProcPtr MarkOverlappedWindows; + ValidateTreeProcPtr ValidateTree; + +#ifdef SHAPE + SetShapeProcPtr SetShape; +#endif + +#ifdef RENDER + CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; +#endif + +} RootlessScreenRec; + + +// "Definition of the Porting Layer for the X11 Sample Server" says +// unwrap and rewrap of screen functions is unnecessary, but +// screen->CreateGC changes after a call to cfbCreateGC. + +#define SCREEN_UNWRAP(screen, fn) \ + screen->fn = SCREENREC(screen)->fn; + +#define SCREEN_WRAP(screen, fn) \ + SCREENREC(screen)->fn = screen->fn; \ + screen->fn = Rootless##fn + + +// Accessors for screen and window privates + +#define SCREENREC(pScreen) \ + ((RootlessScreenRec*)(pScreen)->devPrivates[rootlessScreenPrivateIndex].ptr) + +#define WINREC(pWin) \ + ((RootlessWindowRec *)(pWin)->devPrivates[rootlessWindowPrivateIndex].ptr) + + +// Call a rootless implementation function. +// Many rootless implementation functions are allowed to be NULL. +#define CallFrameProc(pScreen, proc, params) \ + if (SCREENREC(pScreen)->frameProcs.proc) { \ + RL_DEBUG_MSG("calling frame proc " #proc " "); \ + SCREENREC(pScreen)->frameProcs.proc params; \ + } + + +// BoxRec manipulators +// Copied from shadowfb + +#define TRIM_BOX(box, pGC) { \ + BoxPtr extents = &pGC->pCompositeClip->extents;\ + if(box.x1 < extents->x1) box.x1 = extents->x1; \ + if(box.x2 > extents->x2) box.x2 = extents->x2; \ + if(box.y1 < extents->y1) box.y1 = extents->y1; \ + if(box.y2 > extents->y2) box.y2 = extents->y2; \ +} + +#define TRANSLATE_BOX(box, pDraw) { \ + box.x1 += pDraw->x; \ + box.x2 += pDraw->x; \ + box.y1 += pDraw->y; \ + box.y2 += pDraw->y; \ +} + +#define TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC) { \ + TRANSLATE_BOX(box, pDraw); \ + TRIM_BOX(box, pGC); \ +} + +#define BOX_NOT_EMPTY(box) \ + (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0)) + + +// HUGE_ROOT and NORMAL_ROOT +// We don't want to clip windows to the edge of the screen. +// HUGE_ROOT temporarily makes the root window really big. +// This is needed as a wrapper around any function that calls +// SetWinSize or SetBorderSize which clip a window against its +// parents, including the root. + +extern RegionRec rootlessHugeRoot; + +#define HUGE_ROOT(pWin) \ + { \ + WindowPtr w = pWin; \ + while (w->parent) w = w->parent; \ + saveRoot = w->winSize; \ + w->winSize = rootlessHugeRoot; \ + } + +#define NORMAL_ROOT(pWin) \ + { \ + WindowPtr w = pWin; \ + while (w->parent) w = w->parent; \ + w->winSize = saveRoot; \ + } + + +// Returns TRUE if this window is a top-level window (i.e. child of the root) +// The root is not a top-level window. +#define IsTopLevel(pWin) \ + ((pWin) && (pWin)->parent && !(pWin)->parent->parent) + +// Returns TRUE if this window is a root window +#define IsRoot(pWin) \ + ((pWin) == WindowTable[(pWin)->drawable.pScreen->myNum]) + + +/* + * SetPixmapBaseToScreen + * Move the given pixmap's base address to where pixel (0, 0) + * would be if the pixmap's actual data started at (x, y). + */ +#define SetPixmapBaseToScreen(pix, x, y) { \ + PixmapPtr _pPix = (PixmapPtr) (pix); \ + _pPix->devPrivate.ptr = (char *) (_pPix->devPrivate.ptr) - \ + ((int)(x) * _pPix->drawable.bitsPerPixel/8 + \ + (int)(y) * _pPix->devKind); \ +} + + +// Returns the top-level parent of pWindow. +// The root is the top-level parent of itself, even though the root is +// not otherwise considered to be a top-level window. +WindowPtr TopLevelParent(WindowPtr pWindow); + +// Returns TRUE if this window is visible inside a frame +// (e.g. it is visible and has a top-level or root parent) +Bool IsFramedWindow(WindowPtr pWin); + +// Prepare a window for direct access to its backing buffer. +void RootlessStartDrawing(WindowPtr pWindow); + +// Finish drawing to a window's backing buffer. +void RootlessStopDrawing(WindowPtr pWindow); + +// Routines that cause regions to get redrawn. +// DamageRegion and DamageRect are in global coordinates. +// DamageBox is in window-local coordinates. +void RootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion); +void RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h); +void RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox); +void RootlessRedisplay(WindowPtr pWindow); +void RootlessRedisplayScreen(ScreenPtr pScreen); + +// Window reshape needs to be updated. The reshape also forces complete redraw. +void RootlessDamageShape(WindowPtr pWin); + +#endif // _ROOTLESSCOMMON_H diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessGC.c b/xc/programs/Xserver/hw/darwin/quartz/rootlessGC.c new file mode 100644 index 000000000..1542d2c00 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessGC.c @@ -0,0 +1,1218 @@ +/* + * Graphics Context support for Mac OS X rootless X server + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessGC.c,v 1.3 2002/07/24 05:58:33 torrey Exp $ */ + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "dixfontstr.h" +#include "mivalidate.h" +#include "fb.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "rootlessCommon.h" +#include "aqua.h" + + +// GC functions +static void RootlessValidateGC(GCPtr pGC, unsigned long changes, + DrawablePtr pDrawable); +static void RootlessChangeGC(GCPtr pGC, unsigned long mask); +static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void RootlessDestroyGC(GCPtr pGC); +static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, + int nrects); +static void RootlessDestroyClip(GCPtr pGC); +static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc); + +GCFuncs rootlessGCFuncs = { + RootlessValidateGC, + RootlessChangeGC, + RootlessCopyGC, + RootlessDestroyGC, + RootlessChangeClip, + RootlessDestroyClip, + RootlessCopyClip, +}; + +// GC operations +static void RootlessFillSpans(); +static void RootlessSetSpans(); +static void RootlessPutImage(); +static RegionPtr RootlessCopyArea(); +static RegionPtr RootlessCopyPlane(); +static void RootlessPolyPoint(); +static void RootlessPolylines(); +static void RootlessPolySegment(); +static void RootlessPolyRectangle(); +static void RootlessPolyArc(); +static void RootlessFillPolygon(); +static void RootlessPolyFillRect(); +static void RootlessPolyFillArc(); +static int RootlessPolyText8(); +static int RootlessPolyText16(); +static void RootlessImageText8(); +static void RootlessImageText16(); +static void RootlessImageGlyphBlt(); +static void RootlessPolyGlyphBlt(); +static void RootlessPushPixels(); + +static GCOps rootlessGCOps = { + RootlessFillSpans, + RootlessSetSpans, + RootlessPutImage, + RootlessCopyArea, + RootlessCopyPlane, + RootlessPolyPoint, + RootlessPolylines, + RootlessPolySegment, + RootlessPolyRectangle, + RootlessPolyArc, + RootlessFillPolygon, + RootlessPolyFillRect, + RootlessPolyFillArc, + RootlessPolyText8, + RootlessPolyText16, + RootlessImageText8, + RootlessImageText16, + RootlessImageGlyphBlt, + RootlessPolyGlyphBlt, + RootlessPushPixels +#ifdef NEED_LINEHELPER + , NULL +#endif +}; + + +Bool +RootlessCreateGC(GCPtr pGC) +{ + RootlessGCRec *gcrec; + RootlessScreenRec *s; + Bool result; + + SCREEN_UNWRAP(pGC->pScreen, CreateGC); + s = (RootlessScreenRec *) pGC->pScreen-> + devPrivates[rootlessScreenPrivateIndex].ptr; + result = s->CreateGC(pGC); + gcrec = (RootlessGCRec *) pGC->devPrivates[rootlessGCPrivateIndex].ptr; + gcrec->originalOps = NULL; // don't wrap ops yet + gcrec->originalFuncs = pGC->funcs; + pGC->funcs = &rootlessGCFuncs; + + SCREEN_WRAP(pGC->pScreen, CreateGC); + return result; +} + + +// GC func wrapping +// ValidateGC wraps gcOps iff dest is viewable. All others just unwrap&call. + +// GCFUN_UNRAP assumes funcs have been wrapped and +// does not assume ops have been wrapped +#define GCFUNC_UNWRAP(pGC) \ + RootlessGCRec *gcrec = (RootlessGCRec *) \ + (pGC)->devPrivates[rootlessGCPrivateIndex].ptr; \ + (pGC)->funcs = gcrec->originalFuncs; \ + if (gcrec->originalOps) { \ + (pGC)->ops = gcrec->originalOps; \ +} + +#define GCFUNC_WRAP(pGC) \ + gcrec->originalFuncs = (pGC)->funcs; \ + (pGC)->funcs = &rootlessGCFuncs; \ + if (gcrec->originalOps) { \ + gcrec->originalOps = (pGC)->ops; \ + (pGC)->ops = &rootlessGCOps; \ +} + + +static void +RootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + + GCFUNC_UNWRAP(pGC); + + gcrec->originalOps = NULL; + + if (pDrawable->type == DRAWABLE_WINDOW) + { + // We force a planemask so fb doesn't overwrite the alpha channel. + // Left to its own devices, fb will optimize away the planemask. + int depth = pDrawable->depth; + pDrawable->depth = pDrawable->bitsPerPixel; + pGC->planemask &= ~AquaAlphaMask(pDrawable->bitsPerPixel); + pGC->funcs->ValidateGC(pGC, changes, pDrawable); + pDrawable->depth = depth; + + if (((WindowPtr) pDrawable)->viewable) { + gcrec->originalOps = pGC->ops; + } + } else { + pGC->funcs->ValidateGC(pGC, changes, pDrawable); + } + + GCFUNC_WRAP(pGC); +} + +static void RootlessChangeGC(GCPtr pGC, unsigned long mask) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->ChangeGC(pGC, mask); + GCFUNC_WRAP(pGC); +} + +static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) +{ + GCFUNC_UNWRAP(pGCDst); + pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst); + GCFUNC_WRAP(pGCDst); +} + +static void RootlessDestroyGC(GCPtr pGC) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->DestroyGC(pGC); + GCFUNC_WRAP(pGC); +} + +static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); + GCFUNC_WRAP(pGC); +} + +static void RootlessDestroyClip(GCPtr pGC) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->DestroyClip(pGC); + GCFUNC_WRAP(pGC); +} + +static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + GCFUNC_UNWRAP(pgcDst); + pgcDst->funcs->CopyClip(pgcDst, pgcSrc); + GCFUNC_WRAP(pgcDst); +} + + +// GC ops +// We can't use shadowfb because shadowfb assumes one pixmap +// and our root window is a special case. +// So much of this code is copied from shadowfb. + +// assumes both funcs and ops are wrapped +#define GCOP_UNWRAP(pGC) \ + RootlessGCRec *gcrec = (RootlessGCRec *) \ + (pGC)->devPrivates[rootlessGCPrivateIndex].ptr; \ + GCFuncs *saveFuncs = pGC->funcs; \ + (pGC)->funcs = gcrec->originalFuncs; \ + (pGC)->ops = gcrec->originalOps; + +#define GCOP_WRAP(pGC) \ + gcrec->originalOps = (pGC)->ops; \ + (pGC)->funcs = saveFuncs; \ + (pGC)->ops = &rootlessGCOps; + + +static void +RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, int sorted) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("fill spans start "); + + if (nInit <= 0) { + pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); + } else { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nInit; + BoxRec box; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while(--i) { + ppt++; + pwidthInit++; + if(box.x1 > ppt->x) + box.x1 = ppt->x; + if(box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if(box.y1 > ppt->y) + box.y1 = ppt->y; + else if(box.y2 < ppt->y) + box.y2 = ppt->y; + } + + box.y2++; + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill spans end\n"); +} + +static void +RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc, + DDXPointPtr pptInit, int *pwidthInit, + int nspans, int sorted) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("set spans start "); + + if (nspans <= 0) { + pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, + nspans, sorted); + } else { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nspans; + BoxRec box; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while(--i) { + ppt++; + pwidth++; + if(box.x1 > ppt->x) + box.x1 = ppt->x; + if(box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if(box.y1 > ppt->y) + box.y1 = ppt->y; + else if(box.y2 < ppt->y) + box.y2 = ppt->y; + } + + box.y2++; + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, + nspans, sorted); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + GCOP_WRAP(pGC); + RL_DEBUG_MSG("set spans end\n"); +} + +static void +RootlessPutImage(DrawablePtr dst, GCPtr pGC, + int depth, int x, int y, int w, int h, + int leftPad, int format, char *pBits) +{ + BoxRec box; + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("put image start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PutImage(dst, pGC, depth, x,y,w,h, leftPad, format, pBits); + + box.x1 = x + dst->x; + box.x2 = box.x1 + w; + box.y1 = y + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("put image end\n"); +} + +/* changed area is *dest* rect */ +static RegionPtr +RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC, + int srcx, int srcy, int w, int h, + int dstx, int dsty) +{ + RegionPtr result; + BoxRec box; + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst); + + if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) { + RootlessStartDrawing((WindowPtr) pSrc); + } + RootlessStartDrawing((WindowPtr) dst); + result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty); + + box.x1 = dstx + dst->x; + box.x2 = box.x1 + w; + box.y1 = dsty + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("copy area end\n"); + return result; +} + +/* changed area is *dest* rect */ +static RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst, + GCPtr pGC, int srcx, int srcy, + int w, int h, int dstx, int dsty, + unsigned long plane) +{ + RegionPtr result; + BoxRec box; + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("copy plane start "); + + if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) { + RootlessStartDrawing((WindowPtr) pSrc); + } + RootlessStartDrawing((WindowPtr) dst); + result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h, + dstx, dsty, plane); + + box.x1 = dstx + dst->x; + box.x2 = box.x1 + w; + box.y1 = dsty + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("copy plane end\n"); + return result; +} + +// Options for size of changed area: +// 0 = box per point +// 1 = big box around all points +// 2 = accumulate point in 20 pixel radius +#define ROOTLESS_CHANGED_AREA 1 +#define abs(a) ((a) > 0 ? (a) : -(a)) + +/* changed area is box around all points */ +static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("polypoint start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit); + + if (npt > 0) { +#if ROOTLESS_CHANGED_AREA==0 + // box per point + BoxRec box; + + while (npt) { + box.x1 = pptInit->x; + box.y1 = pptInit->y; + box.x2 = box.x1 + 1; + box.y2 = box.y1 + 1; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + npt--; + pptInit++; + } + +#elif ROOTLESS_CHANGED_AREA==1 + // one big box + BoxRec box; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + while(--npt) { + pptInit++; + if(box.x1 > pptInit->x) + box.x1 = pptInit->x; + else if(box.x2 < pptInit->x) + box.x2 = pptInit->x; + if(box.y1 > pptInit->y) + box.y1 = pptInit->y; + else if(box.y2 < pptInit->y) + box.y2 = pptInit->y; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + +#elif ROOTLESS_CHANGED_AREA==2 + // clever(?) method: accumulate point in 20-pixel radius + BoxRec box; + int firstx, firsty; + + box.x2 = box.x1 = firstx = pptInit->x; + box.y2 = box.y1 = firsty = pptInit->y; + while(--npt) { + pptInit++; + if (abs(pptInit->x - firstx) > 20 || + abs(pptInit->y - firsty) > 20) { + box.x2++; + box.y2++; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + box.x2 = box.x1 = firstx = pptInit->x; + box.y2 = box.y1 = firsty = pptInit->y; + } else { + if (box.x1 > pptInit->x) box.x1 = pptInit->x; + else if (box.x2 < pptInit->x) box.x2 = pptInit->x; + if (box.y1 > pptInit->y) box.y1 = pptInit->y; + else if (box.y2 < pptInit->y) box.y2 = pptInit->y; + } + } + box.x2++; + box.y2++; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); +#endif /* ROOTLESS_CHANGED_AREA */ + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polypoint end\n"); +} + +#undef ROOTLESS_CHANGED_AREA + +/* changed area is box around each line */ +static void RootlessPolylines(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("poly lines start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->Polylines(dst, pGC, mode, npt, pptInit); + + if (npt > 0) { + BoxRec box; + int extra = pGC->lineWidth >> 1; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + + if(npt > 1) { + if(pGC->joinStyle == JoinMiter) + extra = 6 * pGC->lineWidth; + else if(pGC->capStyle == CapProjecting) + extra = pGC->lineWidth; + } + + if(mode == CoordModePrevious) { + int x = box.x1; + int y = box.y1; + + while(--npt) { + pptInit++; + x += pptInit->x; + y += pptInit->y; + if(box.x1 > x) + box.x1 = x; + else if(box.x2 < x) + box.x2 = x; + if(box.y1 > y) + box.y1 = y; + else if(box.y2 < y) + box.y2 = y; + } + } else { + while(--npt) { + pptInit++; + if(box.x1 > pptInit->x) + box.x1 = pptInit->x; + else if(box.x2 < pptInit->x) + box.x2 = pptInit->x; + if(box.y1 > pptInit->y) + box.y1 = pptInit->y; + else if(box.y2 < pptInit->y) + box.y2 = pptInit->y; + } + } + + box.x2++; + box.y2++; + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly lines end\n"); +} + +/* changed area is box around each line segment */ +static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC, + int nseg, xSegment *pSeg) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("poly segment start (win 0x%x)", dst); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolySegment(dst, pGC, nseg, pSeg); + + if (nseg > 0) { + BoxRec box; + int extra = pGC->lineWidth; + + if(pGC->capStyle != CapProjecting) + extra >>= 1; + + if(pSeg->x2 > pSeg->x1) { + box.x1 = pSeg->x1; + box.x2 = pSeg->x2; + } else { + box.x2 = pSeg->x1; + box.x1 = pSeg->x2; + } + + if(pSeg->y2 > pSeg->y1) { + box.y1 = pSeg->y1; + box.y2 = pSeg->y2; + } else { + box.y2 = pSeg->y1; + box.y1 = pSeg->y2; + } + + while(--nseg) { + pSeg++; + if(pSeg->x2 > pSeg->x1) { + if(pSeg->x1 < box.x1) box.x1 = pSeg->x1; + if(pSeg->x2 > box.x2) box.x2 = pSeg->x2; + } else { + if(pSeg->x2 < box.x1) box.x1 = pSeg->x2; + if(pSeg->x1 > box.x2) box.x2 = pSeg->x1; + } + if(pSeg->y2 > pSeg->y1) { + if(pSeg->y1 < box.y1) box.y1 = pSeg->y1; + if(pSeg->y2 > box.y2) box.y2 = pSeg->y2; + } else { + if(pSeg->y2 < box.y1) box.y1 = pSeg->y2; + if(pSeg->y1 > box.y2) box.y2 = pSeg->y1; + } + } + + box.x2++; + box.y2++; + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly segment end\n"); +} + +/* changed area is box around each line (not entire rects) */ +static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC, + int nRects, xRectangle *pRects) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("poly rectangle start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyRectangle(dst, pGC, nRects, pRects); + + if (nRects > 0) { + BoxRec box; + int offset1, offset2, offset3; + + offset2 = pGC->lineWidth; + if(!offset2) offset2 = 1; + offset1 = offset2 >> 1; + offset3 = offset2 - offset1; + + while(nRects--) { + box.x1 = pRects->x - offset1; + box.y1 = pRects->y - offset1; + box.x2 = box.x1 + pRects->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x + pRects->width - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + pRects->height - offset1; + box.x2 = box.x1 + pRects->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + pRects++; + } + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly rectangle end\n"); +} + + +/* changed area is box around each arc (assumes all arcs are 360 degrees) */ +static void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("poly arc start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyArc(dst, pGC, narcs, parcs); + + if (narcs > 0) { + int extra = pGC->lineWidth >> 1; + BoxRec box; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while(--narcs) { + parcs++; + if(box.x1 > parcs->x) + box.x1 = parcs->x; + if(box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if(box.y1 > parcs->y) + box.y1 = parcs->y; + if(box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly arc end\n"); +} + + +/* changed area is box around each poly */ +static void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, + int shape, int mode, int count, + DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst, + pGC->fillStyle); + + if (count <= 2) { + pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); + } else { + DDXPointPtr ppt = pptInit; + int i = count; + BoxRec box; + + box.x2 = box.x1 = ppt->x; + box.y2 = box.y1 = ppt->y; + + if(mode != CoordModeOrigin) { + int x = box.x1; + int y = box.y1; + + while(--i) { + ppt++; + x += ppt->x; + y += ppt->y; + if(box.x1 > x) + box.x1 = x; + else if(box.x2 < x) + box.x2 = x; + if(box.y1 > y) + box.y1 = y; + else if(box.y2 < y) + box.y2 = y; + } + } else { + while(--i) { + ppt++; + if(box.x1 > ppt->x) + box.x1 = ppt->x; + else if(box.x2 < ppt->x) + box.x2 = ppt->x; + if(box.y1 > ppt->y) + box.y1 = ppt->y; + else if(box.y2 < ppt->y) + box.y2 = ppt->y; + } + } + + box.x2++; + box.y2++; + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill poly end\n"); +} + +/* changed area is the rects */ +static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, + int nRectsInit, xRectangle *pRectsInit) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst, + pGC->fillStyle); + + if (nRectsInit <= 0) { + pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); + } else { + BoxRec box; + xRectangle *pRects = pRectsInit; + int nRects = nRectsInit; + + box.x1 = pRects->x; + box.x2 = box.x1 + pRects->width; + box.y1 = pRects->y; + box.y2 = box.y1 + pRects->height; + + while(--nRects) { + pRects++; + if(box.x1 > pRects->x) + box.x1 = pRects->x; + if(box.x2 < (pRects->x + pRects->width)) + box.x2 = pRects->x + pRects->width; + if(box.y1 > pRects->y) + box.y1 = pRects->y; + if(box.y2 < (pRects->y + pRects->height)) + box.y2 = pRects->y + pRects->height; + } + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill rect end\n"); +} + + +/* changed area is box around each arc (assuming arcs are all 360 degrees) */ +static void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, + int narcs, xArc *parcs) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("fill arc start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyFillArc(dst, pGC, narcs, parcs); + + if (narcs > 0) { + BoxRec box; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while(--narcs) { + parcs++; + if(box.x1 > parcs->x) + box.x1 = parcs->x; + if(box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if(box.y1 > parcs->y) + box.y1 = parcs->y; + if(box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill arc end\n"); +} + + +static void RootlessImageText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("imagetext8 start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->ImageText8(dst, pGC, x, y, count, chars); + + if (count > 0) { + int top, bot, Min, Max; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if(Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if(Max < 0) Max = 0; + + /* ugh */ + box.x1 = dst->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imagetext8 end\n"); +} + +static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) +{ + int width; // the result, sorta + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("polytext8 start "); + + RootlessStartDrawing((WindowPtr) dst); + width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars); + width -= x; + + if(width > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if(count > 1) { + if(width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polytext8 end\n"); + return (width + x); +} + +static void RootlessImageText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("imagetext16 start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->ImageText16(dst, pGC, x, y, count, chars); + + if (count > 0) { + int top, bot, Min, Max; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if(Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if(Max < 0) Max = 0; + + /* ugh */ + box.x1 = dst->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imagetext16 end\n"); +} + +static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) +{ + int width; // the result, sorta + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("polytext16 start "); + + RootlessStartDrawing((WindowPtr) dst); + width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars); + width -= x; + + if (width > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if(count > 1) { + if(width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polytext16 end\n"); + return width + x; +} + +static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer unused) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("imageglyph start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyph, ppci, unused); + + if (nglyph > 0) { + int top, bot, width = 0; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + box.x1 = ppci[0]->metrics.leftSideBearing; + if(box.x1 > 0) box.x1 = 0; + box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing - + ppci[nglyph - 1]->metrics.characterWidth; + if(box.x2 < 0) box.x2 = 0; + + box.x2 += dst->x + x; + box.x1 += dst->x + x; + + while(nglyph--) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if(width > 0) + box.x2 += width; + else + box.x1 += width; + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imageglyph end\n"); +} + +static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("polyglyph start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase); + + if (nglyph > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing; + box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing; + + if(nglyph > 1) { + int width = 0; + + while(--nglyph) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if(width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polyglyph end\n"); +} + + +/* changed area is in dest */ +static void +RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst, + int dx, int dy, int xOrg, int yOrg) +{ + BoxRec box; + GCOP_UNWRAP(pGC); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg); + + box.x1 = xOrg + dst->x; + box.x2 = box.x1 + dx; + box.y1 = yOrg + dst->y; + box.y2 = box.y1 + dy; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("push pixels end\n"); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessScreen.c b/xc/programs/Xserver/hw/darwin/quartz/rootlessScreen.c new file mode 100644 index 000000000..50428cc4d --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessScreen.c @@ -0,0 +1,419 @@ +/* + * Screen routines for Mac OS X rootless X server + * + * Greg Parker gparker@cs.stanford.edu + * + * February 2001 Created + * March 3, 2001 Restructured as generic rootless mode + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessScreen.c,v 1.3 2002/10/16 21:13:33 dawes Exp $ */ + + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "propertyst.h" +#include "mivalidate.h" +#include "picturestr.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "rootlessCommon.h" +#include "rootlessWindow.h" + +extern int +RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild, VTKind kind); +extern Bool +RootlessCreateGC(GCPtr pGC); + +// Initialize globals +int rootlessGCPrivateIndex = -1; +int rootlessScreenPrivateIndex = -1; +int rootlessWindowPrivateIndex = -1; + + +static Bool +RootlessCloseScreen(int i, ScreenPtr pScreen) +{ + RootlessScreenRec *s; + + s = SCREENREC(pScreen); + + // fixme unwrap everything that was wrapped? + pScreen->CloseScreen = s->CloseScreen; + + xfree(s); + return pScreen->CloseScreen(i, pScreen); +} + + +static void +RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planeMask, char *pdstLine) +{ + ScreenPtr pScreen = pDrawable->pScreen; + SCREEN_UNWRAP(pScreen, GetImage); + + if (pDrawable->type == DRAWABLE_WINDOW) { + // Many apps use GetImage to sync with the visible frame buffer + // FIXME: entire screen or just window or all screens? + RootlessRedisplayScreen(pScreen); + + // RedisplayScreen stops drawing, so we need to start it again + RootlessStartDrawing((WindowPtr)pDrawable); + } + + pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); + + SCREEN_WRAP(pScreen, GetImage); +} + + +/* + * RootlessSourceValidate + * CopyArea and CopyPlane use a GC tied to the destination drawable. + * StartDrawing/StopDrawing wrappers won't be called if source is + * a visible window but the destination isn't. So, we call StartDrawing + * here and leave StopDrawing for the block handler. + */ +static void +RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h) +{ + SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate); + if (pDrawable->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDrawable; + RootlessStartDrawing(pWin); + } + if (pDrawable->pScreen->SourceValidate) { + pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h); + } + SCREEN_WRAP(pDrawable->pScreen, SourceValidate); +} + +#ifdef RENDER + +static void +RootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + WindowPtr srcWin, dstWin, maskWin = NULL; + + if (pMask) { // pMask can be NULL + maskWin = (pMask->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pMask->pDrawable : NULL; + } + srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pSrc->pDrawable : NULL; + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pDst->pDrawable : NULL; + + // SCREEN_UNWRAP(ps, Composite); + ps->Composite = SCREENREC(pScreen)->Composite; + + if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin); + if (maskWin && IsFramedWindow(maskWin)) RootlessStartDrawing(maskWin); + if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin); + + ps->Composite(op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + if (dstWin && IsFramedWindow(dstWin)) { + RootlessDamageRect(dstWin, xDst, yDst, width, height); + } + + ps->Composite = RootlessComposite; + // SCREEN_WRAP(ps, Composite); +} + + +static void +RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int nlist, GlyphListPtr list, GlyphPtr *glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + int x, y; + int n; + GlyphPtr glyph; + WindowPtr srcWin, dstWin; + + srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pSrc->pDrawable : NULL; + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pDst->pDrawable : NULL; + + if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin); + if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin); + + //SCREEN_UNWRAP(ps, Glyphs); + ps->Glyphs = SCREENREC(pScreen)->Glyphs; + ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); + ps->Glyphs = RootlessGlyphs; + //SCREEN_WRAP(ps, Glyphs); + + if (dstWin && IsFramedWindow(dstWin)) { + x = xSrc; + y = ySrc; + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) { + glyph = *glyphs++; + RootlessDamageRect(dstWin, + x - glyph->info.x, y - glyph->info.y, + glyph->info.width, glyph->info.height); + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + } +} + +#endif // RENDER + + +// RootlessValidateTree +// ValidateTree is modified in two ways: +// * top-level windows don't clip each other +// * windows aren't clipped against root. +// These only matter when validating from the root. +static int +RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + int result; + RegionRec saveRoot; + ScreenPtr pScreen = pParent->drawable.pScreen; + + SCREEN_UNWRAP(pScreen, ValidateTree); + RL_DEBUG_MSG("VALIDATETREE start "); + + // Use our custom version to validate from root + if (IsRoot(pParent)) { + RL_DEBUG_MSG("custom "); + result = RootlessMiValidateTree(pParent, pChild, kind); + } else { + HUGE_ROOT(pParent); + result = pScreen->ValidateTree(pParent, pChild, kind); + NORMAL_ROOT(pParent); + } + + SCREEN_WRAP(pScreen, ValidateTree); + RL_DEBUG_MSG("VALIDATETREE end\n"); + + return result; +} + + +// RootlessMarkOverlappedWindows +// MarkOverlappedWindows is modified to ignore overlapping +// top-level windows. +static Bool +RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst, + WindowPtr *ppLayerWin) +{ + RegionRec saveRoot; + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + SCREEN_UNWRAP(pScreen, MarkOverlappedWindows); + RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start "); + + HUGE_ROOT(pWin); + if (IsRoot(pWin)) { + // root - mark nothing + RL_DEBUG_MSG("is root not marking "); + result = FALSE; + } + else if (! IsTopLevel(pWin)) { + // not top-level window - mark normally + result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin); + } + else { + //top-level window - mark children ONLY - NO overlaps with sibs (?) + // This code copied from miMarkOverlappedWindows() + + register WindowPtr pChild; + Bool anyMarked = FALSE; + void (* MarkWindow)() = pScreen->MarkWindow; + + RL_DEBUG_MSG("is top level! "); + /* single layered systems are easy */ + if (ppLayerWin) *ppLayerWin = pWin; + + if (pWin == pFirst) { + /* Blindly mark pWin and all of its inferiors. This is a slight + * overkill if there are mapped windows that outside pWin's border, + * but it's better than wasting time on RectIn checks. + */ + pChild = pWin; + while (1) { + if (pChild->viewable) { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + (* MarkWindow)(pChild); + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } + anyMarked = TRUE; + pFirst = pFirst->nextSib; + } + if (anyMarked) + (* MarkWindow)(pWin->parent); + result = anyMarked; + } + NORMAL_ROOT(pWin); + SCREEN_WRAP(pScreen, MarkOverlappedWindows); + RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n"); + return result; +} + + +// Flush drawing before blocking on select(). +static void +RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask) +{ + RootlessRedisplayScreen((ScreenPtr) pbdata); +} + + +static void +RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask) +{ + // nothing here +} + + +static Bool +RootlessAllocatePrivates(ScreenPtr pScreen) +{ + RootlessScreenRec *s; + static unsigned long rootlessGeneration = 0; + + if (rootlessGeneration != serverGeneration) { + rootlessScreenPrivateIndex = AllocateScreenPrivateIndex(); + if (rootlessScreenPrivateIndex == -1) return FALSE; + rootlessGCPrivateIndex = AllocateGCPrivateIndex(); + if (rootlessGCPrivateIndex == -1) return FALSE; + rootlessWindowPrivateIndex = AllocateWindowPrivateIndex(); + if (rootlessWindowPrivateIndex == -1) return FALSE; + rootlessGeneration = serverGeneration; + } + + // no allocation needed for screen privates + if (!AllocateGCPrivate(pScreen, rootlessGCPrivateIndex, + sizeof(RootlessGCRec))) + return FALSE; + if (!AllocateWindowPrivate(pScreen, rootlessWindowPrivateIndex, 0)) + return FALSE; + + s = xalloc(sizeof(RootlessScreenRec)); + if (! s) return FALSE; + SCREENREC(pScreen) = s; + + return TRUE; +} + + +static void +RootlessWrap(ScreenPtr pScreen) +{ + RootlessScreenRec *s = (RootlessScreenRec*) + pScreen->devPrivates[rootlessScreenPrivateIndex].ptr; + +#define WRAP(a) \ + if (pScreen->a) { \ + s->a = pScreen->a; \ + } else { \ + RL_DEBUG_MSG("null screen fn " #a "\n"); \ + s->a = NULL; \ + } \ + pScreen->a = Rootless##a + + WRAP(CloseScreen); + WRAP(CreateGC); + WRAP(PaintWindowBackground); + WRAP(PaintWindowBorder); + WRAP(CopyWindow); + WRAP(GetImage); + WRAP(SourceValidate); + WRAP(CreateWindow); + WRAP(DestroyWindow); + WRAP(RealizeWindow); + WRAP(UnrealizeWindow); + WRAP(MoveWindow); + WRAP(PositionWindow); + WRAP(ResizeWindow); + WRAP(RestackWindow); + WRAP(ChangeBorderWidth); + WRAP(MarkOverlappedWindows); + WRAP(ValidateTree); + WRAP(ChangeWindowAttributes); + +#ifdef SHAPE + WRAP(SetShape); +#endif + +#ifdef RENDER + { + // Composite and Glyphs don't use normal screen wrapping + PictureScreenPtr ps = GetPictureScreen(pScreen); + s->Composite = ps->Composite; + ps->Composite = RootlessComposite; + s->Glyphs = ps->Glyphs; + ps->Glyphs = RootlessGlyphs; + } +#endif + + // WRAP(ClearToBackground); fixme put this back? useful for shaped wins? + // WRAP(RestoreAreas); fixme put this back? + +#undef WRAP +} + + +/* + * RootlessInit + * Rootless wraps lots of stuff and needs a bunch of devPrivates. + */ +Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcs *procs) +{ + RootlessScreenRec *s; + + if (! RootlessAllocatePrivates(pScreen)) return FALSE; + s = (RootlessScreenRec*) + pScreen->devPrivates[rootlessScreenPrivateIndex].ptr; + + s->pScreen = pScreen; + s->frameProcs = *procs; + + RootlessWrap(pScreen); + + if (!RegisterBlockAndWakeupHandlers (RootlessBlockHandler, + RootlessWakeupHandler, + (pointer) pScreen)) + { + return FALSE; + } + + return TRUE; +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessValTree.c b/xc/programs/Xserver/hw/darwin/quartz/rootlessValTree.c new file mode 100644 index 000000000..c8e5ad0a0 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessValTree.c @@ -0,0 +1,640 @@ +/* + * Calculate window clip lists for rootless mode + * + * This file is very closely based on mivaltree.c. + */ + /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessValTree.c,v 1.2 2002/06/18 19:43:04 torrey Exp $ */ + +/* + * mivaltree.c -- + * Functions for recalculating window clip lists. Main function + * is miValidateTree. + * + +Copyright 1987, 1988, 1989, 1998 The Open Group + +All Rights Reserved. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + * + * Copyright 1987, 1988, 1989 by + * Digital Equipment Corporation, Maynard, Massachusetts, + * + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + ******************************************************************/ + +/* The panoramix components contained the following notice */ +/**************************************************************** +* * +* Copyright (c) Digital Equipment Corporation, 1991, 1997 * +* * +* All Rights Reserved. Unpublished rights reserved under * +* the copyright laws of the United States. * +* * +* The software contained on this media is proprietary to * +* and embodies the confidential technology of Digital * +* Equipment Corporation. Possession, use, duplication or * +* dissemination of the software and media is authorized only * +* pursuant to a valid written license from Digital Equipment * +* Corporation. * +* * +* RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure * +* by the U.S. Government is subject to restrictions as set * +* forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, * +* or in FAR 52.227-19, as applicable. * +* * +*****************************************************************/ + + /* + * Aug '86: Susan Angebranndt -- original code + * July '87: Adam de Boor -- substantially modified and commented + * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible. + * In particular, much improved code for window mapping and + * circulating. + * Bob Scheifler -- avoid miComputeClips for unmapped windows, + * valdata changes + */ +#include "X.h" +#include "scrnintstr.h" +#include "validate.h" +#include "windowstr.h" +#include "mi.h" +#include "regionstr.h" +#include "mivalidate.h" + +#include "globals.h" + +#ifdef SHAPE +/* + * Compute the visibility of a shaped window + */ +int +RootlessShapedWindowIn (pScreen, universe, bounding, rect, x, y) + ScreenPtr pScreen; + RegionPtr universe, bounding; + BoxPtr rect; + register int x, y; +{ + BoxRec box; + register BoxPtr boundBox; + int nbox; + Bool someIn, someOut; + register int t, x1, y1, x2, y2; + + nbox = REGION_NUM_RECTS (bounding); + boundBox = REGION_RECTS (bounding); + someIn = someOut = FALSE; + x1 = rect->x1; + y1 = rect->y1; + x2 = rect->x2; + y2 = rect->y2; + while (nbox--) + { + if ((t = boundBox->x1 + x) < x1) + t = x1; + box.x1 = t; + if ((t = boundBox->y1 + y) < y1) + t = y1; + box.y1 = t; + if ((t = boundBox->x2 + x) > x2) + t = x2; + box.x2 = t; + if ((t = boundBox->y2 + y) > y2) + t = y2; + box.y2 = t; + if (box.x1 > box.x2) + box.x2 = box.x1; + if (box.y1 > box.y2) + box.y2 = box.y1; + switch (RECT_IN_REGION(pScreen, universe, &box)) + { + case rgnIN: + if (someOut) + return rgnPART; + someIn = TRUE; + break; + case rgnOUT: + if (someIn) + return rgnPART; + someOut = TRUE; + break; + default: + return rgnPART; + } + boundBox++; + } + if (someIn) + return rgnIN; + return rgnOUT; +} +#endif + +#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ + HasBorder(w) && \ + (w)->backgroundState == ParentRelative) + + +/* + *----------------------------------------------------------------------- + * RootlessComputeClips -- + * Recompute the clipList, borderClip, exposed and borderExposed + * regions for pParent and its children. Only viewable windows are + * taken into account. + * + * Results: + * None. + * + * Side Effects: + * clipList, borderClip, exposed and borderExposed are altered. + * A VisibilityNotify event may be generated on the parent window. + * + *----------------------------------------------------------------------- + */ +static void +RootlessComputeClips (pParent, pScreen, universe, kind, exposed) + register WindowPtr pParent; + register ScreenPtr pScreen; + register RegionPtr universe; + VTKind kind; + RegionPtr exposed; /* for intermediate calculations */ +{ + int dx, + dy; + RegionRec childUniverse; + register WindowPtr pChild; + int oldVis, newVis; + BoxRec borderSize; + RegionRec childUnion; + Bool overlap; + RegionPtr borderVisible; + Bool resized; + /* + * Figure out the new visibility of this window. + * The extent of the universe should be the same as the extent of + * the borderSize region. If the window is unobscured, this rectangle + * will be completely inside the universe (the universe will cover it + * completely). If the window is completely obscured, none of the + * universe will cover the rectangle. + */ + borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); + borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); + dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent); + if (dx > 32767) + dx = 32767; + borderSize.x2 = dx; + dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent); + if (dy > 32767) + dy = 32767; + borderSize.y2 = dy; + + oldVis = pParent->visibility; + switch (RECT_IN_REGION( pScreen, universe, &borderSize)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnPART: + newVis = VisibilityPartiallyObscured; +#ifdef SHAPE + { + RegionPtr pBounding; + + if ((pBounding = wBoundingShape (pParent))) + { + switch (RootlessShapedWindowIn (pScreen, universe, + pBounding, &borderSize, + pParent->drawable.x, + pParent->drawable.y)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnOUT: + newVis = VisibilityFullyObscured; + break; + } + } + } +#endif + break; + default: + newVis = VisibilityFullyObscured; + break; + } + + pParent->visibility = newVis; + if (oldVis != newVis && + ((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask)) + SendVisibilityNotify(pParent); + + dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x; + dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y; + + /* + * avoid computations when dealing with simple operations + */ + + switch (kind) { + case VTMap: + case VTStack: + case VTUnmap: + break; + case VTMove: + if ((oldVis == newVis) && + ((oldVis == VisibilityFullyObscured) || + (oldVis == VisibilityUnobscured))) + { + pChild = pParent; + while (1) + { + if (pChild->viewable) + { + if (pChild->visibility != VisibilityFullyObscured) + { + REGION_TRANSLATE( pScreen, &pChild->borderClip, + dx, dy); + REGION_TRANSLATE( pScreen, &pChild->clipList, + dx, dy); + pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pChild, dx, dy); + + } + if (pChild->valdata) + { + REGION_INIT(pScreen, + &pChild->valdata->after.borderExposed, + NullBox, 0); + if (HasParentRelativeBorder(pChild)) + { + REGION_SUBTRACT(pScreen, + &pChild->valdata->after.borderExposed, + &pChild->borderClip, + &pChild->winSize); + } + REGION_INIT( pScreen, &pChild->valdata->after.exposed, + NullBox, 0); + } + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pParent)) + pChild = pChild->parent; + if (pChild == pParent) + break; + pChild = pChild->nextSib; + } + return; + } + /* fall through */ + default: + /* + * To calculate exposures correctly, we have to translate the old + * borderClip and clipList regions to the window's new location so there + * is a correspondence between pieces of the new and old clipping regions. + */ + if (dx || dy) + { + /* + * We translate the old clipList because that will be exposed or copied + * if gravity is right. + */ + REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy); + } + break; + case VTBroken: + REGION_EMPTY (pScreen, &pParent->borderClip); + REGION_EMPTY (pScreen, &pParent->clipList); + break; + } + + borderVisible = pParent->valdata->before.borderVisible; + resized = pParent->valdata->before.resized; + REGION_INIT( pScreen, &pParent->valdata->after.borderExposed, NullBox, 0); + REGION_INIT( pScreen, &pParent->valdata->after.exposed, NullBox, 0); + + /* + * Since the borderClip must not be clipped by the children, we do + * the border exposure first... + * + * 'universe' is the window's borderClip. To figure the exposures, remove + * the area that used to be exposed from the new. + * This leaves a region of pieces that weren't exposed before. + */ + + if (HasBorder (pParent)) + { + if (borderVisible) + { + /* + * when the border changes shape, the old visible portions + * of the border will be saved by DIX in borderVisible -- + * use that region and destroy it + */ + REGION_SUBTRACT( pScreen, exposed, universe, borderVisible); + REGION_DESTROY( pScreen, borderVisible); + } + else + { + REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip); + } + if (HasParentRelativeBorder(pParent) && (dx || dy)) { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed, + universe, + &pParent->winSize); + } else { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed, + exposed, &pParent->winSize); + } + + REGION_COPY( pScreen, &pParent->borderClip, universe); + + /* + * To get the right clipList for the parent, and to make doubly sure + * that no child overlaps the parent's border, we remove the parent's + * border from the universe before proceeding. + */ + + REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize); + } + else + REGION_COPY( pScreen, &pParent->borderClip, universe); + + if ((pChild = pParent->firstChild) && pParent->mapped) + { + REGION_INIT(pScreen, &childUniverse, NullBox, 0); + REGION_INIT(pScreen, &childUnion, NullBox, 0); + if ((pChild->drawable.y < pParent->lastChild->drawable.y) || + ((pChild->drawable.y == pParent->lastChild->drawable.y) && + (pChild->drawable.x < pParent->lastChild->drawable.x))) + { + for (; pChild; pChild = pChild->nextSib) + { + if (pChild->viewable) + REGION_APPEND( pScreen, &childUnion, &pChild->borderSize); + } + } + else + { + for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) + { + if (pChild->viewable) + REGION_APPEND( pScreen, &childUnion, &pChild->borderSize); + } + } + REGION_VALIDATE( pScreen, &childUnion, &overlap); + + for (pChild = pParent->firstChild; + pChild; + pChild = pChild->nextSib) + { + if (pChild->viewable) { + /* + * If the child is viewable, we want to remove its extents + * from the current universe, but we only re-clip it if + * it's been marked. + */ + if (pChild->valdata) { + /* + * Figure out the new universe from the child's + * perspective and recurse. + */ + REGION_INTERSECT( pScreen, &childUniverse, + universe, + &pChild->borderSize); + RootlessComputeClips (pChild, pScreen, &childUniverse, + kind, exposed); + } + /* + * Once the child has been processed, we remove its extents + * from the current universe, thus denying its space to any + * other sibling. + */ + if (overlap) + REGION_SUBTRACT( pScreen, universe, universe, + &pChild->borderSize); + } + } + if (!overlap) + REGION_SUBTRACT( pScreen, universe, universe, &childUnion); + REGION_UNINIT( pScreen, &childUnion); + REGION_UNINIT( pScreen, &childUniverse); + } /* if any children */ + + /* + * 'universe' now contains the new clipList for the parent window. + * + * To figure the exposure of the window we subtract the old clip from the + * new, just as for the border. + */ + + if (oldVis == VisibilityFullyObscured || + oldVis == VisibilityNotViewable) + { + REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe); + } + else if (newVis != VisibilityFullyObscured && + newVis != VisibilityNotViewable) + { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed, + universe, &pParent->clipList); + } + + /* + * One last thing: backing storage. We have to try to save what parts of + * the window are about to be obscured. We can just subtract the universe + * from the old clipList and get the areas that were in the old but aren't + * in the new and, hence, are about to be obscured. + */ + if (pParent->backStorage && !resized) + { + REGION_SUBTRACT( pScreen, exposed, &pParent->clipList, universe); + (* pScreen->SaveDoomedAreas)(pParent, exposed, dx, dy); + } + + /* HACK ALERT - copying contents of regions, instead of regions */ + { + RegionRec tmp; + + tmp = pParent->clipList; + pParent->clipList = *universe; + *universe = tmp; + } + +#ifdef NOTDEF + REGION_COPY( pScreen, &pParent->clipList, universe); +#endif + + pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pParent, dx, dy); +} + +static void +RootlessTreeObscured(pParent) + register WindowPtr pParent; +{ + register WindowPtr pChild; + register int oldVis; + + pChild = pParent; + while (1) + { + if (pChild->viewable) + { + oldVis = pChild->visibility; + if (oldVis != (pChild->visibility = VisibilityFullyObscured) && + ((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask)) + SendVisibilityNotify(pChild); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pParent)) + pChild = pChild->parent; + if (pChild == pParent) + break; + pChild = pChild->nextSib; + } +} + +/* + *----------------------------------------------------------------------- + * RootlessMiValidateTree -- + * Recomputes the clip list for pParent and all its inferiors. + * + * Results: + * Always returns 1. + * + * Side Effects: + * The clipList, borderClip, exposed, and borderExposed regions for + * each marked window are altered. + * + * Notes: + * This routine assumes that all affected windows have been marked + * (valdata created) and their winSize and borderSize regions + * adjusted to correspond to their new positions. The borderClip and + * clipList regions should not have been touched. + * + * The top-most level is treated differently from all lower levels + * because pParent is unchanged. For the top level, we merge the + * regions taken up by the marked children back into the clipList + * for pParent, thus forming a region from which the marked children + * can claim their areas. For lower levels, where the old clipList + * and borderClip are invalid, we can't do this and have to do the + * extra operations done in miComputeClips, but this is much faster + * e.g. when only one child has moved... + * + *----------------------------------------------------------------------- + */ +/* + Quartz version: used for validate from root in rootless mode. + We need to make sure top-level windows don't clip each other, + and that top-level windows aren't clipped to the root window. +*/ +/*ARGSUSED*/ +// fixme this is ugly +// Xprint/ValTree.c doesn't work, but maybe that method can? +int +RootlessMiValidateTree (pRoot, pChild, kind) + WindowPtr pRoot; /* Parent to validate */ + WindowPtr pChild; /* First child of pRoot that was + * affected */ + VTKind kind; /* What kind of configuration caused call */ +{ + RegionRec childClip; /* The new borderClip for the current + * child */ + RegionRec exposed; /* For intermediate calculations */ + register ScreenPtr pScreen; + register WindowPtr pWin; + + pScreen = pRoot->drawable.pScreen; + if (pChild == NullWindow) + pChild = pRoot->firstChild; + + REGION_INIT(pScreen, &childClip, NullBox, 0); + REGION_INIT(pScreen, &exposed, NullBox, 0); + + if (REGION_BROKEN (pScreen, &pRoot->clipList) && + !REGION_BROKEN (pScreen, &pRoot->borderClip)) + { + // fixme this might not work, but hopefully doesn't happen anyway. + kind = VTBroken; + REGION_EMPTY (pScreen, &pRoot->clipList); + ErrorF("ValidateTree: BUSTED!\n"); + } + + /* + * Recursively compute the clips for all children of the root. + * They don't clip against each other or the root itself, so + * childClip is always reset to that child's size. + */ + + for (pWin = pChild; + pWin != NullWindow; + pWin = pWin->nextSib) + { + if (pWin->viewable) { + if (pWin->valdata) { + REGION_COPY( pScreen, &childClip, &pWin->borderSize); + RootlessComputeClips (pWin, pScreen, &childClip, kind, &exposed); + } else if (pWin->visibility == VisibilityNotViewable) { + RootlessTreeObscured(pWin); + } + } else { + if (pWin->valdata) { + REGION_EMPTY( pScreen, &pWin->clipList); + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pWin, 0, 0); + REGION_EMPTY( pScreen, &pWin->borderClip); + pWin->valdata = (ValidatePtr)NULL; + } + } + } + + REGION_UNINIT( pScreen, &childClip); + + /* The root is never clipped by its children, so nothing on the root + is ever exposed by moving or mapping its children. */ + REGION_INIT( pScreen, &pRoot->valdata->after.exposed, NullBox, 0); + REGION_INIT( pScreen, &pRoot->valdata->after.borderExposed, NullBox, 0); + + return 1; +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.c b/xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.c new file mode 100644 index 000000000..d283b4181 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.c @@ -0,0 +1,829 @@ +/* + * Rootless window management + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.c,v 1.11 2002/09/28 00:43:39 torrey Exp $ */ + +#include "rootlessCommon.h" +#include "rootlessWindow.h" + +#include "fb.h" + + +/* + * RootlessFrameForWindow + * Returns the rootless frame for the given window, or + * NULL if the the window is not inside a frame. + * Unrealized windows never have a frame. + */ +RootlessFramePtr +RootlessFrameForWindow(WindowPtr pWin) +{ + WindowPtr top = TopLevelParent(pWin); + RootlessWindowRec *winRec; + + if (!top) return NULL; + winRec = WINREC(top); + if (!winRec) return NULL; + return &winRec->frame; +} + + +// RootlessCreateWindow +// For now, don't create a frame until the window is realized. +// Do reset the window size so it's not clipped by the root window. +Bool +RootlessCreateWindow(WindowPtr pWin) +{ + Bool result; + RegionRec saveRoot; + + WINREC(pWin) = NULL; + SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow); + if (!IsRoot(pWin)) { + // win/border size set by DIX, not by wrapped CreateWindow, so + // correct it here. + // Don't HUGE_ROOT when pWin is the root! + HUGE_ROOT(pWin); + SetWinSize(pWin); + SetBorderSize(pWin); + } + result = pWin->drawable.pScreen->CreateWindow(pWin); + if (pWin->parent) { + NORMAL_ROOT(pWin); + } + SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow); + return result; +} + + +// RootlessDestroyWindow +// For now, all window destruction takes place in UnrealizeWindow +Bool +RootlessDestroyWindow(WindowPtr pWin) +{ + Bool result; + + SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow); + result = pWin->drawable.pScreen->DestroyWindow(pWin); + SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow); + return result; +} + + +#ifdef SHAPE + +// RootlessSetShape +// Shape is usually set before the window is mapped, but (for now) we +// don't keep track of frames before they're mapped. So we just record +// that the shape needs to updated later. +void +RootlessSetShape(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + RootlessDamageShape(pWin); + SCREEN_UNWRAP(pScreen, SetShape); + pScreen->SetShape(pWin); + SCREEN_WRAP(pScreen, SetShape); +} + +#endif // SHAPE + + +// Disallow ParentRelative background on top-level windows +// because the root window doesn't really have the right background +// and fb will try to draw on the root instead of on the window. +// ParentRelative prevention is also in PaintWindowBackground/Border() +// so it is no longer really needed here. +Bool +RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask) +{ + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("change window attributes start "); + + SCREEN_UNWRAP(pScreen, ChangeWindowAttributes); + result = pScreen->ChangeWindowAttributes(pWin, vmask); + SCREEN_WRAP(pScreen, ChangeWindowAttributes); + + if (WINREC(pWin)) { + // disallow ParentRelative background state + if (pWin->backgroundState == ParentRelative) { + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + } + } + + RL_DEBUG_MSG("change window attributes end\n"); + return result; +} + + +/* RootlessPositionWindow + * This is a hook for when DIX moves or resizes a window. + * Update the frame position now. (x, y) are *inside* position. + * After this, mi and fb are expecting the pixmap to be at the new location. + */ +Bool +RootlessPositionWindow(WindowPtr pWin, int x, int y) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + Bool result; + + RL_DEBUG_MSG("positionwindow start (win 0x%x)\n", pWin); + + if (winRec) { + if (winRec->drawing) { + // Reset frame's pixmap and move it to the new position. + int bw = wBorderWidth(pWin); + + winRec->pixmap->devPrivate.ptr = winRec->frame.pixelData; + SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw); + + // Move damaged region to correspond to new window position + if (REGION_NOTEMPTY(pScreen, &winRec->damage)) { + REGION_TRANSLATE(pScreen, &winRec->damage, + x - bw - winRec->frame.x, + y - bw - winRec->frame.y); + } + } + } + + SCREEN_UNWRAP(pScreen, PositionWindow); + result = pScreen->PositionWindow(pWin, x, y); + SCREEN_WRAP(pScreen, PositionWindow); + + RL_DEBUG_MSG("positionwindow end\n"); + return result; +} + + +// RootlessRealizeWindow +// The frame is created here and not in CreateWindow so that windows do +// not eat memory until they are realized. +Bool +RootlessRealizeWindow(WindowPtr pWin) +{ + Bool result = FALSE; + RegionRec saveRoot; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin); + + if (IsTopLevel(pWin) || IsRoot(pWin)) { + DrawablePtr d = &pWin->drawable; + RootlessWindowRec *winRec = xalloc(sizeof(RootlessWindowRec)); + int bw = wBorderWidth(pWin); + + RL_DEBUG_MSG("Top level window "); + if (! winRec) goto windowcreatebad; + + winRec->frame.isRoot = (pWin == WindowTable[pScreen->myNum]); + winRec->frame.x = d->x - bw; + winRec->frame.y = d->y - bw; + winRec->frame.w = d->width + 2*bw; + winRec->frame.h = d->height + 2*bw; + winRec->frame.win = pWin; + winRec->frame.devPrivate = NULL; + + REGION_INIT(pScreen, &winRec->damage, NullBox, 0); + winRec->borderWidth = bw; + winRec->drawing = FALSE; + + winRec->pixmap = NULL; + + WINREC(pWin) = winRec; + + RL_DEBUG_MSG("creating frame "); + CallFrameProc(pScreen, CreateFrame, + (pScreen, &WINREC(pWin)->frame, + pWin->prevSib ? &WINREC(pWin->prevSib)->frame : NULL)); + if (!winRec->frame.devPrivate) goto windowcreatebad; + + // Disallow ParentRelative background state on top-level windows. + // This might have been set before the window was mapped. + if (pWin->backgroundState == ParentRelative) { + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + } + +#ifdef SHAPE + // Shape is usually set before the window is mapped, but + // (for now) we don't keep track of frames before they're mapped. + winRec->shapeDamage = TRUE; +#endif + } + + if (!IsRoot(pWin)) HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, RealizeWindow); + result = pScreen->RealizeWindow(pWin); + SCREEN_WRAP(pScreen, RealizeWindow); + if (!IsRoot(pWin)) NORMAL_ROOT(pWin); + + RL_DEBUG_MSG("realizewindow end\n"); + return result; + +windowcreatebad: + RL_DEBUG_MSG("window create bad! "); + RL_DEBUG_MSG("realizewindow end\n"); + return NULL; +} + + +Bool +RootlessUnrealizeWindow(WindowPtr pWin) +{ + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("unrealizewindow start "); + + if (IsTopLevel(pWin) || IsRoot(pWin)) { + RootlessWindowRec *winRec = WINREC(pWin); + + RootlessRedisplay(pWin); + CallFrameProc(pScreen, DestroyFrame, (pScreen, &winRec->frame)); + + REGION_UNINIT(pScreen, &winRec->damage); + + xfree(winRec); + WINREC(pWin) = NULL; + } + + SCREEN_UNWRAP(pScreen, UnrealizeWindow); + result = pScreen->UnrealizeWindow(pWin); + SCREEN_WRAP(pScreen, UnrealizeWindow); + RL_DEBUG_MSG("unrealizewindow end\n"); + return result; +} + + +void +RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib) +{ + RegionRec saveRoot; + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("restackwindow start "); + if (winRec) RL_DEBUG_MSG("restack top level \n"); + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, RestackWindow); + if (pScreen->RestackWindow) pScreen->RestackWindow(pWin, pOldNextSib); + SCREEN_WRAP(pScreen, RestackWindow); + NORMAL_ROOT(pWin); + + if (winRec) { + // fixme simplify the following + + WindowPtr oldNextW, newNextW, oldPrevW, newPrevW; + RootlessFramePtr oldNext, newNext, oldPrev, newPrev; + + oldNextW = pOldNextSib; + while (oldNextW && ! WINREC(oldNextW)) oldNextW = oldNextW->nextSib; + oldNext = oldNextW ? &WINREC(oldNextW)->frame : NULL; + + newNextW = pWin->nextSib; + while (newNextW && ! WINREC(newNextW)) newNextW = newNextW->nextSib; + newNext = newNextW ? &WINREC(newNextW)->frame : NULL; + + oldPrevW= pOldNextSib ? pOldNextSib->prevSib : pWin->parent->lastChild; + while (oldPrevW && ! WINREC(oldPrevW)) oldPrevW = oldPrevW->prevSib; + oldPrev = oldPrevW ? &WINREC(oldPrevW)->frame : NULL; + + newPrevW = pWin->prevSib; + while (newPrevW && ! WINREC(newPrevW)) newPrevW = newPrevW->prevSib; + newPrev = newPrevW ? &WINREC(newPrevW)->frame : NULL; + + if (pWin->prevSib) { + WindowPtr w = pWin->prevSib; + while (w) { + RL_DEBUG_MSG("w 0x%x\n", w); + w = w->parent; + } + } + + CallFrameProc(pScreen, RestackFrame, + (pScreen, &winRec->frame, oldPrev, newPrev)); + } + + RL_DEBUG_MSG("restackwindow end\n"); +} + + +/* + * Specialized window copy procedures + */ + +// Globals needed during window resize and move. +static PixmapPtr gResizeDeathPix = NULL; +static pointer gResizeDeathBits = NULL; +static PixmapPtr gResizeCopyWindowSource = NULL; +static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL; + +// CopyWindow() that doesn't do anything. +// For MoveWindow() of top-level windows. +static void +RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + // some code expects the region to be translated + int dx = ptOldOrg.x - pWin->drawable.x; + int dy = ptOldOrg.y - pWin->drawable.y; + RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW "); + + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); +} + + +// CopyWindow used during ResizeWindow for gravity moves. +// Cloned from fbCopyWindow +// The original always draws on the root pixmap (which we don't have). +// Instead, draw on the parent window's pixmap. +// Resize version: the old location's pixels are in gResizeCopyWindowSource +static void +RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + // Don't unwrap pScreen->CopyWindow. + // The bogus rewrap with RootlessCopyWindow causes a crash if + // CopyWindow is called again during the same resize. + RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin); + + { + RegionRec rgnDst; + int dx, dy; + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + REGION_INIT(pScreen, &rgnDst, NullBox, 0); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + RootlessStartDrawing(pWin); + fbCopyRegion (&gResizeCopyWindowSource->drawable, + &pScreen->GetWindowPixmap(pWin)->drawable, + 0, + &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + + // don't update - resize will update everything + REGION_UNINIT(pScreen, &rgnDst); + fbValidateDrawable (&pWin->drawable); + } + + RL_DEBUG_MSG("resizecopywindowFB end\n"); +} + + +/* Update *new* location of window. Old location is redrawn with + * PaintWindowBackground/Border. + * Cloned from fbCopyWindow + * The original always draws on the root pixmap (which we don't have). + * Instead, draw on the parent window's pixmap. + */ +void +RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + SCREEN_UNWRAP(pScreen, CopyWindow); + RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin); + + { + RegionRec rgnDst; + int dx, dy; + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + + REGION_INIT(pScreen, &rgnDst, NullBox, 0); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + RootlessStartDrawing(pWin); + fbCopyRegion ((DrawablePtr)pWin, (DrawablePtr)pWin, + 0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + + // prgnSrc has been translated to dst position + RootlessDamageRegion(pWin, prgnSrc); + REGION_UNINIT(pScreen, &rgnDst); + fbValidateDrawable (&pWin->drawable); + } + + SCREEN_WRAP(pScreen, CopyWindow); + RL_DEBUG_MSG("copywindowFB end\n"); +} + + +/* + * Window resize procedures + */ + +// Prepare to resize a top-level window. +// The old window's pixels are saved and the implementation is told +// to change the window size. +// (x,y,w,h) is outer frame of window (outside border) +static void +StartFrameResize(WindowPtr pWin, Bool gravity, + int oldX, int oldY, + unsigned int oldW, unsigned int oldH, unsigned int oldBW, + int newX, int newY, + unsigned int newW, unsigned int newH, unsigned int newBW) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + + RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity); + RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d ", + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + RootlessRedisplay(pWin); + + // Make a copy of the current pixmap and all its data. + // The original will go away when we ask the frame manager to + // allocate the new pixmap. + RootlessStartDrawing(pWin); + gResizeDeathBits = xalloc(winRec->frame.bytesPerRow * winRec->frame.h); + memcpy(gResizeDeathBits, winRec->frame.pixelData, + winRec->frame.bytesPerRow * winRec->frame.h); + gResizeDeathPix = + GetScratchPixmapHeader(pScreen, winRec->frame.w, winRec->frame.h, + winRec->frame.depth, winRec->frame.bitsPerPixel, + winRec->frame.bytesPerRow, gResizeDeathBits); + SetPixmapBaseToScreen(gResizeDeathPix, oldX, oldY); + RootlessStopDrawing(pWin); + + winRec->frame.x = newX; + winRec->frame.y = newY; + winRec->frame.w = newW; + winRec->frame.h = newH; + winRec->borderWidth = newBW; + + CallFrameProc(pScreen, StartResizeFrame, + (pScreen, &winRec->frame, oldX, oldY, oldW, oldH)); + RootlessStartDrawing(pWin); + + // Use custom CopyWindow when moving gravity bits around + // ResizeWindow assumes the old window contents are in the same + // pixmap, but here they're in deathPix instead. + if (gravity) { + gResizeCopyWindowSource = gResizeDeathPix; + gResizeOldCopyWindowProc = pScreen->CopyWindow; + pScreen->CopyWindow = RootlessResizeCopyWindow; + } + + // Copy pixels in intersection from src to dst. + // ResizeWindow assumes these pixels are already present when + // making gravity adjustments. + // pWin currently has new-sized pixmap but is in old position. + // fixme border width change! + { + BoxRec rect; + DrawablePtr src = &gResizeDeathPix->drawable; + DrawablePtr dst = &pScreen->GetWindowPixmap(pWin)->drawable; + // These vars are needed because implicit unsigned->signed fails + int oldX2 = (int)(oldX + oldW), newX2 = (int)(newX + newW); + int oldY2 = (int)(oldY + oldH), newY2 = (int)(newY + newH); + + rect.x1 = max(oldX, newX); + rect.y1 = max(oldY, newY); + rect.x2 = min(oldX2, newX2); + rect.y2 = min(oldY2, newY2); + + RL_DEBUG_MSG("Resize copy rect %d %d %d %d ", + rect.x1, rect.y1, rect.x2, rect.y2); + + // rect is the intersection of the old location and new location + if (BOX_NOT_EMPTY(rect)) { + fbCopyWindowProc(src, dst, NULL, &rect, 1, 0, 0, + FALSE, FALSE, 0, 0); + } + } +} + + +static void +FinishFrameResize(WindowPtr pWin, Bool gravity, + int oldX, int oldY, + unsigned int oldW, unsigned int oldH, unsigned int oldBW, + int newX, int newY, + unsigned int newW, unsigned int newH, unsigned int newBW) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + + CallFrameProc(pScreen, FinishResizeFrame, + (pScreen, &winRec->frame, oldX, oldY, oldW, oldH)); + if (wBoundingShape(pWin)) { + RootlessDamageShape(pWin); + } + + // Destroy temp pixmap + FreeScratchPixmapHeader(gResizeDeathPix); + xfree(gResizeDeathBits); + gResizeDeathPix = gResizeDeathBits = NULL; + + if (gravity) { + pScreen->CopyWindow = gResizeOldCopyWindowProc; + gResizeCopyWindowSource = NULL; + } +} + + +// If kind==VTOther, window border is resizing (and borderWidth is +// already changed!!@#$) This case works like window resize, not move. +void +RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind) +{ + CopyWindowProcPtr oldCopyWindowProc = NULL; + RegionRec saveRoot; + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0; + + RL_DEBUG_MSG("movewindow start \n"); + + if (winRec) { + if (kind == VTMove) { + oldX = winRec->frame.x; + oldY = winRec->frame.y; + RootlessRedisplay(pWin); + RootlessStartDrawing(pWin); + } else { + RL_DEBUG_MSG("movewindow border resizing "); + oldBW = winRec->borderWidth; + oldX = winRec->frame.x; + oldY = winRec->frame.y; + oldW = winRec->frame.w; + oldH = winRec->frame.h; + newBW = wBorderWidth(pWin); + newX = x; + newY = y; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + StartFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, MoveWindow); + if (winRec) { + oldCopyWindowProc = pScreen->CopyWindow; + pScreen->CopyWindow = RootlessNoCopyWindow; + } + pScreen->MoveWindow(pWin, x, y, pSib, kind); + if (winRec) { + pScreen->CopyWindow = oldCopyWindowProc; + } + NORMAL_ROOT(pWin); + SCREEN_WRAP(pScreen, MoveWindow); + + if (winRec) { + if (kind == VTMove) { + winRec->frame.x = x; + winRec->frame.y = y; + RootlessStopDrawing(pWin); + CallFrameProc(pScreen, MoveFrame, + (pScreen, &winRec->frame, oldX, oldY)); + } else { + FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + } + + RL_DEBUG_MSG("movewindow end\n"); +} + + +// Note: (x, y, w, h) as passed to this procedure don't match +// the frame definition. +// (x,y) is corner of very outer edge, *outside* border +// w,h is width and height *inside* border, *ignoring* border width +// The rect (x, y, w, h) doesn't mean anything. +// (x, y, w+2*bw, h+2*bw) is total rect +// (x+bw, y+bw, w, h) is inner rect + +void +RootlessResizeWindow(WindowPtr pWin, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib) +{ + RegionRec saveRoot; + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0; + + RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin); + + if (winRec) { + oldBW = winRec->borderWidth; + oldX = winRec->frame.x; + oldY = winRec->frame.y; + oldW = winRec->frame.w; + oldH = winRec->frame.h; + + newBW = oldBW; + newX = x; + newY = y; + newW = w + 2*newBW; + newH = h + 2*newBW; + + StartFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, ResizeWindow); + pScreen->ResizeWindow(pWin, x, y, w, h, pSib); + SCREEN_WRAP(pScreen, ResizeWindow); + NORMAL_ROOT(pWin); + + if (winRec) { + FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + RL_DEBUG_MSG("resizewindow end\n"); +} + + +/* + * SetPixmapOfAncestors + * Set the Pixmaps on all ParentRelative windows up the ancestor chain. + */ +static void +SetPixmapOfAncestors(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr topWin = TopLevelParent(pWin); + RootlessWindowRec *topWinRec = WINREC(topWin); + + while (pWin->backgroundState == ParentRelative) { + if (pWin == topWin) { + // disallow ParentRelative background state on top level + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin); + break; + } + + pWin = pWin->parent; + pScreen->SetWindowPixmap(pWin, topWinRec->pixmap); + } +} + + +/* + * RootlessPaintWindowBackground + * Paint the window background while filling in the alpha channel with all on. + */ +void +RootlessPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what) +{ + int oldBackgroundState = 0; + PixUnion oldBackground; + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREEN_UNWRAP(pScreen, PaintWindowBackground); + RL_DEBUG_MSG("paintwindowbackground start (win 0x%x, framed %i) ", + pWin, IsFramedWindow(pWin)); + + if (IsFramedWindow(pWin)) { + if (IsRoot(pWin)) { + // set root background to magic transparent color + oldBackgroundState = pWin->backgroundState; + oldBackground = pWin->background; + pWin->backgroundState = BackgroundPixel; + pWin->background.pixel = 0x00fffffe; + } + RootlessStartDrawing(pWin); + RootlessDamageRegion(pWin, pRegion); + + // For ParentRelative windows, we have to make sure the window + // pixmap is set correctly all the way up the ancestor chain. + if (pWin->backgroundState == ParentRelative) { + SetPixmapOfAncestors(pWin); + } + } + + pScreen->PaintWindowBackground(pWin, pRegion, what); + + if (IsRoot(pWin)) { + pWin->backgroundState = oldBackgroundState; + pWin->background = oldBackground; + } + + SCREEN_WRAP(pScreen, PaintWindowBackground); + RL_DEBUG_MSG("paintwindowbackground end\n"); +} + + +/* + * RootlessPaintWindowBorder + * Paint the window border while filling in the alpha channel with all on. + */ +void +RootlessPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what) +{ + SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder); + RL_DEBUG_MSG("paintwindowborder start (win 0x%x) ", pWin); + + if (IsFramedWindow(pWin)) { + RootlessStartDrawing(pWin); + RootlessDamageRegion(pWin, pRegion); + + // For ParentRelative windows with tiled borders, we have to make + // sure the window pixmap is set correctly all the way up the + // ancestor chain. + if (!pWin->borderIsPixel && + pWin->backgroundState == ParentRelative) + { + SetPixmapOfAncestors(pWin); + } + } + + pWin->drawable.pScreen->PaintWindowBorder(pWin, pRegion, what); + + SCREEN_WRAP(pWin->drawable.pScreen, PaintWindowBorder); + RL_DEBUG_MSG("paintwindowborder end\n"); +} + + +// fixme untested! +// pWin inside corner stays the same +// pWin->drawable.[xy] stays the same +// frame moves and resizes +void +RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width) +{ + RegionRec saveRoot; + + RL_DEBUG_MSG("change border width "); + if (width != wBorderWidth(pWin)) { + RootlessWindowRec *winRec = WINREC(pWin); + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0; + unsigned int newW = 0, newH = 0, newBW = 0; + + if (winRec) { + oldBW = winRec->borderWidth; + oldX = winRec->frame.x; + oldY = winRec->frame.y; + oldW = winRec->frame.w; + oldH = winRec->frame.h; + + newBW = width; + newX = pWin->drawable.x - newBW; + newY = pWin->drawable.y - newBW; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + + StartFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth); + pWin->drawable.pScreen->ChangeBorderWidth(pWin, width); + SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth); + NORMAL_ROOT(pWin); + + if (winRec) { + FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + } + RL_DEBUG_MSG("change border width end\n"); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.h b/xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.h new file mode 100644 index 000000000..ef3852d93 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.h @@ -0,0 +1,36 @@ +/* + * Rootless window management + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.h,v 1.2 2002/04/03 00:06:32 torrey Exp $ */ + +#ifndef _ROOTLESSWINDOW_H +#define _ROOTLESSWINDOW_H + +#include "rootlessCommon.h" + + +Bool RootlessCreateWindow(WindowPtr pWin); +Bool RootlessDestroyWindow(WindowPtr pWin); + +#ifdef SHAPE +void RootlessSetShape(WindowPtr pWin); +#endif // SHAPE + +Bool RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask); +Bool RootlessPositionWindow(WindowPtr pWin, int x, int y); +Bool RootlessRealizeWindow(WindowPtr pWin); +Bool RootlessUnrealizeWindow(WindowPtr pWin); +void RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib); +void RootlessCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc); +void RootlessMoveWindow(WindowPtr pWin,int x,int y,WindowPtr pSib,VTKind kind); +void RootlessResizeWindow(WindowPtr pWin, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib); +void RootlessPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, + int what); +void RootlessPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, + int what); +void RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width); + +#endif diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/Imakefile b/xc/programs/Xserver/hw/darwin/quartz_1.3/Imakefile new file mode 100644 index 000000000..c4299239a --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/Imakefile @@ -0,0 +1,127 @@ +XCOMM $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/Imakefile,v 1.1 2002/03/28 02:21:20 torrey Exp $ + +#include <Server.tmpl> + +LinkSourceFile(Preferences.m,../quartz) +LinkSourceFile(Preferences.h,../quartz) +LinkSourceFile(XApplication.m,../quartz) +LinkSourceFile(XApplication.h,../quartz) +LinkSourceFile(fakeBoxRec.h,../quartz) +LinkSourceFile(fullscreen.c,../quartz) +LinkSourceFile(fullscreen.h,../quartz) +LinkSourceFile(quartz.c,../quartz) +LinkSourceFile(quartz.h,../quartz) +LinkSourceFile(quartzAudio.c,../quartz) +LinkSourceFile(quartzAudio.h,../quartz) +LinkSourceFile(quartzCocoa.m,../quartz) +LinkSourceFile(quartzCommon.h,../quartz) +LinkSourceFile(quartzCursor.c,../quartz) +LinkSourceFile(quartzCursor.h,../quartz) +LinkSourceFile(quartzPasteboard.c,../quartz) +LinkSourceFile(quartzPasteboard.h,../quartz) +LinkSourceFile(quartzShared.h,../quartz) +LinkSourceFile(pseudoramiX.c,../quartz) +LinkSourceFile(pseudoramiX.h,../quartz) +LinkSourceFile(quartzStartup.c,../quartz) +LinkSourceFile(XDarwinStartup.c,../quartz) +LinkSourceFile(XDarwinStartup.man,../quartz) + +SRCS = Preferences.m \ + XApplication.m \ + XServer.m \ + XView.m \ + XWindow.m \ + fullscreen.c \ + quartz.c \ + quartzAudio.c \ + quartzCocoa.m \ + quartzCursor.c \ + quartzPasteboard.c \ + rootlessAquaGlue.c \ + rootlessAquaImp.m \ + rootlessCommon.c \ + rootlessGC.c \ + rootlessScreen.c \ + rootlessValTree.c \ + rootlessWindow.c \ + pseudoramiX.c + +OBJS = Preferences.o \ + XApplication.o \ + XServer.o \ + XView.o \ + XWindow.o \ + fullscreen.o \ + quartz.o \ + quartzAudio.o \ + quartzCocoa.o \ + quartzCursor.o \ + quartzPasteboard.o \ + rootlessAquaGlue.o \ + rootlessAquaImp.o \ + rootlessCommon.o \ + rootlessGC.o \ + rootlessScreen.o \ + rootlessValTree.o \ + rootlessWindow.o \ + pseudoramiX.o + +INCLUDES = -I. -I$(SERVERSRC)/fb -I$(SERVERSRC)/mi -I$(SERVERSRC)/include \ + -I$(XINCLUDESRC) -I$(FONTINCSRC) -I$(SERVERSRC)/render \ + -I$(EXTINCSRC) -I.. -I$(SERVERSRC)/Xext + +#if defined(XFree86CustomVersion) +CUSTOMVERSION = XFree86CustomVersion +CUSTOMVERDEF = -DXF86_CUSTOM_VERSION='$(CUSTOMVERSION)' +#endif +#if HasCGMachPort +QUARTZDEFINES = -DHAS_CG_MACH_PORT +#endif + +#if XFree86Devel +PBXBUILDSTYLE = -buildstyle Development +DEBUGDEFINES = -DROOTLESSDEBUG +#else +PBXBUILDSTYLE = -buildstyle Deployment +#endif + +DEFINES = $(CUSTOMVERDEF) -DXBINDIR=$(BINDIR) -DXINITDIR=$(XINITDIR) \ + $(QUARTZDEFINES) $(DEBUGDEFINES) +EXTRAMANDEFS = -D__XBinDir__=$(BINDIR) +#if NothingOutsideProjectRoot +XDARWINROOT = $(BINDIR) +#else +XDARWINROOT = /Applications +#endif + +MakeSubdirs($(SUBDIRS)) +DependSubdirs($(SUBDIRS)) + +NormalLibraryObjectRule() +NormalLibraryTarget(XQuartz,$(OBJS)) + +AllTarget(quartzStartup.o) + +AllTarget(XDarwinStartup) +NormalProgramTarget(XDarwinStartup,XDarwinStartup.o, \ + NullParameter,NullParameter, \ + -framework CoreFoundation -framework ApplicationServices) +InstallProgram(XDarwinStartup,$(BINDIR)) +install:: + -(cd $(DESTDIR)$(BINDIR); $(RM) X; $(LN) XDarwinStartup X) + +AllTarget(XDarwin) +XDarwin: + pbxbuild -target XDarwin $(PBXBUILDSTYLE) + +install:: + pbxbuild install -target XDarwin $(PBXBUILDSTYLE) \ + DSTROOT=$(DESTDIR)$(XDARWINROOT) + +InstallManPage(XDarwinStartup,$(MANDIR)) + +clean:: + pbxbuild "clean" -target XDarwin $(PBXBUILDSTYLE) + +DependTarget() + diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/XDarwin.pbproj/project.pbxproj b/xc/programs/Xserver/hw/darwin/quartz_1.3/XDarwin.pbproj/project.pbxproj new file mode 100644 index 000000000..af700a442 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/XDarwin.pbproj/project.pbxproj @@ -0,0 +1,1372 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 32; + objects = { + 01279092000747AA0A000002 = { + isa = PBXFileReference; + path = XServer.m; + refType = 4; + }; + 0127909600074AF60A000002 = { + isa = PBXFileReference; + name = XApplication.m; + path = ../quartz/XApplication.m; + refType = 4; + }; + 0127909800074B1A0A000002 = { + isa = PBXFileReference; + name = XApplication.h; + path = ../quartz/XApplication.h; + refType = 4; + }; + 014C68ED00ED6A9D7F000001 = { + isa = PBXFileReference; + path = XView.h; + refType = 4; + }; + 014C68EE00ED6A9D7F000001 = { + isa = PBXFileReference; + path = XView.m; + refType = 4; + }; + 014C68EF00ED6A9D7F000001 = { + isa = PBXFileReference; + path = XWindow.h; + refType = 4; + }; + 014C68F000ED6A9D7F000001 = { + isa = PBXFileReference; + path = XWindow.m; + refType = 4; + }; + 014C68F200ED7AD67F000001 = { + isa = PBXFileReference; + name = fakeBoxRec.h; + path = ../quartz/fakeBoxRec.h; + refType = 4; + }; + 014C68F300EE5AB97F000001 = { + isa = PBXFileReference; + path = rootlessCommon.c; + refType = 4; + }; + 014C68F400EE5AB97F000001 = { + isa = PBXFileReference; + path = rootlessCommon.h; + refType = 4; + }; + 014C68F700EE678F7F000001 = { + isa = PBXFileReference; + path = rootlessWindow.c; + refType = 4; + }; + 014C68F800EE678F7F000001 = { + isa = PBXFileReference; + path = rootlessWindow.h; + refType = 4; + }; + 015698ED003DF345CE6F79C2 = { + isa = PBXFileReference; + path = XDarwin.icns; + refType = 4; + }; + 0157A37D002CF6D7CE6F79C2 = { + children = ( + F533214601A4B45401000001, + 0157A37E002CF6D7CE6F79C2, + F58D65DF018F79B101000001, + F533213D0193CBE001000001, + 43B962E200617B93416877C2, + F5ACD263C5BE031F01000001, + F51BF62E02026E3501000001, + F5ACD25CC5B5E96601000001, + F587E16401924C6901000001, + ); + isa = PBXVariantGroup; + name = Credits.rtf; + path = ""; + refType = 4; + }; + 0157A37E002CF6D7CE6F79C2 = { + isa = PBXFileReference; + name = English; + path = English.lproj/Credits.rtf; + refType = 4; + }; + 015EDCEA004203A8CE6F79C2 = { + isa = PBXFrameworkReference; + name = IOKit.framework; + path = /System/Library/Frameworks/IOKit.framework; + refType = 0; + }; + 017D6F4400E861FB7F000001 = { + isa = PBXFileReference; + path = rootlessGC.c; + refType = 4; + }; + 017D6F4500E861FB7F000001 = { + isa = PBXFileReference; + path = rootlessScreen.c; + refType = 4; + }; + 018F40F2003E1902CE6F79C2 = { + children = ( + 018F40F3003E1916CE6F79C2, + 021D6BA9003E1BACCE6F79C2, + 3E74E03600863F047F000001, + 018F40F6003E1974CE6F79C2, + ); + isa = PBXGroup; + name = "X Server"; + path = ..; + refType = 4; + }; + 018F40F3003E1916CE6F79C2 = { + isa = PBXFileReference; + path = darwin.c; + refType = 4; + }; + 018F40F6003E1974CE6F79C2 = { + isa = PBXFileReference; + path = darwinKeyboard.c; + refType = 4; + }; + 018F40F8003E1979CE6F79C2 = { + isa = PBXFileReference; + path = quartz.c; + refType = 4; + }; + 018F40FA003E197ECE6F79C2 = { + isa = PBXFileReference; + path = quartz.h; + refType = 4; + }; + 018F40FC003E1983CE6F79C2 = { + isa = PBXFileReference; + path = xfIOKit.c; + refType = 4; + }; + 018F40FE003E1988CE6F79C2 = { + isa = PBXFileReference; + path = xfIOKit.h; + refType = 4; + }; + 018F4100003E19E4CE6F79C2 = { + isa = PBXFileReference; + path = xfIOKitCursor.c; + refType = 4; + }; +//010 +//011 +//012 +//013 +//014 +//020 +//021 +//022 +//023 +//024 + 021D6BA9003E1BACCE6F79C2 = { + isa = PBXFileReference; + path = darwin.h; + refType = 4; + }; + 02A1FEA6006D34BE416877C2 = { + isa = PBXFileReference; + path = xfIOKitStartup.c; + refType = 4; + }; + 02A1FEA8006D38F0416877C2 = { + isa = PBXFileReference; + path = quartzStartup.c; + refType = 4; + }; + 02E03CA000348209CE6F79C2 = { + children = ( + F533214701A4B48301000001, + 02E03CA100348209CE6F79C2, + F58D65E0018F79C001000001, + F533213E0193CBF401000001, + 43B962E300617B93416877C2, + F5ACD268C5BE046401000001, + F51BF62F02026E5C01000001, + F5ACD261C5B5EA2001000001, + F587E16501924C7401000001, + ); + isa = PBXVariantGroup; + name = XDarwinHelp.html; + path = ""; + refType = 4; + }; + 02E03CA100348209CE6F79C2 = { + isa = PBXFileReference; + name = English; + path = English.lproj/XDarwinHelp.html; + refType = 4; + }; +//020 +//021 +//022 +//023 +//024 +//030 +//031 +//032 +//033 +//034 + 0338412F0083BFE57F000001 = { + isa = PBXFileReference; + path = quartzCursor.h; + refType = 4; + }; +//030 +//031 +//032 +//033 +//034 +//040 +//041 +//042 +//043 +//044 + 04329610000763920A000002 = { + isa = PBXFileReference; + name = Preferences.m; + path = ../quartz/Preferences.m; + refType = 4; + }; + 04329611000763920A000002 = { + isa = PBXFileReference; + name = Preferences.h; + path = ../quartz/Preferences.h; + refType = 4; + }; +//040 +//041 +//042 +//043 +//044 +//060 +//061 +//062 +//063 +//064 + 06EB6C3B004099E7CE6F79C2 = { + isa = PBXFileReference; + path = quartzShared.h; + refType = 4; + }; +//060 +//061 +//062 +//063 +//064 +//080 +//081 +//082 +//083 +//084 + 080E96DDFE201D6D7F000001 = { + children = ( + 04329610000763920A000002, + 04329611000763920A000002, + 0127909600074AF60A000002, + 0127909800074B1A0A000002, + 01279092000747AA0A000002, + 1C4A3109004D8F24CE6F79C2, + 014C68EE00ED6A9D7F000001, + 014C68ED00ED6A9D7F000001, + 014C68F000ED6A9D7F000001, + 014C68EF00ED6A9D7F000001, + ); + isa = PBXGroup; + name = Classes; + refType = 4; + }; + 089C165CFE840E0CC02AAC07 = { + children = ( + F533214301A4B3F001000001, + 089C165DFE840E0CC02AAC07, + F58D65DD018F798F01000001, + F533213A0193CBA201000001, + 43B962E100617B49416877C2, + F5ACD269C5BE049301000001, + F51BF62B02026DDA01000001, + F5ACD262C5B5EA4D01000001, + F587E16101924C2F01000001, + ); + isa = PBXVariantGroup; + name = InfoPlist.strings; + refType = 4; + }; + 089C165DFE840E0CC02AAC07 = { + isa = PBXFileReference; + name = English; + path = English.lproj/InfoPlist.strings; + refType = 4; + }; +//080 +//081 +//082 +//083 +//084 +//0A0 +//0A1 +//0A2 +//0A3 +//0A4 + 0A79E19E004499A1CE6F79C2 = { + isa = PBXApplicationReference; + path = XDarwin.app; + refType = 3; + }; + 0A79E19F004499A1CE6F79C2 = { + buildPhases = ( + 0A79E1A0004499A1CE6F79C2, + 0A79E1A1004499A1CE6F79C2, + 0A79E1A2004499A1CE6F79C2, + 0A79E1A3004499A1CE6F79C2, + 0A79E1A4004499A1CE6F79C2, + ); + buildSettings = { + INSTALL_PATH = ""; + OPTIMIZATION_CFLAGS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = XDarwin; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + WRAPPER_EXTENSION = app; + }; + dependencies = ( + ); + isa = PBXApplicationTarget; + name = XDarwin; + productInstallPath = ""; + productName = XDarwin; + productReference = 0A79E19E004499A1CE6F79C2; + productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> +<!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\"> +<plist version=\"0.9\"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>XDarwin</string> + <key>CFBundleGetInfoString</key> + <string>XDarwin 1.1, ©2001-2002 XFree86 Project, Inc.</string> + <key>CFBundleIconFile</key> + <string>XDarwin.icns</string> + <key>CFBundleIdentifier</key> + <string>org.xfree86.XDarwin</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>XDarwin</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>XDarwin 1.1</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string></string> + <key>NSHelpFile</key> + <string>XDarwinHelp.html</string> + <key>NSMainNibFile</key> + <string>MainMenu</string> + <key>NSPrincipalClass</key> + <string>XApplication</string> +</dict> +</plist> +"; + shouldUseHeadermap = 0; + }; + 0A79E1A0004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXHeadersBuildPhase; + name = Headers; + }; + 0A79E1A1004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + 0A79E1A600449EB2CE6F79C2, + 0A79E1A700449EB2CE6F79C2, + 0A79E1A800449EB2CE6F79C2, + 0A79E1A900449EB2CE6F79C2, + 0A79E1AA00449EB2CE6F79C2, + 1220774500712D2D416877C2, + F54BF6ED017D506E01000001, + ); + isa = PBXResourcesBuildPhase; + name = "Bundle Resources"; + }; + 0A79E1A2004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXSourcesBuildPhase; + name = Sources; + }; + 0A79E1A3004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXFrameworksBuildPhase; + name = "Frameworks & Libraries"; + }; + 0A79E1A4004499A1CE6F79C2 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXRezBuildPhase; + name = "ResourceManager Resources"; + }; + 0A79E1A600449EB2CE6F79C2 = { + fileRef = 29B97318FDCFA39411CA2CEA; + isa = PBXBuildFile; + settings = { + }; + }; + 0A79E1A700449EB2CE6F79C2 = { + fileRef = 089C165CFE840E0CC02AAC07; + isa = PBXBuildFile; + settings = { + }; + }; + 0A79E1A800449EB2CE6F79C2 = { + fileRef = 0157A37D002CF6D7CE6F79C2; + isa = PBXBuildFile; + settings = { + }; + }; + 0A79E1A900449EB2CE6F79C2 = { + fileRef = 02E03CA000348209CE6F79C2; + isa = PBXBuildFile; + settings = { + }; + }; + 0A79E1AA00449EB2CE6F79C2 = { + fileRef = 015698ED003DF345CE6F79C2; + isa = PBXBuildFile; + settings = { + }; + }; +//0A0 +//0A1 +//0A2 +//0A3 +//0A4 +//100 +//101 +//102 +//103 +//104 + 1058C7A0FEA54F0111CA2CBB = { + children = ( + F53321400193CCF001000001, + 1BE4F84D0006C9890A000002, + 1058C7A1FEA54F0111CA2CBB, + F53321410193CCF001000001, + 015EDCEA004203A8CE6F79C2, + ); + isa = PBXGroup; + name = "Linked Frameworks"; + refType = 4; + }; + 1058C7A1FEA54F0111CA2CBB = { + isa = PBXFrameworkReference; + name = Cocoa.framework; + path = /System/Library/Frameworks/Cocoa.framework; + refType = 0; + }; + 1058C7A2FEA54F0111CA2CBB = { + children = ( + 29B97325FDCFA39411CA2CEA, + 29B97324FDCFA39411CA2CEA, + ); + isa = PBXGroup; + name = "Other Frameworks"; + refType = 4; + }; +//100 +//101 +//102 +//103 +//104 +//120 +//121 +//122 +//123 +//124 + 1220774300712D2D416877C2 = { + children = ( + F533214501A4B42501000001, + 1220774400712D2D416877C2, + F58D65DE018F79A001000001, + F533213C0193CBC901000001, + 1220774600712D75416877C2, + F5ACD266C5BE03C501000001, + F51BF62D02026E1C01000001, + F5ACD25FC5B5E9AA01000001, + F587E16301924C5E01000001, + ); + isa = PBXVariantGroup; + name = Localizable.strings; + path = ""; + refType = 4; + }; + 1220774400712D2D416877C2 = { + isa = PBXFileReference; + name = English; + path = English.lproj/Localizable.strings; + refType = 4; + }; + 1220774500712D2D416877C2 = { + fileRef = 1220774300712D2D416877C2; + isa = PBXBuildFile; + settings = { + }; + }; + 1220774600712D75416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/Localizable.strings; + refType = 4; + }; +//120 +//121 +//122 +//123 +//124 +//170 +//171 +//172 +//173 +//174 + 170DFAFF00729A35416877C2 = { + isa = PBXFileReference; + name = XDarwinStartup.c; + path = ../quartz/XDarwinStartup.c; + refType = 4; + }; + 170DFB0000729C86416877C2 = { + children = ( + 018F40FC003E1983CE6F79C2, + 018F40FE003E1988CE6F79C2, + 018F4100003E19E4CE6F79C2, + 02A1FEA6006D34BE416877C2, + ); + isa = PBXGroup; + name = IOKit; + path = ..; + refType = 4; + }; +//170 +//171 +//172 +//173 +//174 +//190 +//191 +//192 +//193 +//194 + 19C28FACFE9D520D11CA2CBB = { + children = ( + 0A79E19E004499A1CE6F79C2, + ); + isa = PBXGroup; + name = Products; + refType = 4; + }; +//190 +//191 +//192 +//193 +//194 +//1B0 +//1B1 +//1B2 +//1B3 +//1B4 + 1BD8DE4200B8A3567F000001 = { + children = ( + F533214401A4B40F01000001, + 1BD8DE4300B8A3567F000001, + F58D65DC018F794D01000001, + F533213B0193CBB401000001, + 1BD8DE4700B8A3C77F000001, + F5ACD264C5BE035B01000001, + F51BF62C02026E0601000001, + F5ACD25DC5B5E97701000001, + F587E16201924C5301000001, + ); + isa = PBXVariantGroup; + name = InfoPlist.strings.cpp; + path = ""; + refType = 4; + }; + 1BD8DE4300B8A3567F000001 = { + isa = PBXFileReference; + name = English; + path = English.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + 1BD8DE4400B8A38E7F000001 = { + children = ( + F533214801A4B4D701000001, + 1BD8DE4500B8A38E7F000001, + F58D65E1018F79E001000001, + F533213F0193CC2501000001, + 1BD8DE4800B8A4167F000001, + F5ACD267C5BE03FC01000001, + F51BF63002026E8D01000001, + F5ACD260C5B5E9DF01000001, + F587E16601924C9D01000001, + ); + isa = PBXVariantGroup; + name = XDarwinHelp.html.cpp; + path = ""; + refType = 4; + }; + 1BD8DE4500B8A38E7F000001 = { + isa = PBXFileReference; + name = English; + path = English.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + 1BD8DE4700B8A3C77F000001 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + 1BD8DE4800B8A4167F000001 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + 1BE4F84D0006C9890A000002 = { + isa = PBXFrameworkReference; + name = Carbon.framework; + path = /System/Library/Frameworks/Carbon.framework; + refType = 0; + }; +//1B0 +//1B1 +//1B2 +//1B3 +//1B4 +//1C0 +//1C1 +//1C2 +//1C3 +//1C4 + 1C4A3109004D8F24CE6F79C2 = { + isa = PBXFileReference; + path = XServer.h; + refType = 4; + }; +//1C0 +//1C1 +//1C2 +//1C3 +//1C4 +//230 +//231 +//232 +//233 +//234 + 237A34C10076E37E7F000001 = { + isa = PBXFileReference; + path = quartzAudio.c; + refType = 4; + }; + 237A34C20076E37E7F000001 = { + buildRules = ( + ); + buildSettings = { + COPY_PHASE_STRIP = NO; + }; + isa = PBXBuildStyle; + name = Development; + }; + 237A34C30076E37E7F000001 = { + buildRules = ( + ); + buildSettings = { + COPY_PHASE_STRIP = YES; + }; + isa = PBXBuildStyle; + name = Deployment; + }; + 237A34C40076F4F07F000001 = { + isa = PBXFileReference; + path = quartzAudio.h; + refType = 4; + }; +//230 +//231 +//232 +//233 +//234 +//290 +//291 +//292 +//293 +//294 + 29B97313FDCFA39411CA2CEA = { + buildStyles = ( + 237A34C20076E37E7F000001, + 237A34C30076E37E7F000001, + ); + isa = PBXProject; + knownRegions = ( + English, + Japanese, + French, + German, + Swedish, + Dutch, + Spanish, + ko, + Portuguese, + ); + mainGroup = 29B97314FDCFA39411CA2CEA; + projectDirPath = ""; + targets = ( + 0A79E19F004499A1CE6F79C2, + ); + }; + 29B97314FDCFA39411CA2CEA = { + children = ( + 080E96DDFE201D6D7F000001, + 018F40F2003E1902CE6F79C2, + 170DFB0000729C86416877C2, + 43B962CE00617089416877C2, + F51B53260253F84B01000001, + 32FEE13C00E07C3E7F000001, + 29B97315FDCFA39411CA2CEA, + 29B97317FDCFA39411CA2CEA, + 29B97323FDCFA39411CA2CEA, + 19C28FACFE9D520D11CA2CBB, + ); + isa = PBXGroup; + name = "Xmaster-Cocoa"; + path = ""; + refType = 4; + }; + 29B97315FDCFA39411CA2CEA = { + children = ( + 170DFAFF00729A35416877C2, + ); + isa = PBXGroup; + name = "Other Sources"; + path = ""; + refType = 2; + }; + 29B97317FDCFA39411CA2CEA = { + children = ( + 29B97318FDCFA39411CA2CEA, + 089C165CFE840E0CC02AAC07, + 1BD8DE4200B8A3567F000001, + 1220774300712D2D416877C2, + 0157A37D002CF6D7CE6F79C2, + 02E03CA000348209CE6F79C2, + 1BD8DE4400B8A38E7F000001, + 015698ED003DF345CE6F79C2, + F54BF6EA017D500901000001, + F54BF6EC017D506E01000001, + ); + isa = PBXGroup; + name = Resources; + path = ../bundle; + refType = 4; + }; + 29B97318FDCFA39411CA2CEA = { + children = ( + F533214201A4B3CE01000001, + 29B97319FDCFA39411CA2CEA, + F58D65DB018F793801000001, + F53321390193CB6A01000001, + 43B962E000617B49416877C2, + F5ACD265C5BE038601000001, + F51BF62A02026DAF01000001, + F5ACD25EC5B5E98D01000001, + F587E16001924C1D01000001, + ); + isa = PBXVariantGroup; + name = MainMenu.nib; + path = ""; + refType = 4; + }; + 29B97319FDCFA39411CA2CEA = { + isa = PBXFileReference; + name = English; + path = English.lproj/MainMenu.nib; + refType = 4; + }; + 29B97323FDCFA39411CA2CEA = { + children = ( + 1058C7A0FEA54F0111CA2CBB, + 1058C7A2FEA54F0111CA2CBB, + ); + isa = PBXGroup; + name = Frameworks; + path = ""; + refType = 4; + }; + 29B97324FDCFA39411CA2CEA = { + isa = PBXFrameworkReference; + name = AppKit.framework; + path = /System/Library/Frameworks/AppKit.framework; + refType = 0; + }; + 29B97325FDCFA39411CA2CEA = { + isa = PBXFrameworkReference; + name = Foundation.framework; + path = /System/Library/Frameworks/Foundation.framework; + refType = 0; + }; +//290 +//291 +//292 +//293 +//294 +//320 +//321 +//322 +//323 +//324 + 32FEE13C00E07C3E7F000001 = { + children = ( + 014C68F200ED7AD67F000001, + F5269C2D01D5BC3501000001, + F5269C2E01D5BC3501000001, + 32FEE13E00E07CBE7F000001, + 32FEE13F00E07CBE7F000001, + 32FEE14000E07CBE7F000001, + 32FEE14100E07CBE7F000001, + 32FEE14200E07CBE7F000001, + 014C68F300EE5AB97F000001, + 014C68F400EE5AB97F000001, + 017D6F4400E861FB7F000001, + 017D6F4500E861FB7F000001, + 014C68F700EE678F7F000001, + 014C68F800EE678F7F000001, + 32FEE14900E07D317F000001, + ); + isa = PBXGroup; + name = Rootless; + path = ""; + refType = 4; + }; + 32FEE13E00E07CBE7F000001 = { + isa = PBXFileReference; + path = rootless.h; + refType = 4; + }; + 32FEE13F00E07CBE7F000001 = { + isa = PBXFileReference; + path = rootlessAqua.h; + refType = 4; + }; + 32FEE14000E07CBE7F000001 = { + isa = PBXFileReference; + path = rootlessAquaGlue.c; + refType = 4; + }; + 32FEE14100E07CBE7F000001 = { + isa = PBXFileReference; + path = rootlessAquaImp.h; + refType = 4; + }; + 32FEE14200E07CBE7F000001 = { + isa = PBXFileReference; + path = rootlessAquaImp.m; + refType = 4; + }; + 32FEE14900E07D317F000001 = { + isa = PBXFileReference; + path = rootlessValTree.c; + refType = 4; + }; +//320 +//321 +//322 +//323 +//324 +//350 +//351 +//352 +//353 +//354 + 3576829A0077B8F17F000001 = { + isa = PBXFileReference; + path = quartzCursor.c; + refType = 4; + }; +//350 +//351 +//352 +//353 +//354 +//3E0 +//3E1 +//3E2 +//3E3 +//3E4 + 3E74E03600863F047F000001 = { + isa = PBXFileReference; + path = darwinClut8.h; + refType = 4; + }; +//3E0 +//3E1 +//3E2 +//3E3 +//3E4 +//430 +//431 +//432 +//433 +//434 + 43B962CE00617089416877C2 = { + children = ( + 018F40F8003E1979CE6F79C2, + 018F40FA003E197ECE6F79C2, + 237A34C10076E37E7F000001, + 237A34C40076F4F07F000001, + 3576829A0077B8F17F000001, + 0338412F0083BFE57F000001, + 43B962D000617089416877C2, + 43B962D100617089416877C2, + 43B962CF00617089416877C2, + F5582948015DAD3B01000001, + 06EB6C3B004099E7CE6F79C2, + 02A1FEA8006D38F0416877C2, + ); + isa = PBXGroup; + name = Quartz; + path = ../quartz; + refType = 4; + }; + 43B962CF00617089416877C2 = { + isa = PBXFileReference; + path = quartzCocoa.m; + refType = 4; + }; + 43B962D000617089416877C2 = { + isa = PBXFileReference; + path = quartzPasteboard.c; + refType = 4; + }; + 43B962D100617089416877C2 = { + isa = PBXFileReference; + path = quartzPasteboard.h; + refType = 4; + }; + 43B962E000617B49416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/MainMenu.nib; + refType = 4; + }; + 43B962E100617B49416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/InfoPlist.strings; + refType = 4; + }; + 43B962E200617B93416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/Credits.rtf; + refType = 4; + }; + 43B962E300617B93416877C2 = { + isa = PBXFileReference; + name = Japanese; + path = Japanese.lproj/XDarwinHelp.html; + refType = 4; + }; +//430 +//431 +//432 +//433 +//434 +//F50 +//F51 +//F52 +//F53 +//F54 + F51B53260253F84B01000001 = { + children = ( + F51B53270253F8B701000001, + F51B53280253F8B701000001, + ); + isa = PBXGroup; + name = "Full Screen"; + path = ../quartz; + refType = 4; + }; + F51B53270253F8B701000001 = { + isa = PBXFileReference; + path = fullscreen.c; + refType = 4; + }; + F51B53280253F8B701000001 = { + isa = PBXFileReference; + path = fullscreen.h; + refType = 4; + }; + F51BF62A02026DAF01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/MainMenu.nib; + refType = 4; + }; + F51BF62B02026DDA01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/InfoPlist.strings; + refType = 4; + }; + F51BF62C02026E0601000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F51BF62D02026E1C01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/Localizable.strings; + refType = 4; + }; + F51BF62E02026E3501000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/Credits.rtf; + refType = 4; + }; + F51BF62F02026E5C01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/XDarwinHelp.html; + refType = 4; + }; + F51BF63002026E8D01000001 = { + isa = PBXFileReference; + name = Portuguese; + path = Portuguese.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F5269C2D01D5BC3501000001 = { + isa = PBXFileReference; + name = pseudoramiX.c; + path = ../quartz/pseudoramiX.c; + refType = 4; + }; + F5269C2E01D5BC3501000001 = { + isa = PBXFileReference; + name = pseudoramiX.h; + path = ../quartz/pseudoramiX.h; + refType = 4; + }; + F53321390193CB6A01000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/MainMenu.nib; + refType = 4; + }; + F533213A0193CBA201000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/InfoPlist.strings; + refType = 4; + }; + F533213B0193CBB401000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F533213C0193CBC901000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/Localizable.strings; + refType = 4; + }; + F533213D0193CBE001000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/Credits.rtf; + refType = 4; + }; + F533213E0193CBF401000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/XDarwinHelp.html; + refType = 4; + }; + F533213F0193CC2501000001 = { + isa = PBXFileReference; + name = German; + path = German.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F53321400193CCF001000001 = { + isa = PBXFrameworkReference; + name = ApplicationServices.framework; + path = /System/Library/Frameworks/ApplicationServices.framework; + refType = 0; + }; + F53321410193CCF001000001 = { + isa = PBXFrameworkReference; + name = CoreAudio.framework; + path = /System/Library/Frameworks/CoreAudio.framework; + refType = 0; + }; + F533214201A4B3CE01000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/MainMenu.nib; + refType = 4; + }; + F533214301A4B3F001000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/InfoPlist.strings; + refType = 4; + }; + F533214401A4B40F01000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F533214501A4B42501000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/Localizable.strings; + refType = 4; + }; + F533214601A4B45401000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/Credits.rtf; + refType = 4; + }; + F533214701A4B48301000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/XDarwinHelp.html; + refType = 4; + }; + F533214801A4B4D701000001 = { + isa = PBXFileReference; + name = Dutch; + path = Dutch.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F54BF6EA017D500901000001 = { + isa = PBXFileReference; + path = startXClients.cpp; + refType = 4; + }; + F54BF6EC017D506E01000001 = { + isa = PBXFileReference; + path = startXClients; + refType = 4; + }; + F54BF6ED017D506E01000001 = { + fileRef = F54BF6EC017D506E01000001; + isa = PBXBuildFile; + settings = { + }; + }; + F5582948015DAD3B01000001 = { + isa = PBXFileReference; + path = quartzCommon.h; + refType = 4; + }; + F587E16001924C1D01000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/MainMenu.nib; + refType = 4; + }; + F587E16101924C2F01000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/InfoPlist.strings; + refType = 4; + }; + F587E16201924C5301000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F587E16301924C5E01000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/Localizable.strings; + refType = 4; + }; + F587E16401924C6901000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/Credits.rtf; + refType = 4; + }; + F587E16501924C7401000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/XDarwinHelp.html; + refType = 4; + }; + F587E16601924C9D01000001 = { + isa = PBXFileReference; + name = Swedish; + path = Swedish.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F58D65DB018F793801000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/MainMenu.nib; + refType = 4; + }; + F58D65DC018F794D01000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F58D65DD018F798F01000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/InfoPlist.strings; + refType = 4; + }; + F58D65DE018F79A001000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/Localizable.strings; + refType = 4; + }; + F58D65DF018F79B101000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/Credits.rtf; + refType = 4; + }; + F58D65E0018F79C001000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/XDarwinHelp.html; + refType = 4; + }; + F58D65E1018F79E001000001 = { + isa = PBXFileReference; + name = French; + path = French.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F5ACD25CC5B5E96601000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/Credits.rtf; + refType = 4; + }; + F5ACD25DC5B5E97701000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F5ACD25EC5B5E98D01000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/MainMenu.nib; + refType = 4; + }; + F5ACD25FC5B5E9AA01000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/Localizable.strings; + refType = 4; + }; + F5ACD260C5B5E9DF01000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F5ACD261C5B5EA2001000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/XDarwinHelp.html; + refType = 4; + }; + F5ACD262C5B5EA4D01000001 = { + isa = PBXFileReference; + name = Spanish; + path = Spanish.lproj/InfoPlist.strings; + refType = 4; + }; + F5ACD263C5BE031F01000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/Credits.rtf; + refType = 4; + }; + F5ACD264C5BE035B01000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/InfoPlist.strings.cpp; + refType = 4; + }; + F5ACD265C5BE038601000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/MainMenu.nib; + refType = 4; + }; + F5ACD266C5BE03C501000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/Localizable.strings; + refType = 4; + }; + F5ACD267C5BE03FC01000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/XDarwinHelp.html.cpp; + refType = 4; + }; + F5ACD268C5BE046401000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/XDarwinHelp.html; + refType = 4; + }; + F5ACD269C5BE049301000001 = { + isa = PBXFileReference; + name = ko; + path = ko.lproj/InfoPlist.strings; + refType = 4; + }; + }; + rootObject = 29B97313FDCFA39411CA2CEA; +} diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/XServer.h b/xc/programs/Xserver/hw/darwin/quartz_1.3/XServer.h new file mode 100644 index 000000000..87932fc67 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/XServer.h @@ -0,0 +1,72 @@ +// +// XServer.h +// +// Created by Andreas Monitzer on January 6, 2001. +// +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/XServer.h,v 1.2 2002/06/19 18:12:02 torrey Exp $ */ + +#import <Cocoa/Cocoa.h> + +#include <drivers/event_status_driver.h> // for NXEvent + +@interface XServer : NSObject { + // server state + NSRecursiveLock *serverLock; + NSPort *signalPort; + BOOL serverVisible; + BOOL rootlessMenuBarVisible; + BOOL appQuitting; + UInt32 mouseState; + Class windowClass; + + // server event queue + BOOL sendServerEvents; + int eventWriteFD; + + // Aqua interface + IBOutlet NSWindow *modeWindow; + IBOutlet NSButton *startupModeButton; + IBOutlet NSButton *startFullScreenButton; + IBOutlet NSButton *startRootlessButton; + IBOutlet NSWindow *helpWindow; + IBOutlet NSButton *startupHelpButton; + IBOutlet NSPanel *switchWindow; +} + +- (id)init; + +- (BOOL)translateEvent:(NSEvent *)anEvent; +- (BOOL)getNXMouse:(NXEvent*)ev; + ++ (void)append:(NSString*)value toEnv:(NSString*)name; + +- (void)startX; +- (BOOL)startXClients; +- (void)run; +- (void)toggle; +- (void)show; +- (void)hide; +- (void)killServer; +- (void)readPasteboard; +- (void)writePasteboard; +- (void)sendNXEvent:(NXEvent*)ev; +- (void)sendShowHide:(BOOL)show; + +// Aqua interface actions +- (IBAction)startFullScreen:(id)sender; +- (IBAction)startRootless:(id)sender; +- (IBAction)closeHelpAndShow:(id)sender; +- (IBAction)showAction:(id)sender; + +// NSApplication delegate +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification; +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag; +- (void)applicationWillResignActive:(NSNotification *)aNotification; +- (void)applicationWillBecomeActive:(NSNotification *)aNotification; + +// NSPort delegate +- (void)handlePortMessage:(NSPortMessage *)portMessage; + +@end + diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/XServer.m b/xc/programs/Xserver/hw/darwin/quartz_1.3/XServer.m new file mode 100644 index 000000000..4cd5ab846 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/XServer.m @@ -0,0 +1,832 @@ +// +// XServer.m +// +// This class handles the interaction between the Cocoa front-end +// and the Darwin X server thread. +// +// Created by Andreas Monitzer on January 6, 2001. +// +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/XServer.m,v 1.2 2002/06/19 18:12:02 torrey Exp $ */ + +#import "XServer.h" +#import "Preferences.h" +#import "XWindow.h" +#include "quartzCommon.h" + +#include <unistd.h> +#include <stdio.h> +#include <sys/syslimits.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <pwd.h> +#include <signal.h> +#include <fcntl.h> + +// Types of shells +enum { + shell_Unknown, + shell_Bourne, + shell_C +}; + +typedef struct { + char *name; + int type; +} shellList_t; + +static shellList_t const shellList[] = { + { "csh", shell_C }, // standard C shell + { "tcsh", shell_C }, // ... needs no introduction + { "sh", shell_Bourne }, // standard Bourne shell + { "zsh", shell_Bourne }, // Z shell + { "bash", shell_Bourne }, // GNU Bourne again shell + { NULL, shell_Unknown } +}; + +extern int argcGlobal; +extern char **argvGlobal; +extern char **envpGlobal; +extern int main(int argc, char *argv[], char *envp[]); +extern void HideMenuBar(void); +extern void ShowMenuBar(void); +static void childDone(int sig); + +static NSPortMessage *signalMessage; +static pid_t clientPID; +static XServer *oneXServer; +static NSRect aquaMenuBarBox; + + +@implementation XServer + +- (id)init +{ + self = [super init]; + oneXServer = self; + + serverLock = [[NSRecursiveLock alloc] init]; + clientPID = 0; + sendServerEvents = NO; + serverVisible = NO; + rootlessMenuBarVisible = YES; + appQuitting = NO; + mouseState = 0; + eventWriteFD = quartzEventWriteFD; + windowClass = [XWindow class]; + + // set up a port to safely send messages to main thread from server thread + signalPort = [[NSPort port] retain]; + signalMessage = [[NSPortMessage alloc] initWithSendPort:signalPort + receivePort:signalPort components:nil]; + + // set up receiving end + [signalPort setDelegate:self]; + [[NSRunLoop currentRunLoop] addPort:signalPort + forMode:NSDefaultRunLoopMode]; + [[NSRunLoop currentRunLoop] addPort:signalPort + forMode:NSModalPanelRunLoopMode]; + + return self; +} + +- (NSApplicationTerminateReply) + applicationShouldTerminate:(NSApplication *)sender +{ + // Quit if the X server is not running + if ([serverLock tryLock]) { + appQuitting = YES; + if (clientPID != 0) + kill(clientPID, SIGINT); + return NSTerminateNow; + } + + if (clientPID != 0 || !quartzStartClients) { + int but; + + // Hide the X server and stop sending it events + [self hide]; + sendServerEvents = NO; + + but = NSRunAlertPanel(NSLocalizedString(@"Quit X server?",@""), + NSLocalizedString(@"Quitting the X server will terminate any running X Window System programs.",@""), + NSLocalizedString(@"Quit",@""), + NSLocalizedString(@"Cancel",@""), + nil); + + switch (but) { + case NSAlertDefaultReturn: // quit + break; + case NSAlertAlternateReturn: // cancel + sendServerEvents = YES; + return NSTerminateCancel; + } + } + + appQuitting = YES; + if (clientPID != 0) + kill(clientPID, SIGINT); + [self killServer]; + return NSTerminateNow; +} + +// Ensure that everything has quit cleanly +- (void)applicationWillTerminate:(NSNotification *)aNotification +{ + // Make sure the client process has finished + if (clientPID != 0) { + NSLog(@"Waiting on client process..."); + sleep(2); + + // If the client process hasn't finished yet, kill it off + if (clientPID != 0) { + int clientStatus; + NSLog(@"Killing client process..."); + killpg(clientPID, SIGKILL); + waitpid(clientPID, &clientStatus, 0); + } + } + + // Wait until the X server thread quits + [serverLock lock]; +} + +// returns YES when event was handled +- (BOOL)translateEvent:(NSEvent *)anEvent +{ + NXEvent ev; + static BOOL mouse1Pressed = NO; + BOOL onScreen; + + if (!sendServerEvents) { + return NO; + } + + ev.type = [anEvent type]; + ev.flags = [anEvent modifierFlags]; + + if (!quartzRootless) { + // Check for switch keypress + if ((ev.type == NSKeyDown) && (![anEvent isARepeat]) && + ([anEvent keyCode] == [Preferences keyCode])) + { + unsigned int switchFlags = [Preferences modifiers]; + + // Switch if all the switch modifiers are pressed, while none are + // pressed that should not be, except for caps lock. + if (((ev.flags & switchFlags) == switchFlags) && + ((ev.flags & ~(switchFlags | NSAlphaShiftKeyMask)) == 0)) + { + [self toggle]; + return YES; + } + } + + if (!serverVisible) + return NO; + } + + // If the mouse is not on the valid X display area, + // we don't send the X server key events. + onScreen = [self getNXMouse:&ev]; + + switch (ev.type) { + case NSLeftMouseUp: + if (quartzRootless && !mouse1Pressed) { + // MouseUp after MouseDown in menu - ignore + return NO; + } + mouse1Pressed = NO; + break; + case NSLeftMouseDown: + if (quartzRootless && + ! ([anEvent window] && + [[anEvent window] isKindOfClass:windowClass])) { + // Click in non X window - ignore + return NO; + } + mouse1Pressed = YES; + case NSMouseMoved: + break; + case NSLeftMouseDragged: + case NSRightMouseDragged: + case 27: // undocumented high button MouseDragged event + ev.type=NSMouseMoved; + break; + case NSSystemDefined: + if (![anEvent subtype]==7) + return NO; // we only use multibutton mouse events + if ([anEvent data1] & 1) + return NO; // skip mouse button 1 events + if (mouseState==[anEvent data2]) + return NO; // ignore double events + ev.data.compound.subType=[anEvent subtype]; + ev.data.compound.misc.L[0]=[anEvent data1]; + ev.data.compound.misc.L[1]=mouseState=[anEvent data2]; + break; + case NSScrollWheel: + ev.data.scrollWheel.deltaAxis1=[anEvent deltaY]; + break; + case NSKeyDown: + case NSKeyUp: + if (!onScreen) + return NO; + ev.data.key.keyCode = [anEvent keyCode]; + ev.data.key.repeat = [anEvent isARepeat]; + break; + case NSFlagsChanged: + ev.data.key.keyCode = [anEvent keyCode]; + break; + case 25: // undocumented MouseDown + case 26: // undocumented MouseUp + // Hide these from AppKit to avoid its log messages + return YES; + default: + return NO; + } + + [self sendNXEvent:&ev]; + + // Rootless: Send first NSLeftMouseDown to windows and views so window + // ordering can be suppressed. + // Don't pass further events - they (incorrectly?) bring the window + // forward no matter what. + if (quartzRootless && + (ev.type == NSLeftMouseDown || ev.type == NSLeftMouseUp) && + [anEvent clickCount] == 1 && + [[anEvent window] isKindOfClass:windowClass]) + { + return NO; + } + + return YES; +} + +// Fill in NXEvent with mouse coordinates, inverting y coordinate. +// For rootless mode, the menu bar is treated as not part of the usable +// X display area and the cursor position is adjusted accordingly. +// Returns YES if the cursor is not in the menu bar. +- (BOOL)getNXMouse:(NXEvent*)ev +{ + NSPoint pt = [NSEvent mouseLocation]; + + ev->location.x = (int)(pt.x); + + if (quartzRootless && NSMouseInRect(pt, aquaMenuBarBox, NO)) { + // mouse in menu bar - tell X11 that it's just below instead + ev->location.y = aquaMenuBarHeight; + return NO; + } else { + ev->location.y = NSHeight([[NSScreen mainScreen] frame]) - (int)(pt.y); + return YES; + } +} + +// Append a string to the given enviroment variable ++ (void)append:(NSString*)value toEnv:(NSString*)name +{ + setenv([name cString], + [[[NSString stringWithCString:getenv([name cString])] + stringByAppendingString:value] cString],1); +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + // Block SIGPIPE + // SIGPIPE repeatably killed the (rootless) server when closing a + // dozen xterms in rapid succession. Those SIGPIPEs should have been + // sent to the X server thread, which ignores them, but somehow they + // ended up in this thread instead. + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGPIPE); + // pthread_sigmask not implemented yet + // pthread_sigmask(SIG_BLOCK, &set, NULL); + sigprocmask(SIG_BLOCK, &set, NULL); + } + + if (quartzRootless == -1) { + // The display mode was not set from the command line. + // Show mode pick panel? + if ([Preferences modeWindow]) { + if ([Preferences rootless]) + [startRootlessButton setKeyEquivalent:@"\r"]; + else + [startFullScreenButton setKeyEquivalent:@"\r"]; + [modeWindow makeKeyAndOrderFront:nil]; + } else { + // Otherwise use default mode + quartzRootless = [Preferences rootless]; + [self startX]; + } + } else { + [self startX]; + } +} + +// Start the X server thread and the client process +- (void)startX +{ + NSDictionary *appDictionary; + NSString *appVersion; + + [modeWindow close]; + + // Calculate the height of the menu bar so rootless mode can avoid it + if (quartzRootless) { + aquaMenuBarHeight = NSHeight([[NSScreen mainScreen] frame]) - + NSMaxY([[NSScreen mainScreen] visibleFrame]) - 1; + aquaMenuBarBox = + NSMakeRect(0, NSMaxY([[NSScreen mainScreen] visibleFrame]) + 1, + NSWidth([[NSScreen mainScreen] frame]), + aquaMenuBarHeight); + } + + // Write the XDarwin version to the console log + appDictionary = [[NSBundle mainBundle] infoDictionary]; + appVersion = [appDictionary objectForKey:@"CFBundleShortVersionString"]; + if (appVersion) + NSLog(@"\n%@", appVersion); + else + NSLog(@"No version"); + + // Start the X server thread + [NSThread detachNewThreadSelector:@selector(run) toTarget:self + withObject:nil]; + sendServerEvents = YES; + + // Start the X clients if started from GUI + if (quartzStartClients) { + [self startXClients]; + } + + if (quartzRootless) { + // There is no help window for rootless; just start + [helpWindow close]; + helpWindow = nil; + if ([NSApp isActive]) + [self sendShowHide:YES]; + else + [self sendShowHide:NO]; + } else { + // Show the X switch window if not using dock icon switching + if (![Preferences dockSwitch]) + [switchWindow orderFront:nil]; + + if ([Preferences startupHelp]) { + // display the full screen mode help + [self sendShowHide:NO]; + [helpWindow makeKeyAndOrderFront:nil]; + } else { + // start running full screen and make sure X is visible + ShowMenuBar(); + [self closeHelpAndShow:nil]; + } + } +} + +// Start the first X clients in a separate process +- (BOOL)startXClients +{ + struct passwd *passwdUser; + NSString *shellPath, *dashShellName, *commandStr, *startXPath; + NSMutableString *safeStartXPath; + NSRange aRange; + NSBundle *thisBundle; + const char *shellPathStr, *newargv[3], *shellNameStr; + int fd[2], outFD, length, shellType, i; + + // Register to catch the signal when the client processs finishes + signal(SIGCHLD, childDone); + + // Get user's password database entry + passwdUser = getpwuid(getuid()); + + // Find the shell to use + if ([Preferences useDefaultShell]) + shellPath = [NSString stringWithCString:passwdUser->pw_shell]; + else + shellPath = [Preferences shellString]; + + dashShellName = [NSString stringWithFormat:@"-%@", + [shellPath lastPathComponent]]; + shellPathStr = [shellPath cString]; + shellNameStr = [[shellPath lastPathComponent] cString]; + + if (access(shellPathStr, X_OK)) { + NSLog(@"Shell %s is not valid!", shellPathStr); + return NO; + } + + // Find the type of shell + for (i = 0; shellList[i].name; i++) { + if (!strcmp(shellNameStr, shellList[i].name)) + break; + } + shellType = shellList[i].type; + + newargv[0] = [dashShellName cString]; + if (shellType == shell_Bourne) { + // Bourne shells need to be told they are interactive to make + // sure they read all their initialization files. + newargv[1] = "-i"; + newargv[2] = NULL; + } else { + newargv[1] = NULL; + } + + // Create a pipe to communicate with the X client process + NSAssert(pipe(fd) == 0, @"Could not create new pipe."); + + // Open a file descriptor for writing to stdout and stderr + outFD = open("/dev/console", O_WRONLY, 0); + if (outFD == -1) { + outFD = open("/dev/null", O_WRONLY, 0); + NSAssert(outFD != -1, @"Could not open shell output."); + } + + // Fork process to start X clients in user's default shell + // Sadly we can't use NSTask because we need to start a login shell. + // Login shells are started by passing "-" as the first character of + // argument 0. NSTask forces argument 0 to be the shell's name. + clientPID = vfork(); + if (clientPID == 0) { + + // Inside the new process: + if (fd[0] != STDIN_FILENO) { + dup2(fd[0], STDIN_FILENO); // Take stdin from pipe + close(fd[0]); + } + close(fd[1]); // Close write end of pipe + if (outFD == STDOUT_FILENO) { // Setup stdout and stderr + dup2(outFD, STDERR_FILENO); + } else if (outFD == STDERR_FILENO) { + dup2(outFD, STDOUT_FILENO); + } else { + dup2(outFD, STDERR_FILENO); + dup2(outFD, STDOUT_FILENO); + close(outFD); + } + + // Setup environment + setenv("HOME", passwdUser->pw_dir, 1); + setenv("SHELL", shellPathStr, 1); + setenv("LOGNAME", passwdUser->pw_name, 1); + setenv("USER", passwdUser->pw_name, 1); + setenv("TERM", "unknown", 1); + if (chdir(passwdUser->pw_dir)) // Change to user's home dir + NSLog(@"Could not change to user's home directory."); + + execv(shellPathStr, newargv); // Start user's shell + + NSLog(@"Could not start X client process with errno = %i.", errno); + _exit(127); + } + + // In parent process: + close(fd[0]); // Close read end of pipe + close(outFD); // Close output file descriptor + + thisBundle = [NSBundle bundleForClass:[self class]]; + startXPath = [thisBundle pathForResource:@"startXClients" ofType:nil]; + if (!startXPath) { + NSLog(@"Could not find startXClients in application bundle!"); + return NO; + } + + // We will run the startXClients script with the path in single quotes + // in case there are problematic characters in the path. We still have + // to worry about there being single quotes in the path. So, replace + // all instances of the ' character in startXPath with '\''. + safeStartXPath = [NSMutableString stringWithString:startXPath]; + aRange = NSMakeRange(0, [safeStartXPath length]); + while (aRange.length) { + aRange = [safeStartXPath rangeOfString:@"'" options:0 range:aRange]; + if (!aRange.length) + break; + [safeStartXPath replaceCharactersInRange:aRange + withString:@"\'\\'\'"]; + aRange.location += 4; + aRange.length = [safeStartXPath length] - aRange.location; + } + + if ([Preferences addToPath]) { + commandStr = [NSString stringWithFormat:@"'%@' :%d %@\n", + safeStartXPath, [Preferences display], + [Preferences addToPathString]]; + } else { + commandStr = [NSString stringWithFormat:@"'%@' :%d\n", + safeStartXPath, [Preferences display]]; + } + + length = [commandStr cStringLength]; + if (write(fd[1], [commandStr cString], length) != length) { + NSLog(@"Write to X client process failed."); + return NO; + } + + // Close the pipe so that shell will terminate when xinit quits + close(fd[1]); + + return YES; +} + +// Run the X server thread +- (void)run +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + [serverLock lock]; + main(argcGlobal, argvGlobal, envpGlobal); + serverVisible = NO; + [pool release]; + [serverLock unlock]; + QuartzMessageMainThread(kQuartzServerDied); +} + +// Full screen mode was picked in the mode pick panel +- (IBAction)startFullScreen:(id)sender +{ + [Preferences setModeWindow:[startupModeButton intValue]]; + [Preferences saveToDisk]; + quartzRootless = FALSE; + [self startX]; +} + +// Rootless mode was picked in the mode pick panel +- (IBAction)startRootless:(id)sender +{ + [Preferences setModeWindow:[startupModeButton intValue]]; + [Preferences saveToDisk]; + quartzRootless = TRUE; + [self startX]; +} + +// Close the help splash screen and show the X server +- (IBAction)closeHelpAndShow:(id)sender +{ + if (sender) { + int helpVal = [startupHelpButton intValue]; + [Preferences setStartupHelp:helpVal]; + [Preferences saveToDisk]; + } + [helpWindow close]; + helpWindow = nil; + + serverVisible = YES; + [self sendShowHide:YES]; + [NSApp activateIgnoringOtherApps:YES]; +} + +// Show the X server when sent message from GUI +- (IBAction)showAction:(id)sender +{ + if (sendServerEvents) + [self sendShowHide:YES]; +} + +// Show or hide the X server or menu bar in rootless mode +- (void)toggle +{ + if (quartzRootless) { +#if 0 + // FIXME: Remove or add option to not dodge menubar + if (rootlessMenuBarVisible) + HideMenuBar(); + else + ShowMenuBar(); + rootlessMenuBarVisible = !rootlessMenuBarVisible; +#endif + } else { + if (serverVisible) + [self hide]; + else + [self show]; + } +} + +// Show the X server on screen +- (void)show +{ + if (!serverVisible && sendServerEvents) { + [self sendShowHide:YES]; + } +} + +// Hide the X server from the screen +- (void)hide +{ + if (serverVisible && sendServerEvents) { + [self sendShowHide:NO]; + } +} + +// Kill the X server thread +- (void)killServer +{ + NXEvent ev; + + if (serverVisible) + [self hide]; + + ev.type = NX_APPDEFINED; + ev.data.compound.subType = kXDarwinQuit; + [self sendNXEvent:&ev]; +} + +// Tell the X server to show or hide itself. +// This ignores the current X server visible state. +// +// In full screen mode, the order we do things is important and must be +// preserved between the threads. X drawing operations have to be performed +// in the X server thread. It appears that we have the additional +// constraint that we must hide and show the menu bar in the main thread. +// +// To show the X server: +// 1. Capture the displays. (Main thread) +// 2. Hide the menu bar. (Must be in main thread) +// 3. Send event to X server thread to redraw X screen. +// 4. Redraw the X screen. (Must be in X server thread) +// +// To hide the X server: +// 1. Send event to X server thread to stop drawing. +// 2. Stop drawing to the X screen. (Must be in X server thread) +// 3. Message main thread that drawing is stopped. +// 4. If main thread still wants X server hidden: +// a. Release the displays. (Main thread) +// b. Unhide the menu bar. (Must be in main thread) +// Otherwise we have already queued an event to start drawing again. +// +- (void)sendShowHide:(BOOL)show +{ + NXEvent ev; + + [self getNXMouse:&ev]; + ev.type = NX_APPDEFINED; + + if (show) { + if (!quartzRootless) { + QuartzFSCapture(); + HideMenuBar(); + } + ev.data.compound.subType = kXDarwinShow; + [self sendNXEvent:&ev]; + + // inform the X server of the current modifier state + ev.flags = [[NSApp currentEvent] modifierFlags]; + ev.data.compound.subType = kXDarwinUpdateModifiers; + [self sendNXEvent:&ev]; + + // put the pasteboard into the X cut buffer + [self readPasteboard]; + } else { + // put the X cut buffer on the pasteboard + [self writePasteboard]; + + ev.data.compound.subType = kXDarwinHide; + [self sendNXEvent:&ev]; + } + + serverVisible = show; +} + +// Tell the X server to read from the pasteboard into the X cut buffer +- (void)readPasteboard +{ + NXEvent ev; + + ev.type = NX_APPDEFINED; + ev.data.compound.subType = kXDarwinReadPasteboard; + [self sendNXEvent:&ev]; +} + +// Tell the X server to write the X cut buffer into the pasteboard +- (void)writePasteboard +{ + NXEvent ev; + + ev.type = NX_APPDEFINED; + ev.data.compound.subType = kXDarwinWritePasteboard; + [self sendNXEvent:&ev]; +} + +- (void)sendNXEvent:(NXEvent*)ev +{ + int bytesWritten; + + if (quartzRootless && + (ev->type == NSLeftMouseDown || ev->type == NSLeftMouseUp || + (ev->type == NSSystemDefined && ev->data.compound.subType == 7))) + { + // mouse button event - send mouseMoved to this position too + // X gets confused if it gets a click that isn't at the last + // reported mouse position. + NXEvent moveEvent = *ev; + moveEvent.type = NSMouseMoved; + [self sendNXEvent:&moveEvent]; + } + + bytesWritten = write(eventWriteFD, ev, sizeof(*ev)); + if (bytesWritten == sizeof(*ev)) + return; + NSLog(@"Bad write to event pipe."); + // FIXME: handle bad writes better? +} + +// Handle messages from the X server thread +- (void)handlePortMessage:(NSPortMessage *)portMessage +{ + unsigned msg = [portMessage msgid]; + + switch(msg) { + case kQuartzServerHidden: + // Make sure the X server wasn't queued to be shown again while + // the hide was pending. + if (!quartzRootless && !serverVisible) { + QuartzFSRelease(); + ShowMenuBar(); + } + + // FIXME: This hack is necessary (but not completely effective) + // since Mac OS X 10.0.2 + [NSCursor unhide]; + break; + + case kQuartzServerDied: + sendServerEvents = NO; + if (!appQuitting) { + [NSApp terminate:nil]; // quit if we aren't already + } + break; + + default: + NSLog(@"Unknown message from server thread."); + } +} + +// Quit the X server when the X client process finishes +- (void)clientProcessDone:(int)clientStatus +{ + if (WIFEXITED(clientStatus)) { + int exitStatus = WEXITSTATUS(clientStatus); + if (exitStatus != 0) + NSLog(@"X client process terminated with status %i.", exitStatus); + } else { + NSLog(@"X client process terminated abnormally."); + } + + if (!appQuitting) { + [NSApp terminate:nil]; // quit if we aren't already + } +} + +// Called when the user clicks the application icon, +// but not when Cmd-Tab is used. +// Rootless: Don't switch until applicationWillBecomeActive. +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication + hasVisibleWindows:(BOOL)flag +{ + if ([Preferences dockSwitch] && !quartzRootless) { + [self show]; + } + return NO; +} + +- (void)applicationWillResignActive:(NSNotification *)aNotification +{ + [self hide]; +} + +- (void)applicationWillBecomeActive:(NSNotification *)aNotification +{ + if (quartzRootless) + [self show]; +} + +@end + +// Send a message to the main thread, which calls handlePortMessage in +// response. Must only be called from the X server thread because +// NSPort is not thread safe. +void QuartzMessageMainThread(unsigned msg) +{ + [signalMessage setMsgid:msg]; + [signalMessage sendBeforeDate:[NSDate distantPast]]; +} + +// Handle SIGCHLD signals +static void childDone(int sig) +{ + int clientStatus; + + if (clientPID == 0) + return; + + // Make sure it was the client task that finished + if (waitpid(clientPID, &clientStatus, WNOHANG) == clientPID) { + if (WIFSTOPPED(clientStatus)) + return; + clientPID = 0; + [oneXServer clientProcessDone:clientStatus]; + } +} diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/XView.h b/xc/programs/Xserver/hw/darwin/quartz_1.3/XView.h new file mode 100644 index 000000000..14a8dc917 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/XView.h @@ -0,0 +1,50 @@ +/* + * NSView subclass for Mac OS X rootless X server + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/XView.h,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#import <Cocoa/Cocoa.h> + +#include <drivers/event_status_driver.h> +#include "fakeBoxRec.h" + +@interface XView : NSView +{ + char *mBits; + int mBytesPerRow; + int mBitsPerSample; + int mSamplesPerPixel; + int mBitsPerPixel; + int mDepth; + BOOL mShaped; +} + +- (id)initWithFrame:(NSRect)aRect; +- (void)dealloc; + +- (void)drawRect:(NSRect)aRect; +- (BOOL)isFlipped; +- (BOOL)acceptsFirstResponder; +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent; +- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent; + +- (void)mouseDown:(NSEvent *)anEvent; + +- (void)setFrameSize:(NSSize)newSize; + +- (void)allocBitsForSize:(NSSize)newSize; +- (char *)bits; +- (void)getBits:(char **)bits + rowBytes:(int *)rowBytes + depth:(int *)depth + bitsPerPixel:(int *)bpp; + +- (void)refreshRects:(fakeBoxRec *)rectList count:(int)count; +- (void)reshapeRects:(fakeBoxRec *)eraseRects count:(int)count; + +- (void)copyToScreen:(fakeBoxRec *)rectList count:(int)count + fromTemp:(BOOL)copyFromTemp; +- (void)copyToShapeBits:(fakeBoxRec *)rectList count:(int)count; +- (void)eraseFromShapeBits:(fakeBoxRec *)rectList count:(int)count; + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/XView.m b/xc/programs/Xserver/hw/darwin/quartz_1.3/XView.m new file mode 100644 index 000000000..56b8ecf97 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/XView.m @@ -0,0 +1,330 @@ +/* + * NSView subclass for Mac OS X rootless X server + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/XView.m,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#include <ApplicationServices/ApplicationServices.h> + +#import "XView.h" +#include "fakeBoxRec.h" + +static const void *infobytes(void *info) +{ + return info; +} + + +static unsigned long *shapeBits = NULL; +static int shapeWidth = 0; +static int shapeHeight = 0; + +static void reallocShapeBits(NSSize minSize) +{ + if (shapeWidth < minSize.width || shapeHeight < minSize.height) { + shapeWidth = minSize.width; + shapeHeight = minSize.height; + if (shapeBits) free(shapeBits); + shapeBits = (unsigned long *) malloc(4 * shapeWidth * shapeHeight); + } +} + + +@implementation XView + +- (id)initWithFrame:(NSRect)aRect +{ + self = [super initWithFrame:aRect]; + if (!self) return nil; + + mShaped = NO; + mBitsPerSample = 8; + mSamplesPerPixel = 3; + mDepth = mBitsPerSample * mSamplesPerPixel; + mBitsPerPixel = 32; + mBits = nil; + [self allocBitsForSize:aRect.size]; + + return self; +} + +- (void)dealloc +{ + if (mBits) free(mBits); + [super dealloc]; +} + +- (void)drawRect:(NSRect)aRect +{ + // Never draw here. +} + +- (BOOL)isFlipped +{ + return NO; +} + +- (BOOL)isOpaque +{ + return !mShaped; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent +{ + return YES; +} + +- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent +{ + return YES; +} + + +- (void)mouseDown:(NSEvent *)anEvent +{ + // Only X is allowed to restack windows. + [NSApp preventWindowOrdering]; + [[self nextResponder] mouseDown:anEvent]; +} + +- (void)mouseUp:(NSEvent *)anEvent +{ + // Bring app to front if necessary + // Don't bring app to front in mouseDown; mousedown-mouseup is too + // long and X gets what looks like a mouse drag. + if (! [NSApp isActive]) { + [NSApp activateIgnoringOtherApps:YES]; + [NSApp arrangeInFront:nil]; // fixme only bring some windows forward? + } + + [[self nextResponder] mouseDown:anEvent]; +} + + +// Reallocate bits. +// setFrame goes through here too. +- (void)setFrameSize:(NSSize)newSize +{ + [self allocBitsForSize:newSize]; + [super setFrameSize:newSize]; +} + +- (void)allocBitsForSize:(NSSize)newSize +{ + if (mBits) free(mBits); + mBytesPerRow = newSize.width * mBitsPerPixel / 8; + mBits = calloc(mBytesPerRow * newSize.height, 1); +} + +- (char *)bits +{ + return mBits; +} + +- (void)getBits:(char **)bits + rowBytes:(int *)rowBytes + depth:(int *)depth + bitsPerPixel:(int *)bpp +{ + *bits = mBits; + *rowBytes = mBytesPerRow; + *depth = mDepth; + *bpp = mBitsPerPixel; +} + +- (void)refreshRects:(fakeBoxRec *)rectList count:(int)count +{ + if (!mShaped) { + [self lockFocus]; + [self copyToScreen:rectList count:count fromTemp:NO]; + } else { + [self copyToShapeBits:rectList count:count]; + [self lockFocus]; + [self copyToScreen:rectList count:count fromTemp:YES]; + } + [[NSGraphicsContext currentContext] flushGraphics]; + [self unlockFocus]; +} + +// eraseRects are OUTSIDE the new shape +- (void)reshapeRects:(fakeBoxRec *)eraseRects count:(int)count +{ + fakeBoxRec bounds = {0, 0, [self frame].size.width, + [self frame].size.height}; + + if (count == 0 && !mShaped) { + [self refreshRects:&bounds count:1]; + } else { + // View is shaped, or used to be shaped. + // Shaped windows never become unshaped. + // (Mac OS X 10.0.4 does not allow transparent windows + // to become opaque.) + + mShaped = YES; + + // Magic. 10.0.4 and 10.1 both require the alpha channel to be + // cleared explicitly. 10.0.4 additionally requires the view to + // be unlocked between this and the drawing code below. + [self lockFocus]; + [[NSColor clearColor] set]; + NSRectFill([self frame]); + [self unlockFocus]; + + // copy everything from X11 to temp + // erase eraseRects from temp + // copy everything from temp to screen + [self lockFocus]; + [self copyToShapeBits:&bounds count:1]; + [self eraseFromShapeBits:eraseRects count:count]; + [self copyToScreen:&bounds count:1 fromTemp:YES]; + [[NSGraphicsContext currentContext] flushGraphics]; + [self unlockFocus]; + } +} + + +- (void)eraseFromShapeBits:(fakeBoxRec *)rectList count:(int)count +{ + unsigned long *dst = NULL; // don't assign yet + int dstWidth = 0; // don't assign yet + fakeBoxRec *r; + fakeBoxRec *end; + + assert(mBitsPerPixel == 32); + reallocShapeBits([self frame].size); + dst = shapeBits; + dstWidth = shapeWidth; + + for (r = rectList, end = rectList + count; r < end; r++) { + unsigned long *dstline = dst + dstWidth*r->y1 + r->x1; + int h = r->y2 - r->y1; + + while (h--) { + unsigned long *dstp = dstline; + int w = r->x2 - r->x1; + + while (w--) { + *dstp++ = 0x00000000; + } + dstline += dstWidth; + } + } +} + +// assumes X11 bits and temp bits are 32-bit +- (void)copyToShapeBits:(fakeBoxRec *)rectList count:(int)count +{ + unsigned long *src = (unsigned long *) mBits; + unsigned long *dst = NULL; // don't assign yet + int srcWidth = mBytesPerRow / 4; + int dstWidth = 0; // don't assign yet + fakeBoxRec *r; + fakeBoxRec *end; + + assert(mBitsPerPixel == 32); + reallocShapeBits([self frame].size); + dst = shapeBits; + dstWidth = shapeWidth; + + for (r = rectList, end = rectList + count; r < end; r++) { + unsigned long *srcline = src + srcWidth*r->y1 + r->x1; + unsigned long *dstline = dst + dstWidth*r->y1 + r->x1; + int h = r->y2 - r->y1; + + while (h--) { + unsigned long *srcp = srcline; + unsigned long *dstp = dstline; + int w = r->x2 - r->x1; + + while (w--) { + *dstp++ = *srcp++ | 0xff000000; + } + srcline += srcWidth; + dstline += dstWidth; + } + } +} + + +// Copy boxes to the screen from the per-window pixmaps where X draws. +// rectList is in local, X-flipped coordinates. +- (void)copyToScreen:(fakeBoxRec *)rectList count:(int)count + fromTemp:(BOOL)copyFromTemp +{ + unsigned char *offsetbits; + fakeBoxRec *r; + fakeBoxRec *end; + NSRect bounds; + char *srcBits; + int bytesPerRow; + int bitsPerPixel; + int bitsPerSample; + CGImageAlphaInfo alpha; + CGContextRef destCtx = (CGContextRef)[[NSGraphicsContext currentContext] + graphicsPort]; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + // fixme colorspace leaks? + const CGDataProviderDirectAccessCallbacks cb = { + infobytes, NULL, NULL, NULL + }; + + if (copyFromTemp) { + // shapeBits assumed to be 32-bit + srcBits = (char *)shapeBits; + bytesPerRow = 4 * shapeWidth; + bitsPerPixel = 32; + bitsPerSample = 8; + alpha = kCGImageAlphaPremultipliedFirst; // premultiplied ARGB + } else { + srcBits = mBits; + bytesPerRow = mBytesPerRow; + bitsPerPixel = mBitsPerPixel; + bitsPerSample = mBitsPerSample; + alpha = kCGImageAlphaNoneSkipFirst; // xRGB + } + + bounds = [self frame]; + bounds.origin.x = bounds.origin.y = 0; + + for (r = rectList, end = rectList + count; r < end; r++) { + NSRect nsr = {{r->x1, r->y1}, {r->x2-r->x1, r->y2-r->y1}}; + CGRect destRect; + CGDataProviderRef dataProviderRef; + CGImageRef imageRef; + + // Clip to window + // (bounds origin is (0,0) so it can be used in either flip) + // fixme is this necessary with pixmap-per-window? + nsr = NSIntersectionRect(nsr, bounds); + + // Disallow empty rects + if (nsr.size.width <= 0 || nsr.size.height <= 0) continue; + + offsetbits = srcBits + (int)(nsr.origin.y * bytesPerRow + + nsr.origin.x * bitsPerPixel/8); + + // Flip r to Cocoa-flipped + nsr.origin.y = bounds.size.height - nsr.origin.y - nsr.size.height; + destRect = CGRectMake(nsr.origin.x, nsr.origin.y, + nsr.size.width, nsr.size.height); + + dataProviderRef = CGDataProviderCreateDirectAccess(offsetbits, + destRect.size.height * bytesPerRow, &cb); + + imageRef = CGImageCreate(destRect.size.width, destRect.size.height, + bitsPerSample, bitsPerPixel, bytesPerRow, + colorSpace, alpha, dataProviderRef, NULL, + 1, kCGRenderingIntentDefault); + + CGContextDrawImage(destCtx, destRect, imageRef); + CGImageRelease(imageRef); + CGDataProviderRelease(dataProviderRef); + } +} + + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/XWindow.h b/xc/programs/Xserver/hw/darwin/quartz_1.3/XWindow.h new file mode 100644 index 000000000..4f7d1ec78 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/XWindow.h @@ -0,0 +1,36 @@ +/* + * NSWindow subclass for Mac OS X rootless X server + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/XWindow.h,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#import <Cocoa/Cocoa.h> +#import "XView.h" + +#include "fakeBoxRec.h" + +@interface XWindow : NSWindow +{ + XView *mView; +} + +- (id)initWithContentRect:(NSRect)aRect + isRoot:(BOOL)isRoot; +- (void)dealloc; + +- (char *)bits; +- (void)getBits:(char **)bits + rowBytes:(int *)rowBytes + depth:(int *)depth + bitsPerPixel:(int *)bpp; + +- (void)refreshRects:(fakeBoxRec *)rectList + count:(int)count; + +- (void)orderWindow:(NSWindowOrderingMode)place + relativeTo:(int)otherWindowNumber; + +- (void)sendEvent:(NSEvent *)anEvent; +- (BOOL)canBecomeMainWindow; +- (BOOL)canBecomeKeyWindow; + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/XWindow.m b/xc/programs/Xserver/hw/darwin/quartz_1.3/XWindow.m new file mode 100644 index 000000000..02d030819 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/XWindow.m @@ -0,0 +1,104 @@ +/* + * NSWindow subclass for Mac OS X rootless X server + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/XWindow.m,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#import "XWindow.h" + + +@implementation XWindow + +// XWindow MUST NOT autodisplay! Autodisplay can cause a deadlock. +// event thread - autodisplay: locks view hierarchy, then window +// X Server thread - window resize: locks window, then view hierarchy +// Deadlock occurs if each thread gets one lock and waits for the other. + +// XWindow MUST defer! Otherwise an assertion fails in +// NSViewHierarchyLock sometimes. + +- (id)initWithContentRect:(NSRect)aRect + isRoot:(BOOL)isRoot +{ + int style; + NSRect viewRect = {{0, 0}, {aRect.size.width, aRect.size.height}}; + style = NSBorderlessWindowMask; + + self = [super initWithContentRect: aRect + styleMask: style + backing: NSBackingStoreBuffered + defer: YES]; + if (! self) return NULL; + + [self setBackgroundColor:[NSColor clearColor]]; // erase transparent + [self setAlphaValue:1.0]; // draw opaque + [self setOpaque:YES]; // changed when window is shaped + + [self useOptimizedDrawing:YES]; // Has no overlapping sub-views + [self setAutodisplay:NO]; // MUST NOT autodisplay! See comment above + [self disableFlushWindow]; // We do all the flushing manually + [self setHasShadow: !isRoot]; // All windows have shadows except root + + // [self setAcceptsMouseMovedEvents:YES]; // MUST be AFTER orderFront? + + mView = [[XView alloc] initWithFrame: viewRect]; + [self setContentView:mView]; + [self setInitialFirstResponder:mView]; + + return self; +} + +- (void)dealloc +{ + [mView release]; + [super dealloc]; +} + +- (char *)bits +{ + return [mView bits]; +} + +- (void)getBits:(char **)bits + rowBytes:(int *)rowBytes + depth:(int *)depth + bitsPerPixel:(int *)bpp +{ + [mView getBits:bits rowBytes:rowBytes depth:depth bitsPerPixel:bpp]; +} + + +// rects are X-flip and LOCAL coords +- (void)refreshRects:(fakeBoxRec *)rectList count:(int)count; +{ + [mView refreshRects:rectList count:count]; +} + + +// Deferred windows don't handle mouse moved events very well. +- (void)orderWindow:(NSWindowOrderingMode)place + relativeTo:(int)otherWindowNumber +{ + [super orderWindow:place relativeTo:otherWindowNumber]; + [self setAcceptsMouseMovedEvents:YES]; +} + +- (void)sendEvent:(NSEvent *)anEvent +{ + [super sendEvent:anEvent]; + [self setAcceptsMouseMovedEvents:YES]; +} + +// XWindow may be frameless, and frameless windows default to +// NO key and NO main. +// update: we *don't* want main or key status after all +- (BOOL)canBecomeMainWindow +{ + return NO; +} + +- (BOOL)canBecomeKeyWindow +{ + return NO; +} + +@end diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootless.h b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootless.h new file mode 100644 index 000000000..716d8564a --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootless.h @@ -0,0 +1,127 @@ +/* + * External interface to generic rootless mode + * + * Greg Parker gparker@cs.stanford.edu March 3, 2001 + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootless.h,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#ifndef _ROOTLESS_H +#define _ROOTLESS_H + +#include "mi.h" +#include "gcstruct.h" + +// RootlessFrameRec +// Describes a single rootless window (aka frame). +// The rootless mode keeps track of window position, and the +// rootless implementation is responsible for the pixmap. +// Multiple screens: all coordinates are SCREEN-LOCAL, not global. + + +typedef struct RootlessFrameRec { + /* Data maintained by rootless mode */ + /* position and size, including window border, in screen coordinates */ + int x; + int y; + unsigned int w; + unsigned int h; + WindowPtr win; /* the top-level window drawn in this frame */ + int isRoot; /* TRUE if this is the root window */ + + /* Data maintained by rootless implementation */ + char *pixelData; + int depth; // color bits per pixel; depth <= bitsPerPixel + int bitsPerPixel; + int bytesPerRow; + + void *devPrivate; /* for caller's use */ +} RootlessFrameRec, *RootlessFramePtr; + + +// Create a new frame. +// pUpper is the window above the new frame, or NULL if the new +// frame will be on top. +// pFrame is completely initialized. devPrivate is NULL +// The pixmap must be valid when this is done. +typedef void (*RootlessCreateFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, RootlessFramePtr pUpper); + +// Destroy a frame. Caller must free any private data and the pixmap. +// All drawing is stopped and all updates are flushed before this is called. +typedef void (*RootlessDestroyFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame); + +// Move a frame on screen. +// The frame changes position and nothing else. +// pFrame and pFrame->win already contain the information about the +// new position. oldX and oldY are the old position. +// All updates are flushed before this is called. +// The pixmap may change during this function. +typedef void (*RootlessMoveFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, int oldX, int oldY); + +// Change frame ordering (aka stacking, layering) +// pFrame->win already has its new siblings. +// pOldNext is the window that was below this one, or NULL if this was +// at the bottom. +// pNewNext is the window that is now below this one, or NULL if this is +// now at the bottom. +typedef void (*RootlessRestackFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, + RootlessFramePtr pOldNext, RootlessFramePtr pNewNext); + +// Flush drawing updates to the screen. +// pDamage contains all changed pixels. +// pDamage is in frame-local coordinates. +// pDamage is clipped to the frame bounds and the frame shape. +typedef void (*RootlessUpdateRegionProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, RegionPtr pDamage); + +// Change the frame's shape. +// pNewShape is in frame-local coordinates. +// Everything outside pNewShape is no longer part of the frame. +// pNewShape is {0, 0, width, height} for a plain-shaped frame. +// fixme can the pixmap change here? +// fixme reimplement shape +typedef void (*RootlessReshapeFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, RegionPtr pNewShape); + +// Frame is about to resize. +// The frame has its new position and size already. +// postconditions: +// The pixmap MUST point to a pixmap with the new size. +// The pixmap data is undefined. +// The old pixmap may be destroyed here. +typedef void (*RootlessStartResizeFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY, unsigned int oldW, unsigned int oldH); + +// Frame is done resizing. +// Destroy the old pixmap if you haven't already. +typedef void (*RootlessFinishResizeFrameProc) + (ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY, unsigned int oldW, unsigned int oldH); + + +// The callback function list. +// Any of these may be NULL. +typedef struct RootlessFrameProcs { + RootlessCreateFrameProc CreateFrame; + RootlessDestroyFrameProc DestroyFrame; + + RootlessMoveFrameProc MoveFrame; + RootlessStartResizeFrameProc StartResizeFrame; + RootlessFinishResizeFrameProc FinishResizeFrame; + RootlessRestackFrameProc RestackFrame; + RootlessReshapeFrameProc ReshapeFrame; + + RootlessUpdateRegionProc UpdateRegion; + + // RootlessStartDrawingProc StartDrawing; + // RootlessStopDrawingProc StopDrawing; +} RootlessFrameProcs; + +// Initialize rootless mode on the given screen. +Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcs *procs); + +#endif /* _ROOTLESS_H */ diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAqua.h b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAqua.h new file mode 100644 index 000000000..b89a879e9 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAqua.h @@ -0,0 +1,15 @@ +/* + * Rootless setup for Aqua + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAqua.h,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#ifndef _ROOTLESSAQUA_H +#define _ROOTLESSAQUA_H + +Bool AquaAddScreen(int index, ScreenPtr pScreen); +Bool AquaSetupScreen(int index, ScreenPtr pScreen); +void AquaDisplayInit(void); + +#endif /* _ROOTLESSAQUA_H */ diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaGlue.c b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaGlue.c new file mode 100644 index 000000000..29cbd6e10 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaGlue.c @@ -0,0 +1,226 @@ +/* + * Generic rootless to Aqua specific glue code + * + * This code acts as a glue between the generic rootless X server code + * and the Aqua specific implementation, which includes definitions that + * conflict with stardard X types. + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaGlue.c,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#include "quartzCommon.h" +#include "darwin.h" +#include "rootlessAqua.h" +#include "rootlessAquaImp.h" +#include "rootless.h" + +#include "regionstr.h" +#include "scrnintstr.h" +#include "globals.h" // dixScreenOrigins[] + + +///////////////////////////////////////// +// Rootless mode callback glue + +static void +AquaGlueCreateFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + RootlessFramePtr pUpper) +{ + int sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + int sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + pFrame->devPrivate = AquaNewWindow(pUpper ? pUpper->devPrivate : NULL, + pFrame->x + sx, pFrame->y + sy, + pFrame->w, pFrame->h, + pFrame->isRoot); + AquaGetPixmap(pFrame->devPrivate, &pFrame->pixelData, + &pFrame->bytesPerRow, &pFrame->depth, + &pFrame->bitsPerPixel); +} + + +static void +AquaGlueDestroyFrame(ScreenPtr pScreen, RootlessFramePtr pFrame) +{ + AquaDestroyWindow(pFrame->devPrivate); +} + +static void +AquaGlueMoveFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY) +{ + int sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + int sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + AquaMoveWindow(pFrame->devPrivate, pFrame->x + sx, pFrame->y + sy); +} + + +static void +AquaGlueStartResizeFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY, + unsigned int oldW, unsigned int oldH) +{ + int sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + int sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + AquaStartResizeWindow(pFrame->devPrivate, + pFrame->x + sx, pFrame->y + sy, pFrame->w, pFrame->h); + AquaGetPixmap(pFrame->devPrivate, &pFrame->pixelData, + &pFrame->bytesPerRow, &pFrame->depth, + &pFrame->bitsPerPixel); +} + +static void +AquaGlueFinishResizeFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + int oldX, int oldY, + unsigned int oldW, unsigned int oldH) +{ + int sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + int sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + AquaFinishResizeWindow(pFrame->devPrivate, + pFrame->x + sx, pFrame->y + sy, + pFrame->w, pFrame->h); +} + + +static void +AquaGlueRestackFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + RootlessFramePtr pOldPrev, + RootlessFramePtr pNewPrev) +{ + AquaRestackWindow(pFrame->devPrivate, + pNewPrev ? pNewPrev->devPrivate : NULL); +} + +static void +AquaGlueReshapeFrame(ScreenPtr pScreen, RootlessFramePtr pFrame, + RegionPtr pNewShape) +{ + // Don't correct for dixScreenOrigins here. + // pNewShape is in window-local coordinates. + BoxRec shapeBox = {0, 0, pFrame->w, pFrame->h}; + if (pFrame->isRoot) return; // shouldn't happen; mi or dix covers this + + REGION_INVERSE(pScreen, pNewShape, pNewShape, &shapeBox); + AquaReshapeWindow(pFrame->devPrivate, + (fakeBoxRec *) REGION_RECTS(pNewShape), + REGION_NUM_RECTS(pNewShape)); +} + +static void +AquaGlueUpdateRegion(ScreenPtr pScreen, RootlessFramePtr pFrame, + RegionPtr pDamage) +{ + AquaUpdateRects(pFrame->devPrivate, + (fakeBoxRec *) REGION_RECTS(pDamage), + REGION_NUM_RECTS(pDamage)); +} + +#if 0 +static void +AquaGlueStartDrawing(ScreenPtr pScreen, RootlessFramePtr pFrame) +{ + AquaStartDrawing(pFrame->devPrivate, &pFrame->pixelData, + &pFrame->bytesPerRow, &pFrame->depth, + &pFrame->bitsPerPixel); +} + +static void +AquaGlueStopDrawing(ScreenPtr pScreen, RootlessFramePtr pFrame) +{ + AquaStopDrawing(pFrame->devPrivate); +} +#endif + +static RootlessFrameProcs aquaRootlessProcs = { + AquaGlueCreateFrame, + AquaGlueDestroyFrame, + AquaGlueMoveFrame, + AquaGlueStartResizeFrame, + AquaGlueFinishResizeFrame, + AquaGlueRestackFrame, + AquaGlueReshapeFrame, + AquaGlueUpdateRegion +}; + + +/////////////////////////////////////// +// Rootless mode initialization. +// Exported by rootlessAqua.h + +/* + * AquaDisplayInit + * Find all Aqua screens. + */ +void +AquaDisplayInit(void) +{ + darwinScreensFound = AquaDisplayCount(); +} + + +/* + * AquaAddScreen + * Init the framebuffer and record pixmap parameters for the screen. + */ +Bool +AquaAddScreen(int index, ScreenPtr pScreen) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + QuartzScreenPtr displayInfo = QUARTZ_PRIV(pScreen); + CGRect cgRect; + CGDisplayCount numDisplays; + CGDisplayCount allocatedDisplays = 0; + CGDirectDisplayID *displays = NULL; + CGDisplayErr cgErr; + + dfb->pixelInfo.pixelType = kIORGBDirectPixels; + AquaScreenInit(index, &dfb->x, &dfb->y, &dfb->width, &dfb->height, + &dfb->pitch, &dfb->pixelInfo.bitsPerComponent, + &dfb->pixelInfo.componentCount, &dfb->bitsPerPixel); + dfb->colorBitsPerPixel = dfb->pixelInfo.bitsPerComponent * + dfb->pixelInfo.componentCount; + + // No frame buffer - it's all in window pixmaps. + dfb->framebuffer = NULL; // malloc(dfb.pitch * dfb.height); + + // Get all CoreGraphics displays covered by this X11 display. + cgRect = CGRectMake(dfb->x, dfb->y, dfb->width, dfb->height); + do { + cgErr = CGGetDisplaysWithRect(cgRect, 0, NULL, &numDisplays); + if (cgErr) break; + allocatedDisplays = numDisplays; + displays = xrealloc(displays, + numDisplays * sizeof(CGDirectDisplayID)); + cgErr = CGGetDisplaysWithRect(cgRect, allocatedDisplays, displays, + &numDisplays); + if (cgErr != CGDisplayNoErr) break; + } while (numDisplays > allocatedDisplays); + + if (cgErr != CGDisplayNoErr || numDisplays == 0) { + ErrorF("Could not find CGDirectDisplayID(s) for X11 screen %d: %dx%d @ %d,%d.\n", + index, dfb->width, dfb->height, dfb->x, dfb->y); + return FALSE; + } + + // This X11 screen covers all CoreGraphics displays we just found. + // If there's more than one CG display, then video mirroring is on + // or PseudoramiX is on. + displayInfo->displayCount = allocatedDisplays; + displayInfo->displayIDs = displays; + + return TRUE; +} + +/* + * AquaSetupScreen + * Setup the screen for rootless access. + */ +Bool +AquaSetupScreen(int index, ScreenPtr pScreen) +{ + return RootlessInit(pScreen, &aquaRootlessProcs); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaImp.h b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaImp.h new file mode 100644 index 000000000..9ec56dca8 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaImp.h @@ -0,0 +1,38 @@ +/* + * Rootless implementation for Mac OS X Aqua environment + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaImp.h,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#ifndef _ROOTLESSAQUAIMP_H +#define _ROOTLESSAQUAIMP_H + +#include "fakeBoxRec.h" + +int AquaDisplayCount(); + +void AquaScreenInit(int index, int *x, int *y, int *width, int *height, + int *rowBytes, unsigned long *bps, unsigned long *spp, + int *bpp); + +void *AquaNewWindow(void *upperw, int x, int y, int w, int h, int isRoot); + +void AquaDestroyWindow(void *rw); + +void AquaMoveWindow(void *rw, int x, int y); + +void AquaStartResizeWindow(void *rw, int x, int y, int w, int h); + +void AquaFinishResizeWindow(void *rw, int x, int y, int w, int h); + +void AquaUpdateRects(void *rw, fakeBoxRec *rects, int count); + +void AquaRestackWindow(void *rw, void *lowerw); + +void AquaReshapeWindow(void *rw, fakeBoxRec *rects, int count); + +void AquaGetPixmap(void *rw, char **bits, + int *rowBytes, int *depth, int *bpp); + +#endif /* _ROOTLESSAQUAIMP_H */ diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaImp.m b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaImp.m new file mode 100644 index 000000000..b3d9ae374 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaImp.m @@ -0,0 +1,237 @@ +/* + * Rootless implementation for Mac OS X Aqua environment + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessAquaImp.m,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#include "rootlessAquaImp.h" +#include "XWindow.h" +#include "fakeBoxRec.h" +#include "quartzCommon.h" +#include "pseudoramiX.h" + +extern void ErrorF(const char *, ...); + +typedef struct { + XWindow *window; +} AquaWindowRec; + + +#define WINREC(rw) ((AquaWindowRec *)rw) + + +// Multihead note: When rootless mode uses PseudoramiX, the +// X server only sees one screen; only PseudoramiX itself knows +// about all of the screens. + +int AquaDisplayCount() +{ + aquaNumScreens = [[NSScreen screens] count]; + + if (noPseudoramiXExtension) { + return aquaNumScreens; + } else { + return 1; // only PseudoramiX knows about the rest + } +} + +void AquaScreenInit(int index, int *x, int *y, int *width, int *height, + int *rowBytes, unsigned long *bps, unsigned long *spp, + int *bpp) +{ + *bps = 8; + *spp = 3; + *bpp = 32; + + if (noPseudoramiXExtension) { + NSScreen *screen = [[NSScreen screens] objectAtIndex:index]; + NSRect frame = [screen frame]; + + // set x, y so (0,0) is top left of main screen + *x = NSMinX(frame); + *y = NSHeight([[NSScreen mainScreen] frame]) - NSHeight(frame) - + NSMinY(frame); + + *width = NSWidth(frame); + *height = NSHeight(frame); + *rowBytes = (*width) * (*bpp) / 8; + + // Shift the usable part of main screen down to avoid the menu bar. + if (NSEqualRects(frame, [[NSScreen mainScreen] frame])) { + *y += aquaMenuBarHeight; + *height -= aquaMenuBarHeight; + } + + } else { + int i; + NSRect unionRect = NSMakeRect(0, 0, 0, 0); + NSArray *screens = [NSScreen screens]; + + // Get the union of all screens (minus the menu bar on main screen) + for (i = 0; i < [screens count]; i++) { + NSScreen *screen = [screens objectAtIndex:i]; + NSRect frame = [screen frame]; + frame.origin.y = [[NSScreen mainScreen] frame].size.height - + frame.size.height - frame.origin.y; + if (NSEqualRects([screen frame], [[NSScreen mainScreen] frame])) { + frame.origin.y += aquaMenuBarHeight; + frame.size.height -= aquaMenuBarHeight; + } + unionRect = NSUnionRect(unionRect, frame); + } + + // Use unionRect as the screen size for the X server. + *x = unionRect.origin.x; + *y = unionRect.origin.y; + *width = unionRect.size.width; + *height = unionRect.size.height; + *rowBytes = (*width) * (*bpp) / 8; + + // Tell PseudoramiX about the real screens. + // InitOutput() will move the big screen to (0,0), + // so compensate for that here. + for (i = 0; i < [screens count]; i++) { + NSScreen *screen = [screens objectAtIndex:i]; + NSRect frame = [screen frame]; + int j; + + // Skip this screen if it's a mirrored copy of an earlier screen. + for (j = 0; j < i; j++) { + if (NSEqualRects(frame, [[screens objectAtIndex:j] frame])) { + ErrorF("PseudoramiX screen %d is a mirror of screen %d.\n", + i, j); + break; + } + } + if (j < i) continue; // this screen is a mirrored copy + + frame.origin.y = [[NSScreen mainScreen] frame].size.height - + frame.size.height - frame.origin.y; + + if (NSEqualRects([screen frame], [[NSScreen mainScreen] frame])) { + frame.origin.y += aquaMenuBarHeight; + frame.size.height -= aquaMenuBarHeight; + } + + ErrorF("PseudoramiX screen %d added: %dx%d @ (%d,%d).\n", i, + (int)frame.size.width, (int)frame.size.height, + (int)frame.origin.x, (int)frame.origin.y); + + frame.origin.x -= unionRect.origin.x; + frame.origin.y -= unionRect.origin.y; + + ErrorF("PseudoramiX screen %d placed at X11 coordinate (%d,%d).\n", + i, (int)frame.origin.x, (int)frame.origin.y); + + PseudoramiXAddScreen(frame.origin.x, frame.origin.y, + frame.size.width, frame.size.height); + } + } +} + +void *AquaNewWindow(void *upperw, int x, int y, int w, int h, int isRoot) +{ + AquaWindowRec *winRec = (AquaWindowRec *)malloc(sizeof(AquaWindowRec)); + NSRect frame = NSMakeRect(x, NSHeight([[NSScreen mainScreen] frame]) - + y - h, w, h); + + winRec->window = [[XWindow alloc] initWithContentRect:frame isRoot:isRoot]; + + if (upperw) { + AquaWindowRec *upperRec = WINREC(upperw); + int uppernum = [upperRec->window windowNumber]; + [winRec->window orderWindow:NSWindowBelow relativeTo:uppernum]; + } else { + [winRec->window orderFront:nil]; + } + + // fixme hide root for now + if (isRoot) [winRec->window orderOut:nil]; + + return winRec; +} + +void AquaDestroyWindow(void *rw) +{ + AquaWindowRec *winRec = WINREC(rw); + + [winRec->window release]; +} + +void AquaMoveWindow(void *rw, int x, int y) +{ + AquaWindowRec *winRec = WINREC(rw); + NSPoint topLeft = NSMakePoint(x, NSHeight([[NSScreen mainScreen] frame]) - + y); + + [winRec->window setFrameTopLeftPoint:topLeft]; +} + +void AquaStartResizeWindow(void *rw, int x, int y, int w, int h) +{ + AquaWindowRec *winRec = WINREC(rw); + NSRect frame = NSMakeRect(x, NSHeight([[NSScreen mainScreen] frame]) - + y - h, w, h); + + [winRec->window setFrame:frame display:NO]; +} + +void AquaFinishResizeWindow(void *rw, int x, int y, int w, int h) +{ + // refresh everything? fixme yes for testing + fakeBoxRec box = {0, 0, w, h}; + AquaWindowRec *winRec = WINREC(rw); + + [winRec->window refreshRects:&box count:1]; +} + +void AquaUpdateRects(void *rw, fakeBoxRec *rects, int count) +{ + AquaWindowRec *winRec = WINREC(rw); + + [winRec->window refreshRects:rects count:count]; +} + +// fixme is this upperw or lowerw? +void AquaRestackWindow(void *rw, void *upperw) +{ + AquaWindowRec *winRec = WINREC(rw); + + if (upperw) { + AquaWindowRec *upperRec = WINREC(upperw); + int uppernum = [upperRec->window windowNumber]; + [winRec->window orderWindow:NSWindowBelow relativeTo:uppernum]; + } else { + [winRec->window orderFront:nil]; + } + // [winRec->window setAcceptsMouseMovedEvents:YES]; + // fixme prefer to orderFront whenever possible - pass upperw, not lowerw +} + +// rects are the areas not part of the new shape +void AquaReshapeWindow(void *rw, fakeBoxRec *rects, int count) +{ + AquaWindowRec *winRec = WINREC(rw); + + // make transparent if window is now shaped + // transparent windows never go back to opaque + if (count > 0) { + [winRec->window setOpaque:NO]; + } + + [[winRec->window contentView] reshapeRects:rects count:count]; + + if (! [winRec->window isOpaque]) { + // force update of window shadow + [winRec->window setHasShadow:NO]; + [winRec->window setHasShadow:YES]; + } +} + +void AquaGetPixmap(void *rw, char **bits, + int *rowBytes, int *depth, int *bpp) +{ + AquaWindowRec *winRec = WINREC(rw); + + [winRec->window getBits:bits rowBytes:rowBytes depth:depth + bitsPerPixel:bpp]; +} diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessCommon.c b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessCommon.c new file mode 100644 index 000000000..9fb51f203 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessCommon.c @@ -0,0 +1,262 @@ +/* + * Common rootless definitions and code + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessCommon.c,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#include "rootlessCommon.h" + + +RegionRec rootlessHugeRoot = {{-32767, -32767, 32767, 32767}, NULL}; + + +// Returns the top-level parent of pWindow. +// The root is the top-level parent of itself, even though the root is +// not otherwise considered to be a top-level window. +WindowPtr TopLevelParent(WindowPtr pWindow) +{ + WindowPtr top = pWindow; + + if (IsRoot(pWindow)) return pWindow; // root is top-level parent of itself + while (top && ! IsTopLevel(top)) top = top->parent; + return top; +} + + +// Returns TRUE if this window is visible inside a frame +// (e.g. it is visible and has a top-level or root parent) +Bool IsFramedWindow(WindowPtr pWin) +{ + WindowPtr top; + + if (! pWin->realized) return FALSE; + top = TopLevelParent(pWin); + return (top && WINREC(top)); +} + + +// Move the given pixmap's base address to where pixel (0, 0) +// would be if the pixmap's actual data started at (x, y) +void SetPixmapBaseToScreen(PixmapPtr pix, int x, int y) +{ + pix->devPrivate.ptr = (char *)(pix->devPrivate.ptr) - + (pix->drawable.bitsPerPixel/8 * x + y*pix->devKind); +} + + +// Update pWindow's pixmap. +// This needs to be called every time a window moves relative to +// its top-level parent, or the parent's pixmap data is reallocated. +// Three cases: +// * window is top-level with no existing pixmap: make one +// * window is top-level with existing pixmap: update it in place +// * window is descendant of top-level: point to top-level's pixmap +void UpdatePixmap(WindowPtr pWindow) +{ + WindowPtr top = TopLevelParent(pWindow); + RootlessWindowRec *winRec; + ScreenPtr pScreen = pWindow->drawable.pScreen; + PixmapPtr pix; + + RL_DEBUG_MSG("update pixmap (win 0x%x)", pWindow); + + // Don't use IsFramedWindow(); window is unrealized during RealizeWindow(). + + if (! top) { + RL_DEBUG_MSG("no parent\n"); + return; + } + winRec = WINREC(top); + if (!winRec) { + RL_DEBUG_MSG("not framed\n"); + return; + } + + if (pWindow == top) { + // This is the top window. Update its pixmap. + if (winRec->pixmap == NULL) { + // Allocate a new pixmap. + pix = GetScratchPixmapHeader(pScreen, + winRec->frame.w, winRec->frame.h, + winRec->frame.depth, + winRec->frame.bitsPerPixel, + winRec->frame.bytesPerRow, + winRec->frame.pixelData); + SetPixmapBaseToScreen(pix, winRec->frame.x, winRec->frame.y); + pScreen->SetWindowPixmap(pWindow, pix); + winRec->pixmap = pix; + } else { + // Update existing pixmap. Update in place so we don't have to + // change the children's pixmaps. + pix = winRec->pixmap; + pScreen->ModifyPixmapHeader(pix, + winRec->frame.w, winRec->frame.h, + winRec->frame.depth, + winRec->frame.bitsPerPixel, + winRec->frame.bytesPerRow, + winRec->frame.pixelData); + SetPixmapBaseToScreen(pix, winRec->frame.x, winRec->frame.y); + } + } else { + // This is not the top window. Point to the parent's pixmap. + pix = winRec->pixmap; + pScreen->SetWindowPixmap(pWindow, pix); + } + + RL_DEBUG_MSG("done\n"); +} + + +#ifdef SHAPE + +// boundingShape = outside border (like borderClip) +// clipShape = inside border (like clipList) +// Both are in window-local coordinates +// We only care about boundingShape (fixme true?) + +// RootlessReallySetShape is used in several places other than SetShape. +// Most importantly, SetShape is often called on unmapped windows, so we +// have to wait until the window is mapped to reshape the frame. +static void RootlessReallySetShape(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec newShape; + + if (IsRoot(pWin)) return; + if (!IsTopLevel(pWin)) return; + if (!winRec) return; + + if (wBoundingShape(pWin)) { + // wBoundingShape is relative to *inner* origin of window. + // Translate by borderWidth to get the outside-relative position. + REGION_INIT(pScreen, &newShape, NullBox, 0); + REGION_COPY(pScreen, &newShape, wBoundingShape(pWin)); + REGION_TRANSLATE(pScreen, &newShape, pWin->borderWidth, + pWin->borderWidth); + } else { + newShape.data = NULL; + newShape.extents.x1 = 0; + newShape.extents.y1 = 0; + newShape.extents.x2 = winRec->frame.w; + newShape.extents.y2 = winRec->frame.h; + } + RL_DEBUG_MSG("reshaping..."); + RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ", + REGION_NUM_RECTS(&newShape), + newShape.extents.x1, newShape.extents.y1, + newShape.extents.x2, newShape.extents.y2); + CallFrameProc(pScreen, ReshapeFrame,(pScreen, &winRec->frame, &newShape)); + REGION_UNINIT(pScreen, &newShape); +} + +#endif // SHAPE + + +// pRegion is GLOBAL +void +RootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion) +{ + pWindow = TopLevelParent(pWindow); + if (!pWindow) { + RL_DEBUG_MSG("RootlessDamageRegion: window is not framed\n"); + } else if (!WINREC(pWindow)) { + RL_DEBUG_MSG("RootlessDamageRegion: top-level window not a frame\n"); + } else { + REGION_UNION((pWindow)->drawable.pScreen, &WINREC(pWindow)->damage, + &WINREC(pWindow)->damage, (pRegion)); + } +} + + +// pBox is GLOBAL +void +RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox) +{ + RegionRec region; + + REGION_INIT(pWindow->drawable.pScreen, ®ion, pBox, 1); + RootlessDamageRegion(pWindow, ®ion); +} + + +// (x, y, w, h) is in window-local coordinates. +void +RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h) +{ + BoxRec box; + RegionRec region; + + x += pWindow->drawable.x; + y += pWindow->drawable.y; + box.x1 = x; + box.x2 = x + w; + box.y1 = y; + box.y2 = y + h; + REGION_INIT(pWindow->drawable.pScreen, ®ion, &box, 1); + RootlessDamageRegion(pWindow, ®ion); +} + +#ifdef SHAPE + +void +RootlessDamageShape(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + + // We only care about the shape of top-level framed windows. + if (IsRoot(pWin)) return; + if (!IsTopLevel(pWin)) return; + if (!winRec) return; + + winRec->shapeDamage = TRUE; +} + +#endif // SHAPE + +void +RootlessRedisplay(WindowPtr pWindow) +{ + RootlessWindowRec *winRec = WINREC(pWindow); + ScreenPtr pScreen = pWindow->drawable.pScreen; + +#ifdef SHAPE + if (winRec->shapeDamage) { + // Reshape the window. This will also update the entire window. + RootlessReallySetShape(pWindow); + REGION_EMPTY(pScreen, &winRec->damage); + winRec->shapeDamage = FALSE; + } + else +#endif // SHAPE + if (REGION_NOTEMPTY(pScreen, &winRec->damage)) { + REGION_INTERSECT(pScreen, &winRec->damage, &winRec->damage, + &pWindow->borderSize); + + // move region to window local coords + REGION_TRANSLATE(pScreen, &winRec->damage, + -winRec->frame.x, -winRec->frame.y); + CallFrameProc(pScreen, UpdateRegion, + (pScreen, &winRec->frame, &winRec->damage)); + REGION_EMPTY(pScreen, &winRec->damage); + } +} + + +void +RootlessRedisplayScreen(ScreenPtr pScreen) +{ + WindowPtr root = WindowTable[pScreen->myNum]; + + if (root) { + WindowPtr win; + + RootlessRedisplay(root); + for (win = root->firstChild; win; win = win->nextSib) { + if (WINREC(win)) { + RootlessRedisplay(win); + } + } + } +} diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessCommon.h b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessCommon.h new file mode 100644 index 000000000..a34a28592 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessCommon.h @@ -0,0 +1,214 @@ +/* + * Common internal rootless definitions and code + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessCommon.h,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#ifndef _ROOTLESSCOMMON_H +#define _ROOTLESSCOMMON_H + +#include "rootless.h" + +#include "pixmapstr.h" +#include "windowstr.h" + +#ifdef RENDER +#include "picturestr.h" +#endif + + +// Debug output, or not. +#ifdef ROOTLESSDEBUG +#define RL_DEBUG_MSG ErrorF +#else +#define RL_DEBUG_MSG(a, ...) +#endif + + +// Global variables +extern int rootlessGCPrivateIndex; +extern int rootlessScreenPrivateIndex; +extern int rootlessWindowPrivateIndex; + + +// RootlessGCRec: private per-gc data +typedef struct { + GCFuncs *originalFuncs; + GCOps *originalOps; +} RootlessGCRec; + + +// RootlessWindowRec: private per-window data +typedef struct RootlessWindowRec { + RootlessFrameRec frame; + RegionRec damage; + unsigned int borderWidth; // needed for MoveWindow(VTOther) (%$#@!!!) + PixmapPtr pixmap; +#ifdef SHAPE + BOOL shapeDamage; // TRUE if shape has changed +#endif +} RootlessWindowRec; + + +// RootlessScreenRec: per-screen private data +typedef struct { + ScreenPtr pScreen; + RootlessFrameProcs frameProcs; + + CloseScreenProcPtr CloseScreen; + + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + MoveWindowProcPtr MoveWindow; + ResizeWindowProcPtr ResizeWindow; + RestackWindowProcPtr RestackWindow; + ChangeBorderWidthProcPtr ChangeBorderWidth; + PositionWindowProcPtr PositionWindow; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + + CreateGCProcPtr CreateGC; + PaintWindowBackgroundProcPtr PaintWindowBackground; + PaintWindowBorderProcPtr PaintWindowBorder; + CopyWindowProcPtr CopyWindow; + GetImageProcPtr GetImage; + + MarkOverlappedWindowsProcPtr MarkOverlappedWindows; + ValidateTreeProcPtr ValidateTree; + +#ifdef SHAPE + SetShapeProcPtr SetShape; +#endif + +#ifdef RENDER + CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; +#endif + +} RootlessScreenRec; + + +// "Definition of the Porting Layer for the X11 Sample Server" says +// unwrap and rewrap of screen functions is unnecessary, but +// screen->CreateGC changes after a call to cfbCreateGC. + +#define SCREEN_UNWRAP(screen, fn) \ + screen->fn = SCREENREC(screen)->fn; + +#define SCREEN_WRAP(screen, fn) \ + SCREENREC(screen)->fn = screen->fn; \ + screen->fn = Rootless##fn + + +// Accessors for screen and window privates + +#define SCREENREC(pScreen) \ + ((RootlessScreenRec*)(pScreen)->devPrivates[rootlessScreenPrivateIndex].ptr) + +#define WINREC(pWin) \ + ((RootlessWindowRec *)(pWin)->devPrivates[rootlessWindowPrivateIndex].ptr) + + +// Call a rootless implementation function. +// Many rootless implementation functions are allowed to be NULL. +#define CallFrameProc(pScreen, proc, params) \ + if (SCREENREC(pScreen)->frameProcs.proc) { \ + RL_DEBUG_MSG("calling frame proc " #proc " "); \ + SCREENREC(pScreen)->frameProcs.proc params; \ + } + + +// BoxRec manipulators +// Copied from shadowfb + +#define TRIM_BOX(box, pGC) { \ + BoxPtr extents = &pGC->pCompositeClip->extents;\ + if(box.x1 < extents->x1) box.x1 = extents->x1; \ + if(box.x2 > extents->x2) box.x2 = extents->x2; \ + if(box.y1 < extents->y1) box.y1 = extents->y1; \ + if(box.y2 > extents->y2) box.y2 = extents->y2; \ +} + +#define TRANSLATE_BOX(box, pDraw) { \ + box.x1 += pDraw->x; \ + box.x2 += pDraw->x; \ + box.y1 += pDraw->y; \ + box.y2 += pDraw->y; \ +} + +#define TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC) { \ + TRANSLATE_BOX(box, pDraw); \ + TRIM_BOX(box, pGC); \ +} + +#define BOX_NOT_EMPTY(box) \ + (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0)) + + +// HUGE_ROOT and NORMAL_ROOT +// We don't want to clip windows to the edge of the screen. +// HUGE_ROOT temporarily makes the root window really big. +// This is needed as a wrapper around any function that calls +// SetWinSize or SetBorderSize which clip a window against its +// parents, including the root. + +extern RegionRec rootlessHugeRoot; + +#define HUGE_ROOT(pWin) \ + { \ + WindowPtr w = pWin; \ + while (w->parent) w = w->parent; \ + saveRoot = w->winSize; \ + w->winSize = rootlessHugeRoot; \ + } + +#define NORMAL_ROOT(pWin) \ + { \ + WindowPtr w = pWin; \ + while (w->parent) w = w->parent; \ + w->winSize = saveRoot; \ + } + + +// Returns TRUE if this window is a top-level window (i.e. child of the root) +// The root is not a top-level window. +#define IsTopLevel(pWin) \ + ((pWin) && (pWin)->parent && !(pWin)->parent->parent) + +// Returns TRUE if this window is a root window +#define IsRoot(pWin) \ + ((pWin) == WindowTable[(pWin)->drawable.pScreen->myNum]) + +// Returns the top-level parent of pWindow. +// The root is the top-level parent of itself, even though the root is +// not otherwise considered to be a top-level window. +WindowPtr TopLevelParent(WindowPtr pWindow); + +// Returns TRUE if this window is visible inside a frame +// (e.g. it is visible and has a top-level or root parent) +Bool IsFramedWindow(WindowPtr pWin); + +// Move the given pixmap's base address to where pixel (0, 0) +// would be if the pixmap's actual data started at (x, y). +void SetPixmapBaseToScreen(PixmapPtr pix, int x, int y); + +// Update pWindow's pixmap. +// This needs to be called every time a window moves relative to +// its top-level parent, or the parent's pixmap data is reallocated. +void UpdatePixmap(WindowPtr pWindow); + +// Routines that cause regions to get redrawn. +// DamageRegion and DamageRect are in global coordinates. +// DamageBox is in window-local coordinates. +void RootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion); +void RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h); +void RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox); +void RootlessRedisplay(WindowPtr pWindow); +void RootlessRedisplayScreen(ScreenPtr pScreen); + +// Window reshape needs to be updated. The reshape also forces complete redraw. +void RootlessDamageShape(WindowPtr pWin); + +#endif // _ROOTLESSCOMMON_H diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessGC.c b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessGC.c new file mode 100644 index 000000000..6d8eb9318 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessGC.c @@ -0,0 +1,1170 @@ +/* + * Graphics Context support for Mac OS X rootless X server + * + * Greg Parker gparker@cs.stanford.edu + * + * February 2001 Created + * March 3, 2001 Restructured as generic rootless mode + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessGC.c,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "dixfontstr.h" +#include "mivalidate.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "rootlessCommon.h" + + +// GC functions +static void RootlessValidateGC(GCPtr pGC, unsigned long changes, + DrawablePtr pDrawable); +static void RootlessChangeGC(GCPtr pGC, unsigned long mask); +static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void RootlessDestroyGC(GCPtr pGC); +static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, + int nrects); +static void RootlessDestroyClip(GCPtr pGC); +static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc); + +GCFuncs rootlessGCFuncs = { + RootlessValidateGC, + RootlessChangeGC, + RootlessCopyGC, + RootlessDestroyGC, + RootlessChangeClip, + RootlessDestroyClip, + RootlessCopyClip, +}; + +// GC operations +static void RootlessFillSpans(); +static void RootlessSetSpans(); +static void RootlessPutImage(); +static RegionPtr RootlessCopyArea(); +static RegionPtr RootlessCopyPlane(); +static void RootlessPolyPoint(); +static void RootlessPolylines(); +static void RootlessPolySegment(); +static void RootlessPolyRectangle(); +static void RootlessPolyArc(); +static void RootlessFillPolygon(); +static void RootlessPolyFillRect(); +static void RootlessPolyFillArc(); +static int RootlessPolyText8(); +static int RootlessPolyText16(); +static void RootlessImageText8(); +static void RootlessImageText16(); +static void RootlessImageGlyphBlt(); +static void RootlessPolyGlyphBlt(); +static void RootlessPushPixels(); + +static GCOps rootlessGCOps = { + RootlessFillSpans, + RootlessSetSpans, + RootlessPutImage, + RootlessCopyArea, + RootlessCopyPlane, + RootlessPolyPoint, + RootlessPolylines, + RootlessPolySegment, + RootlessPolyRectangle, + RootlessPolyArc, + RootlessFillPolygon, + RootlessPolyFillRect, + RootlessPolyFillArc, + RootlessPolyText8, + RootlessPolyText16, + RootlessImageText8, + RootlessImageText16, + RootlessImageGlyphBlt, + RootlessPolyGlyphBlt, + RootlessPushPixels +#ifdef NEED_LINEHELPER + , NULL +#endif +}; + + +Bool +RootlessCreateGC(GCPtr pGC) +{ + RootlessGCRec *gcrec; + RootlessScreenRec *s; + Bool result; + + SCREEN_UNWRAP(pGC->pScreen, CreateGC); + s = (RootlessScreenRec *) pGC->pScreen-> + devPrivates[rootlessScreenPrivateIndex].ptr; + result = s->CreateGC(pGC); + gcrec = (RootlessGCRec *) pGC->devPrivates[rootlessGCPrivateIndex].ptr; + gcrec->originalOps = NULL; // don't wrap ops yet + gcrec->originalFuncs = pGC->funcs; + pGC->funcs = &rootlessGCFuncs; + + SCREEN_WRAP(pGC->pScreen, CreateGC); + return result; +} + + +// GC func wrapping +// ValidateGC wraps gcOps iff dest is viewable. All others just unwrap&call. + +// GCFUN_UNRAP assumes funcs have been wrapped and +// does not assume ops have been wrapped +#define GCFUNC_UNWRAP(pGC) \ + RootlessGCRec *gcrec = (RootlessGCRec *) \ + (pGC)->devPrivates[rootlessGCPrivateIndex].ptr; \ + (pGC)->funcs = gcrec->originalFuncs; \ + if (gcrec->originalOps) { \ + (pGC)->ops = gcrec->originalOps; \ +} + +#define GCFUNC_WRAP(pGC) \ + gcrec->originalFuncs = (pGC)->funcs; \ + (pGC)->funcs = &rootlessGCFuncs; \ + if (gcrec->originalOps) { \ + gcrec->originalOps = (pGC)->ops; \ + (pGC)->ops = &rootlessGCOps; \ +} + + +static void +RootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + GCFUNC_UNWRAP(pGC); + + pGC->funcs->ValidateGC(pGC, changes, pDrawable); + + gcrec->originalOps = NULL; + + if (pDrawable->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr) pDrawable; + + if (pWin->viewable) { + gcrec->originalOps = pGC->ops; + } + } + + GCFUNC_WRAP(pGC); +} + +static void RootlessChangeGC(GCPtr pGC, unsigned long mask) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->ChangeGC(pGC, mask); + GCFUNC_WRAP(pGC); +} + +static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) +{ + GCFUNC_UNWRAP(pGCDst); + pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst); + GCFUNC_WRAP(pGCDst); +} + +static void RootlessDestroyGC(GCPtr pGC) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->DestroyGC(pGC); + GCFUNC_WRAP(pGC); +} + +static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); + GCFUNC_WRAP(pGC); +} + +static void RootlessDestroyClip(GCPtr pGC) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->DestroyClip(pGC); + GCFUNC_WRAP(pGC); +} + +static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + GCFUNC_UNWRAP(pgcDst); + pgcDst->funcs->CopyClip(pgcDst, pgcSrc); + GCFUNC_WRAP(pgcDst); +} + + +// GC ops +// We can't use shadowfb because shadowfb assumes one pixmap +// and our root window is a special case. +// So much of this code is copied from shadowfb. + +// assumes both funcs and ops are wrapped +#define GCOP_UNWRAP(pGC) \ + RootlessGCRec *gcrec = (RootlessGCRec *) \ + (pGC)->devPrivates[rootlessGCPrivateIndex].ptr; \ + GCFuncs *saveFuncs = pGC->funcs; \ + (pGC)->funcs = gcrec->originalFuncs; \ + (pGC)->ops = gcrec->originalOps; + +#define GCOP_WRAP(pGC) \ + gcrec->originalOps = (pGC)->ops; \ + (pGC)->funcs = saveFuncs; \ + (pGC)->ops = &rootlessGCOps; + + +static void +RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, int sorted) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("fill spans start "); + + if (nInit <= 0) { + pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); + } else { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nInit; + BoxRec box; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while(--i) { + ppt++; + pwidthInit++; + if(box.x1 > ppt->x) + box.x1 = ppt->x; + if(box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if(box.y1 > ppt->y) + box.y1 = ppt->y; + else if(box.y2 < ppt->y) + box.y2 = ppt->y; + } + + box.y2++; + + pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill spans end\n"); +} + +static void +RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc, + DDXPointPtr pptInit, int *pwidthInit, + int nspans, int sorted) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("set spans start "); + + if (nspans <= 0) { + pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, + nspans, sorted); + } else { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nspans; + BoxRec box; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while(--i) { + ppt++; + pwidth++; + if(box.x1 > ppt->x) + box.x1 = ppt->x; + if(box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if(box.y1 > ppt->y) + box.y1 = ppt->y; + else if(box.y2 < ppt->y) + box.y2 = ppt->y; + } + + box.y2++; + + pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, + nspans, sorted); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + GCOP_WRAP(pGC); + RL_DEBUG_MSG("set spans end\n"); +} + +static void +RootlessPutImage(DrawablePtr dst, GCPtr pGC, + int depth, int x, int y, int w, int h, + int leftPad, int format, char *pBits) +{ + BoxRec box; + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("put image start "); + + pGC->ops->PutImage(dst, pGC, depth, x,y,w,h, leftPad, format, pBits); + + box.x1 = x + dst->x; + box.x2 = box.x1 + w; + box.y1 = y + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("put image end\n"); +} + +/* changed area is *dest* rect */ +/* If this code ever goes back go StartDrawing/StopDrawing: + * start and stop dst always + * start and stop src if src->type is DRAWABLE_WINDOW and src is framed + */ +static RegionPtr +RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC, + int srcx, int srcy, int w, int h, + int dstx, int dsty) +{ + RegionPtr result; + BoxRec box; + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst); + + result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty); + + box.x1 = dstx + dst->x; + box.x2 = box.x1 + w; + box.y1 = dsty + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("copy area end\n"); + return result; +} + +/* changed area is *dest* rect */ +/* If this code ever goes back go StartDrawing/StopDrawing: + * start and stop dst always + * start and stop src if src->type is DRAWABLE_WINDOW and src is framed + */ +static RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst, + GCPtr pGC, int srcx, int srcy, + int w, int h, int dstx, int dsty, + unsigned long plane) +{ + RegionPtr result; + BoxRec box; + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("copy plane start "); + + result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h, + dstx, dsty, plane); + + box.x1 = dstx + dst->x; + box.x2 = box.x1 + w; + box.y1 = dsty + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("copy plane end\n"); + return result; +} + +// Options for size of changed area: +// 0 = box per point +// 1 = big box around all points +// 2 = accumulate point in 20 pixel radius +#define ROOTLESS_CHANGED_AREA 1 +#define abs(a) ((a) > 0 ? (a) : -(a)) + +/* changed area is box around all points */ +static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("polypoint start "); + + pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit); + + if (npt > 0) { +#if ROOTLESS_CHANGED_AREA==0 + // box per point + BoxRec box; + + while (npt) { + box.x1 = pptInit->x; + box.y1 = pptInit->y; + box.x2 = box.x1 + 1; + box.y2 = box.y1 + 1; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + npt--; + pptInit++; + } + +#elif ROOTLESS_CHANGED_AREA==1 + // one big box + BoxRec box; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + while(--npt) { + pptInit++; + if(box.x1 > pptInit->x) + box.x1 = pptInit->x; + else if(box.x2 < pptInit->x) + box.x2 = pptInit->x; + if(box.y1 > pptInit->y) + box.y1 = pptInit->y; + else if(box.y2 < pptInit->y) + box.y2 = pptInit->y; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + +#elif ROOTLESS_CHANGED_AREA==2 + // clever(?) method: accumulate point in 20-pixel radius + BoxRec box; + int firstx, firsty; + + box.x2 = box.x1 = firstx = pptInit->x; + box.y2 = box.y1 = firsty = pptInit->y; + while(--npt) { + pptInit++; + if (abs(pptInit->x - firstx) > 20 || + abs(pptInit->y - firsty) > 20) { + box.x2++; + box.y2++; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + box.x2 = box.x1 = firstx = pptInit->x; + box.y2 = box.y1 = firsty = pptInit->y; + } else { + if (box.x1 > pptInit->x) box.x1 = pptInit->x; + else if (box.x2 < pptInit->x) box.x2 = pptInit->x; + if (box.y1 > pptInit->y) box.y1 = pptInit->y; + else if (box.y2 < pptInit->y) box.y2 = pptInit->y; + } + } + box.x2++; + box.y2++; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); +#endif /* ROOTLESS_CHANGED_AREA */ + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polypoint end\n"); +} + +#undef ROOTLESS_CHANGED_AREA + +/* changed area is box around each line */ +static void RootlessPolylines(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("poly lines start "); + + pGC->ops->Polylines(dst, pGC, mode, npt, pptInit); + + if (npt > 0) { + BoxRec box; + int extra = pGC->lineWidth >> 1; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + + if(npt > 1) { + if(pGC->joinStyle == JoinMiter) + extra = 6 * pGC->lineWidth; + else if(pGC->capStyle == CapProjecting) + extra = pGC->lineWidth; + } + + if(mode == CoordModePrevious) { + int x = box.x1; + int y = box.y1; + + while(--npt) { + pptInit++; + x += pptInit->x; + y += pptInit->y; + if(box.x1 > x) + box.x1 = x; + else if(box.x2 < x) + box.x2 = x; + if(box.y1 > y) + box.y1 = y; + else if(box.y2 < y) + box.y2 = y; + } + } else { + while(--npt) { + pptInit++; + if(box.x1 > pptInit->x) + box.x1 = pptInit->x; + else if(box.x2 < pptInit->x) + box.x2 = pptInit->x; + if(box.y1 > pptInit->y) + box.y1 = pptInit->y; + else if(box.y2 < pptInit->y) + box.y2 = pptInit->y; + } + } + + box.x2++; + box.y2++; + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly lines end\n"); +} + +/* changed area is box around each line segment */ +static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC, + int nseg, xSegment *pSeg) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("poly segment start (win 0x%x)", dst); + + pGC->ops->PolySegment(dst, pGC, nseg, pSeg); + + if (nseg > 0) { + BoxRec box; + int extra = pGC->lineWidth; + + if(pGC->capStyle != CapProjecting) + extra >>= 1; + + if(pSeg->x2 > pSeg->x1) { + box.x1 = pSeg->x1; + box.x2 = pSeg->x2; + } else { + box.x2 = pSeg->x1; + box.x1 = pSeg->x2; + } + + if(pSeg->y2 > pSeg->y1) { + box.y1 = pSeg->y1; + box.y2 = pSeg->y2; + } else { + box.y2 = pSeg->y1; + box.y1 = pSeg->y2; + } + + while(--nseg) { + pSeg++; + if(pSeg->x2 > pSeg->x1) { + if(pSeg->x1 < box.x1) box.x1 = pSeg->x1; + if(pSeg->x2 > box.x2) box.x2 = pSeg->x2; + } else { + if(pSeg->x2 < box.x1) box.x1 = pSeg->x2; + if(pSeg->x1 > box.x2) box.x2 = pSeg->x1; + } + if(pSeg->y2 > pSeg->y1) { + if(pSeg->y1 < box.y1) box.y1 = pSeg->y1; + if(pSeg->y2 > box.y2) box.y2 = pSeg->y2; + } else { + if(pSeg->y2 < box.y1) box.y1 = pSeg->y2; + if(pSeg->y1 > box.y2) box.y2 = pSeg->y1; + } + } + + box.x2++; + box.y2++; + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly segment end\n"); +} + +/* changed area is box around each line (not entire rects) */ +static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC, + int nRects, xRectangle *pRects) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("poly rectangle start "); + + pGC->ops->PolyRectangle(dst, pGC, nRects, pRects); + + if (nRects > 0) { + BoxRec box; + int offset1, offset2, offset3; + + offset2 = pGC->lineWidth; + if(!offset2) offset2 = 1; + offset1 = offset2 >> 1; + offset3 = offset2 - offset1; + + while(nRects--) { + box.x1 = pRects->x - offset1; + box.y1 = pRects->y - offset1; + box.x2 = box.x1 + pRects->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x + pRects->width - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + pRects->height - offset1; + box.x2 = box.x1 + pRects->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + pRects++; + } + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly rectangle end\n"); +} + + +/* changed area is box around each arc (assumes all arcs are 360 degrees) */ +static void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("poly arc start "); + + pGC->ops->PolyArc(dst, pGC, narcs, parcs); + + if (narcs > 0) { + int extra = pGC->lineWidth >> 1; + BoxRec box; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while(--narcs) { + parcs++; + if(box.x1 > parcs->x) + box.x1 = parcs->x; + if(box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if(box.y1 > parcs->y) + box.y1 = parcs->y; + if(box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + if(extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly arc end\n"); +} + + +/* changed area is box around each poly */ +static void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, + int shape, int mode, int count, + DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("fill poly start "); + + if (count <= 2) { + pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); + } else { + DDXPointPtr ppt = pptInit; + int i = count; + BoxRec box; + + box.x2 = box.x1 = ppt->x; + box.y2 = box.y1 = ppt->y; + + if(mode != CoordModeOrigin) { + int x = box.x1; + int y = box.y1; + + while(--i) { + ppt++; + x += ppt->x; + y += ppt->y; + if(box.x1 > x) + box.x1 = x; + else if(box.x2 < x) + box.x2 = x; + if(box.y1 > y) + box.y1 = y; + else if(box.y2 < y) + box.y2 = y; + } + } else { + while(--i) { + ppt++; + if(box.x1 > ppt->x) + box.x1 = ppt->x; + else if(box.x2 < ppt->x) + box.x2 = ppt->x; + if(box.y1 > ppt->y) + box.y1 = ppt->y; + else if(box.y2 < ppt->y) + box.y2 = ppt->y; + } + } + + box.x2++; + box.y2++; + + pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill poly end\n"); +} + +/* changed area is the rects */ +static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, + int nRectsInit, xRectangle *pRectsInit) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("fill rect start (win 0x%x)", dst); + + if (nRectsInit <= 0) { + pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); + } else { + BoxRec box; + xRectangle *pRects = pRectsInit; + int nRects = nRectsInit; + + box.x1 = pRects->x; + box.x2 = box.x1 + pRects->width; + box.y1 = pRects->y; + box.y2 = box.y1 + pRects->height; + + while(--nRects) { + pRects++; + if(box.x1 > pRects->x) + box.x1 = pRects->x; + if(box.x2 < (pRects->x + pRects->width)) + box.x2 = pRects->x + pRects->width; + if(box.y1 > pRects->y) + box.y1 = pRects->y; + if(box.y2 < (pRects->y + pRects->height)) + box.y2 = pRects->y + pRects->height; + } + + /* cfb messes with the pRectsInit so we have to do our + calculations first */ + + pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill rect end\n"); +} + + +/* changed area is box around each arc (assuming arcs are all 360 degrees) */ +static void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, + int narcs, xArc *parcs) +{ + GCOP_UNWRAP(pGC); + + RL_DEBUG_MSG("fill arc start "); + + pGC->ops->PolyFillArc(dst, pGC, narcs, parcs); + + if (narcs > 0) { + BoxRec box; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while(--narcs) { + parcs++; + if(box.x1 > parcs->x) + box.x1 = parcs->x; + if(box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if(box.y1 > parcs->y) + box.y1 = parcs->y; + if(box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill arc end"); +} + + +static void RootlessImageText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("imagetext8 start "); + + pGC->ops->ImageText8(dst, pGC, x, y, count, chars); + + if (count > 0) { + int top, bot, Min, Max; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if(Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if(Max < 0) Max = 0; + + /* ugh */ + box.x1 = dst->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imagetext8 end\n"); +} + +static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) +{ + int width; // the result, sorta + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("polytext8 start "); + + width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars); + width -= x; + + if(width > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if(count > 1) { + if(width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polytext8 end\n"); + return (width + x); +} + +static void RootlessImageText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("imagetext16 start "); + + pGC->ops->ImageText16(dst, pGC, x, y, count, chars); + + if (count > 0) { + int top, bot, Min, Max; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if(Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if(Max < 0) Max = 0; + + /* ugh */ + box.x1 = dst->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imagetext16 end\n"); +} + +static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) +{ + int width; // the result, sorta + + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("polytext16 start "); + + width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars); + width -= x; + + if (width > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if(count > 1) { + if(width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polytext16 end\n"); + return width + x; +} + +static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer unused) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("imageglyph start "); + + pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyph, ppci, unused); + + if (nglyph > 0) { + int top, bot, width = 0; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + box.x1 = ppci[0]->metrics.leftSideBearing; + if(box.x1 > 0) box.x1 = 0; + box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing - + ppci[nglyph - 1]->metrics.characterWidth; + if(box.x2 < 0) box.x2 = 0; + + box.x2 += dst->x + x; + box.x1 += dst->x + x; + + while(nglyph--) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if(width > 0) + box.x2 += width; + else + box.x1 += width; + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imageglyph end\n"); +} + +static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + GCOP_UNWRAP(pGC); + RL_DEBUG_MSG("polyglyph start "); + + pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase); + + if (nglyph > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing; + box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing; + + if(nglyph > 1) { + int width = 0; + + while(--nglyph) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if(width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polyglyph end\n"); +} + + +/* changed area is in dest */ +static void +RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst, + int dx, int dy, int xOrg, int yOrg) +{ + BoxRec box; + GCOP_UNWRAP(pGC); + + pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg); + + box.x1 = xOrg + dst->x; + box.x2 = box.x1 + dx; + box.y1 = yOrg + dst->y; + box.y2 = box.y1 + dy; + + TRIM_BOX(box, pGC); + if(BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("push pixels end\n"); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessScreen.c b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessScreen.c new file mode 100644 index 000000000..c864e118a --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessScreen.c @@ -0,0 +1,426 @@ +/* + * Screen routines for Mac OS X rootless X server + * + * Greg Parker gparker@cs.stanford.edu + * + * February 2001 Created + * March 3, 2001 Restructured as generic rootless mode + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessScreen.c,v 1.2 2002/10/16 21:13:33 dawes Exp $ */ + + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "propertyst.h" +#include "mivalidate.h" +#include "picturestr.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "rootlessCommon.h" +#include "rootlessWindow.h" + +extern int +rootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild, VTKind kind); +extern Bool +RootlessCreateGC(GCPtr pGC); + +// Initialize globals +int rootlessGCPrivateIndex = -1; +int rootlessScreenPrivateIndex = -1; +int rootlessWindowPrivateIndex = -1; + + +static Bool +RootlessCloseScreen(int i, ScreenPtr pScreen) +{ + RootlessScreenRec *s; + + s = SCREENREC(pScreen); + + // fixme unwrap everything that was wrapped? + pScreen->CloseScreen = s->CloseScreen; + + xfree(s); + return pScreen->CloseScreen(i, pScreen); +} + + +static void +RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planeMask, char *pdstLine) +{ + ScreenPtr pScreen = pDrawable->pScreen; + SCREEN_UNWRAP(pScreen, GetImage); + + if (pDrawable->type == DRAWABLE_WINDOW) { + /* Many apps use GetImage to sync with the visible frame buffer */ + // fixme entire screen or just window or all screens? + RootlessRedisplayScreen(pScreen); + } + + pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); + + SCREEN_WRAP(pScreen, GetImage); +} + + +#ifdef RENDER + +static void +RootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + WindowPtr dstWin; + + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pDst->pDrawable : NULL; + + // SCREEN_UNWRAP(ps, Composite); + ps->Composite = SCREENREC(pScreen)->Composite; + + ps->Composite(op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + if (dstWin && IsFramedWindow(dstWin)) { + RootlessDamageRect(dstWin, xDst, yDst, width, height); + } + + ps->Composite = RootlessComposite; + // SCREEN_WRAP(ps, Composite); +} + + +static void +RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int nlist, GlyphListPtr list, GlyphPtr *glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + int x, y; + int n; + GlyphPtr glyph; + WindowPtr dstWin; + + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pDst->pDrawable : NULL; + + //SCREEN_UNWRAP(ps, Glyphs); + ps->Glyphs = SCREENREC(pScreen)->Glyphs; + ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); + ps->Glyphs = RootlessGlyphs; + //SCREEN_WRAP(ps, Glyphs); + + if (dstWin && IsFramedWindow(dstWin)) { + x = xSrc; + y = ySrc; + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) { + glyph = *glyphs++; + RootlessDamageRect(dstWin, + x - glyph->info.x, y - glyph->info.y, + glyph->info.width, glyph->info.height); + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + } +} + +#endif // RENDER + + +// RootlessValidateTree +// ValidateTree is modified in two ways: +// * top-level windows don't clip each other +// * windows aren't clipped against root. +// These only matter when validating from the root. +static int +RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + int result; + RegionRec saveRoot; + ScreenPtr pScreen = pParent->drawable.pScreen; + + SCREEN_UNWRAP(pScreen, ValidateTree); + RL_DEBUG_MSG("VALIDATETREE start "); + + // Use our custom version to validate from root + if (IsRoot(pParent)) { + RL_DEBUG_MSG("custom "); + result = rootlessMiValidateTree(pParent, pChild, kind); + } else { + HUGE_ROOT(pParent); + result = pScreen->ValidateTree(pParent, pChild, kind); + NORMAL_ROOT(pParent); + } + + SCREEN_WRAP(pScreen, ValidateTree); + RL_DEBUG_MSG("VALIDATETREE end\n"); + + return result; +} + + +// RootlessMarkOverlappedWindows +// MarkOverlappedWindows is modified to ignore overlapping +// top-level windows. +static Bool +RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst, + WindowPtr *ppLayerWin) +{ + RegionRec saveRoot; + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + SCREEN_UNWRAP(pScreen, MarkOverlappedWindows); + RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start "); + + HUGE_ROOT(pWin); + if (IsRoot(pWin)) { + // root - mark nothing + RL_DEBUG_MSG("is root not marking "); + result = FALSE; + } + else if (! IsTopLevel(pWin)) { + // not top-level window - mark normally + result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin); + } + else { + //top-level window - mark children ONLY - NO overlaps with sibs (?) + // This code copied from miMarkOverlappedWindows() + + register WindowPtr pChild; + Bool anyMarked = FALSE; + void (* MarkWindow)() = pScreen->MarkWindow; + + RL_DEBUG_MSG("is top level! "); + /* single layered systems are easy */ + if (ppLayerWin) *ppLayerWin = pWin; + + if (pWin == pFirst) { + /* Blindly mark pWin and all of its inferiors. This is a slight + * overkill if there are mapped windows that outside pWin's border, + * but it's better than wasting time on RectIn checks. + */ + pChild = pWin; + while (1) { + if (pChild->viewable) { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + (* MarkWindow)(pChild); + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } + anyMarked = TRUE; + pFirst = pFirst->nextSib; + } + if (anyMarked) + (* MarkWindow)(pWin->parent); + result = anyMarked; + } + NORMAL_ROOT(pWin); + SCREEN_WRAP(pScreen, MarkOverlappedWindows); + RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n"); + return result; +} + + +static void +RootlessPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what) +{ + int oldBackgroundState = 0; + PixUnion oldBackground; + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREEN_UNWRAP(pScreen, PaintWindowBackground); + RL_DEBUG_MSG("paintwindowbackground start (win 0x%x) ", pWin); + if (IsFramedWindow(pWin)) { + if (IsRoot(pWin)) { + // set root background to magic transparent color + oldBackgroundState = pWin->backgroundState; + oldBackground = pWin->background; + pWin->backgroundState = BackgroundPixel; + pWin->background.pixel = 0x00fffffe; + } + } + + pScreen->PaintWindowBackground(pWin, pRegion, what); + + if (IsFramedWindow(pWin)) { + RootlessDamageRegion(pWin, pRegion); + if (IsRoot(pWin)) { + pWin->backgroundState = oldBackgroundState; + pWin->background = oldBackground; + } + } + SCREEN_WRAP(pScreen, PaintWindowBackground); + RL_DEBUG_MSG("paintwindowbackground end\n"); +} + + +static void +RootlessPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what) +{ + SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder); + RL_DEBUG_MSG("paintwindowborder start (win 0x%x) ", pWin); + pWin->drawable.pScreen->PaintWindowBorder(pWin, pRegion, what); + if (IsFramedWindow(pWin)) { + RootlessDamageRegion(pWin, pRegion); + } + SCREEN_WRAP(pWin->drawable.pScreen, PaintWindowBorder); + RL_DEBUG_MSG("paintwindowborder end\n"); +} + + +// Flush drawing before blocking on select(). +static void +RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask) +{ + RootlessRedisplayScreen((ScreenPtr) pbdata); +} + + +static void +RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask) +{ + // nothing here +} + + +static Bool +RootlessAllocatePrivates(ScreenPtr pScreen) +{ + RootlessScreenRec *s; + static unsigned long rootlessGeneration = 0; + + if (rootlessGeneration != serverGeneration) { + rootlessScreenPrivateIndex = AllocateScreenPrivateIndex(); + if (rootlessScreenPrivateIndex == -1) return FALSE; + rootlessGCPrivateIndex = AllocateGCPrivateIndex(); + if (rootlessGCPrivateIndex == -1) return FALSE; + rootlessWindowPrivateIndex = AllocateWindowPrivateIndex(); + if (rootlessWindowPrivateIndex == -1) return FALSE; + rootlessGeneration = serverGeneration; + } + + // no allocation needed for screen privates + if (!AllocateGCPrivate(pScreen, rootlessGCPrivateIndex, + sizeof(RootlessGCRec))) + return FALSE; + if (!AllocateWindowPrivate(pScreen, rootlessWindowPrivateIndex, 0)) + return FALSE; + + s = xalloc(sizeof(RootlessScreenRec)); + if (! s) return FALSE; + SCREENREC(pScreen) = s; + + return TRUE; +} + + +static void +RootlessWrap(ScreenPtr pScreen) +{ + RootlessScreenRec *s = (RootlessScreenRec*) + pScreen->devPrivates[rootlessScreenPrivateIndex].ptr; + +#define WRAP(a) \ + if (pScreen->a) { \ + s->a = pScreen->a; \ + } else { \ + RL_DEBUG_MSG("null screen fn " #a "\n"); \ + s->a = NULL; \ + } \ + pScreen->a = Rootless##a + + WRAP(CloseScreen); + WRAP(CreateGC); + WRAP(PaintWindowBackground); + WRAP(PaintWindowBorder); + WRAP(CopyWindow); + WRAP(GetImage); + WRAP(CreateWindow); + WRAP(DestroyWindow); + WRAP(RealizeWindow); + WRAP(UnrealizeWindow); + WRAP(MoveWindow); + WRAP(PositionWindow); + WRAP(ResizeWindow); + WRAP(RestackWindow); + WRAP(ChangeBorderWidth); + WRAP(MarkOverlappedWindows); + WRAP(ValidateTree); + WRAP(ChangeWindowAttributes); + +#ifdef SHAPE + WRAP(SetShape); +#endif + +#ifdef RENDER + { + // Composite and Glyphs don't use normal screen wrapping + PictureScreenPtr ps = GetPictureScreen(pScreen); + s->Composite = ps->Composite; + ps->Composite = RootlessComposite; + s->Glyphs = ps->Glyphs; + ps->Glyphs = RootlessGlyphs; + } +#endif + + // WRAP(ClearToBackground); fixme put this back? useful for shaped wins? + // WRAP(RestoreAreas); fixme put this back? + +#undef WRAP +} + + +/* + * RootlessInit + * Rootless wraps lots of stuff and needs a bunch of devPrivates. + */ +Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcs *procs) +{ + RootlessScreenRec *s; + + if (! RootlessAllocatePrivates(pScreen)) return FALSE; + s = (RootlessScreenRec*) + pScreen->devPrivates[rootlessScreenPrivateIndex].ptr; + + s->pScreen = pScreen; + s->frameProcs = *procs; + + RootlessWrap(pScreen); + + if (!RegisterBlockAndWakeupHandlers (RootlessBlockHandler, + RootlessWakeupHandler, + (pointer) pScreen)) + { + return FALSE; + } + + return TRUE; +} diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessValTree.c b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessValTree.c new file mode 100644 index 000000000..abcb152c7 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessValTree.c @@ -0,0 +1,744 @@ +/* + * Calculate window clip lists for rootless mode + * + * This file is very closely based on mivaltree.c. + */ + /* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessValTree.c,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +/* + * mivaltree.c -- + * Functions for recalculating window clip lists. Main function + * is miValidateTree. + * + +Copyright 1987, 1988, 1989, 1998 The Open Group + +All Rights Reserved. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + * + * Copyright 1987, 1988, 1989 by + * Digital Equipment Corporation, Maynard, Massachusetts, + * + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + ******************************************************************/ + +/* The panoramix components contained the following notice */ +/**************************************************************** +* * +* Copyright (c) Digital Equipment Corporation, 1991, 1997 * +* * +* All Rights Reserved. Unpublished rights reserved under * +* the copyright laws of the United States. * +* * +* The software contained on this media is proprietary to * +* and embodies the confidential technology of Digital * +* Equipment Corporation. Possession, use, duplication or * +* dissemination of the software and media is authorized only * +* pursuant to a valid written license from Digital Equipment * +* Corporation. * +* * +* RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure * +* by the U.S. Government is subject to restrictions as set * +* forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, * +* or in FAR 52.227-19, as applicable. * +* * +*****************************************************************/ + + /* + * Aug '86: Susan Angebranndt -- original code + * July '87: Adam de Boor -- substantially modified and commented + * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible. + * In particular, much improved code for window mapping and + * circulating. + * Bob Scheifler -- avoid miComputeClips for unmapped windows, + * valdata changes + */ +#include "X.h" +#include "scrnintstr.h" +#include "validate.h" +#include "windowstr.h" +#include "mi.h" +#include "regionstr.h" +#include "mivalidate.h" + +#include "globals.h" + +#ifdef SHAPE +/* + * Compute the visibility of a shaped window + */ +int +rootlessShapedWindowIn (pScreen, universe, bounding, rect, x, y) + ScreenPtr pScreen; + RegionPtr universe, bounding; + BoxPtr rect; + register int x, y; +{ + BoxRec box; + register BoxPtr boundBox; + int nbox; + Bool someIn, someOut; + register int t, x1, y1, x2, y2; + + nbox = REGION_NUM_RECTS (bounding); + boundBox = REGION_RECTS (bounding); + someIn = someOut = FALSE; + x1 = rect->x1; + y1 = rect->y1; + x2 = rect->x2; + y2 = rect->y2; + while (nbox--) + { + if ((t = boundBox->x1 + x) < x1) + t = x1; + box.x1 = t; + if ((t = boundBox->y1 + y) < y1) + t = y1; + box.y1 = t; + if ((t = boundBox->x2 + x) > x2) + t = x2; + box.x2 = t; + if ((t = boundBox->y2 + y) > y2) + t = y2; + box.y2 = t; + if (box.x1 > box.x2) + box.x2 = box.x1; + if (box.y1 > box.y2) + box.y2 = box.y1; + switch (RECT_IN_REGION(pScreen, universe, &box)) + { + case rgnIN: + if (someOut) + return rgnPART; + someIn = TRUE; + break; + case rgnOUT: + if (someIn) + return rgnPART; + someOut = TRUE; + break; + default: + return rgnPART; + } + boundBox++; + } + if (someIn) + return rgnIN; + return rgnOUT; +} +#endif + +#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ + HasBorder(w) && \ + (w)->backgroundState == ParentRelative) + + +/* + *----------------------------------------------------------------------- + * miComputeClips -- + * Recompute the clipList, borderClip, exposed and borderExposed + * regions for pParent and its children. Only viewable windows are + * taken into account. + * + * Results: + * None. + * + * Side Effects: + * clipList, borderClip, exposed and borderExposed are altered. + * A VisibilityNotify event may be generated on the parent window. + * + *----------------------------------------------------------------------- + */ +static void +rootlessComputeClips (pParent, pScreen, universe, kind, exposed) + register WindowPtr pParent; + register ScreenPtr pScreen; + register RegionPtr universe; + VTKind kind; + RegionPtr exposed; /* for intermediate calculations */ +{ + int dx, + dy; + RegionRec childUniverse; + register WindowPtr pChild; + int oldVis, newVis; + BoxRec borderSize; + RegionRec childUnion; + Bool overlap; + RegionPtr borderVisible; + Bool resized; + /* + * Figure out the new visibility of this window. + * The extent of the universe should be the same as the extent of + * the borderSize region. If the window is unobscured, this rectangle + * will be completely inside the universe (the universe will cover it + * completely). If the window is completely obscured, none of the + * universe will cover the rectangle. + */ + borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); + borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); + dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent); + if (dx > 32767) + dx = 32767; + borderSize.x2 = dx; + dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent); + if (dy > 32767) + dy = 32767; + borderSize.y2 = dy; + + oldVis = pParent->visibility; + switch (RECT_IN_REGION( pScreen, universe, &borderSize)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnPART: + newVis = VisibilityPartiallyObscured; +#ifdef SHAPE + { + RegionPtr pBounding; + + if ((pBounding = wBoundingShape (pParent))) + { + switch (rootlessShapedWindowIn (pScreen, universe, + pBounding, &borderSize, + pParent->drawable.x, + pParent->drawable.y)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnOUT: + newVis = VisibilityFullyObscured; + break; + } + } + } +#endif + break; + default: + newVis = VisibilityFullyObscured; + break; + } + + pParent->visibility = newVis; + if (oldVis != newVis && + ((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask)) + SendVisibilityNotify(pParent); + + dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x; + dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y; + + /* + * avoid computations when dealing with simple operations + */ + + switch (kind) { + case VTMap: + case VTStack: + case VTUnmap: + break; + case VTMove: + if ((oldVis == newVis) && + ((oldVis == VisibilityFullyObscured) || + (oldVis == VisibilityUnobscured))) + { + pChild = pParent; + while (1) + { + if (pChild->viewable) + { + if (pChild->visibility != VisibilityFullyObscured) + { + REGION_TRANSLATE( pScreen, &pChild->borderClip, + dx, dy); + REGION_TRANSLATE( pScreen, &pChild->clipList, + dx, dy); + pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pChild, dx, dy); + + } + if (pChild->valdata) + { + REGION_INIT(pScreen, + &pChild->valdata->after.borderExposed, + NullBox, 0); + if (HasParentRelativeBorder(pChild)) + { + REGION_SUBTRACT(pScreen, + &pChild->valdata->after.borderExposed, + &pChild->borderClip, + &pChild->winSize); + } + REGION_INIT( pScreen, &pChild->valdata->after.exposed, + NullBox, 0); + } + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pParent)) + pChild = pChild->parent; + if (pChild == pParent) + break; + pChild = pChild->nextSib; + } + return; + } + /* fall through */ + default: + /* + * To calculate exposures correctly, we have to translate the old + * borderClip and clipList regions to the window's new location so there + * is a correspondence between pieces of the new and old clipping regions. + */ + if (dx || dy) + { + /* + * We translate the old clipList because that will be exposed or copied + * if gravity is right. + */ + REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy); + } + break; + case VTBroken: + REGION_EMPTY (pScreen, &pParent->borderClip); + REGION_EMPTY (pScreen, &pParent->clipList); + break; + } + + borderVisible = pParent->valdata->before.borderVisible; + resized = pParent->valdata->before.resized; + REGION_INIT( pScreen, &pParent->valdata->after.borderExposed, NullBox, 0); + REGION_INIT( pScreen, &pParent->valdata->after.exposed, NullBox, 0); + + /* + * Since the borderClip must not be clipped by the children, we do + * the border exposure first... + * + * 'universe' is the window's borderClip. To figure the exposures, remove + * the area that used to be exposed from the new. + * This leaves a region of pieces that weren't exposed before. + */ + + if (HasBorder (pParent)) + { + if (borderVisible) + { + /* + * when the border changes shape, the old visible portions + * of the border will be saved by DIX in borderVisible -- + * use that region and destroy it + */ + REGION_SUBTRACT( pScreen, exposed, universe, borderVisible); + REGION_DESTROY( pScreen, borderVisible); + } + else + { + REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip); + } + if (HasParentRelativeBorder(pParent) && (dx || dy)) { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed, + universe, + &pParent->winSize); + } else { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed, + exposed, &pParent->winSize); + } + + REGION_COPY( pScreen, &pParent->borderClip, universe); + + /* + * To get the right clipList for the parent, and to make doubly sure + * that no child overlaps the parent's border, we remove the parent's + * border from the universe before proceeding. + */ + + REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize); + } + else + REGION_COPY( pScreen, &pParent->borderClip, universe); + + if ((pChild = pParent->firstChild) && pParent->mapped) + { + REGION_INIT(pScreen, &childUniverse, NullBox, 0); + REGION_INIT(pScreen, &childUnion, NullBox, 0); + if ((pChild->drawable.y < pParent->lastChild->drawable.y) || + ((pChild->drawable.y == pParent->lastChild->drawable.y) && + (pChild->drawable.x < pParent->lastChild->drawable.x))) + { + for (; pChild; pChild = pChild->nextSib) + { + if (pChild->viewable) + REGION_APPEND( pScreen, &childUnion, &pChild->borderSize); + } + } + else + { + for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) + { + if (pChild->viewable) + REGION_APPEND( pScreen, &childUnion, &pChild->borderSize); + } + } + REGION_VALIDATE( pScreen, &childUnion, &overlap); + + for (pChild = pParent->firstChild; + pChild; + pChild = pChild->nextSib) + { + if (pChild->viewable) { + /* + * If the child is viewable, we want to remove its extents + * from the current universe, but we only re-clip it if + * it's been marked. + */ + if (pChild->valdata) { + /* + * Figure out the new universe from the child's + * perspective and recurse. + */ + REGION_INTERSECT( pScreen, &childUniverse, + universe, + &pChild->borderSize); + rootlessComputeClips (pChild, pScreen, &childUniverse, + kind, exposed); + } + /* + * Once the child has been processed, we remove its extents + * from the current universe, thus denying its space to any + * other sibling. + */ + if (overlap) + REGION_SUBTRACT( pScreen, universe, universe, + &pChild->borderSize); + } + } + if (!overlap) + REGION_SUBTRACT( pScreen, universe, universe, &childUnion); + REGION_UNINIT( pScreen, &childUnion); + REGION_UNINIT( pScreen, &childUniverse); + } /* if any children */ + + /* + * 'universe' now contains the new clipList for the parent window. + * + * To figure the exposure of the window we subtract the old clip from the + * new, just as for the border. + */ + + if (oldVis == VisibilityFullyObscured || + oldVis == VisibilityNotViewable) + { + REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe); + } + else if (newVis != VisibilityFullyObscured && + newVis != VisibilityNotViewable) + { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed, + universe, &pParent->clipList); + } + + /* + * One last thing: backing storage. We have to try to save what parts of + * the window are about to be obscured. We can just subtract the universe + * from the old clipList and get the areas that were in the old but aren't + * in the new and, hence, are about to be obscured. + */ + if (pParent->backStorage && !resized) + { + REGION_SUBTRACT( pScreen, exposed, &pParent->clipList, universe); + (* pScreen->SaveDoomedAreas)(pParent, exposed, dx, dy); + } + + /* HACK ALERT - copying contents of regions, instead of regions */ + { + RegionRec tmp; + + tmp = pParent->clipList; + pParent->clipList = *universe; + *universe = tmp; + } + +#ifdef NOTDEF + REGION_COPY( pScreen, &pParent->clipList, universe); +#endif + + pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pParent, dx, dy); +} + +static void +rootlessTreeObscured(pParent) + register WindowPtr pParent; +{ + register WindowPtr pChild; + register int oldVis; + + pChild = pParent; + while (1) + { + if (pChild->viewable) + { + oldVis = pChild->visibility; + if (oldVis != (pChild->visibility = VisibilityFullyObscured) && + ((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask)) + SendVisibilityNotify(pChild); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pParent)) + pChild = pChild->parent; + if (pChild == pParent) + break; + pChild = pChild->nextSib; + } +} + +/* + *----------------------------------------------------------------------- + * miValidateTree -- + * Recomputes the clip list for pParent and all its inferiors. + * + * Results: + * Always returns 1. + * + * Side Effects: + * The clipList, borderClip, exposed, and borderExposed regions for + * each marked window are altered. + * + * Notes: + * This routine assumes that all affected windows have been marked + * (valdata created) and their winSize and borderSize regions + * adjusted to correspond to their new positions. The borderClip and + * clipList regions should not have been touched. + * + * The top-most level is treated differently from all lower levels + * because pParent is unchanged. For the top level, we merge the + * regions taken up by the marked children back into the clipList + * for pParent, thus forming a region from which the marked children + * can claim their areas. For lower levels, where the old clipList + * and borderClip are invalid, we can't do this and have to do the + * extra operations done in miComputeClips, but this is much faster + * e.g. when only one child has moved... + * + *----------------------------------------------------------------------- + */ +/* + Quartz version: used for validate from root in rootless mode. + We need to make sure top-level windows don't clip each other, + and that top-level windows aren't clipped to the root window. +*/ +/*ARGSUSED*/ +// fixme this is ugly +// Xprint/ValTree.c doesn't work, but maybe that method can? +int +rootlessMiValidateTree (pRoot, pChild, kind) + WindowPtr pRoot; /* Parent to validate */ + WindowPtr pChild; /* First child of pRoot that was + * affected */ + VTKind kind; /* What kind of configuration caused call */ +{ + RegionRec totalClip; /* Total clipping region available to + * the marked children. pRoot's clipList + * merged with the borderClips of all + * the marked children. */ + RegionRec childClip; /* The new borderClip for the current + * child */ + RegionRec childUnion; /* the space covered by borderSize for + * all marked children */ + RegionRec exposed; /* For intermediate calculations */ + register ScreenPtr pScreen; + register WindowPtr pWin; + Bool overlap; + int viewvals; + Bool forward; + + pScreen = pRoot->drawable.pScreen; + if (pChild == NullWindow) + pChild = pRoot->firstChild; + + REGION_INIT(pScreen, &childClip, NullBox, 0); + REGION_INIT(pScreen, &exposed, NullBox, 0); + + /* + * compute the area of the parent window occupied + * by the marked children + the parent itself. This + * is the area which can be divied up among the marked + * children in their new configuration. + */ + REGION_INIT(pScreen, &totalClip, NullBox, 0); + viewvals = 0; + if (REGION_BROKEN (pScreen, &pRoot->clipList) && + !REGION_BROKEN (pScreen, &pRoot->borderClip)) + { + kind = VTBroken; + /* + * When rebuilding clip lists after out of memory, + * assume everything is busted. + */ + forward = TRUE; + REGION_COPY (pScreen, &totalClip, &pRoot->borderClip); + REGION_INTERSECT (pScreen, &totalClip, &totalClip, &pRoot->winSize); + + for (pWin = pRoot->firstChild; pWin != pChild; pWin = pWin->nextSib) + { + if (pWin->viewable) + REGION_SUBTRACT (pScreen, &totalClip, &totalClip, &pWin->borderSize); + } + for (pWin = pChild; pWin; pWin = pWin->nextSib) + if (pWin->valdata && pWin->viewable) + viewvals++; + + REGION_EMPTY (pScreen, &pRoot->clipList); + ErrorF("ValidateTree: BUSTED!\n"); + } + else + { + if ((pChild->drawable.y < pRoot->lastChild->drawable.y) || + ((pChild->drawable.y == pRoot->lastChild->drawable.y) && + (pChild->drawable.x < pRoot->lastChild->drawable.x))) + { + forward = TRUE; + for (pWin = pChild; pWin; pWin = pWin->nextSib) + { + if (pWin->valdata) + { + REGION_APPEND( pScreen, &totalClip, &pWin->borderClip); + if (pWin->viewable) + viewvals++; + } + } + } + else + { + forward = FALSE; + pWin = pRoot->lastChild; + while (1) + { + if (pWin->valdata) + { + REGION_APPEND( pScreen, &totalClip, &pWin->borderClip); + if (pWin->viewable) + viewvals++; + } + if (pWin == pChild) + break; + pWin = pWin->prevSib; + } + } + REGION_VALIDATE( pScreen, &totalClip, &overlap); + } + + + // calculate childUnion so we can subtract it from totalClip later + REGION_INIT(pScreen, &childUnion, NullBox, 0); + if (kind != VTStack) { + if (forward) + { + for (pWin = pChild; pWin; pWin = pWin->nextSib) + if (pWin->valdata && pWin->viewable) + REGION_APPEND( pScreen, &childUnion, + &pWin->borderSize); + } + else + { + pWin = pRoot->lastChild; + while (1) + { + if (pWin->valdata && pWin->viewable) + REGION_APPEND( pScreen, &childUnion, + &pWin->borderSize); + if (pWin == pChild) + break; + pWin = pWin->prevSib; + } + } + REGION_VALIDATE(pScreen, &childUnion, &overlap); + } + + + /* + * Now go through the children of the root and figure their new + * borderClips from the totalClip, passing that off to miComputeClips + * to handle recursively. Once that's done, we remove the child + * from the totalClip to clip any siblings below it. + */ + + for (pWin = pChild; + pWin != NullWindow; + pWin = pWin->nextSib) + { + if (pWin->viewable) { + if (pWin->valdata) { + REGION_COPY( pScreen, &childClip, &pWin->borderSize); + rootlessComputeClips (pWin, pScreen, &childClip, kind, &exposed); + } else if (pWin->visibility == VisibilityNotViewable) { + rootlessTreeObscured(pWin); + } + } else { + if (pWin->valdata) { + REGION_EMPTY( pScreen, &pWin->clipList); + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pWin, 0, 0); + REGION_EMPTY( pScreen, &pWin->borderClip); + pWin->valdata = (ValidatePtr)NULL; + } + } + } + + REGION_UNINIT( pScreen, &childClip); + + // REGION_SUBTRACT(pScreen, &totalClip, &totalClip, &childUnion); + REGION_UNINIT(pScreen, &childUnion); + + REGION_INIT( pScreen, &pRoot->valdata->after.exposed, NullBox, 0); + REGION_INIT( pScreen, &pRoot->valdata->after.borderExposed, NullBox, 0); + + + REGION_UNINIT( pScreen, &totalClip); + REGION_UNINIT( pScreen, &exposed); + //if (pScreen->ClipNotify) + //(*pScreen->ClipNotify) (pRoot, 0, 0); + return (1); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessWindow.c b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessWindow.c new file mode 100644 index 000000000..15bdc4563 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessWindow.c @@ -0,0 +1,674 @@ +/* + * Rootless window management + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessWindow.c,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#include "rootlessCommon.h" +#include "rootlessWindow.h" + +#include "fb.h" + + +// RootlessCreateWindow +// For now, don't create a frame until the window is realized. +// Do reset the window size so it's not clipped by the root window. +Bool +RootlessCreateWindow(WindowPtr pWin) +{ + Bool result; + RegionRec saveRoot; + + WINREC(pWin) = NULL; + SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow); + if (!IsRoot(pWin)) { + // win/border size set by DIX, not by wrapped CreateWindow, so + // correct it here. + // Don't HUGE_ROOT when pWin is the root! + HUGE_ROOT(pWin); + SetWinSize(pWin); + SetBorderSize(pWin); + } + result = pWin->drawable.pScreen->CreateWindow(pWin); + if (pWin->parent) { + NORMAL_ROOT(pWin); + } + SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow); + return result; +} + + +// RootlessDestroyWindow +// For now, all window destruction takes place in UnrealizeWindow +Bool +RootlessDestroyWindow(WindowPtr pWin) +{ + Bool result; + + SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow); + result = pWin->drawable.pScreen->DestroyWindow(pWin); + SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow); + return result; +} + + +#ifdef SHAPE + +// RootlessSetShape +// Shape is usually set before the window is mapped, but (for now) we +// don't keep track of frames before they're mapped. So we just record +// that the shape needs to updated later. +void +RootlessSetShape(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + RootlessDamageShape(pWin); + SCREEN_UNWRAP(pScreen, SetShape); + pScreen->SetShape(pWin); + SCREEN_WRAP(pScreen, SetShape); +} + +#endif // SHAPE + + +// Disallow ParentRelative background on top-level windows +// because the root window doesn't really have the right background +// and cfb will try to draw on the root instead of on the window. +// fixme what about fb? +// fixme implement ParentRelative with real transparency? +// ParentRelative prevention is also in RealizeWindow() +Bool +RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask) +{ + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("change window attributes start "); + + SCREEN_UNWRAP(pScreen, ChangeWindowAttributes); + result = pScreen->ChangeWindowAttributes(pWin, vmask); + SCREEN_WRAP(pScreen, ChangeWindowAttributes); + + if (WINREC(pWin)) { + // disallow ParentRelative background state + if (pWin->backgroundState == ParentRelative) { + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + } + } + + RL_DEBUG_MSG("change window attributes end\n"); + return result; +} + + +// Update the frame position now. +// (x, y) are *inside* position! +// After this, mi and fb are expecting the pixmap to be at the new location. +Bool +RootlessPositionWindow(WindowPtr pWin, int x, int y) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + Bool result; + + RL_DEBUG_MSG("positionwindow start\n"); + if (winRec) { + winRec->frame.x = x - pWin->borderWidth; + winRec->frame.y = y - pWin->borderWidth; + } + + UpdatePixmap(pWin); + + SCREEN_UNWRAP(pScreen, PositionWindow); + result = pScreen->PositionWindow(pWin, x, y); + SCREEN_WRAP(pScreen, PositionWindow); + + RL_DEBUG_MSG("positionwindow end\n"); + return result; +} + + +// RootlessRealizeWindow +// The frame is created here and not in CreateWindow. +// fixme change this? probably not - would be faster, but eat more memory +Bool +RootlessRealizeWindow(WindowPtr pWin) +{ + Bool result = FALSE; + RegionRec saveRoot; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("realizewindow start "); + + if (IsTopLevel(pWin) || IsRoot(pWin)) { + DrawablePtr d = &pWin->drawable; + RootlessWindowRec *winRec = xalloc(sizeof(RootlessWindowRec)); + + if (! winRec) goto windowcreatebad; + + winRec->frame.isRoot = (pWin == WindowTable[pScreen->myNum]); + winRec->frame.x = d->x - pWin->borderWidth; + winRec->frame.y = d->y - pWin->borderWidth; + winRec->frame.w = d->width + 2*pWin->borderWidth; + winRec->frame.h = d->height + 2*pWin->borderWidth; + winRec->frame.win = pWin; + winRec->frame.devPrivate = NULL; + + REGION_INIT(pScreen, &winRec->damage, NullBox, 0); + winRec->borderWidth = pWin->borderWidth; + + winRec->pixmap = NULL; + // UpdatePixmap() called below + + WINREC(pWin) = winRec; + + RL_DEBUG_MSG("creating frame "); + CallFrameProc(pScreen, CreateFrame, + (pScreen, &WINREC(pWin)->frame, + pWin->prevSib ? &WINREC(pWin->prevSib)->frame : NULL)); + + // fixme implement ParentRelative with transparency? + // need non-interfering fb first + // Disallow ParentRelative background state + // This might have been set before the window was mapped + if (pWin->backgroundState == ParentRelative) { + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + } + +#ifdef SHAPE + // Shape is usually set before the window is mapped, but + // (for now) we don't keep track of frames before they're mapped. + winRec->shapeDamage = TRUE; +#endif + } + + UpdatePixmap(pWin); + + if (!IsRoot(pWin)) HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, RealizeWindow); + result = pScreen->RealizeWindow(pWin); + SCREEN_WRAP(pScreen, RealizeWindow); + if (!IsRoot(pWin)) NORMAL_ROOT(pWin); + + RL_DEBUG_MSG("realizewindow end\n"); + return result; + +windowcreatebad: + RL_DEBUG_MSG("window create bad! "); + RL_DEBUG_MSG("realizewindow end\n"); + return NULL; +} + + +Bool +RootlessUnrealizeWindow(WindowPtr pWin) +{ + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("unrealizewindow start "); + + if (IsTopLevel(pWin) || IsRoot(pWin)) { + RootlessWindowRec *winRec = WINREC(pWin); + + RootlessRedisplay(pWin); + CallFrameProc(pScreen, DestroyFrame, (pScreen, &winRec->frame)); + + REGION_UNINIT(pScreen, &winRec->damage); + + xfree(winRec); + WINREC(pWin) = NULL; + } + + SCREEN_UNWRAP(pScreen, UnrealizeWindow); + result = pScreen->UnrealizeWindow(pWin); + SCREEN_WRAP(pScreen, UnrealizeWindow); + RL_DEBUG_MSG("unrealizewindow end\n"); + return result; +} + + +void +RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib) +{ + RegionRec saveRoot; + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("restackwindow start "); + if (winRec) RL_DEBUG_MSG("restack top level \n"); + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, RestackWindow); + if (pScreen->RestackWindow) pScreen->RestackWindow(pWin, pOldNextSib); + SCREEN_WRAP(pScreen, RestackWindow); + NORMAL_ROOT(pWin); + + if (winRec) { + // fixme simplify the following + + WindowPtr oldNextW, newNextW, oldPrevW, newPrevW; + RootlessFramePtr oldNext, newNext, oldPrev, newPrev; + + oldNextW = pOldNextSib; + while (oldNextW && ! WINREC(oldNextW)) oldNextW = oldNextW->nextSib; + oldNext = oldNextW ? &WINREC(oldNextW)->frame : NULL; + + newNextW = pWin->nextSib; + while (newNextW && ! WINREC(newNextW)) newNextW = newNextW->nextSib; + newNext = newNextW ? &WINREC(newNextW)->frame : NULL; + + oldPrevW= pOldNextSib ? pOldNextSib->prevSib : pWin->parent->lastChild; + while (oldPrevW && ! WINREC(oldPrevW)) oldPrevW = oldPrevW->prevSib; + oldPrev = oldPrevW ? &WINREC(oldPrevW)->frame : NULL; + + newPrevW = pWin->prevSib; + while (newPrevW && ! WINREC(newPrevW)) newPrevW = newPrevW->prevSib; + newPrev = newPrevW ? &WINREC(newPrevW)->frame : NULL; + + if (pWin->prevSib) { + WindowPtr w = pWin->prevSib; + while (w) { + RL_DEBUG_MSG("w 0x%x\n", w); + w = w->parent; + } + } + + CallFrameProc(pScreen, RestackFrame, + (pScreen, &winRec->frame, oldPrev, newPrev)); + } + + RL_DEBUG_MSG("restackwindow end\n"); +} + + +/* + * Specialized window copy procedures + */ + +// Globals needed during window resize and move. +static PixmapPtr gResizeDeathPix = NULL; +static pointer gResizeDeathBits = NULL; +static PixmapPtr gResizeCopyWindowSource = NULL; +static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL; + +// CopyWindow() that doesn't do anything. +// For MoveWindow() of top-level windows. +static void +RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + // some code expects the region to be translated + int dx = ptOldOrg.x - pWin->drawable.x; + int dy = ptOldOrg.y - pWin->drawable.y; + RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW "); + + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); +} + + +// CopyWindow used during ResizeWindow for gravity moves. +// Cloned from fbCopyWindow +// The original always draws on the root pixmap (which we don't have). +// Instead, draw on the parent window's pixmap. +// Resize version: the old location's pixels are in gResizeCopyWindowSource +static void +RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + SCREEN_UNWRAP(pScreen, CopyWindow); + RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin); + + { + RegionRec rgnDst; + int dx, dy; + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + REGION_INIT (pScreen, &rgnDst, NullBox, 0); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + fbCopyRegion (&gResizeCopyWindowSource->drawable, + &pScreen->GetWindowPixmap(pWin)->drawable, + 0, + &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + + // don't update - resize will update everything + // fixme DO update? + REGION_UNINIT(pScreen, &rgnDst); + fbValidateDrawable (&pWin->drawable); + } + + SCREEN_WRAP(pScreen, CopyWindow); + RL_DEBUG_MSG("resizecopywindowFB end\n"); +} + + +/* Update *new* location of window. Old location is redrawn with + * PaintWindowBackground/Border. + * Cloned from fbCopyWindow + * The original always draws on the root pixmap (which we don't have). + * Instead, draw on the parent window's pixmap. + */ +void +RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + SCREEN_UNWRAP(pScreen, CopyWindow); + RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin); + + { + RegionRec rgnDst; + int dx, dy; + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + + REGION_INIT(pScreen, &rgnDst, NullBox, 0); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + fbCopyRegion ((DrawablePtr)pWin, (DrawablePtr)pWin, + 0, + &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + + // prgnSrc has been translated to dst position + RootlessDamageRegion(pWin, prgnSrc); + REGION_UNINIT(pScreen, &rgnDst); + fbValidateDrawable (&pWin->drawable); + } + + SCREEN_WRAP(pScreen, CopyWindow); + RL_DEBUG_MSG("copywindowFB end\n"); +} + + +/* + * Window resize procedures + */ + +// Prepare to resize a window. +// The old window's pixels are saved and the implementation is told +// to change the window size. +// (x,y,w,h) is outer frame of window (outside border) +static void +StartFrameResize(WindowPtr pWin, Bool gravity, + int oldX, int oldY, + unsigned int oldW, unsigned int oldH, unsigned int oldBW, + int newX, int newY, + unsigned int newW, unsigned int newH, unsigned int newBW) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + + RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW "); + RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d ", + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + RootlessRedisplay(pWin); + + // Make a copy of the current pixmap and all its data. + // The original will go away when we ask the frame manager to + // allocate the new pixmap. + + gResizeDeathBits = xalloc(winRec->frame.bytesPerRow * winRec->frame.h); + memcpy(gResizeDeathBits, winRec->frame.pixelData, + winRec->frame.bytesPerRow * winRec->frame.h); + gResizeDeathPix = + GetScratchPixmapHeader(pScreen, winRec->frame.w, winRec->frame.h, + winRec->frame.depth, winRec->frame.bitsPerPixel, + winRec->frame.bytesPerRow, gResizeDeathBits); + SetPixmapBaseToScreen(gResizeDeathPix, winRec->frame.x, winRec->frame.y); + + winRec->frame.x = newX; + winRec->frame.y = newY; + winRec->frame.w = newW; + winRec->frame.h = newH; + winRec->borderWidth = newBW; + + CallFrameProc(pScreen, StartResizeFrame, + (pScreen, &winRec->frame, oldX, oldY, oldW, oldH)); + UpdatePixmap(pWin); + + // Use custom CopyWindow when moving gravity bits around + // ResizeWindow assumes the old window contents are in the same + // pixmap, but here they're in deathPix instead. + if (gravity) { + gResizeCopyWindowSource = gResizeDeathPix; + gResizeOldCopyWindowProc = pScreen->CopyWindow; + pScreen->CopyWindow = RootlessResizeCopyWindow; + } + + // Copy pixels in intersection from src to dst. + // ResizeWindow assumes these pixels are already present when + // making gravity adjustments. + // pWin currently has new-sized pixmap but is in old position + // fixme border width change! + { + RegionRec r; + DrawablePtr src = &gResizeDeathPix->drawable; + DrawablePtr dst = &pScreen->GetWindowPixmap(pWin)->drawable; + // These vars are needed because implicit unsigned->signed fails + int oldX2 = (int)(oldX + oldW), newX2 = (int)(newX + newW); + int oldY2 = (int)(oldY + oldH), newY2 = (int)(newY + newH); + + r.data = NULL; + r.extents.x1 = max(oldX, newX); + r.extents.y1 = max(oldY, newY); + r.extents.x2 = min(oldX2, newX2); + r.extents.y2 = min(oldY2, newY2); + + // r is now intersection of of old location and new location + if (r.extents.x2 > r.extents.x1 && r.extents.y2 > r.extents.y1) { +#if 0 + DDXPointRec srcPt = {r.extents.x1, r.extents.y1}; + // Correct for border width change + // fixme need to correct for border width change + int dx = newX - oldX; + int dy = newY - oldY; + REGION_TRANSLATE(pScreen, &r, dx, dy); +#endif + fbCopyRegion(src, dst, NULL, &r, 0, 0, fbCopyWindowProc, 0, 0); + } + REGION_UNINIT(pScreen, &r); + } +} + + +static void +FinishFrameResize(WindowPtr pWin, Bool gravity, + int oldX, int oldY, + unsigned int oldW, unsigned int oldH, unsigned int oldBW, + int newX, int newY, + unsigned int newW, unsigned int newH, unsigned int newBW) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + + CallFrameProc(pScreen, FinishResizeFrame, + (pScreen, &winRec->frame, oldX, oldY, oldW, oldH)); + if (wBoundingShape(pWin)) { + RootlessDamageShape(pWin); + } + + // Destroy temp pixmap + FreeScratchPixmapHeader(gResizeDeathPix); + xfree(gResizeDeathBits); + gResizeDeathPix = gResizeDeathBits = NULL; + + if (gravity) { + pScreen->CopyWindow = gResizeOldCopyWindowProc; + gResizeCopyWindowSource = NULL; + } +} + + +// If kind==VTOther, window border is resizing (and borderWidth is +// already changed!!@#$) This case works like window resize, not move. +void +RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind) +{ + CopyWindowProcPtr oldCopyWindowProc = NULL; + RegionRec saveRoot; + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0; + + RL_DEBUG_MSG("movewindow start \n"); + + if (winRec) { + if (kind == VTMove) { + oldX = winRec->frame.x; + oldY = winRec->frame.y; + RootlessRedisplay(pWin); + } else { + RL_DEBUG_MSG("movewindow border resizing "); + oldBW = winRec->borderWidth; + oldX = winRec->frame.x; + oldY = winRec->frame.y; + oldW = winRec->frame.w; + oldH = winRec->frame.h; + newBW = pWin->borderWidth; + newX = x; + newY = y; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + StartFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, MoveWindow); + if (winRec) { + oldCopyWindowProc = pScreen->CopyWindow; + pScreen->CopyWindow = RootlessNoCopyWindow; + } + pScreen->MoveWindow(pWin, x, y, pSib, kind); + if (winRec) { + pScreen->CopyWindow = oldCopyWindowProc; + } + NORMAL_ROOT(pWin); + SCREEN_WRAP(pScreen, MoveWindow); + + if (winRec) { + if (kind == VTMove) { + // PositionWindow has already set the new frame position. + CallFrameProc(pScreen, MoveFrame, + (pScreen, &winRec->frame, oldX, oldY)); + } else { + FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + } + + RL_DEBUG_MSG("movewindow end\n"); +} + + +// Note: (x, y, w, h) as passed to this procedure don't match +// the frame definition. +// (x,y) is corner of very outer edge, *outside* border +// w,h is width and height *inside8 border, *ignoring* border width +// The rect (x, y, w, h) doesn't mean anything. +// (x, y, w+2*bw, h+2*bw) is total rect +// (x+bw, y+bw, w, h) is inner rect + +void +RootlessResizeWindow(WindowPtr pWin, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib) +{ + RegionRec saveRoot; + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0; + + RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin); + + if (winRec) { + oldBW = winRec->borderWidth; + oldX = winRec->frame.x; + oldY = winRec->frame.y; + oldW = winRec->frame.w; + oldH = winRec->frame.h; + + newBW = oldBW; + newX = x; + newY = y; + newW = w + 2*newBW; + newH = h + 2*newBW; + + StartFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, ResizeWindow); + pScreen->ResizeWindow(pWin, x, y, w, h, pSib); + SCREEN_WRAP(pScreen, ResizeWindow); + NORMAL_ROOT(pWin); + + if (winRec) { + FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + RL_DEBUG_MSG("resizewindow end\n"); +} + + +// fixme untested! +// pWin inside corner stays the same +// pWin->drawable.[xy] stays the same +// frame moves and resizes +void +RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width) +{ + RegionRec saveRoot; + + RL_DEBUG_MSG("change border width "); + if (width != pWin->borderWidth) { + RootlessWindowRec *winRec = WINREC(pWin); + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0; + unsigned int newW = 0, newH = 0, newBW = 0; + + if (winRec) { + oldBW = winRec->borderWidth; + oldX = winRec->frame.x; + oldY = winRec->frame.y; + oldW = winRec->frame.w; + oldH = winRec->frame.h; + + newBW = width; + newX = pWin->drawable.x - newBW; + newY = pWin->drawable.y - newBW; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + + StartFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth); + pWin->drawable.pScreen->ChangeBorderWidth(pWin, width); + SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth); + NORMAL_ROOT(pWin); + + if (winRec) { + FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + } + RL_DEBUG_MSG("change border width end\n"); +} diff --git a/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessWindow.h b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessWindow.h new file mode 100644 index 000000000..0c752e012 --- /dev/null +++ b/xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessWindow.h @@ -0,0 +1,32 @@ +/* + * Rootless window management + * + * Greg Parker gparker@cs.stanford.edu + */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz_1.3/rootlessWindow.h,v 1.1 2002/03/28 02:21:20 torrey Exp $ */ + +#ifndef _ROOTLESSWINDOW_H +#define _ROOTLESSWINDOW_H + +#include "rootlessCommon.h" + + +Bool RootlessCreateWindow(WindowPtr pWin); +Bool RootlessDestroyWindow(WindowPtr pWin); + +#ifdef SHAPE +void RootlessSetShape(WindowPtr pWin); +#endif // SHAPE + +Bool RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask); +Bool RootlessPositionWindow(WindowPtr pWin, int x, int y); +Bool RootlessRealizeWindow(WindowPtr pWin); +Bool RootlessUnrealizeWindow(WindowPtr pWin); +void RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib); +void RootlessCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc); +void RootlessMoveWindow(WindowPtr pWin,int x,int y,WindowPtr pSib,VTKind kind); +void RootlessResizeWindow(WindowPtr pWin, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib); +void RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width); + +#endif diff --git a/xc/programs/Xserver/hw/kdrive/pcmcia/pcmciarotate.c b/xc/programs/Xserver/hw/kdrive/pcmcia/pcmciarotate.c new file mode 100644 index 000000000..a8eb72d55 --- /dev/null +++ b/xc/programs/Xserver/hw/kdrive/pcmcia/pcmciarotate.c @@ -0,0 +1,332 @@ +/* + * $XFree86: xc/programs/Xserver/hw/kdrive/pcmcia/pcmciarotate.c,v 1.1 2002/10/13 19:35:56 keithp Exp $ + * + * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "X.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "font.h" +#include "dixfontstr.h" +#include "fontstruct.h" +#include "mi.h" +#include "regionstr.h" +#include "globals.h" +#include "gcstruct.h" +#include "shadow.h" +#include "fb.h" + +/* + * These indicate which way the source (shadow) is scanned when + * walking the screen in a particular direction + */ + +#define LEFT_TO_RIGHT 1 +#define RIGHT_TO_LEFT -1 +#define TOP_TO_BOTTOM 2 +#define BOTTOM_TO_TOP -2 + +typedef CARD16 PcBits; +typedef INT32 PcStride; + +#define PC_SHIFT 4 +#define PC_UNIT (1 << PC_SHIFT) +#define PC_HALFUNIT (1 << (PC_SHIFT-1)) +#define PC_MASK (PC_UNIT - 1) +#define PC_ALLONES ((PcBits) -1) + +#define PcScrRight(x,b) FbScrRight(x,b) +#define PcScrLeft(x,b) FbScrLeft(x,b) +#define PcBitsMask(x,w) (PcScrRight(PC_ALLONES,(x) & PC_MASK) & \ + PcScrLeft(PC_ALLONES,(PC_UNIT - ((x) + (w))) & PC_MASK)) + +#define pcGetDrawable(pDrawable, pointer, stride, bpp, xoff, yoff) { \ + PixmapPtr _pPix; \ + if ((pDrawable)->type != DRAWABLE_PIXMAP) \ + _pPix = fbGetWindowPixmap(pDrawable); \ + else \ + _pPix = (PixmapPtr) (pDrawable); \ + (pointer) = (PcBits *) _pPix->devPrivate.ptr; \ + (stride) = ((int) _pPix->devKind) / sizeof (PcBits); \ + (bpp) = _pPix->drawable.bitsPerPixel; \ + (xoff) = 0; \ + (yoff) = 0; \ +} + +void +pcmciaUpdateRotatePacked (ScreenPtr pScreen, + shadowBufPtr pBuf) +{ + RegionPtr damage = &pBuf->damage; + PixmapPtr pShadow = pBuf->pPixmap; + int nbox = REGION_NUM_RECTS (damage); + BoxPtr pbox = REGION_RECTS (damage); + PcBits *shaBits; + PcStride shaStride; + int shaBpp; + int shaXoff, shaYoff; + int box_x1, box_x2, box_y1, box_y2; + int sha_x1, sha_y1; + int scr_x1, scr_x2, scr_y1, scr_y2, scr_w, scr_h; + int scr_x, scr_y; + int w; + int pixelsPerBits; + int pixelsMask; + PcStride shaStepOverY, shaStepDownY, shaStepOverX, shaStepDownX; + PcBits *shaLine, *sha; + int shaHeight = pShadow->drawable.height; + int shaWidth = pShadow->drawable.width; + PcBits shaMask; + int shaFirstShift, shaShift; + int o_x_dir; + int o_y_dir; + int x_dir; + int y_dir; + + pcGetDrawable (&pShadow->drawable, shaBits, shaStride, shaBpp, shaXoff, shaYoff); + pixelsPerBits = (sizeof (PcBits) * 8) / shaBpp; + pixelsMask = ~(pixelsPerBits - 1); + shaMask = PcBitsMask (PC_UNIT-shaBpp, shaBpp); + /* + * Compute rotation related constants to walk the shadow + */ + o_x_dir = LEFT_TO_RIGHT; + o_y_dir = TOP_TO_BOTTOM; + if (pBuf->randr & SHADOW_REFLECT_X) + o_x_dir = -o_x_dir; + if (pBuf->randr & SHADOW_REFLECT_Y) + o_y_dir = -o_y_dir; + switch (pBuf->randr & (SHADOW_ROTATE_ALL)) { + case SHADOW_ROTATE_0: /* upper left shadow -> upper left screen */ + default: + x_dir = o_x_dir; + y_dir = o_y_dir; + break; + case SHADOW_ROTATE_90: /* upper right shadow -> upper left screen */ + x_dir = o_y_dir; + y_dir = -o_x_dir; + break; + case SHADOW_ROTATE_180: /* lower right shadow -> upper left screen */ + x_dir = -o_x_dir; + y_dir = -o_y_dir; + break; + case SHADOW_ROTATE_270: /* lower left shadow -> upper left screen */ + x_dir = -o_y_dir; + y_dir = o_x_dir; + break; + } + switch (x_dir) { + case LEFT_TO_RIGHT: + shaStepOverX = shaBpp; + shaStepOverY = 0; + break; + case TOP_TO_BOTTOM: + shaStepOverX = 0; + shaStepOverY = shaStride; + break; + case RIGHT_TO_LEFT: + shaStepOverX = -shaBpp; + shaStepOverY = 0; + break; + case BOTTOM_TO_TOP: + shaStepOverX = 0; + shaStepOverY = -shaStride; + break; + } + switch (y_dir) { + case TOP_TO_BOTTOM: + shaStepDownX = 0; + shaStepDownY = shaStride; + break; + case RIGHT_TO_LEFT: + shaStepDownX = -shaBpp; + shaStepDownY = 0; + break; + case BOTTOM_TO_TOP: + shaStepDownX = 0; + shaStepDownY = -shaStride; + break; + case LEFT_TO_RIGHT: + shaStepDownX = shaBpp; + shaStepDownY = 0; + break; + } + + while (nbox--) + { + box_x1 = pbox->x1; + box_y1 = pbox->y1; + box_x2 = pbox->x2; + box_y2 = pbox->y2; + pbox++; + + /* + * Compute screen and shadow locations for this box + */ + switch (x_dir) { + case LEFT_TO_RIGHT: + scr_x1 = box_x1 & pixelsMask; + scr_x2 = (box_x2 + pixelsPerBits - 1) & pixelsMask; + + sha_x1 = scr_x1; + break; + case TOP_TO_BOTTOM: + scr_x1 = box_y1 & pixelsMask; + scr_x2 = (box_y2 + pixelsPerBits - 1) & pixelsMask; + + sha_y1 = scr_x1; + break; + case RIGHT_TO_LEFT: + scr_x1 = (shaWidth - box_x2) & pixelsMask; + scr_x2 = (shaWidth - box_x1 + pixelsPerBits - 1) & pixelsMask; + + sha_x1 = (shaWidth - scr_x1 - 1); + break; + case BOTTOM_TO_TOP: + scr_x1 = (shaHeight - box_y2) & pixelsMask; + scr_x2 = (shaHeight - box_y1 + pixelsPerBits - 1) & pixelsMask; + + sha_y1 = (shaHeight - scr_x1 - 1); + break; + } + switch (y_dir) { + case TOP_TO_BOTTOM: + scr_y1 = box_y1; + scr_y2 = box_y2; + + sha_y1 = scr_y1; + break; + case RIGHT_TO_LEFT: + scr_y1 = (shaWidth - box_x2); + scr_y2 = (shaWidth - box_x1); + + sha_x1 = box_x2 - 1; + break; + case BOTTOM_TO_TOP: + scr_y1 = shaHeight - box_y2; + scr_y2 = shaHeight - box_y1; + + sha_y1 = box_y2 - 1; + break; + case LEFT_TO_RIGHT: + scr_y1 = box_x1; + scr_y2 = box_x2; + + sha_x1 = box_x1; + break; + } + scr_w = ((scr_x2 - scr_x1) * shaBpp) >> PC_SHIFT; + scr_h = scr_y2 - scr_y1; + scr_y = scr_y1; + + /* shift amount for first pixel on screen */ + shaFirstShift = PC_UNIT - ((sha_x1 * shaBpp) & PC_MASK) - shaBpp; + + /* pointer to shadow data first placed on screen */ + shaLine = (shaBits + + sha_y1 * shaStride + + ((sha_x1 * shaBpp) >> PC_SHIFT)); + + /* + * Copy the bits, always write across the physical frame buffer + * to take advantage of write combining. + */ + while (scr_h--) + { + int p; + PcBits bits; + PcBits *win; + int i; + CARD32 winSize; + + sha = shaLine; + shaShift = shaFirstShift; + w = scr_w; + scr_x = scr_x1 * shaBpp >> PC_SHIFT; + + while (w) + { + /* + * Map some of this line + */ + win = (PcBits *) (*pBuf->window) (pScreen, + scr_y, + scr_x << 1, + SHADOW_WINDOW_WRITE, + &winSize, + pBuf->closure); + i = (winSize >> 1); + if (i > w) + i = w; + w -= i; + scr_x += i; + /* + * Copy the portion of the line mapped + */ + while (i--) + { + bits = 0; + p = pixelsPerBits; + /* + * Build one word of output from multiple inputs + * + * Note that for 90/270 rotations, this will walk + * down the shadow hitting each scanline once. + * This is probably not very efficient. + */ + while (p--) + { + bits = PcScrLeft(bits, shaBpp); + bits |= PcScrRight (*sha, shaShift) & shaMask; + + shaShift -= shaStepOverX; + if (shaShift >= PC_UNIT) + { + shaShift -= PC_UNIT; + sha--; + } + else if (shaShift < 0) + { + shaShift += PC_UNIT; + sha++; + } + sha += shaStepOverY; + } + *win++ = bits; + } + } + scr_y++; + shaFirstShift -= shaStepDownX; + if (shaFirstShift >= PC_UNIT) + { + shaFirstShift -= PC_UNIT; + shaLine--; + } + else if (shaFirstShift < 0) + { + shaFirstShift += PC_UNIT; + shaLine++; + } + shaLine += shaStepDownY; + } + } +} diff --git a/xc/programs/Xserver/hw/xfree86/Domain.note b/xc/programs/Xserver/hw/xfree86/Domain.note new file mode 100644 index 000000000..3db2aefae --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/Domain.note @@ -0,0 +1,159 @@ +The purpose of the changes described here is to implement a more general +framework for multi-head on systems with more than one host-to-PCI bridge. +The changes also implement a basic port of XFree86 to SPARC Solaris. + +These changes are derived from David S. Miller's submission #4653 to the +patch list. David Andrew of Sun Microsystems was also kind enough to +arrange for a hardware loan for development of these changes. + +These changes are known to work on several SPARC SunOS and UltraSPARC +Linux configurations. Linux kernel work is in progress to port these +changes to Linux/PowerPC. + +Several loose ends still need to be addressed before these changes can be +considered stable. The bulk of this note is devoted to enumerating what +remains to be done, along with other notes, broken down into various broad +categories. + +SPARC SunOS (aka Solaris) +------------------------- +- An overview of this XFree86 port is available in README.Solaris. +- The keyboard map code in hw/xfree86/os-support/sunos/sun_kbdEv.c needs + to be extended to handle more than only the sun5 keyboard I targeted it + for. Even for the sun5, the map is incomplete as several keys are not + mapped. What is there is just barely usable. +- On exit, the server will zero out /dev/fb, but that might not be the + right thing to do for all primary adapters. This does however + appear to emulate the behaviour of Sun's commercial servers. It also + eliminates the need for output drivers to save and restore video memory + contents. (They still need to save/restore the mode timing however.) + This also chimes into a long-standing XFree86 policy to not save/restore + video memory contents if the mode on entry is found to be non-VGA, a + policy several existing drivers comply with. +- The SBUS drivers (sunbw2, suncg14, suncg3, suncg6, sunffb, sunleo and + suntcx), the common layer's SBUS code and the fbdev driver have all + only been compile tested. There are likely to be Linux'isms within + them that remain to be dealt with. +- It still needs to be verified whether or not this work adversely + affected support for ix86 Solaris. + +UltraSPARC Linux +---------------- +- Although this code can be compiled using any Linux/SPARC64 kernel, it + can only run successfully using 2.4.12 or later. +- I haven't had time to sufficiently dig into XKB to properly configure it + for sun5 keyboards. Given XFree86 on Linux/SPARC has been around for a + while, it's likely someone has already done this, and I'd appreciate + receiving a copy of a working XF86Config input section. + +PowerPC Linux +------------- +- As mentioned above, kernel work is in progress to port this PCI scheme + to Linux/PowerPC. +- Aside from kernel work, the inX() and outX() definitions in compiler.h + will need to be changed to do something akin to their SPARC definitions, + i.e. consider their port argument to be a virtual address. + +Other Linux ports to multi-domain architectures +----------------------------------------------- +- Comments in os-support/bus/linuxPci.c document the kernel interface + required to port these changes. In short, Linux ports, such as Alpha + and mips, should follow SPARC and PowerPC's lead in providing support to + mmap() PCI devices through their /proc/bus/pci pseudo-files and to treat + such requests for host bridges as requests to mmap() space provided by + these bridges. + +Other OS's +---------- +- In the right hands, either linuxPci.c or sparcPci.c can be used as a + guide for what would need to be done to port this scheme to other OS's. + Perhaps the largest difference between the two (in terms of interface to + the common layer) is that the SunOS port includes internally generated + domain numbers in PCITAG's, whereas the Linux port doesn't need to. The + remainder of the PCI code (which is OS-independent) can handle either + scheme. +- Required entry points are xf86GetPciDomain(), xf86MapDomainMemory(), + xf86MapDomainIO() and xf86ReadDomainMemory(). Replacements for + xf86BusAccWindowsFromOS(), xf86PciBusAccWindowsFromOS() and + xf86AccResFromOS() might also be required. +- Development of these changes has detected the fact that the XFree86 port + to the PowerMax OS is broken, and has been for some time, i.e. since + shortly after its introduction, back in the 3.9* days. + +SPARC PCI (OS-independent) +-------------------------- +- The "Simba" PCI-to-PCI bridge used in SPARC's does not implement VGA + routing, as defined in the PCI specs. Fortunately, OpenPROM seems to + always route VGA resources to the bus with PCI connectors, but this also + causes the common layer to not mark any PCI adapter as primary. + +Multiple PCI domains (architecture- and OS-independent) +------------------------------------------------------- +- This implementation assumes every host-to-PCI bridge provides access to + a separate PCI domain. Each such domain provides three different + "address" spaces: PCI configuration, I/O and memory. The + implementation can also deal with situations where more than one PCI + domain share (different subsets of) the same PCI configuration space. I + have unconfirmed information that suggests it might be necessary to also + allow the sharing of PCI memory spaces. +- This implementation also assumes the CPU's physical address space + includes the entirety of each domain's I/O and memory spaces. I know + this'll need to be changed to deal with the so-called UniNorth bridge, + found on PowerPC's, which allows access to only a subset of the memory + space behind it. +- Ideally, the common layer should mark as primary up to one PCI adapter + per domain. This has yet to be done. +- Something needs to be done about PCI master aborts on primary buses. + For details on this, see my long-winded diatribe in sparcPci.c, and + related comments in linuxPci.c. Suffice it to say here that I see the + eventual implementation of host bridge drivers within XFree86 as + unavoidable at this point. +- DGA is broken on multi-domain platforms. The information passed to the + client to locate the framebuffer still needs to be revised. The best way + to deal with this is to change all drivers' OpenFramebuffer() function to + call a common layer routine to set the device name and displacements to be + returned to the DGA client. + +Output drivers +-------------- +Most drivers currently used on ix86 need(ed) source code changes. +- Calls to xf86ReadBIOS() and xf86MapVidMem() were replaced with calls to + xf86ReadDomainMemory() and xf86MapDomainMemory() respectively. Except + for the "ati" and "atimisc" modules, this has already been done. +- All ix86-style I/O port numbers need to be declared as an IOADDRESS, a + type defined in xf86Pci.h as "unsigned long". Such port numbers also + need to be offset by a displacement which is also defined as an + IOADDRESS. Before a driver's PreInit() is called, the common layer + makes this displacement available in ScrnInfoRec.domainIOBase. For + single-domain architectures, such as ix86, domainIOBase will always be + zero. Current use of vgaHWRec.PIOOffset has also been adjusted + accordingly. Some drivers have been changed to keep a copy of this + displacement in their private structure. Internally, an IOADDRESS is + actually a pointer that has been recasted to an unsigned long, but the + common layer "hides" this fact from the driver ABI, which means that I/O + port numbers, as seen by drivers, remain as integers rather than + addresses. Aside from the ati and atimisc modules, s3, sis and tseng + are the only modules left whose I/O still needs to be converted (I've + temporarily run out of steam). +- Note that these conversions are not necessarily sufficient to produce + drivers that will work on any given multi-domain architecture. A driver + that, for example, had endianness problems, still does. But, at least, + these conversions, along with the supporting common layer changes, make + PCI drivers more widely amenable to porting. +- rdinx(), wrinx(), modinx(), testrg(), testinx() and testinx2() are not + given enough information to allow for the relocation of their I/O. They + are consequently being deleted. The apm and ark drivers, the only + remaining callers of the first three, have been changed to use local + definitions instead. The last three (test*()) were already unused. +- As a temporary measure, these changes completely disable ISA-style + probing on SPARC's and PowerPC's. This means that driver calls to + xf86MatchIsaInstances(), while still valid, will always return detection + failure on SPARC's and PowerPC's. This will be dealt with when a more + general master abort handling scheme is implemented. +- I need to make a decision about the master abort issues mentionned above + before I can convert the "ati" and "atimisc" modules. Consequently, + these modules still need to be compiled with -DAVOID_CPIO on + multi-domain architectures, and support for Mach64 variants as + non-primary heads is not yet available. + +$XFree86: xc/programs/Xserver/hw/xfree86/Domain.note,v 1.2 2002/01/25 21:55:49 tsi Exp $ diff --git a/xc/programs/Xserver/hw/xfree86/doc/README.Solaris b/xc/programs/Xserver/hw/xfree86/doc/README.Solaris new file mode 100644 index 000000000..eccf3615c --- /dev/null +++ b/xc/programs/Xserver/hw/xfree86/doc/README.Solaris @@ -0,0 +1,222 @@ + Information for Solaris + + David Holland, modified by Marc Aurele La France + + 2001 October 01 + +1. What is XFree86 + +XFree86 is a port of X11R6.5.1 that supports several versions of Unix. It is +derived from X386 1.2 which was the X server distributed with X11R5. This +release consists of many new features and performance improvements as well as +many bug fixes. The release is available as a source code distribution, as +well as binary distributions for many architectures. + +The sources for XFree86 are available by anonymous ftp from: + + ftp://ftp.XFree86.org/pub/XFree86/current + +Solaris binaries for XFree86 are available for anonymous ftp at the same +address. Currently, two binary distributions are available: one for Solaris +8 x86, the other for previous Solaris x86 releases. They are not inter- +changeable. No binary distribution is available for Solaris/SPARC as it is +still under development. + +2. The VT-switching sub-system in Solaris x86 + +The virtual terminal sub-system is a undocumented, and unsupported feature of +Solaris x86. Therefore if you use virtual terminals, you do so at YOUR OWN +RISK. + +Virtual terminals are not available in Solaris SPARC, and their availability +has been removed in Solaris8 x86. + +When available, the virtual terminals of Solaris work basically the same way +as most other SVR4 VT sub-systems. However, there are a number of limita- +tions documented below. + +First, if you are running a Solaris 2.4 x86 system, and you want VT's, you +will have to create the necessary devices first, so become root. + +Verify the chanmux device driver's major number is 100: + + # grep -i chanmux /etc/name_to_major + chanmux 100 + # + +If the number after 'chanmux' is anything but 100, I would suggest you imme- +diately abort your attempt to create virtual terminals, and learn to live +without them. + +However, if it is 100, then as root type the following commands to create the +maximum allowable number of virtual terminals. + + # cd /dev + # mknod vt01 c 100 1 + # mknod vt02 c 100 2 + # mknod vt03 c 100 3 + # mknod vt04 c 100 4 + # mknod vt05 c 100 5 + # mknod vt06 c 100 6 + # mknod vt07 c 100 7 + +There is no need for a reconfiguration boot. + +Secondly, for both 2.1, and 2.4 x86 systems, add a few lines to the inittab +to enable logins on them. + +(Note, do NOT make a mistake here, you could lock yourself out of the system) + + --------------------->Snip Snip<----------------------------------------------- + v1:234:respawn:/usr/lib/saf/ttymon -g -h -p "`uname -n` VT01 login: " -T AT386 -d /dev/vt01 -l console + v2:234:respawn:/usr/lib/saf/ttymon -g -h -p "`uname -n` VT02 login: " -T AT386 -d /dev/vt02 -l console + v3:234:respawn:/usr/lib/saf/ttymon -g -h -p "`uname -n` VT03 login: " -T AT386 -d /dev/vt03 -l console + v4:234:respawn:/usr/lib/saf/ttymon -g -h -p "`uname -n` VT04 login: " -T AT386 -d /dev/vt04 -l console + ---------------------->End Here<----------------------------------------------- + +These four lines enable four VT's on Alt-SysReq-F1 through Alt-SysReq-F4. + +Then execute the command 'init q' to immediately enable the virtual termi- +nals. + +The keys used for VT switching are as follows: + + Alt-SysReq-F1 through Alt-SysReq-F7 enable VT screens 1-7 respec- + tively (if the VT is active). + + Alt-SysReq-n enables the next active VT screen. + + Alt-SysReq-p enables the previous active VT screen. + + Alt-SysReq-h returns to the console. + +If you are using virtual terminals, you must leave at least one free for use +by the Xserver. + +Limitations of the virtual terminal sub-system under Solaris x86: + +There are only a total of 8 available VT's (7 normal VT's + 1 console) not +the usual 15. If you have all 8 allocated, and you attempt to allocate a +additional VT you will panic the system. (This bug is worked around in the +Solaris XFree86 Xserver.) + +From a programming stand point, they work pretty much as documented in the +AT&T Unix System V/386 Release 4 Integrated Software Development Guide, how- +ever a number of ioctl() calls are broken. + +3. Notes for building XFree86 on Solaris + + 1. Both GCC, and ProWorks are supported by XFree86. The minimum recom- + mended GCC release is 2.7.2. Some earlier GCC's are known to not work + and should be avoided. + + You should also make certain your version of GCC predefines `sun'. If + needed edit /usr/local/lib/gcc-lib/*/*/specs, and modify the *prede- + fines: line. + + On SPARCs, regardless of the compiler you use, ensure it generates + 32-bit binaries. At this time, 64-bit binaries will probably not work. + + 2. Also on SPARCs, you will need to set BuildXFree86OnSparcSunOS to YES in + ~xc/config/cf/host.def. Otherwise, you can only build the old depre- + cated Xsun* servers. + + 3. A Threaded Xlib compiled with GCC has subtle problems. It'll work 98% + of the time, however clients will occasionally exhibit strange hangs. + Most notably image viewers such as xv-3.10 exhibit this problem. + + It is recommended that you set ThreadedX in ~xc/config/cf/host.def to + NO, if you are using GCC. ProWorks does not have this problem. + Whether this behaviour still exists with newer GCC's has not been veri- + fied. + + 4. To build XFree86 with GCC you need gcc and (optionally) c++filt from + GNU binutils. Don't install gas or ld from GNU binutils, use the one + provided by Sun. + + You might need to setup a /opt/SUNWspro/bin directory containing sym- + bolic links named cc, CC, and c++filt pointing respectively to the + actual gcc, g++ and c++filt commands. + + 5. If you are using ProWorks to compile the XFree86 distribution, you need + to modify your PATH appropriately so the ProWorks tools are available. + Normally, they should be in /opt/SUNWspro/bin + + 6. You MUST put /usr/ccs/bin at the front of your PATH. There are known + problems with some GNU replacements for the utilities found there. So + the /usr/ccs/bin versions of these programs must be found before any + possible GNU versions. (Most notably GNU 'ar' does not work during the + build). + +4. Notes for running XFree86 on Solaris + + 1. Depending on the release or architecture of Solaris you are running, + you might need to install an OS driver for an aperture device. + + Under Solaris x86 2.5 and later, there's a system driver (/dev/xsvc) + that provides this functionality. It will be detected automatically by + the server, so you don't need to install the aperture driver. + + For older Solaris x86 and for Solaris SPARC releases, the source for + this driver is included in xc/programs/Xserver/hw/xfree86/etc/apSo- + laris.shar of the source distribution. This file can usually also be + found in the /usr/X11R6/lib/X11/etc directory when XFree86 is + installed. Building, and installing the driver is relatively straight + forward. Please read its accompanying README file. + + 2. If you have not made the Virtual Terminal devices, you will need to + specify the terminal device to run the Xserver on. The correct device + is vt00 so your xinit command would look like so: + + xinit -- vt00 + + If you have made the virtual terminal devices you do not need to spec- + ify the VT to run the Xserver on. + + 3. For Solaris you will probably want to set your LD_LIBRARY_PATH to + /usr/X11R6/lib:/usr/openwin/lib:/usr/dt/lib. Including /usr/X11R6/lib + in your LD_LIBRARY_PATH is probably not necessary, however it doesn't + hurt. :) + + Including /usr/openwin/lib in the LD_LIBRARY_PATH is recommended + because some Sun supplied binaries were not compiled with LD_RUN_PATH + set properly at compile time. + + Motif and CDE applications may require /usr/dt/lib in your + LD_LIBRARY_PATH too. + + 4. Xqueue is NOT supported under Solaris. The includes necessary for + Xqueue are available, however the driver does not seem to be in the + kernel. (Go figure) + + 5. If you want to use xdm with Solaris, extract the files from the shar + file in /usr/X11R6/lib/X11/etc/XdmConf.svr4 into a temporary directory. + The README file tells where the individual files need to be installed. + Be sure to read through each file and make any site-specific changes + that you need. + +5. Known bugs, and work arounds with Solaris + + 1. The Solaris 2.1 for x86 OpenWindows filemgr does not work against a + X11R5 Xserver, it probably will also not work against a X11R6 Xserver. + Attempting to 'Drag and Drop' a file causes the filemgr to abort with + an 'X error' + + Solaris x86 2.4 does not have this problem. + + There is no known work around. + + 2. The SPARC port is still quite new, so instability is to be expected + (and reported!). It might even have broken some aspects of the x86 + port. + +6. Bug Notification + +Bug reports should be sent to one of the XFree86@XFree86.org, +Xpert@XFree86.org, or Newbie@XFree86.org (depending on your level of com- +fort). + + Generated from XFree86: xc/programs/Xserver/hw/xfree86/doc/sgml/Solaris.sgml,v 1.3 2002/01/25 21:55:53 tsi Exp $ + + +$XFree86: xc/programs/Xserver/hw/xfree86/doc/README.Solaris,v 1.3 2002/01/28 22:24:17 tsi Exp $ diff --git a/xc/programs/Xserver/hw/xwin/X.ico b/xc/programs/Xserver/hw/xwin/X.ico Binary files differnew file mode 100644 index 000000000..26e2cf947 --- /dev/null +++ b/xc/programs/Xserver/hw/xwin/X.ico diff --git a/xc/programs/Xserver/hw/xwin/XWin.rc b/xc/programs/Xserver/hw/xwin/XWin.rc new file mode 100644 index 000000000..73533ba4e --- /dev/null +++ b/xc/programs/Xserver/hw/xwin/XWin.rc @@ -0,0 +1,60 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Harold L Hunt II + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/XWin.rc,v 1.1 2002/10/17 08:18:21 alanh Exp $ */ + +#include "resource.h" + + +/* + * Dialogs + */ + +DEPTH_CHANGE_BOX DIALOG DISCARDABLE 32, 32, 180, 100 +STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE +FONT 8, "MS Sans Serif" +CAPTION "Cygwin/XFree86" +BEGIN + DEFPUSHBUTTON "Dismiss", IDOK, 66, 80, 50, 14 + CTEXT "Cygwin/XFree86", IDC_STATIC, 40, 12, 100, 8 + CTEXT "Disruptive screen configuration change.", IDC_STATIC, 7, 40, 166, 8 + CTEXT "Restore previous resolution to use Cygwin/XFree86.", IDC_STATIC, 7, 52, 166, 8 +END + + +/* + * Menus + */ + + +/* + * Icons + */ + +IDI_XWIN ICON DISCARDABLE "X.ico" diff --git a/xc/programs/Xserver/hw/xwin/resource.h b/xc/programs/Xserver/hw/xwin/resource.h new file mode 100644 index 000000000..b0b4b23c9 --- /dev/null +++ b/xc/programs/Xserver/hw/xwin/resource.h @@ -0,0 +1,41 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Harold L Hunt II + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/resource.h,v 1.1 2002/10/17 08:18:21 alanh Exp $ */ + +#include "winms.h" + + +/* + * Local defines + */ + +#define IDM_APP_ABOUT 40001 +#define IDC_STATIC -1 +#define IDI_XWIN 101 diff --git a/xc/programs/Xserver/hw/xwin/winconfig.c b/xc/programs/Xserver/hw/xwin/winconfig.c new file mode 100644 index 000000000..bc336527c --- /dev/null +++ b/xc/programs/Xserver/hw/xwin/winconfig.c @@ -0,0 +1,949 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Alexander Gottwald + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winconfig.c,v 1.1 2002/10/17 08:18:22 alanh Exp $ */ + +#include "win.h" +#include "winconfig.h" +#include "winmsg.h" +#include "globals.h" + +#ifdef XKB +#define XKB_IN_SERVER +#include "XKBsrv.h" +#endif + +#ifndef CONFIGPATH +#define CONFIGPATH "%A," "%R," \ + "/etc/X11/%R," "%P/etc/X11/%R," \ + "%E," "%F," \ + "/etc/X11/%F," "%P/etc/X11/%F," \ + "%D/%X," \ + "/etc/X11/%X-%M," "/etc/X11/%X," "/etc/%X," \ + "%P/etc/X11/%X.%H," "%P/etc/X11/%X-%M," \ + "%P/etc/X11/%X," \ + "%P/lib/X11/%X.%H," "%P/lib/X11/%X-%M," \ + "%P/lib/X11/%X" +#endif + +XF86ConfigPtr g_xf86configptr = NULL; +WinCmdlineRec g_cmdline = { + NULL, /* configFile */ + NULL, /* fontPath */ + NULL, /* rgbPath */ + NULL, /* keyboard */ +#ifdef XKB + FALSE, /* noXkbExtension */ + NULL, /* xkbMap */ +#endif + NULL, /* screenname */ + NULL, /* mousename */ + FALSE, /* emulate3Buttons */ + 0 /* emulate3Timeout */ +}; + +winInfoRec g_winInfo = { + { /* keyboard */ + 0, /* leds */ + 500, /* delay */ + 30 /* rate */ +#ifdef XKB + } + , + { /* xkb */ + FALSE, /* disable */ + NULL, /* rules */ + NULL, /* model */ + NULL, /* layout */ + NULL, /* variant */ + NULL, /* options */ + NULL, /* initialMap */ + NULL, /* keymap */ + NULL, /* types */ + NULL, /* compat */ + NULL, /* keycodes */ + NULL, /* symbols */ + NULL /* geometry */ +#endif + } + , + { + FALSE, + 50} +}; + +serverLayoutRec g_winConfigLayout; + +static Bool ParseOptionValue (int scrnIndex, pointer options, + OptionInfoPtr p); +static Bool configLayout (serverLayoutPtr, XF86ConfLayoutPtr, char *); +static Bool configImpliedLayout (serverLayoutPtr, XF86ConfScreenPtr); +static Bool GetBoolValue (OptionInfoPtr p, const char *s); + +#define NULL_IF_EMPTY(x) (winNameCompare(x,"")?x:NULL) + + +Bool +winReadConfigfile () +{ + Bool retval = TRUE; + const char *filename; + + MessageType from = X_DEFAULT; + char *xf86ConfigFile = NULL; + + if (g_cmdline.configFile) + { + from = X_CMDLINE; + xf86ConfigFile = g_cmdline.configFile; + } + + /* Parse config file into data structure */ + + filename = xf86openConfigFile (CONFIGPATH, xf86ConfigFile, PROJECTROOT); + if (filename) + { + winMsg (from, "Using config file: \"%s\"\n", filename); + } + else + { + winMsg (X_ERROR, "Unable to locate/open config file"); + if (xf86ConfigFile) + ErrorF (": \"%s\"", xf86ConfigFile); + ErrorF ("\n"); + return FALSE; + } + if ((g_xf86configptr = xf86readConfigFile ()) == NULL) + { + winMsg (X_ERROR, "Problem parsing the config file\n"); + return FALSE; + } + xf86closeConfigFile (); + + winMsg (X_NONE, "Markers: "); + winMsg (X_PROBED, "probed, "); + winMsg (X_CONFIG, "from config file, "); + winMsg (X_DEFAULT, "default setting,\n "); + winMsg (X_CMDLINE, "from command line, "); + winMsg (X_NOTICE, "notice, "); + winMsg (X_INFO, "informational,\n "); + winMsg (X_WARNING, "warning, "); + winMsg (X_ERROR, "error, "); + winMsg (X_UNKNOWN, "unknown.\n"); + + /* set options from data structure */ + + if (g_xf86configptr->conf_layout_lst == NULL || g_cmdline.screenname != NULL) + { + if (g_cmdline.screenname == NULL) + { + winMsg (X_WARNING, + "No Layout section. Using the first Screen section.\n"); + } + if (!configImpliedLayout (&g_winConfigLayout, + g_xf86configptr->conf_screen_lst)) + { + winMsg (X_ERROR, "Unable to determine the screen layout\n"); + return FALSE; + } + } + else + { + /* Check if layout is given in the config file */ + if (g_xf86configptr->conf_flags != NULL) + { + char *dfltlayout = NULL; + pointer optlist = g_xf86configptr->conf_flags->flg_option_lst; + + if (optlist && winFindOption (optlist, "defaultserverlayout")) + dfltlayout = + winSetStrOption (optlist, "defaultserverlayout", NULL); + + if (!configLayout (&g_winConfigLayout, + g_xf86configptr->conf_layout_lst, + dfltlayout)) + { + winMsg (X_ERROR, "Unable to determine the screen layout\n"); + return FALSE; + } + } + else + { + if (!configLayout (&g_winConfigLayout, + g_xf86configptr->conf_layout_lst, + NULL)) + { + winMsg (X_ERROR, "Unable to determin the screen layout\n"); + return FALSE; + } + } + } + + /* setup special config files */ + winConfigFiles (); + return retval; +} + + +/* Set the keyboard configuration */ + +Bool +winConfigKeyboard (DeviceIntPtr pDevice) +{ + XF86ConfInputPtr kbd = NULL; + XF86ConfInputPtr input_list = NULL; + MessageType from = X_DEFAULT; + MessageType kbdfrom = X_CONFIG; + + /* Setup defaults */ +#ifdef XKB + g_winInfo.xkb.disable = FALSE; +# ifdef PC98 /* japanese */ /* not implemented */ + g_winInfo.xkb.rules = "xfree98"; + g_winInfo.xkb.model = "pc98"; + g_winInfo.xkb.layout = "nex/jp"; + g_winInfo.xkb.variant = NULL; + g_winInfo.xkb.options = NULL; +# else + g_winInfo.xkb.rules = "xfree86"; + g_winInfo.xkb.model = "pc101"; + g_winInfo.xkb.layout = "us"; + g_winInfo.xkb.variant = NULL; + g_winInfo.xkb.options = NULL; +# endif /* PC98 */ + g_winInfo.xkb.initialMap = NULL; + g_winInfo.xkb.keymap = NULL; + g_winInfo.xkb.types = NULL; + g_winInfo.xkb.compat = NULL; + g_winInfo.xkb.keycodes = NULL; + g_winInfo.xkb.symbols = NULL; + g_winInfo.xkb.geometry = NULL; +#endif /* XKB */ + + /* parse the configuration */ + + if (g_cmdline.keyboard) + kbdfrom = X_CMDLINE; + + /* + * Until the layout code is finished, I search for the keyboard + * device and configure the server with it. + */ + + if (g_xf86configptr != NULL) + input_list = g_xf86configptr->conf_input_lst; + + while (input_list != NULL) + { + if (winNameCompare (input_list->inp_driver, "keyboard") == 0) + { + /* Check if device name matches requested name */ + if (g_cmdline.keyboard && winNameCompare (input_list->inp_identifier, + g_cmdline.keyboard)) + continue; + kbd = input_list; + } + input_list = input_list->list.next; + } + + if (kbd != NULL) + { + if (kbd->inp_identifier) + winMsg (kbdfrom, "Using keyboard \"%s\" as primary keyboard\n", + kbd->inp_identifier); + +#ifdef XKB + from = X_DEFAULT; + if (g_cmdline.noXkbExtension) + { + from = X_CMDLINE; + g_winInfo.xkb.disable = TRUE; + } + else if (kbd->inp_option_lst) + { + int b = winSetBoolOption (kbd->inp_option_lst, "XkbDisable", FALSE); + if (b) + { + from = X_CONFIG; + g_winInfo.xkb.disable = TRUE; + } + } + if (g_winInfo.xkb.disable) + { + winMsg (from, "XkbExtension disabled\n"); + } + else + { + char *s; + + if ((s = winSetStrOption (kbd->inp_option_lst, "XkbRules", NULL))) + { + g_winInfo.xkb.rules = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: rules: \"%s\"\n", s); + } + + if ((s = winSetStrOption (kbd->inp_option_lst, "XkbModel", NULL))) + { + g_winInfo.xkb.model = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: model: \"%s\"\n", s); + } + + if ((s = winSetStrOption (kbd->inp_option_lst, "XkbLayout", NULL))) + { + g_winInfo.xkb.layout = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: layout: \"%s\"\n", s); + } + + if ((s = winSetStrOption (kbd->inp_option_lst, "XkbVariant", NULL))) + { + g_winInfo.xkb.variant = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: variant: \"%s\"\n", s); + } + + if ((s = winSetStrOption (kbd->inp_option_lst, "XkbOptions", NULL))) + { + g_winInfo.xkb.options = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: options: \"%s\"\n", s); + } + + from = X_CMDLINE; + if (!XkbInitialMap) + { + s = + winSetStrOption (kbd->inp_option_lst, "XkbInitialMap", NULL); + if (s) + { + XkbInitialMap = NULL_IF_EMPTY (s); + from = X_CONFIG; + } + } + + if ((s = winSetStrOption (kbd->inp_option_lst, "XkbKeymap", NULL))) + { + g_winInfo.xkb.keymap = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: keymap: \"%s\" " + " (overrides other XKB settings)\n", s); + } + + if ((s = winSetStrOption (kbd->inp_option_lst, "XkbCompat", NULL))) + { + g_winInfo.xkb.compat = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: compat: \"%s\"\n", s); + } + + if ((s = winSetStrOption (kbd->inp_option_lst, "XkbTypes", NULL))) + { + g_winInfo.xkb.types = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: types: \"%s\"\n", s); + } + + if ( + (s = + winSetStrOption (kbd->inp_option_lst, "XkbKeycodes", NULL))) + { + g_winInfo.xkb.keycodes = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: keycodes: \"%s\"\n", s); + } + + if ( + (s = + winSetStrOption (kbd->inp_option_lst, "XkbGeometry", NULL))) + { + g_winInfo.xkb.geometry = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: geometry: \"%s\"\n", s); + } + + if ((s = winSetStrOption (kbd->inp_option_lst, "XkbSymbols", NULL))) + { + g_winInfo.xkb.symbols = NULL_IF_EMPTY (s); + winMsg (X_CONFIG, "XKB: symbols: \"%s\"\n", s); + } + } +#endif + } + else + { + winMsg (X_ERROR, "No primary keyboard configured\n"); + winMsg (X_DEFAULT, "Using compiletime defaults for keyboard\n"); + } + + return TRUE; +} + + +Bool +winConfigMouse (DeviceIntPtr pDevice) +{ + MessageType mousefrom = X_CONFIG; + XF86ConfInputPtr mouse = NULL; + XF86ConfInputPtr input_list = NULL; + + if (g_cmdline.mouse) + mousefrom = X_CMDLINE; + + if (g_xf86configptr != NULL) + input_list = g_xf86configptr->conf_input_lst; + + while (input_list != NULL) + { + if (winNameCompare (input_list->inp_driver, "mouse") == 0) + { + /* Check if device name matches requested name */ + if (g_cmdline.mouse && winNameCompare (input_list->inp_identifier, + g_cmdline.mouse)) + continue; + mouse = input_list; + } + input_list = input_list->list.next; + } + + if (mouse != NULL) + { + if (mouse->inp_identifier) + winMsg (mousefrom, "Using pointer \"%s\" as primary pointer\n", + mouse->inp_identifier); + + g_winInfo.pointer.emulate3Buttons = + winSetBoolOption (mouse->inp_option_lst, "Emulate3Buttons", FALSE); + if (g_cmdline.emulate3buttons) + g_winInfo.pointer.emulate3Buttons = g_cmdline.emulate3buttons; + + g_winInfo.pointer.emulate3Timeout = + winSetIntOption (mouse->inp_option_lst, "Emulate3Timeout", 50); + if (g_cmdline.emulate3timeout) + g_winInfo.pointer.emulate3Timeout = g_cmdline.emulate3timeout; + } + else + { + winMsg (X_ERROR, "No primary pointer configured\n"); + winMsg (X_DEFAULT, "Using compiletime defaults for pointer\n"); + } + + return TRUE; +} + + +Bool +winConfigFiles () +{ + MessageType from; + XF86ConfFilesPtr filesptr = NULL; + + /* set some shortcuts */ + if (g_xf86configptr != NULL) + { + filesptr = g_xf86configptr->conf_files; + } + + + /* Fontpath */ + from = X_DEFAULT; + + if (g_cmdline.fontPath) + { + from = X_CMDLINE; + defaultFontPath = g_cmdline.fontPath; + } + else if (filesptr != NULL && filesptr->file_fontpath) + { + from = X_CONFIG; + defaultFontPath = xstrdup (filesptr->file_fontpath); + } + winMsg (from, "FontPath set to \"%s\"\n", defaultFontPath); + + /* RGBPath */ + from = X_DEFAULT; + if (g_cmdline.rgbPath) + { + from = X_CMDLINE; + rgbPath = g_cmdline.rgbPath; + } + else if (filesptr != NULL && filesptr->file_rgbpath) + { + from = X_CONFIG; + rgbPath = xstrdup (filesptr->file_rgbpath); + } + winMsg (from, "RgbPath set to \"%s\"\n", rgbPath); + + return TRUE; +} + + +Bool +winConfigOptions () +{ + return TRUE; +} + + +Bool +winConfigScreens () +{ + return TRUE; +} + + +char * +winSetStrOption (pointer optlist, const char *name, char *deflt) +{ + OptionInfoRec o; + + o.name = name; + o.type = OPTV_STRING; + if (ParseOptionValue (-1, optlist, &o)) + deflt = o.value.str; + if (deflt) + return xstrdup (deflt); + else + return NULL; +} + + +int +winSetBoolOption (pointer optlist, const char *name, int deflt) +{ + OptionInfoRec o; + + o.name = name; + o.type = OPTV_BOOLEAN; + if (ParseOptionValue (-1, optlist, &o)) + deflt = o.value.bool; + return deflt; +} + + +int +winSetIntOption (pointer optlist, const char *name, int deflt) +{ + OptionInfoRec o; + + o.name = name; + o.type = OPTV_INTEGER; + if (ParseOptionValue (-1, optlist, &o)) + deflt = o.value.num; + return deflt; +} + + +double +winSetRealOption (pointer optlist, const char *name, double deflt) +{ + OptionInfoRec o; + + o.name = name; + o.type = OPTV_REAL; + if (ParseOptionValue (-1, optlist, &o)) + deflt = o.value.realnum; + return deflt; +} + + +/* + * Compare two strings for equality. This is caseinsensitive and + * The characters '_', ' ' (space) and '\t' (tab) are treated as + * not existing. + */ + +int +winNameCompare (const char *s1, const char *s2) +{ + char c1, c2; + + if (!s1 || *s1 == 0) + { + if (!s2 || *s2 == 0) + return 0; + else + return 1; + } + + while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') + s1++; + while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') + s2++; + + c1 = (isupper (*s1) ? tolower (*s1) : *s1); + c2 = (isupper (*s2) ? tolower (*s2) : *s2); + + while (c1 == c2) + { + if (c1 == 0) + return 0; + s1++; + s2++; + + while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') + s1++; + while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') + s2++; + + c1 = (isupper (*s1) ? tolower (*s1) : *s1); + c2 = (isupper (*s2) ? tolower (*s2) : *s2); + } + return (c1 - c2); +} + + +/* + * Find the named option in the list. + * @return the pointer to the option record, or NULL if not found. + */ + +XF86OptionPtr +winFindOption (XF86OptionPtr list, const char *name) +{ + while (list) + { + if (winNameCompare (list->opt_name, name) == 0) + return list; + list = list->list.next; + } + return NULL; +} + + +/* + * Find the Value of an named option. + * @return The option value or NULL if not found. + */ + +char * +winFindOptionValue (XF86OptionPtr list, const char *name) +{ + list = winFindOption (list, name); + if (list) + { + if (list->opt_val) + return (list->opt_val); + else + return ""; + } + return (NULL); +} + + +/* + * Parse the option. + */ + +static Bool +ParseOptionValue (int scrnIndex, pointer options, OptionInfoPtr p) +{ + char *s, *end; + + if ((s = winFindOptionValue (options, p->name)) != NULL) + { + switch (p->type) + { + case OPTV_INTEGER: + if (*s == '\0') + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires an integer value\n", + p->name); + p->found = FALSE; + } + else + { + p->value.num = strtoul (s, &end, 0); + if (*end == '\0') + { + p->found = TRUE; + } + else + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires an integer value\n", + p->name); + p->found = FALSE; + } + } + break; + case OPTV_STRING: + if (*s == '\0') + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires an string value\n", p->name); + p->found = FALSE; + } + else + { + p->value.str = s; + p->found = TRUE; + } + break; + case OPTV_ANYSTR: + p->value.str = s; + p->found = TRUE; + break; + case OPTV_REAL: + if (*s == '\0') + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires a floating point value\n", + p->name); + p->found = FALSE; + } + else + { + p->value.realnum = strtod (s, &end); + if (*end == '\0') + { + p->found = TRUE; + } + else + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires a floating point value\n", + p->name); + p->found = FALSE; + } + } + break; + case OPTV_BOOLEAN: + if (GetBoolValue (p, s)) + { + p->found = TRUE; + } + else + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires a boolean value\n", p->name); + p->found = FALSE; + } + break; + case OPTV_FREQ: + if (*s == '\0') + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires a frequency value\n", + p->name); + p->found = FALSE; + } + else + { + double freq = strtod (s, &end); + int units = 0; + + if (end != s) + { + p->found = TRUE; + if (!winNameCompare (end, "Hz")) + units = 1; + else if (!winNameCompare (end, "kHz") || + !winNameCompare (end, "k")) + units = 1000; + else if (!winNameCompare (end, "MHz") || + !winNameCompare (end, "M")) + units = 1000000; + else + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires a frequency value\n", + p->name); + p->found = FALSE; + } + if (p->found) + freq *= (double) units; + } + else + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires a frequency value\n", + p->name); + p->found = FALSE; + } + if (p->found) + { + p->value.freq.freq = freq; + p->value.freq.units = units; + } + } + break; + case OPTV_NONE: + /* Should never get here */ + p->found = FALSE; + break; + } + if (p->found) + { + winDrvMsgVerb (scrnIndex, X_CONFIG, 2, "Option \"%s\"", p->name); + if (!(p->type == OPTV_BOOLEAN && *s == 0)) + { + winErrorFVerb (2, " \"%s\"", s); + } + winErrorFVerb (2, "\n"); + } + } + else if (p->type == OPTV_BOOLEAN) + { + /* Look for matches with options with or without a "No" prefix. */ + char *n, *newn; + OptionInfoRec opt; + + n = winNormalizeName (p->name); + if (!n) + { + p->found = FALSE; + return FALSE; + } + if (strncmp (n, "no", 2) == 0) + { + newn = n + 2; + } + else + { + free (n); + n = malloc (strlen (p->name) + 2 + 1); + if (!n) + { + p->found = FALSE; + return FALSE; + } + strcpy (n, "No"); + strcat (n, p->name); + newn = n; + } + if ((s = winFindOptionValue (options, newn)) != NULL) + { + if (GetBoolValue (&opt, s)) + { + p->value.bool = !opt.value.bool; + p->found = TRUE; + } + else + { + winDrvMsg (scrnIndex, X_WARNING, + "Option \"%s\" requires a boolean value\n", newn); + p->found = FALSE; + } + } + else + { + p->found = FALSE; + } + if (p->found) + { + winDrvMsgVerb (scrnIndex, X_CONFIG, 2, "Option \"%s\"", newn); + if (*s != 0) + { + winErrorFVerb (2, " \"%s\"", s); + } + winErrorFVerb (2, "\n"); + } + free (n); + } + else + { + p->found = FALSE; + } + return p->found; +} + + +static Bool +configLayout (serverLayoutPtr servlayoutp, XF86ConfLayoutPtr conf_layout, + char *default_layout) +{ +#if 0 +#pragma warn UNIMPLEMENTED +#endif + return TRUE; +} + + +static Bool +configImpliedLayout (serverLayoutPtr servlayoutp, + XF86ConfScreenPtr conf_screen) +{ +#if 0 +#pragma warn UNIMPLEMENTED +#endif + return TRUE; +} + + +static Bool +GetBoolValue (OptionInfoPtr p, const char *s) +{ + if (*s == 0) + { + p->value.bool = TRUE; + } + else + { + if (winNameCompare (s, "1") == 0) + p->value.bool = TRUE; + else if (winNameCompare (s, "on") == 0) + p->value.bool = TRUE; + else if (winNameCompare (s, "true") == 0) + p->value.bool = TRUE; + else if (winNameCompare (s, "yes") == 0) + p->value.bool = TRUE; + else if (winNameCompare (s, "0") == 0) + p->value.bool = FALSE; + else if (winNameCompare (s, "off") == 0) + p->value.bool = FALSE; + else if (winNameCompare (s, "false") == 0) + p->value.bool = FALSE; + else if (winNameCompare (s, "no") == 0) + p->value.bool = FALSE; + } + return TRUE; +} + + +char * +winNormalizeName (const char *s) +{ + char *ret, *q; + const char *p; + + if (s == NULL) + return NULL; + + ret = malloc (strlen (s) + 1); + for (p = s, q = ret; *p != 0; p++) + { + switch (*p) + { + case '_': + case ' ': + case '\t': + continue; + default: + if (isupper (*p)) + *q++ = tolower (*p); + else + *q++ = *p; + } + } + *q = '\0'; + return ret; +} diff --git a/xc/programs/Xserver/hw/xwin/winconfig.h b/xc/programs/Xserver/hw/xwin/winconfig.h new file mode 100644 index 000000000..d3099b373 --- /dev/null +++ b/xc/programs/Xserver/hw/xwin/winconfig.h @@ -0,0 +1,332 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Alexander Gottwald + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winconfig.h,v 1.1 2002/10/17 08:18:22 alanh Exp $ */ +#ifndef __WIN_CONFIG_H__ +#define __WIN_CONFIG_H__ + +#include "win.h" +#include "../xfree86/parser/xf86Parser.h" + + +/* These are taken from hw/xfree86/common/xf86str.h */ + +typedef struct +{ + CARD32 red, green, blue; +} +rgb; + + +typedef struct +{ + float red, green, blue; +} +Gamma; + + +typedef struct +{ + char *identifier; + char *vendor; + char *board; + char *chipset; + char *ramdac; + char *driver; + struct _confscreenrec *myScreenSection; + Bool claimed; + Bool active; + Bool inUse; + int videoRam; + int textClockFreq; + pointer options; + int screen; /* For multi-CRTC cards */ +} +GDevRec, *GDevPtr; + + +typedef struct +{ + char *identifier; + char *driver; + pointer commonOptions; + pointer extraOptions; +} +IDevRec, *IDevPtr; + + +typedef struct +{ + int frameX0; + int frameY0; + int virtualX; + int virtualY; + int depth; + int fbbpp; + rgb weight; + rgb blackColour; + rgb whiteColour; + int defaultVisual; + char **modes; + pointer options; +} +DispRec, *DispPtr; + + +typedef struct _confxvportrec +{ + char *identifier; + pointer options; +} +confXvPortRec, *confXvPortPtr; + + +typedef struct _confxvadaptrec +{ + char *identifier; + int numports; + confXvPortPtr ports; + pointer options; +} +confXvAdaptorRec, *confXvAdaptorPtr; + + +typedef struct _confscreenrec +{ + char *id; + int screennum; + int defaultdepth; + int defaultbpp; + int defaultfbbpp; + GDevPtr device; + int numdisplays; + DispPtr displays; + int numxvadaptors; + confXvAdaptorPtr xvadaptors; + pointer options; +} +confScreenRec, *confScreenPtr; + + +typedef enum +{ + PosObsolete = -1, + PosAbsolute = 0, + PosRightOf, + PosLeftOf, + PosAbove, + PosBelow, + PosRelative +} +PositionType; + + +typedef struct _screenlayoutrec +{ + confScreenPtr screen; + char *topname; + confScreenPtr top; + char *bottomname; + confScreenPtr bottom; + char *leftname; + confScreenPtr left; + char *rightname; + confScreenPtr right; + PositionType where; + int x; + int y; + char *refname; + confScreenPtr refscreen; +} +screenLayoutRec, *screenLayoutPtr; + + +typedef struct _serverlayoutrec +{ + char *id; + screenLayoutPtr screens; + GDevPtr inactives; + IDevPtr inputs; + pointer options; +} +serverLayoutRec, *serverLayoutPtr; + + +/* + * winconfig.c + */ + +typedef struct +{ + /* Files */ + char *configFile; + char *fontPath; + char *rgbPath; + /* input devices - keyboard */ + char *keyboard; +#ifdef XKB + Bool noXkbExtension; + char *xkbMap; +#endif + /* layout */ + char *screenname; + /* mouse settings */ + char *mouse; + Bool emulate3buttons; + long emulate3timeout; +} +WinCmdlineRec, *WinCmdlinePtr; + + +extern WinCmdlineRec g_cmdline; + +extern XF86ConfigPtr g_xf86configptr; +extern serverLayoutRec g_winConfigLayout; + + +/* + * Function prototypes + */ + +Bool winReadConfigfile (void); +Bool winConfigFiles (void); +Bool winConfigOptions (void); +Bool winConfigScreens (void); +Bool winConfigKeyboard (DeviceIntPtr pDevice); +Bool winConfigMouse (DeviceIntPtr pDevice); + + +typedef struct +{ + double freq; + int units; +} +OptFrequency; + + +typedef union +{ + unsigned long num; + char *str; + double realnum; + Bool bool; + OptFrequency freq; +} +ValueUnion; + + +typedef enum +{ + OPTV_NONE = 0, + OPTV_INTEGER, + OPTV_STRING, /* a non-empty string */ + OPTV_ANYSTR, /* Any string, including an empty one */ + OPTV_REAL, + OPTV_BOOLEAN, + OPTV_FREQ +} +OptionValueType; + + +typedef enum +{ + OPTUNITS_HZ = 1, + OPTUNITS_KHZ, + OPTUNITS_MHZ +} +OptFreqUnits; + + +typedef struct +{ + int token; + const char *name; + OptionValueType type; + ValueUnion value; + Bool found; +} +OptionInfoRec, *OptionInfoPtr; + + +/* + * Function prototypes + */ + +char *winSetStrOption (pointer optlist, const char *name, char *deflt); +int winSetBoolOption (pointer optlist, const char *name, int deflt); +int winSetIntOption (pointer optlist, const char *name, int deflt); +double winSetRealOption (pointer optlist, const char *name, double deflt); + +XF86OptionPtr winFindOption (XF86OptionPtr list, const char *name); +char *winFindOptionValue (XF86OptionPtr list, const char *name); +int winNameCompare (const char *s1, const char *s2); +char *winNormalizeName (const char *s); + + +typedef struct +{ + struct + { + long leds; + long delay; + long rate; + } + keyboard; +#ifdef XKB + struct + { + Bool disable; + char *rules; + char *model; + char *layout; + char *variant; + char *options; + char *initialMap; + char *keymap; + char *types; + char *compat; + char *keycodes; + char *symbols; + char *geometry; + } + xkb; +#endif + struct + { + Bool emulate3Buttons; + long emulate3Timeout; + } + pointer; +} +winInfoRec, *winInfoPtr; + + +extern winInfoRec g_winInfo; + +#endif diff --git a/xc/programs/Xserver/hw/xwin/winmsg.c b/xc/programs/Xserver/hw/xwin/winmsg.c new file mode 100644 index 000000000..35342c359 --- /dev/null +++ b/xc/programs/Xserver/hw/xwin/winmsg.c @@ -0,0 +1,119 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Alexander Gottwald + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winmsg.c,v 1.1 2002/10/17 08:18:22 alanh Exp $ */ + +#include "win.h" +#include "winmsg.h" +#include <stdarg.h> + +#ifndef VERBOSE_LEVEL +#define VERBOSE_LEVEL 4 +#endif + + +void winVMsg (int, MessageType, int verb, const char *, va_list); + + +void +winVMsg (int scrnIndex, MessageType type, int verb, const char *format, + va_list ap) +{ + const char *prefix = NULL; + + if (verb && verb > VERBOSE_LEVEL) + return; + +#undef __msg +#define __msg(name,string) case name: prefix = string; break; +#undef _msg +#define _msg(name,string) __msg(name,string) + switch (type) + { + MESSAGE_STRINGS default:prefix = NULL; + break; + } +#undef __msg +#undef _msg + + if (prefix != NULL) + ErrorF ("%s ", prefix); + VErrorF (format, ap); +} + + +void +winDrvMsg (int scrnIndex, MessageType type, const char *format, ...) +{ + va_list ap; + va_start (ap, format); + winVMsg (scrnIndex, type, 0, format, ap); + va_end (ap); +} + + +void +winMsg (MessageType type, const char *format, ...) +{ + va_list ap; + va_start (ap, format); + winVMsg (0, type, 0, format, ap); + va_end (ap); +} + + +void +winDrvMsgVerb (int scrnIndex, MessageType type, int verb, const char *format, + ...) +{ + va_list ap; + va_start (ap, format); + winVMsg (scrnIndex, type, verb, format, ap); + va_end (ap); +} + + +void +winMsgVerb (MessageType type, int verb, const char *format, ...) +{ + va_list ap; + va_start (ap, format); + winVMsg (0, type, verb, format, ap); + va_end (ap); +} + + +void +winErrorFVerb (int verb, const char *format, ...) +{ + va_list ap; + va_start (ap, format); + winVMsg (0, X_NONE, verb, format, ap); + va_end (ap); +} diff --git a/xc/programs/Xserver/hw/xwin/winmsg.h b/xc/programs/Xserver/hw/xwin/winmsg.h new file mode 100644 index 000000000..c873d4beb --- /dev/null +++ b/xc/programs/Xserver/hw/xwin/winmsg.h @@ -0,0 +1,72 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Alexander Gottwald + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winmsg.h,v 1.1 2002/10/17 08:18:22 alanh Exp $ */ + +#ifndef __WIN_MSG_H__ +#define __WIN_MSG_H__ + + +#define __msg_name(name,string) name +#define __msg(name,string) __msg_name(name,string) +#define _msg(name,string) __msg(name,string), + +#define MESSAGE_STRINGS \ + _msg(X_PROBED,"(--)" /* Value was probed */)\ + _msg(X_CONFIG,"(**)" /* Value was given in the config file */)\ + _msg(X_DEFAULT,"(==)" /* Value is a default */)\ + _msg(X_CMDLINE,"(++)" /* Value was given on the command line */)\ + _msg(X_NOTICE,"(!!)" /* Notice */) \ + _msg(X_ERROR,"(EE)" /* Error message */) \ + _msg(X_WARNING,"(WW)" /* Warning message */) \ + _msg(X_INFO,"(II)" /* Informational message */) \ + _msg(X_UNKNOWN,"(?""?)" /* Unknown, trigraph fix */) \ + _msg(X_NONE,NULL /* No prefix */) \ + __msg(X_NOT_IMPLEMENTED,"(NI)" /* Not implemented */) + +typedef enum +{ + MESSAGE_STRINGS +} +MessageType; + + +/* + * Function prototypes + */ + +void winDrvMsgVerb (int scrnIndex, + MessageType type, int verb, const char *format, ...); +void winDrvMsg (int scrnIndex, MessageType type, const char *format, ...); +void winMsgVerb (MessageType type, int verb, const char *format, ...); +void winMsg (MessageType type, const char *format, ...); + +void winErrorFVerb (int verb, const char *format, ...); + +#endif diff --git a/xc/programs/Xserver/hw/xwin/winregistry.c b/xc/programs/Xserver/hw/xwin/winregistry.c new file mode 100644 index 000000000..b31fcf641 --- /dev/null +++ b/xc/programs/Xserver/hw/xwin/winregistry.c @@ -0,0 +1,66 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. + * + *Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + *"Software"), to deal in the Software without restriction, including + *without limitation the rights to use, copy, modify, merge, publish, + *distribute, sublicense, and/or sell copies of the Software, and to + *permit persons to whom the Software is furnished to do so, subject to + *the following conditions: + * + *The above copyright notice and this permission notice shall be + *included in all copies or substantial portions of the Software. + * + *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR + *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + *Except as contained in this notice, the name of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Harold L Hunt II + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winregistry.c,v 1.1 2002/07/05 09:19:26 alanh Exp $ */ + +#include "win.h" + + +DWORD +winGetRegistryDWORD (HKEY hkey, char *pszRegistryKey) +{ + HKEY hkResult; + DWORD dwDisposition; + + RegCreateKeyEx (hkey, + pszRegistryKey, + 0, + '\0', + REG_OPTION_NON_VOLATILE, + KEY_READ, + NULL, + &hkResult, + &dwDisposition); + + if (dwDisposition == REG_CREATED_NEW_KEY) + { + ErrorF ("winGetRegistryDWORD - Created new key: %s\n", pszRegistryKey); + } + else if (dwDisposition == REG_OPENED_EXISTING_KEY) + { + ErrorF ("winGetRegistryDWORD - Opened existing key: %s\n", + pszRegistryKey); + } + + /* Free the registry key handle */ + RegCloseKey (hkResult); + hkResult = NULL; + + return 0; +} |