~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.m

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Rootless implementation for Mac OS X Aqua environment
 
3
 */
 
4
/*
 
5
 * Copyright (c) 2001 Greg Parker. All Rights Reserved.
 
6
 * Copyright (c) 2002 Torrey T. Lyons. All Rights Reserved.
 
7
 *
 
8
 * Permission is hereby granted, free of charge, to any person obtaining a
 
9
 * copy of this software and associated documentation files (the "Software"),
 
10
 * to deal in the Software without restriction, including without limitation
 
11
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
12
 * and/or sell copies of the Software, and to permit persons to whom the
 
13
 * Software is furnished to do so, subject to the following conditions:
 
14
 *
 
15
 * The above copyright notice and this permission notice shall be included in
 
16
 * all copies or substantial portions of the Software.
 
17
 *
 
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 
21
 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
22
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
23
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
24
 * DEALINGS IN THE SOFTWARE.
 
25
 *
 
26
 * Except as contained in this notice, the name(s) of the above copyright
 
27
 * holders shall not be used in advertising or otherwise to promote the sale,
 
28
 * use or other dealings in this Software without prior written authorization.
 
29
 */
 
30
/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessAquaImp.m,v 1.6 2003/01/24 00:11:39 torrey Exp $ */
 
31
 
 
32
#include "rootlessAquaImp.h"
 
33
#include "fakeBoxRec.h"
 
34
#include "quartzCommon.h"
 
35
#include "aquaCommon.h"
 
36
#include "pseudoramiX.h"
 
37
#import <Cocoa/Cocoa.h>
 
38
#include <ApplicationServices/ApplicationServices.h>
 
39
#import "XView.h"
 
40
 
 
41
extern void ErrorF(const char *, ...);
 
42
 
 
43
 
 
44
/*
 
45
 * AquaDisplayCount
 
46
 *  Return the number of displays.
 
47
 *  Multihead note: When rootless mode uses PseudoramiX, the
 
48
 *  X server only sees one screen; only PseudoramiX itself knows
 
49
 *  about all of the screens.
 
50
 */
 
51
int AquaDisplayCount()
 
52
{
 
53
    aquaNumScreens = [[NSScreen screens] count];
 
54
 
 
55
    if (noPseudoramiXExtension) {
 
56
        return aquaNumScreens;
 
57
    } else {
 
58
        return 1; // only PseudoramiX knows about the rest
 
59
    }
 
60
}
 
61
 
 
62
 
 
63
void AquaScreenInit(int index, int *x, int *y, int *width, int *height,
 
64
                    int *rowBytes, int *bps, int *spp, int *bpp)
 
65
{
 
66
    *spp = 3;
 
67
    *bps = CGDisplayBitsPerSample(kCGDirectMainDisplay);
 
68
    *bpp = CGDisplayBitsPerPixel(kCGDirectMainDisplay);
 
69
 
 
70
    if (noPseudoramiXExtension) {
 
71
        NSScreen *screen = [[NSScreen screens] objectAtIndex:index];
 
72
        NSRect frame = [screen frame];
 
73
 
 
74
        // set x, y so (0,0) is top left of main screen
 
75
        *x = NSMinX(frame);
 
76
        *y = NSHeight([[NSScreen mainScreen] frame]) - NSHeight(frame) -
 
77
            NSMinY(frame);
 
78
 
 
79
        *width =  NSWidth(frame);
 
80
        *height = NSHeight(frame);
 
81
        *rowBytes = (*width) * (*bpp) / 8;
 
82
 
 
83
        // Shift the usable part of main screen down to avoid the menu bar.
 
84
        if (NSEqualRects(frame, [[NSScreen mainScreen] frame])) {
 
85
            *y      += aquaMenuBarHeight;
 
86
            *height -= aquaMenuBarHeight;
 
87
        }
 
88
 
 
89
    } else {
 
90
        int i;
 
91
        NSRect unionRect = NSMakeRect(0, 0, 0, 0);
 
92
        NSArray *screens = [NSScreen screens];
 
93
 
 
94
        // Get the union of all screens (minus the menu bar on main screen)
 
95
        for (i = 0; i < [screens count]; i++) {
 
96
            NSScreen *screen = [screens objectAtIndex:i];
 
97
            NSRect frame = [screen frame];
 
98
            frame.origin.y = [[NSScreen mainScreen] frame].size.height -
 
99
                             frame.size.height - frame.origin.y;
 
100
            if (NSEqualRects([screen frame], [[NSScreen mainScreen] frame])) {
 
101
                frame.origin.y    += aquaMenuBarHeight;
 
102
                frame.size.height -= aquaMenuBarHeight;
 
103
            }
 
104
            unionRect = NSUnionRect(unionRect, frame);
 
105
        }
 
106
 
 
107
        // Use unionRect as the screen size for the X server.
 
108
        *x = unionRect.origin.x;
 
109
        *y = unionRect.origin.y;
 
110
        *width = unionRect.size.width;
 
111
        *height = unionRect.size.height;
 
112
        *rowBytes = (*width) * (*bpp) / 8;
 
113
 
 
114
        // Tell PseudoramiX about the real screens.
 
115
        // InitOutput() will move the big screen to (0,0),
 
116
        // so compensate for that here.
 
117
        for (i = 0; i < [screens count]; i++) {
 
118
            NSScreen *screen = [screens objectAtIndex:i];
 
119
            NSRect frame = [screen frame];
 
120
            int j;
 
121
 
 
122
            // Skip this screen if it's a mirrored copy of an earlier screen.
 
123
            for (j = 0; j < i; j++) {
 
124
                if (NSEqualRects(frame, [[screens objectAtIndex:j] frame])) {
 
125
                    ErrorF("PseudoramiX screen %d is a mirror of screen %d.\n",
 
126
                           i, j);
 
127
                    break;
 
128
                }
 
129
            }
 
130
            if (j < i) continue; // this screen is a mirrored copy
 
131
 
 
132
            frame.origin.y = [[NSScreen mainScreen] frame].size.height -
 
133
                             frame.size.height - frame.origin.y;
 
134
 
 
135
            if (NSEqualRects([screen frame], [[NSScreen mainScreen] frame])) {
 
136
                frame.origin.y    += aquaMenuBarHeight;
 
137
                frame.size.height -= aquaMenuBarHeight;
 
138
            }
 
139
 
 
140
            ErrorF("PseudoramiX screen %d added: %dx%d @ (%d,%d).\n", i,
 
141
                   (int)frame.size.width, (int)frame.size.height,
 
142
                   (int)frame.origin.x, (int)frame.origin.y);
 
143
 
 
144
            frame.origin.x -= unionRect.origin.x;
 
145
            frame.origin.y -= unionRect.origin.y;
 
146
 
 
147
            ErrorF("PseudoramiX screen %d placed at X11 coordinate (%d,%d).\n",
 
148
                   i, (int)frame.origin.x, (int)frame.origin.y);
 
149
 
 
150
            PseudoramiXAddScreen(frame.origin.x, frame.origin.y,
 
151
                                 frame.size.width, frame.size.height);
 
152
        }
 
153
    }
 
154
}
 
155
 
 
156
 
 
157
/*
 
158
 * AquaNewWindow
 
159
 *  Create a new on-screen window.
 
160
 *  Rootless windows must not autodisplay! Autodisplay can cause a deadlock.
 
161
 *    Event thread - autodisplay: locks view hierarchy, then window
 
162
 *    X Server thread - window resize: locks window, then view hierarchy
 
163
 *  Deadlock occurs if each thread gets one lock and waits for the other.
 
164
*/
 
165
void *AquaNewWindow(void *upperw, int x, int y, int w, int h, int isRoot)
 
166
{
 
167
    AquaWindowRec *winRec = (AquaWindowRec *)malloc(sizeof(AquaWindowRec));
 
168
    NSRect frame = NSMakeRect(x, NSHeight([[NSScreen mainScreen] frame]) -
 
169
                              y - h, w, h);
 
170
    NSWindow *theWindow;
 
171
    XView *theView;
 
172
 
 
173
    // Create an NSWindow for the new X11 window
 
174
    theWindow = [[NSWindow alloc] initWithContentRect:frame
 
175
                                  styleMask:NSBorderlessWindowMask
 
176
                                  backing:NSBackingStoreBuffered
 
177
                                  defer:YES];
 
178
    if (!theWindow) return NULL;
 
179
 
 
180
    [theWindow setBackgroundColor:[NSColor clearColor]];  // erase transparent
 
181
    [theWindow setAlphaValue:1.0];       // draw opaque
 
182
    [theWindow setOpaque:YES];           // changed when window is shaped
 
183
 
 
184
    [theWindow useOptimizedDrawing:YES]; // Has no overlapping sub-views
 
185
    [theWindow setAutodisplay:NO];       // See comment above
 
186
    [theWindow disableFlushWindow];      // We do all the flushing manually
 
187
    [theWindow setHasShadow:!isRoot];    // All windows have shadows except root
 
188
    [theWindow setReleasedWhenClosed:YES]; // Default, but we want to be sure
 
189
 
 
190
    theView = [[XView alloc] initWithFrame:frame];
 
191
    [theWindow setContentView:theView];
 
192
    [theWindow setInitialFirstResponder:theView];
 
193
 
 
194
    if (upperw) {
 
195
        AquaWindowRec *upperRec = AQUA_WINREC(upperw);
 
196
        int uppernum = [upperRec->window windowNumber];
 
197
        [theWindow orderWindow:NSWindowBelow relativeTo:uppernum];
 
198
    } else {
 
199
        if (!isRoot) {
 
200
            [theWindow orderFront:nil];
 
201
            winRec->port = NULL;
 
202
        }
 
203
    }
 
204
 
 
205
    [theWindow setAcceptsMouseMovedEvents:YES];
 
206
 
 
207
    winRec->window = theWindow;
 
208
    winRec->view = theView;
 
209
 
 
210
    if (!isRoot) {
 
211
        winRec->rootGWorld = NULL;
 
212
        [theView lockFocus];
 
213
        // Fill the window with white to make sure alpha channel is set
 
214
        NSEraseRect(frame);
 
215
        winRec->port = [theView qdPort];
 
216
        winRec->context = [[NSGraphicsContext currentContext] graphicsPort];
 
217
        // CreateCGContextForPort(winRec->port, &winRec->context);
 
218
        [theView unlockFocus];
 
219
    } else {
 
220
        // Allocate the offscreen graphics world for root window drawing
 
221
        GWorldPtr rootGWorld;
 
222
        Rect globalRect;
 
223
 
 
224
        SetRect(&globalRect, x, y, x+w, y+h);
 
225
        if (NewGWorld(&rootGWorld, 0, &globalRect, NULL, NULL, 0))
 
226
            return NULL;
 
227
        winRec->rootGWorld = rootGWorld;
 
228
    }
 
229
 
 
230
    return winRec;
 
231
}
 
232
 
 
233
 
 
234
void AquaDestroyWindow(void *rw)
 
235
{
 
236
    AquaWindowRec *winRec = AQUA_WINREC(rw);
 
237
 
 
238
    [winRec->window orderOut:nil];
 
239
    [winRec->window close];
 
240
    [winRec->view release];
 
241
    if (winRec->rootGWorld) {
 
242
        DisposeGWorld(winRec->rootGWorld);
 
243
    }
 
244
    free(rw);
 
245
}
 
246
 
 
247
 
 
248
void AquaMoveWindow(void *rw, int x, int y)
 
249
{
 
250
    AquaWindowRec *winRec = AQUA_WINREC(rw);
 
251
    NSPoint topLeft = NSMakePoint(x, NSHeight([[NSScreen mainScreen] frame]) -
 
252
                                  y);
 
253
 
 
254
    [winRec->window setFrameTopLeftPoint:topLeft];
 
255
}
 
256
 
 
257
 
 
258
/*
 
259
 * AquaStartResizeWindow
 
260
 *  Resize the on screen window.
 
261
 */
 
262
void AquaStartResizeWindow(void *rw, int x, int y, int w, int h)
 
263
{
 
264
    AquaWindowRec *winRec = AQUA_WINREC(rw);
 
265
    NSRect frame = NSMakeRect(x, NSHeight([[NSScreen mainScreen] frame]) -
 
266
                              y - h, w, h);
 
267
 
 
268
    [winRec->window setFrame:frame display:NO];
 
269
}
 
270
 
 
271
 
 
272
void AquaFinishResizeWindow(void *rw, int x, int y, int w, int h)
 
273
{
 
274
    // refresh everything? fixme yes for testing
 
275
    fakeBoxRec box = {0, 0, w, h};
 
276
    AquaUpdateRects(rw, &box, 1);
 
277
}
 
278
 
 
279
 
 
280
/*
 
281
 * AquaUpdateRects
 
282
 *  Flush rectangular regions from a window's backing buffer
 
283
 *  (or PixMap for the root window) to the screen.
 
284
 */
 
285
void AquaUpdateRects(void *rw, fakeBoxRec *fakeRects, int count)
 
286
{
 
287
    AquaWindowRec *winRec = AQUA_WINREC(rw);
 
288
    fakeBoxRec *rects, *end;
 
289
    static RgnHandle rgn = NULL;
 
290
    static RgnHandle box = NULL;
 
291
 
 
292
    if (!rgn) rgn = NewRgn();
 
293
    if (!box) box = NewRgn();
 
294
 
 
295
    if (winRec->rootGWorld) {
 
296
        // FIXME: Draw from the root PixMap to the normally
 
297
        // invisible root window.
 
298
    } else {
 
299
        for (rects = fakeRects, end = fakeRects+count; rects < end; rects++) {
 
300
            Rect qdrect;
 
301
            qdrect.left = rects->x1;
 
302
            qdrect.top = rects->y1;
 
303
            qdrect.right = rects->x2;
 
304
            qdrect.bottom = rects->y2;
 
305
 
 
306
            RectRgn(box, &qdrect);
 
307
            UnionRgn(rgn, box, rgn);
 
308
        }
 
309
 
 
310
        QDFlushPortBuffer(winRec->port, rgn);
 
311
    }
 
312
 
 
313
    SetEmptyRgn(rgn);
 
314
    SetEmptyRgn(box);
 
315
}
 
316
 
 
317
 
 
318
/*
 
319
 * AquaRestackWindow
 
320
 *  Change the window order. Put the window behind upperw or on top if
 
321
 *  upperw is NULL.
 
322
 */
 
323
void AquaRestackWindow(void *rw, void *upperw)
 
324
{
 
325
    AquaWindowRec *winRec = AQUA_WINREC(rw);
 
326
 
 
327
    if (upperw) {
 
328
        AquaWindowRec *upperRec = AQUA_WINREC(upperw);
 
329
        int uppernum = [upperRec->window windowNumber];
 
330
        [winRec->window orderWindow:NSWindowBelow relativeTo:uppernum];
 
331
    } else {
 
332
        [winRec->window makeKeyAndOrderFront:nil];
 
333
    }
 
334
}
 
335
 
 
336
 
 
337
/*
 
338
 * AquaReshapeWindow
 
339
 *  Set the shape of a window. The rectangles are the areas that are
 
340
 *  not part of the new shape.
 
341
 */
 
342
void AquaReshapeWindow(void *rw, fakeBoxRec *fakeRects, int count)
 
343
{
 
344
    AquaWindowRec *winRec = AQUA_WINREC(rw);
 
345
    NSRect frame = [winRec->view frame];
 
346
    int winHeight = NSHeight(frame);
 
347
 
 
348
    [winRec->view lockFocus];
 
349
 
 
350
    // If window is currently shaped we need to undo the previous shape
 
351
    if (![winRec->window isOpaque]) {
 
352
        [[NSColor whiteColor] set];
 
353
        NSRectFillUsingOperation(frame, NSCompositeDestinationAtop);
 
354
    }
 
355
 
 
356
    if (count > 0) {
 
357
        fakeBoxRec *rects, *end;
 
358
 
 
359
        // Make transparent if window is now shaped.
 
360
        [winRec->window setOpaque:NO];
 
361
 
 
362
        // Clear the areas outside the window shape
 
363
        [[NSColor clearColor] set];
 
364
        for (rects = fakeRects, end = fakeRects+count; rects < end; rects++) {
 
365
            int rectHeight = rects->y2 - rects->y1;
 
366
            NSRectFill( NSMakeRect(rects->x1,
 
367
                                   winHeight - rects->y1 - rectHeight,
 
368
                                   rects->x2 - rects->x1, rectHeight) );
 
369
        }
 
370
        [[NSGraphicsContext currentContext] flushGraphics];
 
371
 
 
372
        // force update of window shadow
 
373
        [winRec->window setHasShadow:NO];
 
374
        [winRec->window setHasShadow:YES];
 
375
 
 
376
    } else {
 
377
        fakeBoxRec bounds = {0, 0, NSWidth(frame), winHeight};
 
378
 
 
379
        [winRec->window setOpaque:YES];
 
380
        AquaUpdateRects(rw, &bounds, 1);
 
381
    }
 
382
 
 
383
    [winRec->view unlockFocus];
 
384
}
 
385
 
 
386
 
 
387
/* AquaStartDrawing
 
388
 *  When a window's buffer is not being drawn to, the CoreGraphics
 
389
 *  window server may compress or move it. Call this routine
 
390
 *  to lock down the buffer during direct drawing. It returns
 
391
 *  a pointer to the backing buffer and its depth, etc.
 
392
 */
 
393
void AquaStartDrawing(void *rw, char **bits,
 
394
                      int *rowBytes, int *depth, int *bpp)
 
395
{
 
396
    AquaWindowRec *winRec = AQUA_WINREC(rw);
 
397
    PixMapHandle pix;
 
398
 
 
399
    if (! winRec->rootGWorld) {
 
400
        [winRec->view lockFocus];
 
401
        winRec->port = [winRec->view qdPort];
 
402
        LockPortBits(winRec->port);
 
403
        [winRec->view unlockFocus];
 
404
        pix = GetPortPixMap(winRec->port);
 
405
    } else {
 
406
        pix = GetGWorldPixMap(winRec->rootGWorld);
 
407
        LockPixels(pix);
 
408
    }
 
409
 
 
410
    *bits = GetPixBaseAddr(pix);
 
411
    *rowBytes = GetPixRowBytes(pix) & 0x3fff; // fixme is mask needed?
 
412
    *depth = (**pix).cmpCount * (**pix).cmpSize; // fixme use GetPixDepth(pix)?
 
413
    *bpp = (**pix).pixelSize;
 
414
}
 
415
 
 
416
 
 
417
/*
 
418
 * AquaStopDrawing
 
419
 *  When direct access to a window's buffer is no longer needed, this
 
420
 *  routine should be called to allow CoreGraphics to compress or
 
421
 *  move it.
 
422
 */
 
423
void AquaStopDrawing(void *rw)
 
424
{
 
425
    AquaWindowRec *winRec = AQUA_WINREC(rw);
 
426
 
 
427
    if (! winRec->rootGWorld) {
 
428
        UnlockPortBits(winRec->port);
 
429
    } else {
 
430
        PixMapHandle pix = GetGWorldPixMap(winRec->rootGWorld);
 
431
        UnlockPixels(pix);
 
432
    }
 
433
}