diff options
Diffstat (limited to 'xorg-server/hw/xquartz')
32 files changed, 4318 insertions, 4483 deletions
diff --git a/xorg-server/hw/xquartz/GL/capabilities.c b/xorg-server/hw/xquartz/GL/capabilities.c index fc7dd57dd..da52cc7c4 100644 --- a/xorg-server/hw/xquartz/GL/capabilities.c +++ b/xorg-server/hw/xquartz/GL/capabilities.c @@ -1,543 +1,543 @@ -/* - * Copyright (c) 2008 Apple Inc. - * - * 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#include <OpenGL/OpenGL.h> -#include <OpenGL/gl.h> -#include <OpenGL/glu.h> -#include <OpenGL/glext.h> -#include <ApplicationServices/ApplicationServices.h> - -#include "capabilities.h" - -#define Cursor X_Cursor -#include "os.h" -#undef Cursor - -static void handleBufferModes(struct glCapabilitiesConfig *c, GLint bufferModes) { - if(bufferModes & kCGLStereoscopicBit) { - c->stereo = true; - } - - if(bufferModes & kCGLDoubleBufferBit) { - c->buffers = 2; - } else { - c->buffers = 1; - } -} - -static void handleStencilModes(struct glCapabilitiesConfig *c, GLint smodes) { - int offset = 0; - - if(kCGL0Bit & smodes) - c->stencil_bit_depths[offset++] = 0; - - if(kCGL1Bit & smodes) - c->stencil_bit_depths[offset++] = 1; - - if(kCGL2Bit & smodes) - c->stencil_bit_depths[offset++] = 2; - - if(kCGL3Bit & smodes) - c->stencil_bit_depths[offset++] = 3; - - if(kCGL4Bit & smodes) - c->stencil_bit_depths[offset++] = 4; - - if(kCGL5Bit & smodes) - c->stencil_bit_depths[offset++] = 5; - - if(kCGL6Bit & smodes) - c->stencil_bit_depths[offset++] = 6; - - if(kCGL8Bit & smodes) - c->stencil_bit_depths[offset++] = 8; - - if(kCGL10Bit & smodes) - c->stencil_bit_depths[offset++] = 10; - - if(kCGL12Bit & smodes) - c->stencil_bit_depths[offset++] = 12; - - if(kCGL16Bit & smodes) - c->stencil_bit_depths[offset++] = 16; - - if(kCGL24Bit & smodes) - c->stencil_bit_depths[offset++] = 24; - - if(kCGL32Bit & smodes) - c->stencil_bit_depths[offset++] = 32; - - if(kCGL48Bit & smodes) - c->stencil_bit_depths[offset++] = 48; - - if(kCGL64Bit & smodes) - c->stencil_bit_depths[offset++] = 64; - - if(kCGL96Bit & smodes) - c->stencil_bit_depths[offset++] = 96; - - if(kCGL128Bit & smodes) - c->stencil_bit_depths[offset++] = 128; - - assert(offset < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS); - - c->total_stencil_bit_depths = offset; -} - -static int handleColorAndAccumulation(struct glColorBufCapabilities *c, - GLint cmodes, int forAccum) { - int offset = 0; - - /*1*/ - if(kCGLRGB444Bit & cmodes) { - c[offset].r = 4; - c[offset].g = 4; - c[offset].b = 4; - ++offset; - } - - /*2*/ - if(kCGLARGB4444Bit & cmodes) { - c[offset].a = 4; - c[offset].r = 4; - c[offset].g = 4; - c[offset].b = 4; - c[offset].is_argb = true; - ++offset; - } - - /*3*/ - if(kCGLRGB444A8Bit & cmodes) { - c[offset].r = 4; - c[offset].g = 4; - c[offset].b = 4; - c[offset].a = 8; - ++offset; - } - - /*4*/ - if(kCGLRGB555Bit & cmodes) { - c[offset].r = 5; - c[offset].g = 5; - c[offset].b = 5; - ++offset; - } - - /*5*/ - if(kCGLARGB1555Bit & cmodes) { - c[offset].a = 1; - c[offset].r = 5; - c[offset].g = 5; - c[offset].b = 5; - c[offset].is_argb = true; - ++offset; - } - - /*6*/ - if(kCGLRGB555A8Bit & cmodes) { - c[offset].r = 5; - c[offset].g = 5; - c[offset].b = 5; - c[offset].a = 8; - ++offset; - } - - /*7*/ - if(kCGLRGB565Bit & cmodes) { - c[offset].r = 5; - c[offset].g = 6; - c[offset].b = 5; - ++offset; - } - - /*8*/ - if(kCGLRGB565A8Bit & cmodes) { - c[offset].r = 5; - c[offset].g = 6; - c[offset].b = 5; - c[offset].a = 8; - ++offset; - } - - /*9*/ - if(kCGLRGB888Bit & cmodes) { - c[offset].r = 8; - c[offset].g = 8; - c[offset].b = 8; - ++offset; - } - - /*10*/ - if(kCGLARGB8888Bit & cmodes) { - c[offset].a = 8; - c[offset].r = 8; - c[offset].g = 8; - c[offset].b = 8; - c[offset].is_argb = true; - ++offset; - } - - /*11*/ - if(kCGLRGB888A8Bit & cmodes) { - c[offset].r = 8; - c[offset].g = 8; - c[offset].b = 8; - c[offset].a = 8; - ++offset; - } - - if(forAccum) { -//#if 0 - /* FIXME - * Disable this path, because some part of libGL, X, or Xplugin - * doesn't work with sizes greater than 8. - * When this is enabled and visuals are chosen using depths - * such as 16, the result is that the windows don't redraw - * and are often white, until a resize. - */ - - /*12*/ - if(kCGLRGB101010Bit & cmodes) { - c[offset].r = 10; - c[offset].g = 10; - c[offset].b = 10; - ++offset; - } - - /*13*/ - if(kCGLARGB2101010Bit & cmodes) { - c[offset].a = 2; - c[offset].r = 10; - c[offset].g = 10; - c[offset].b = 10; - c[offset].is_argb = true; - ++offset; - } - - /*14*/ - if(kCGLRGB101010_A8Bit & cmodes) { - c[offset].r = 10; - c[offset].g = 10; - c[offset].b = 10; - c[offset].a = 8; - ++offset; - } - - /*15*/ - if(kCGLRGB121212Bit & cmodes) { - c[offset].r = 12; - c[offset].g = 12; - c[offset].b = 12; - ++offset; - } - - /*16*/ - if(kCGLARGB12121212Bit & cmodes) { - c[offset].a = 12; - c[offset].r = 12; - c[offset].g = 12; - c[offset].b = 12; - c[offset].is_argb = true; - ++offset; - } - - /*17*/ - if(kCGLRGB161616Bit & cmodes) { - c[offset].r = 16; - c[offset].g = 16; - c[offset].b = 16; - ++offset; - } - - /*18*/ - if(kCGLRGBA16161616Bit & cmodes) { - c[offset].r = 16; - c[offset].g = 16; - c[offset].b = 16; - c[offset].a = 16; - ++offset; - } - } -//#endif - - /* FIXME should we handle the floating point color modes, and if so, how? */ - - return offset; -} - - -static void handleColorModes(struct glCapabilitiesConfig *c, GLint cmodes) { - c->total_color_buffers = handleColorAndAccumulation(c->color_buffers, - cmodes, 0); - - assert(c->total_color_buffers < GLCAPS_COLOR_BUFFERS); -} - -static void handleAccumulationModes(struct glCapabilitiesConfig *c, GLint cmodes) { - c->total_accum_buffers = handleColorAndAccumulation(c->accum_buffers, - cmodes, 1); - assert(c->total_accum_buffers < GLCAPS_COLOR_BUFFERS); -} - -static void handleDepthModes(struct glCapabilitiesConfig *c, GLint dmodes) { - int offset = 0; -#define DEPTH(flag,value) do { \ - if(dmodes & flag) { \ - c->depth_buffers[offset++] = value; \ - } \ - } while(0) - - /*1*/ - DEPTH(kCGL0Bit, 0); - /*2*/ - DEPTH(kCGL1Bit, 1); - /*3*/ - DEPTH(kCGL2Bit, 2); - /*4*/ - DEPTH(kCGL3Bit, 3); - /*5*/ - DEPTH(kCGL4Bit, 4); - /*6*/ - DEPTH(kCGL5Bit, 5); - /*7*/ - DEPTH(kCGL6Bit, 6); - /*8*/ - DEPTH(kCGL8Bit, 8); - /*9*/ - DEPTH(kCGL10Bit, 10); - /*10*/ - DEPTH(kCGL12Bit, 12); - /*11*/ - DEPTH(kCGL16Bit, 16); - /*12*/ - DEPTH(kCGL24Bit, 24); - /*13*/ - DEPTH(kCGL32Bit, 32); - /*14*/ - DEPTH(kCGL48Bit, 48); - /*15*/ - DEPTH(kCGL64Bit, 64); - /*16*/ - DEPTH(kCGL96Bit, 96); - /*17*/ - DEPTH(kCGL128Bit, 128); - -#undef DEPTH - - c->total_depth_buffer_depths = offset; - assert(c->total_depth_buffer_depths < GLCAPS_DEPTH_BUFFERS); -} - -/* Return non-zero if an error occured. */ -static CGLError handleRendererDescriptions(CGLRendererInfoObj info, GLint r, - struct glCapabilitiesConfig *c) { - CGLError err; - GLint accelerated = 0, flags = 0, aux = 0, samplebufs = 0, samples = 0; - - err = CGLDescribeRenderer (info, r, kCGLRPAccelerated, &accelerated); - - if(err) - return err; - - c->accelerated = accelerated; - - /* Buffering modes: single/double, stereo */ - err = CGLDescribeRenderer(info, r, kCGLRPBufferModes, &flags); - - if(err) - return err; - - handleBufferModes(c, flags); - - /* AUX buffers */ - err = CGLDescribeRenderer(info, r, kCGLRPMaxAuxBuffers, &aux); - - if(err) - return err; - - c->aux_buffers = aux; - - - /* Depth buffer size */ - err = CGLDescribeRenderer(info, r, kCGLRPDepthModes, &flags); - - if(err) - return err; - - handleDepthModes(c, flags); - - - /* Multisample buffers */ - err = CGLDescribeRenderer(info, r, kCGLRPMaxSampleBuffers, &samplebufs); - - if(err) - return err; - - c->multisample_buffers = samplebufs; - - - /* Multisample samples per multisample buffer */ - err = CGLDescribeRenderer(info, r, kCGLRPMaxSamples, &samples); - - if(err) - return err; - - c->multisample_samples = samples; - - - /* Stencil bit depths */ - err = CGLDescribeRenderer(info, r, kCGLRPStencilModes, &flags); - - if(err) - return err; - - handleStencilModes(c, flags); - - - /* Color modes (RGB/RGBA depths supported */ - err = CGLDescribeRenderer(info, r, kCGLRPColorModes, &flags); - - if(err) - return err; - - handleColorModes(c, flags); - - err = CGLDescribeRenderer(info, r, kCGLRPAccumModes, &flags); - - if(err) - return err; - - handleAccumulationModes(c, flags); - - return kCGLNoError; -} - -static void initCapabilities(struct glCapabilities *cap) { - cap->configurations = NULL; - cap->total_configurations = 0; -} - -static void initConfig(struct glCapabilitiesConfig *c) { - int i; - - c->accelerated = false; - c->stereo = false; - c->aux_buffers = 0; - c->buffers = 0; - - c->total_depth_buffer_depths = 0; - - for(i = 0; i < GLCAPS_DEPTH_BUFFERS; ++i) { - c->depth_buffers[i] = GLCAPS_INVALID_DEPTH_VALUE; - } - - c->multisample_buffers = 0; - c->multisample_samples = 0; - - c->total_stencil_bit_depths = 0; - - for(i = 0; i < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS; ++i) { - c->stencil_bit_depths[i] = GLCAPS_INVALID_STENCIL_DEPTH; - } - - c->total_color_buffers = 0; - - for(i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) { - c->color_buffers[i].r = c->color_buffers[i].g = - c->color_buffers[i].b = c->color_buffers[i].a = - GLCAPS_COLOR_BUF_INVALID_VALUE; - c->color_buffers[i].is_argb = false; - } - - c->total_accum_buffers = 0; - - for(i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) { - c->accum_buffers[i].r = c->accum_buffers[i].g = - c->accum_buffers[i].b = c->accum_buffers[i].a = - GLCAPS_COLOR_BUF_INVALID_VALUE; - c->accum_buffers[i].is_argb = false; - } - - c->next = NULL; -} - -void freeGlCapabilities(struct glCapabilities *cap) { - struct glCapabilitiesConfig *conf, *next; - - conf = cap->configurations; - - while(conf) { - next = conf->next; - free(conf); - conf = next; - } - - cap->configurations = NULL; -} - -/*Return true if an error occured. */ -bool getGlCapabilities(struct glCapabilities *cap) { - CGLRendererInfoObj info; - CGLError err; - GLint numRenderers = 0, r; - - initCapabilities(cap); - - err = CGLQueryRendererInfo((GLuint)-1, &info, &numRenderers); - if(err) { - fprintf(stderr, "CGLQueryRendererInfo error: %s\n", CGLErrorString(err)); - return err; - } - - for(r = 0; r < numRenderers; r++) { - struct glCapabilitiesConfig tmpconf, *conf; - - initConfig(&tmpconf); - - err = handleRendererDescriptions(info, r, &tmpconf); - if(err) { - fprintf(stderr, "handleRendererDescriptions returned error: %s\n", CGLErrorString(err)); - fprintf(stderr, "trying to continue...\n"); - continue; - } - - conf = malloc(sizeof(*conf)); - if(NULL == conf) { - FatalError("Unable to allocate memory for OpenGL capabilities\n"); - } - - /* Copy the struct. */ - *conf = tmpconf; - - /* Now link the configuration into the list. */ - conf->next = cap->configurations; - cap->configurations = conf; - } - - CGLDestroyRendererInfo(info); - - /* No error occured. We are done. */ - return kCGLNoError; -} +/*
+ * Copyright (c) 2008 Apple Inc.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#include <OpenGL/glext.h>
+#include <ApplicationServices/ApplicationServices.h>
+
+#include "capabilities.h"
+
+#define Cursor X_Cursor
+#include "os.h"
+#undef Cursor
+
+static void handleBufferModes(struct glCapabilitiesConfig *c, GLint bufferModes) {
+ if(bufferModes & kCGLStereoscopicBit) {
+ c->stereo = true;
+ }
+
+ if(bufferModes & kCGLDoubleBufferBit) {
+ c->buffers = 2;
+ } else {
+ c->buffers = 1;
+ }
+}
+
+static void handleStencilModes(struct glCapabilitiesConfig *c, GLint smodes) {
+ int offset = 0;
+
+ if(kCGL0Bit & smodes)
+ c->stencil_bit_depths[offset++] = 0;
+
+ if(kCGL1Bit & smodes)
+ c->stencil_bit_depths[offset++] = 1;
+
+ if(kCGL2Bit & smodes)
+ c->stencil_bit_depths[offset++] = 2;
+
+ if(kCGL3Bit & smodes)
+ c->stencil_bit_depths[offset++] = 3;
+
+ if(kCGL4Bit & smodes)
+ c->stencil_bit_depths[offset++] = 4;
+
+ if(kCGL5Bit & smodes)
+ c->stencil_bit_depths[offset++] = 5;
+
+ if(kCGL6Bit & smodes)
+ c->stencil_bit_depths[offset++] = 6;
+
+ if(kCGL8Bit & smodes)
+ c->stencil_bit_depths[offset++] = 8;
+
+ if(kCGL10Bit & smodes)
+ c->stencil_bit_depths[offset++] = 10;
+
+ if(kCGL12Bit & smodes)
+ c->stencil_bit_depths[offset++] = 12;
+
+ if(kCGL16Bit & smodes)
+ c->stencil_bit_depths[offset++] = 16;
+
+ if(kCGL24Bit & smodes)
+ c->stencil_bit_depths[offset++] = 24;
+
+ if(kCGL32Bit & smodes)
+ c->stencil_bit_depths[offset++] = 32;
+
+ if(kCGL48Bit & smodes)
+ c->stencil_bit_depths[offset++] = 48;
+
+ if(kCGL64Bit & smodes)
+ c->stencil_bit_depths[offset++] = 64;
+
+ if(kCGL96Bit & smodes)
+ c->stencil_bit_depths[offset++] = 96;
+
+ if(kCGL128Bit & smodes)
+ c->stencil_bit_depths[offset++] = 128;
+
+ assert(offset < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS);
+
+ c->total_stencil_bit_depths = offset;
+}
+
+static int handleColorAndAccumulation(struct glColorBufCapabilities *c,
+ GLint cmodes, int forAccum) {
+ int offset = 0;
+
+ /*1*/
+ if(kCGLRGB444Bit & cmodes) {
+ c[offset].r = 4;
+ c[offset].g = 4;
+ c[offset].b = 4;
+ ++offset;
+ }
+
+ /*2*/
+ if(kCGLARGB4444Bit & cmodes) {
+ c[offset].a = 4;
+ c[offset].r = 4;
+ c[offset].g = 4;
+ c[offset].b = 4;
+ c[offset].is_argb = true;
+ ++offset;
+ }
+
+ /*3*/
+ if(kCGLRGB444A8Bit & cmodes) {
+ c[offset].r = 4;
+ c[offset].g = 4;
+ c[offset].b = 4;
+ c[offset].a = 8;
+ ++offset;
+ }
+
+ /*4*/
+ if(kCGLRGB555Bit & cmodes) {
+ c[offset].r = 5;
+ c[offset].g = 5;
+ c[offset].b = 5;
+ ++offset;
+ }
+
+ /*5*/
+ if(kCGLARGB1555Bit & cmodes) {
+ c[offset].a = 1;
+ c[offset].r = 5;
+ c[offset].g = 5;
+ c[offset].b = 5;
+ c[offset].is_argb = true;
+ ++offset;
+ }
+
+ /*6*/
+ if(kCGLRGB555A8Bit & cmodes) {
+ c[offset].r = 5;
+ c[offset].g = 5;
+ c[offset].b = 5;
+ c[offset].a = 8;
+ ++offset;
+ }
+
+ /*7*/
+ if(kCGLRGB565Bit & cmodes) {
+ c[offset].r = 5;
+ c[offset].g = 6;
+ c[offset].b = 5;
+ ++offset;
+ }
+
+ /*8*/
+ if(kCGLRGB565A8Bit & cmodes) {
+ c[offset].r = 5;
+ c[offset].g = 6;
+ c[offset].b = 5;
+ c[offset].a = 8;
+ ++offset;
+ }
+
+ /*9*/
+ if(kCGLRGB888Bit & cmodes) {
+ c[offset].r = 8;
+ c[offset].g = 8;
+ c[offset].b = 8;
+ ++offset;
+ }
+
+ /*10*/
+ if(kCGLARGB8888Bit & cmodes) {
+ c[offset].a = 8;
+ c[offset].r = 8;
+ c[offset].g = 8;
+ c[offset].b = 8;
+ c[offset].is_argb = true;
+ ++offset;
+ }
+
+ /*11*/
+ if(kCGLRGB888A8Bit & cmodes) {
+ c[offset].r = 8;
+ c[offset].g = 8;
+ c[offset].b = 8;
+ c[offset].a = 8;
+ ++offset;
+ }
+
+ if(forAccum) {
+//#if 0
+ /* FIXME
+ * Disable this path, because some part of libGL, X, or Xplugin
+ * doesn't work with sizes greater than 8.
+ * When this is enabled and visuals are chosen using depths
+ * such as 16, the result is that the windows don't redraw
+ * and are often white, until a resize.
+ */
+
+ /*12*/
+ if(kCGLRGB101010Bit & cmodes) {
+ c[offset].r = 10;
+ c[offset].g = 10;
+ c[offset].b = 10;
+ ++offset;
+ }
+
+ /*13*/
+ if(kCGLARGB2101010Bit & cmodes) {
+ c[offset].a = 2;
+ c[offset].r = 10;
+ c[offset].g = 10;
+ c[offset].b = 10;
+ c[offset].is_argb = true;
+ ++offset;
+ }
+
+ /*14*/
+ if(kCGLRGB101010_A8Bit & cmodes) {
+ c[offset].r = 10;
+ c[offset].g = 10;
+ c[offset].b = 10;
+ c[offset].a = 8;
+ ++offset;
+ }
+
+ /*15*/
+ if(kCGLRGB121212Bit & cmodes) {
+ c[offset].r = 12;
+ c[offset].g = 12;
+ c[offset].b = 12;
+ ++offset;
+ }
+
+ /*16*/
+ if(kCGLARGB12121212Bit & cmodes) {
+ c[offset].a = 12;
+ c[offset].r = 12;
+ c[offset].g = 12;
+ c[offset].b = 12;
+ c[offset].is_argb = true;
+ ++offset;
+ }
+
+ /*17*/
+ if(kCGLRGB161616Bit & cmodes) {
+ c[offset].r = 16;
+ c[offset].g = 16;
+ c[offset].b = 16;
+ ++offset;
+ }
+
+ /*18*/
+ if(kCGLRGBA16161616Bit & cmodes) {
+ c[offset].r = 16;
+ c[offset].g = 16;
+ c[offset].b = 16;
+ c[offset].a = 16;
+ ++offset;
+ }
+ }
+//#endif
+
+ /* FIXME should we handle the floating point color modes, and if so, how? */
+
+ return offset;
+}
+
+
+static void handleColorModes(struct glCapabilitiesConfig *c, GLint cmodes) {
+ c->total_color_buffers = handleColorAndAccumulation(c->color_buffers,
+ cmodes, 0);
+
+ assert(c->total_color_buffers < GLCAPS_COLOR_BUFFERS);
+}
+
+static void handleAccumulationModes(struct glCapabilitiesConfig *c, GLint cmodes) {
+ c->total_accum_buffers = handleColorAndAccumulation(c->accum_buffers,
+ cmodes, 1);
+ assert(c->total_accum_buffers < GLCAPS_COLOR_BUFFERS);
+}
+
+static void handleDepthModes(struct glCapabilitiesConfig *c, GLint dmodes) {
+ int offset = 0;
+#define DEPTH(flag,value) do { \
+ if(dmodes & flag) { \
+ c->depth_buffers[offset++] = value; \
+ } \
+ } while(0)
+
+ /*1*/
+ DEPTH(kCGL0Bit, 0);
+ /*2*/
+ DEPTH(kCGL1Bit, 1);
+ /*3*/
+ DEPTH(kCGL2Bit, 2);
+ /*4*/
+ DEPTH(kCGL3Bit, 3);
+ /*5*/
+ DEPTH(kCGL4Bit, 4);
+ /*6*/
+ DEPTH(kCGL5Bit, 5);
+ /*7*/
+ DEPTH(kCGL6Bit, 6);
+ /*8*/
+ DEPTH(kCGL8Bit, 8);
+ /*9*/
+ DEPTH(kCGL10Bit, 10);
+ /*10*/
+ DEPTH(kCGL12Bit, 12);
+ /*11*/
+ DEPTH(kCGL16Bit, 16);
+ /*12*/
+ DEPTH(kCGL24Bit, 24);
+ /*13*/
+ DEPTH(kCGL32Bit, 32);
+ /*14*/
+ DEPTH(kCGL48Bit, 48);
+ /*15*/
+ DEPTH(kCGL64Bit, 64);
+ /*16*/
+ DEPTH(kCGL96Bit, 96);
+ /*17*/
+ DEPTH(kCGL128Bit, 128);
+
+#undef DEPTH
+
+ c->total_depth_buffer_depths = offset;
+ assert(c->total_depth_buffer_depths < GLCAPS_DEPTH_BUFFERS);
+}
+
+/* Return non-zero if an error occured. */
+static CGLError handleRendererDescriptions(CGLRendererInfoObj info, GLint r,
+ struct glCapabilitiesConfig *c) {
+ CGLError err;
+ GLint accelerated = 0, flags = 0, aux = 0, samplebufs = 0, samples = 0;
+
+ err = CGLDescribeRenderer (info, r, kCGLRPAccelerated, &accelerated);
+
+ if(err)
+ return err;
+
+ c->accelerated = accelerated;
+
+ /* Buffering modes: single/double, stereo */
+ err = CGLDescribeRenderer(info, r, kCGLRPBufferModes, &flags);
+
+ if(err)
+ return err;
+
+ handleBufferModes(c, flags);
+
+ /* AUX buffers */
+ err = CGLDescribeRenderer(info, r, kCGLRPMaxAuxBuffers, &aux);
+
+ if(err)
+ return err;
+
+ c->aux_buffers = aux;
+
+
+ /* Depth buffer size */
+ err = CGLDescribeRenderer(info, r, kCGLRPDepthModes, &flags);
+
+ if(err)
+ return err;
+
+ handleDepthModes(c, flags);
+
+
+ /* Multisample buffers */
+ err = CGLDescribeRenderer(info, r, kCGLRPMaxSampleBuffers, &samplebufs);
+
+ if(err)
+ return err;
+
+ c->multisample_buffers = samplebufs;
+
+
+ /* Multisample samples per multisample buffer */
+ err = CGLDescribeRenderer(info, r, kCGLRPMaxSamples, &samples);
+
+ if(err)
+ return err;
+
+ c->multisample_samples = samples;
+
+
+ /* Stencil bit depths */
+ err = CGLDescribeRenderer(info, r, kCGLRPStencilModes, &flags);
+
+ if(err)
+ return err;
+
+ handleStencilModes(c, flags);
+
+
+ /* Color modes (RGB/RGBA depths supported */
+ err = CGLDescribeRenderer(info, r, kCGLRPColorModes, &flags);
+
+ if(err)
+ return err;
+
+ handleColorModes(c, flags);
+
+ err = CGLDescribeRenderer(info, r, kCGLRPAccumModes, &flags);
+
+ if(err)
+ return err;
+
+ handleAccumulationModes(c, flags);
+
+ return kCGLNoError;
+}
+
+static void initCapabilities(struct glCapabilities *cap) {
+ cap->configurations = NULL;
+ cap->total_configurations = 0;
+}
+
+static void initConfig(struct glCapabilitiesConfig *c) {
+ int i;
+
+ c->accelerated = false;
+ c->stereo = false;
+ c->aux_buffers = 0;
+ c->buffers = 0;
+
+ c->total_depth_buffer_depths = 0;
+
+ for(i = 0; i < GLCAPS_DEPTH_BUFFERS; ++i) {
+ c->depth_buffers[i] = GLCAPS_INVALID_DEPTH_VALUE;
+ }
+
+ c->multisample_buffers = 0;
+ c->multisample_samples = 0;
+
+ c->total_stencil_bit_depths = 0;
+
+ for(i = 0; i < GLCAPS_STENCIL_BIT_DEPTH_BUFFERS; ++i) {
+ c->stencil_bit_depths[i] = GLCAPS_INVALID_STENCIL_DEPTH;
+ }
+
+ c->total_color_buffers = 0;
+
+ for(i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) {
+ c->color_buffers[i].r = c->color_buffers[i].g =
+ c->color_buffers[i].b = c->color_buffers[i].a =
+ GLCAPS_COLOR_BUF_INVALID_VALUE;
+ c->color_buffers[i].is_argb = false;
+ }
+
+ c->total_accum_buffers = 0;
+
+ for(i = 0; i < GLCAPS_COLOR_BUFFERS; ++i) {
+ c->accum_buffers[i].r = c->accum_buffers[i].g =
+ c->accum_buffers[i].b = c->accum_buffers[i].a =
+ GLCAPS_COLOR_BUF_INVALID_VALUE;
+ c->accum_buffers[i].is_argb = false;
+ }
+
+ c->next = NULL;
+}
+
+void freeGlCapabilities(struct glCapabilities *cap) {
+ struct glCapabilitiesConfig *conf, *next;
+
+ conf = cap->configurations;
+
+ while(conf) {
+ next = conf->next;
+ free(conf);
+ conf = next;
+ }
+
+ cap->configurations = NULL;
+}
+
+/*Return true if an error occured. */
+bool getGlCapabilities(struct glCapabilities *cap) {
+ CGLRendererInfoObj info;
+ CGLError err;
+ GLint numRenderers = 0, r;
+
+ initCapabilities(cap);
+
+ err = CGLQueryRendererInfo((GLuint)-1, &info, &numRenderers);
+ if(err) {
+ ErrorF("CGLQueryRendererInfo error: %s\n", CGLErrorString(err));
+ return err;
+ }
+
+ for(r = 0; r < numRenderers; r++) {
+ struct glCapabilitiesConfig tmpconf, *conf;
+
+ initConfig(&tmpconf);
+
+ err = handleRendererDescriptions(info, r, &tmpconf);
+ if(err) {
+ ErrorF("handleRendererDescriptions returned error: %s\n", CGLErrorString(err));
+ ErrorF("trying to continue...\n");
+ continue;
+ }
+
+ conf = malloc(sizeof(*conf));
+ if(NULL == conf) {
+ FatalError("Unable to allocate memory for OpenGL capabilities\n");
+ }
+
+ /* Copy the struct. */
+ *conf = tmpconf;
+
+ /* Now link the configuration into the list. */
+ conf->next = cap->configurations;
+ cap->configurations = conf;
+ }
+
+ CGLDestroyRendererInfo(info);
+
+ /* No error occured. We are done. */
+ return kCGLNoError;
+}
diff --git a/xorg-server/hw/xquartz/GL/indirect.c b/xorg-server/hw/xquartz/GL/indirect.c index b7ee109ed..e7df57326 100644 --- a/xorg-server/hw/xquartz/GL/indirect.c +++ b/xorg-server/hw/xquartz/GL/indirect.c @@ -139,7 +139,6 @@ #include <glxcontext.h>
#include <glxext.h>
#include <glxutil.h>
-#include <glxscreens.h>
#include <GL/internal/glcore.h>
#include "x-hash.h"
#include "x-list.h"
diff --git a/xorg-server/hw/xquartz/GL/visualConfigs.c b/xorg-server/hw/xquartz/GL/visualConfigs.c index 0d5793262..f78b14a6e 100644 --- a/xorg-server/hw/xquartz/GL/visualConfigs.c +++ b/xorg-server/hw/xquartz/GL/visualConfigs.c @@ -51,7 +51,6 @@ #include <glxcontext.h>
#include <glxext.h>
#include <glxutil.h>
-#include <glxscreens.h>
#include <GL/internal/glcore.h>
#include "capabilities.h"
diff --git a/xorg-server/hw/xquartz/Makefile.am b/xorg-server/hw/xquartz/Makefile.am index 61b04e0e1..4daac9017 100644 --- a/xorg-server/hw/xquartz/Makefile.am +++ b/xorg-server/hw/xquartz/Makefile.am @@ -1,54 +1,52 @@ -noinst_LTLIBRARIES = libXquartz.la -AM_CFLAGS = $(DIX_CFLAGS) -AM_OBJCFLAGS = $(DIX_CFLAGS) -AM_CPPFLAGS = \ - -DBUILD_DATE=\"$(BUILD_DATE)\" \ - -DXSERVER_VERSION=\"$(VERSION)\" \ - -DINXQUARTZ \ - -DUSE_NEW_CLUT \ - -DXFree86Server \ - -I$(top_srcdir)/miext/rootless \ - -DX11LIBDIR=\"$(libdir)\" - -if GLX -GL_DIR = GL -endif - -SUBDIRS = bundle . $(GL_DIR) xpr pbproxy mach-startup man - -DIST_SUBDIRS = bundle . GL xpr pbproxy mach-startup man - -libXquartz_la_SOURCES = \ - $(top_srcdir)/fb/fbcmap_mi.c \ - $(top_srcdir)/mi/miinitext.c \ - X11Application.m \ - X11Controller.m \ - applewm.c \ - darwin.c \ - darwinEvents.c \ - darwinXinput.c \ - keysym2ucs.c \ - pseudoramiX.c \ - quartz.c \ - quartzCocoa.m \ - quartzKeyboard.c \ - quartzStartup.c \ - quartzRandR.c \ - threadSafety.c - -EXTRA_DIST = \ - X11Application.h \ - X11Controller.h \ - applewmExt.h \ - darwin.h \ - darwinfb.h \ - darwinEvents.h \ - keysym2ucs.h \ - pseudoramiX.h \ - quartz.h \ - quartzCommon.h \ - quartzKeyboard.h \ - quartzRandR.h \ - sanitizedCarbon.h \ - sanitizedCocoa.h \ - threadSafety.h +noinst_LTLIBRARIES = libXquartz.la
+AM_CFLAGS = $(DIX_CFLAGS)
+AM_OBJCFLAGS = $(DIX_CFLAGS)
+AM_CPPFLAGS = \
+ -DBUILD_DATE=\"$(BUILD_DATE)\" \
+ -DXSERVER_VERSION=\"$(VERSION)\" \
+ -DINXQUARTZ \
+ -DUSE_NEW_CLUT \
+ -DXFree86Server \
+ -I$(top_srcdir)/miext/rootless \
+ -DX11LIBDIR=\"$(libdir)\"
+
+if GLX
+GL_DIR = GL
+endif
+
+SUBDIRS = bundle . $(GL_DIR) xpr pbproxy mach-startup man
+
+DIST_SUBDIRS = bundle . GL xpr pbproxy mach-startup man
+
+libXquartz_la_SOURCES = \
+ $(top_srcdir)/fb/fbcmap_mi.c \
+ $(top_srcdir)/mi/miinitext.c \
+ X11Application.m \
+ X11Controller.m \
+ applewm.c \
+ darwin.c \
+ darwinEvents.c \
+ darwinXinput.c \
+ keysym2ucs.c \
+ pseudoramiX.c \
+ quartz.c \
+ quartzCocoa.m \
+ quartzKeyboard.c \
+ quartzStartup.c \
+ quartzRandR.c
+
+EXTRA_DIST = \
+ X11Application.h \
+ X11Controller.h \
+ applewmExt.h \
+ darwin.h \
+ darwinfb.h \
+ darwinEvents.h \
+ keysym2ucs.h \
+ pseudoramiX.h \
+ quartz.h \
+ quartzCommon.h \
+ quartzKeyboard.h \
+ quartzRandR.h \
+ sanitizedCarbon.h \
+ sanitizedCocoa.h
diff --git a/xorg-server/hw/xquartz/X11Application.m b/xorg-server/hw/xquartz/X11Application.m index 9c2857228..3d845d914 100644 --- a/xorg-server/hw/xquartz/X11Application.m +++ b/xorg-server/hw/xquartz/X11Application.m @@ -41,7 +41,6 @@ #include "quartz.h"
#include "darwinEvents.h"
#include "quartzKeyboard.h"
-#include "quartz.h"
#include <X11/extensions/applewmconst.h>
#include "micmap.h"
#include "exglobals.h"
@@ -237,8 +236,7 @@ static void message_kit_thread (SEL selector, NSObject *arg) { if ([self isActive]) {
[self deactivate];
- if (!_x_active && quartzProcs->IsX11Window([e window],
- [e windowNumber]))
+ if (!_x_active && quartzProcs->IsX11Window([e windowNumber]))
[self activateX:YES];
}
}
@@ -980,7 +978,7 @@ static inline pthread_t create_thread(void *(*func)(void *), void *arg) { static void *xpbproxy_x_thread(void *args) {
xpbproxy_run();
- fprintf(stderr, "xpbproxy thread is terminating unexpectedly.\n");
+ ErrorF("xpbproxy thread is terminating unexpectedly.\n");
return NULL;
}
@@ -1014,7 +1012,7 @@ void X11ApplicationMain (int argc, char **argv, char **envp) { NSMaxY([[NSScreen mainScreen] visibleFrame]);
#ifdef HAVE_LIBDISPATCH
- eventTranslationQueue = dispatch_queue_create(LAUNCHD_ID_PREFIX".X11.NSEventsToX11EventsQueue", NULL);
+ eventTranslationQueue = dispatch_queue_create(BUNDLE_ID_PREFIX".X11.NSEventsToX11EventsQueue", NULL);
assert(eventTranslationQueue != NULL);
#endif
@@ -1023,15 +1021,15 @@ void X11ApplicationMain (int argc, char **argv, char **envp) { last_key_layout = TISCopyCurrentKeyboardLayoutInputSource();
if(!last_key_layout)
- fprintf(stderr, "X11ApplicationMain: Unable to determine TISCopyCurrentKeyboardLayoutInputSource() at startup.\n");
+ ErrorF("X11ApplicationMain: Unable to determine TISCopyCurrentKeyboardLayoutInputSource() at startup.\n");
#else
KLGetCurrentKeyboardLayout(&last_key_layout);
if(!last_key_layout)
- fprintf(stderr, "X11ApplicationMain: Unable to determine KLGetCurrentKeyboardLayout() at startup.\n");
+ ErrorF("X11ApplicationMain: Unable to determine KLGetCurrentKeyboardLayout() at startup.\n");
#endif
if (!QuartsResyncKeymap(FALSE)) {
- fprintf(stderr, "X11ApplicationMain: Could not build a valid keymap.\n");
+ ErrorF("X11ApplicationMain: Could not build a valid keymap.\n");
}
/* Tell the server thread that it can proceed */
@@ -1372,7 +1370,7 @@ static const char *untrusted_str(NSEvent *e) { #endif
/* Update keyInfo */
if (!QuartsResyncKeymap(TRUE)) {
- fprintf(stderr, "sendX11NSEvent: Could not build a valid keymap.\n");
+ ErrorF("sendX11NSEvent: Could not build a valid keymap.\n");
}
}
}
diff --git a/xorg-server/hw/xquartz/applewmExt.h b/xorg-server/hw/xquartz/applewmExt.h index 5ef8b5496..aae5e9169 100644 --- a/xorg-server/hw/xquartz/applewmExt.h +++ b/xorg-server/hw/xquartz/applewmExt.h @@ -1,88 +1,101 @@ -/* - * External interface for the server's AppleWM support - */ -/************************************************************************** - -Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. -Copyright (c) 2003-2004 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, sub license, 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 (including the -next paragraph) 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 NON-INFRINGEMENT. -IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. - -**************************************************************************/ - -#ifndef _APPLEWMEXT_H_ -#define _APPLEWMEXT_H_ - -#include "window.h" - -typedef int (*DisableUpdateProc)(void); -typedef int (*EnableUpdateProc)(void); -typedef int (*SetWindowLevelProc)(WindowPtr pWin, int level); -typedef int (*FrameGetRectProc)(int type, int class, const BoxRec *outer, - const BoxRec *inner, BoxRec *ret); -typedef int (*FrameHitTestProc)(int class, int x, int y, - const BoxRec *outer, - const BoxRec *inner, int *ret); -typedef int (*FrameDrawProc)(WindowPtr pWin, int class, unsigned int attr, - const BoxRec *outer, const BoxRec *inner, - unsigned int title_len, - const unsigned char *title_bytes); -typedef int (*SendPSNProc)(uint32_t hi, uint32_t lo); -typedef int (*AttachTransientProc)(WindowPtr pWinChild, WindowPtr pWinParent); - -/* - * AppleWM implementation function list - */ -typedef struct _AppleWMProcs { - DisableUpdateProc DisableUpdate; - EnableUpdateProc EnableUpdate; - SetWindowLevelProc SetWindowLevel; - FrameGetRectProc FrameGetRect; - FrameHitTestProc FrameHitTest; - FrameDrawProc FrameDraw; - SendPSNProc SendPSN; - AttachTransientProc AttachTransient; -} AppleWMProcsRec, *AppleWMProcsPtr; - -void AppleWMExtensionInit( - AppleWMProcsPtr procsPtr -); - -void AppleWMSetScreenOrigin( - WindowPtr pWin -); - -Bool AppleWMDoReorderWindow( - WindowPtr pWin -); - -void AppleWMSendEvent( - int /* type */, - unsigned int /* mask */, - int /* which */, - int /* arg */ -); - -unsigned int AppleWMSelectedEvents( - void -); - -#endif /* _APPLEWMEXT_H_ */ +/*
+ * External interface for the server's AppleWM support
+ */
+/**************************************************************************
+
+Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved.
+Copyright (c) 2003-2004 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, sub license, 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 (including the
+next paragraph) 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 NON-INFRINGEMENT.
+IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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.
+
+**************************************************************************/
+
+#ifndef _APPLEWMEXT_H_
+#define _APPLEWMEXT_H_
+
+#include "window.h"
+#include <Xplugin.h>
+
+typedef int (*DisableUpdateProc)(void);
+typedef int (*EnableUpdateProc)(void);
+typedef int (*SetWindowLevelProc)(WindowPtr pWin, int level);
+#if XPLUGIN_VERSION < 4
+typedef int (*FrameGetRectProc)(int type, int class, const BoxRec *outer,
+ const BoxRec *inner, BoxRec *ret);
+typedef int (*FrameHitTestProc)(int class, int x, int y,
+ const BoxRec *outer,
+ const BoxRec *inner, int *ret);
+typedef int (*FrameDrawProc)(WindowPtr pWin, int class, unsigned int attr,
+ const BoxRec *outer, const BoxRec *inner,
+ unsigned int title_len,
+ const unsigned char *title_bytes);
+#else
+typedef int (*FrameGetRectProc)(xp_frame_rect type, xp_frame_class class, const BoxRec *outer,
+ const BoxRec *inner, BoxRec *ret);
+typedef int (*FrameHitTestProc)(xp_frame_class class, int x, int y,
+ const BoxRec *outer,
+ const BoxRec *inner, int *ret);
+typedef int (*FrameDrawProc)(WindowPtr pWin, xp_frame_class class, xp_frame_attr attr,
+ const BoxRec *outer, const BoxRec *inner,
+ unsigned int title_len,
+ const unsigned char *title_bytes);
+#endif
+typedef int (*SendPSNProc)(uint32_t hi, uint32_t lo);
+typedef int (*AttachTransientProc)(WindowPtr pWinChild, WindowPtr pWinParent);
+
+/*
+ * AppleWM implementation function list
+ */
+typedef struct _AppleWMProcs {
+ DisableUpdateProc DisableUpdate;
+ EnableUpdateProc EnableUpdate;
+ SetWindowLevelProc SetWindowLevel;
+ FrameGetRectProc FrameGetRect;
+ FrameHitTestProc FrameHitTest;
+ FrameDrawProc FrameDraw;
+ SendPSNProc SendPSN;
+ AttachTransientProc AttachTransient;
+} AppleWMProcsRec, *AppleWMProcsPtr;
+
+void AppleWMExtensionInit(
+ AppleWMProcsPtr procsPtr
+);
+
+void AppleWMSetScreenOrigin(
+ WindowPtr pWin
+);
+
+Bool AppleWMDoReorderWindow(
+ WindowPtr pWin
+);
+
+void AppleWMSendEvent(
+ int /* type */,
+ unsigned int /* mask */,
+ int /* which */,
+ int /* arg */
+);
+
+unsigned int AppleWMSelectedEvents(
+ void
+);
+
+#endif /* _APPLEWMEXT_H_ */
diff --git a/xorg-server/hw/xquartz/bundle/Info.plist.cpp b/xorg-server/hw/xquartz/bundle/Info.plist.cpp index a2a22ad64..444400674 100644 --- a/xorg-server/hw/xquartz/bundle/Info.plist.cpp +++ b/xorg-server/hw/xquartz/bundle/Info.plist.cpp @@ -7,11 +7,11 @@ <key>CFBundleExecutable</key>
<string>X11</string>
<key>CFBundleGetInfoString</key>
- <string>LAUNCHD_ID_PREFIX.X11</string>
+ <string>BUNDLE_ID_PREFIX.X11</string>
<key>CFBundleIconFile</key>
<string>X11.icns</string>
<key>CFBundleIdentifier</key>
- <string>LAUNCHD_ID_PREFIX.X11</string>
+ <string>BUNDLE_ID_PREFIX.X11</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -19,9 +19,9 @@ <key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>2.6.1</string>
+ <string>2.7.0</string>
<key>CFBundleVersion</key>
- <string>2.6.1</string>
+ <string>2.7.0</string>
<key>CFBundleSignature</key>
<string>x11a</string>
<key>CSResourcesFileMapped</key>
diff --git a/xorg-server/hw/xquartz/bundle/Makefile.am b/xorg-server/hw/xquartz/bundle/Makefile.am index 34598aa6a..a455b147d 100644 --- a/xorg-server/hw/xquartz/bundle/Makefile.am +++ b/xorg-server/hw/xquartz/bundle/Makefile.am @@ -1,7 +1,7 @@ include cpprules.in
CPP_FILES_FLAGS = \
- -DLAUNCHD_ID_PREFIX="$(LAUNCHD_ID_PREFIX)" \
+ -DBUNDLE_ID_PREFIX="$(BUNDLE_ID_PREFIX)" \
-DAPPLE_APPLICATION_NAME="$(APPLE_APPLICATION_NAME)"
if XQUARTZ_SPARKLE
diff --git a/xorg-server/hw/xquartz/darwin.c b/xorg-server/hw/xquartz/darwin.c index cfeacae42..e12d7786b 100644 --- a/xorg-server/hw/xquartz/darwin.c +++ b/xorg-server/hw/xquartz/darwin.c @@ -133,28 +133,12 @@ static PixmapFormatRec formats[] = { };
const int NUMFORMATS = sizeof(formats)/sizeof(formats[0]);
-#ifndef OSNAME
-#define OSNAME " Darwin"
-#endif
-#ifndef OSVENDOR
-#define OSVENDOR ""
-#endif
-#ifndef PRE_RELEASE
-#define PRE_RELEASE XORG_VERSION_SNAP
-#endif
-#ifndef BUILD_DATE
-#define BUILD_DATE ""
-#endif
-#ifndef XORG_RELEASE
-#define XORG_RELEASE "?"
-#endif
-
void
DarwinPrintBanner(void)
{
- // this should change depending on which specific server we are building
ErrorF("Xquartz starting:\n");
- ErrorF("X.Org X Server %s\nBuild Date: %s\n", XSERVER_VERSION, BUILD_DATE );
+ ErrorF("X.Org X Server %s\n", XSERVER_VERSION);
+ ErrorF("Build Date: %s\n", BUILD_DATE );
}
@@ -605,6 +589,13 @@ void OsVendorFatalError( void ) void OsVendorInit(void)
{
if (serverGeneration == 1) {
+ char *lf;
+ char *home = getenv("HOME");
+ assert(home);
+ assert(0 < asprintf(&lf, "%s/Library/Logs/X11.%s.log", home, bundle_id_prefix));
+ LogInit(lf, ".old");
+ free(lf);
+
DarwinPrintBanner();
#ifdef ENABLE_DEBUG_LOG
{
diff --git a/xorg-server/hw/xquartz/darwin.h b/xorg-server/hw/xquartz/darwin.h index ec9d52d97..da53a261d 100644 --- a/xorg-server/hw/xquartz/darwin.h +++ b/xorg-server/hw/xquartz/darwin.h @@ -34,8 +34,6 @@ #include <X11/extensions/XKB.h>
#include <assert.h>
-#include "threadSafety.h"
-
#include "darwinfb.h"
// From darwin.c
@@ -75,12 +73,15 @@ extern int darwinDesiredDepth; extern int darwinMainScreenX;
extern int darwinMainScreenY;
+// bundle-main.c
+extern char *bundle_id_prefix;
+
#define ENABLE_DEBUG_LOG 1
#ifdef ENABLE_DEBUG_LOG
extern FILE *debug_log_fp;
#define DEBUG_LOG_NAME "x11-debug.txt"
-#define DEBUG_LOG(msg, args...) if (debug_log_fp) fprintf(debug_log_fp, "%s:%s:%s:%d " msg, threadSafetyID(pthread_self()), __FILE__, __FUNCTION__, __LINE__, ##args ); fflush(debug_log_fp);
+#define DEBUG_LOG(msg, args...) if (debug_log_fp) fprintf(debug_log_fp, "%s:%s:%d " msg, __FILE__, __FUNCTION__, __LINE__, ##args ); fflush(debug_log_fp);
#else
#define DEBUG_LOG(msg, args...)
#endif
diff --git a/xorg-server/hw/xquartz/darwinEvents.c b/xorg-server/hw/xquartz/darwinEvents.c index b591f7728..185df4a43 100644 --- a/xorg-server/hw/xquartz/darwinEvents.c +++ b/xorg-server/hw/xquartz/darwinEvents.c @@ -113,7 +113,7 @@ void darwinEvents_lock(void) { if((err = pthread_mutex_lock(&mieq_lock))) {
ErrorF("%s:%s:%d: Failed to lock mieq_lock: %d\n",
__FILE__, __FUNCTION__, __LINE__, err);
- spewCallStack();
+ xorg_backtrace();
}
if(darwinEvents == NULL) {
pthread_cond_wait(&mieq_ready_cond, &mieq_lock);
@@ -126,7 +126,7 @@ void darwinEvents_unlock(void) { if((err = pthread_mutex_unlock(&mieq_lock))) {
ErrorF("%s:%s:%d: Failed to unlock mieq_lock: %d\n",
__FILE__, __FUNCTION__, __LINE__, err);
- spewCallStack();
+ xorg_backtrace();
}
}
@@ -197,8 +197,6 @@ static void DarwinUpdateModifiers( static void DarwinEventHandler(int screenNum, InternalEvent *ie, DeviceIntPtr dev) {
XQuartzEvent *e = &(ie->xquartz_event);
- TA_SERVER();
-
switch(e->subtype) {
case kXquartzControllerNotify:
DEBUG_LOG("kXquartzControllerNotify\n");
@@ -381,8 +379,6 @@ void ProcessInputEvents(void) { char nullbyte;
int x = sizeof(nullbyte);
- TA_SERVER();
-
mieqProcessInputEvents();
// Empty the signaling pipe
diff --git a/xorg-server/hw/xquartz/mach-startup/bundle-main.c b/xorg-server/hw/xquartz/mach-startup/bundle-main.c index 774dda664..ddb12741c 100644 --- a/xorg-server/hw/xquartz/mach-startup/bundle-main.c +++ b/xorg-server/hw/xquartz/mach-startup/bundle-main.c @@ -64,6 +64,9 @@ /* From darwinEvents.c ... but don't want to pull in all the server cruft */
void DarwinListenOnOpenFD(int fd);
+/* Ditto, from os/log.c */
+extern void ErrorF(const char *f, ...) _X_ATTRIBUTE_PRINTF(1,2);
+
extern int noPanoramiXExtension;
#define DEFAULT_CLIENT X11BINDIR "/xterm"
@@ -88,7 +91,7 @@ asm (".desc ___crashreporter_info__, 0x10"); static const char *__crashreporter_info__base = "X.Org X Server " XSERVER_VERSION " Build Date: " BUILD_DATE;
-static char *launchd_id_prefix = NULL;
+char *bundle_id_prefix = NULL;
static char *server_bootstrap_name = NULL;
#define DEBUG 1
@@ -134,19 +137,27 @@ static mach_port_t checkin_or_register(char *bname) { /* We probably were not started by launchd or the old mach_init */
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
if (kr != KERN_SUCCESS) {
- fprintf(stderr, "mach_port_allocate(): %s\n", mach_error_string(kr));
+ ErrorF("mach_port_allocate(): %s\n", mach_error_string(kr));
exit(EXIT_FAILURE);
}
kr = mach_port_insert_right(mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND);
if (kr != KERN_SUCCESS) {
- fprintf(stderr, "mach_port_insert_right(): %s\n", mach_error_string(kr));
+ ErrorF("mach_port_insert_right(): %s\n", mach_error_string(kr));
exit(EXIT_FAILURE);
}
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // bootstrap_register
+#endif
kr = bootstrap_register(bootstrap_port, bname, mp);
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
if (kr != KERN_SUCCESS) {
- fprintf(stderr, "bootstrap_register(): %s\n", mach_error_string(kr));
+ ErrorF("bootstrap_register(): %s\n", mach_error_string(kr));
exit(EXIT_FAILURE);
}
@@ -189,7 +200,7 @@ static int accept_fd_handoff(int connected_fd) { *((int*)CMSG_DATA(cmsg)) = -1;
if(recvmsg(connected_fd, &msg, 0) < 0) {
- fprintf(stderr, "X11.app: Error receiving $DISPLAY file descriptor. recvmsg() error: %s\n", strerror(errno));
+ ErrorF("X11.app: Error receiving $DISPLAY file descriptor. recvmsg() error: %s\n", strerror(errno));
return -1;
}
@@ -222,14 +233,14 @@ static void *socket_handoff_thread(void *arg) { while(launchd_fd == -1) {
connected_fd = accept(handoff_data->fd, NULL, NULL);
if(connected_fd == -1) {
- fprintf(stderr, "X11.app: Failed to accept incoming connection on socket (fd=%d): %s\n", handoff_data->fd, strerror(errno));
+ ErrorF("X11.app: Failed to accept incoming connection on socket (fd=%d): %s\n", handoff_data->fd, strerror(errno));
sleep(2);
continue;
}
launchd_fd = accept_fd_handoff(connected_fd);
if(launchd_fd == -1)
- fprintf(stderr, "X11.app: Error receiving $DISPLAY file descriptor, no descriptor received? Waiting for another connection.\n");
+ ErrorF("X11.app: Error receiving $DISPLAY file descriptor, no descriptor received? Waiting for another connection.\n");
close(connected_fd);
}
@@ -238,7 +249,7 @@ static void *socket_handoff_thread(void *arg) { unlink(handoff_data->filename);
free(handoff_data);
- fprintf(stderr, "X11.app Handing off fd to server thread via DarwinListenOnOpenFD(%d)\n", launchd_fd);
+ ErrorF("X11.app Handing off fd to server thread via DarwinListenOnOpenFD(%d)\n", launchd_fd);
DarwinListenOnOpenFD(launchd_fd);
#ifndef HAVE_LIBDISPATCH
@@ -266,24 +277,24 @@ static int create_socket(char *filename_out) { ret_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(ret_fd == -1) {
- fprintf(stderr, "X11.app: Failed to create socket (try %d / %d): %s - %s\n", (int)try+1, (int)try_max, filename_out, strerror(errno));
+ ErrorF("X11.app: Failed to create socket (try %d / %d): %s - %s\n", (int)try+1, (int)try_max, filename_out, strerror(errno));
continue;
}
if(bind(ret_fd, servaddr, servaddr_len) != 0) {
- fprintf(stderr, "X11.app: Failed to bind socket: %d - %s\n", errno, strerror(errno));
+ ErrorF("X11.app: Failed to bind socket: %d - %s\n", errno, strerror(errno));
close(ret_fd);
return 0;
}
if(listen(ret_fd, 10) != 0) {
- fprintf(stderr, "X11.app: Failed to listen to socket: %s - %d - %s\n", filename_out, errno, strerror(errno));
+ ErrorF("X11.app: Failed to listen to socket: %s - %d - %s\n", filename_out, errno, strerror(errno));
close(ret_fd);
return 0;
}
#ifdef DEBUG
- fprintf(stderr, "X11.app: Listening on socket for fd handoff: (%d) %s\n", ret_fd, filename_out);
+ ErrorF("X11.app: Listening on socket for fd handoff: (%d) %s\n", ret_fd, filename_out);
#endif
return ret_fd;
@@ -301,7 +312,7 @@ kern_return_t do_request_fd_handoff_socket(mach_port_t port, string_t filename) handoff_data = (socket_handoff_t *)calloc(1,sizeof(socket_handoff_t));
if(!handoff_data) {
- fprintf(stderr, "X11.app: Error allocating memory for handoff_data\n");
+ ErrorF("X11.app: Error allocating memory for handoff_data\n");
return KERN_FAILURE;
}
@@ -322,7 +333,7 @@ kern_return_t do_request_fd_handoff_socket(mach_port_t port, string_t filename) #endif
#ifdef DEBUG
- fprintf(stderr, "X11.app: Thread created for handoff. Returning success to tell caller to connect and push the fd.\n");
+ ErrorF("X11.app: Thread created for handoff. Returning success to tell caller to connect and push the fd.\n");
#endif
return KERN_SUCCESS;
@@ -347,7 +358,7 @@ kern_return_t do_start_x11_server(mach_port_t port, string_array_t argv, * unset DISPLAY or we can run into problems with pbproxy
*/
if(!launchd_socket_handed_off) {
- fprintf(stderr, "X11.app: No launchd socket handed off, unsetting DISPLAY\n");
+ ErrorF("X11.app: No launchd socket handed off, unsetting DISPLAY\n");
unsetenv("DISPLAY");
}
@@ -355,10 +366,10 @@ kern_return_t do_start_x11_server(mach_port_t port, string_array_t argv, return KERN_FAILURE;
}
- fprintf(stderr, "X11.app: do_start_x11_server(): argc=%d\n", argvCnt);
+ ErrorF("X11.app: do_start_x11_server(): argc=%d\n", argvCnt);
for(i=0; i < argvCnt; i++) {
_argv[i] = argv[i];
- fprintf(stderr, "\targv[%u] = %s\n", (unsigned)i, argv[i]);
+ ErrorF("\targv[%u] = %s\n", (unsigned)i, argv[i]);
}
_argv[argvCnt] = NULL;
@@ -396,7 +407,7 @@ static int startup_trigger(int argc, char **argv, char **envp) { newenvp = (string_array_t)alloca(envpc * sizeof(string_t));
if(!newargv || !newenvp) {
- fprintf(stderr, "Memory allocation failure\n");
+ ErrorF("Memory allocation failure\n");
exit(EXIT_FAILURE);
}
@@ -410,16 +421,16 @@ static int startup_trigger(int argc, char **argv, char **envp) { kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp);
if (kr != KERN_SUCCESS) {
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
- fprintf(stderr, "bootstrap_look_up(%s): %s\n", server_bootstrap_name, bootstrap_strerror(kr));
+ ErrorF("bootstrap_look_up(%s): %s\n", server_bootstrap_name, bootstrap_strerror(kr));
#else
- fprintf(stderr, "bootstrap_look_up(%s): %ul\n", server_bootstrap_name, (unsigned long)kr);
+ ErrorF("bootstrap_look_up(%s): %ul\n", server_bootstrap_name, (unsigned long)kr);
#endif
exit(EXIT_FAILURE);
}
kr = start_x11_server(mp, newargv, argc, newenvp, envpc);
if (kr != KERN_SUCCESS) {
- fprintf(stderr, "start_x11_server: %s\n", mach_error_string(kr));
+ ErrorF("start_x11_server: %s\n", mach_error_string(kr));
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
@@ -441,10 +452,10 @@ static int startup_trigger(int argc, char **argv, char **envp) { /* Start the server */
if((s = getenv("DISPLAY"))) {
- fprintf(stderr, "X11.app: Could not connect to server (DISPLAY=\"%s\", unsetting). Starting X server.\n", s);
+ ErrorF("X11.app: Could not connect to server (DISPLAY=\"%s\", unsetting). Starting X server.\n", s);
unsetenv("DISPLAY");
} else {
- fprintf(stderr, "X11.app: Could not connect to server (DISPLAY is not set). Starting X server.\n");
+ ErrorF("X11.app: Could not connect to server (DISPLAY is not set). Starting X server.\n");
}
return execute(command_from_prefs("startx_script", DEFAULT_STARTX));
}
@@ -483,23 +494,23 @@ static void setup_env(void) { /* fallback to hardcoded value if we can't discover it */
if(!pds) {
- pds = LAUNCHD_ID_PREFIX".X11";
+ pds = BUNDLE_ID_PREFIX".X11";
}
server_bootstrap_name = strdup(pds);
if(!server_bootstrap_name) {
- fprintf(stderr, "X11.app: Memory allocation error.\n");
+ ErrorF("X11.app: Memory allocation error.\n");
exit(1);
}
setenv("X11_PREFS_DOMAIN", server_bootstrap_name, 1);
len = strlen(server_bootstrap_name);
- launchd_id_prefix = malloc(sizeof(char) * (len - 3));
- if(!launchd_id_prefix) {
- fprintf(stderr, "X11.app: Memory allocation error.\n");
+ bundle_id_prefix = malloc(sizeof(char) * (len - 3));
+ if(!bundle_id_prefix) {
+ ErrorF("X11.app: Memory allocation error.\n");
exit(1);
}
- strlcpy(launchd_id_prefix, server_bootstrap_name, len - 3);
+ strlcpy(bundle_id_prefix, server_bootstrap_name, len - 3);
/* We need to unset DISPLAY if it is not our socket */
if(disp) {
@@ -511,27 +522,27 @@ static void setup_env(void) { }
if(s && *s) {
- if(strcmp(launchd_id_prefix, "org.x") == 0 && strcmp(s, ":0") == 0) {
- fprintf(stderr, "X11.app: Detected old style launchd DISPLAY, please update xinit.\n");
+ if(strcmp(bundle_id_prefix, "org.x") == 0 && strcmp(s, ":0") == 0) {
+ ErrorF("X11.app: Detected old style launchd DISPLAY, please update xinit.\n");
} else {
temp = (char *)malloc(sizeof(char) * len);
if(!temp) {
- fprintf(stderr, "X11.app: Memory allocation error creating space for socket name test.\n");
+ ErrorF("X11.app: Memory allocation error creating space for socket name test.\n");
exit(1);
}
- strlcpy(temp, launchd_id_prefix, len);
+ strlcpy(temp, bundle_id_prefix, len);
strlcat(temp, ":0", len);
if(strcmp(temp, s) != 0) {
/* If we don't have a match, unset it. */
- fprintf(stderr, "X11.app: DISPLAY (\"%s\") does not match our id (\"%s\"), unsetting.\n", disp, launchd_id_prefix);
+ ErrorF("X11.app: DISPLAY (\"%s\") does not match our id (\"%s\"), unsetting.\n", disp, bundle_id_prefix);
unsetenv("DISPLAY");
}
free(temp);
}
} else {
/* The DISPLAY environment variable is not formatted like a launchd socket, so reset. */
- fprintf(stderr, "X11.app: DISPLAY does not look like a launchd set variable, unsetting.\n");
+ ErrorF("X11.app: DISPLAY does not look like a launchd set variable, unsetting.\n");
unsetenv("DISPLAY");
}
}
@@ -562,9 +573,9 @@ int main(int argc, char **argv, char **envp) { /* Setup the initial crasherporter info */
strlcpy(__crashreporter_info_buff__, __crashreporter_info__base, sizeof(__crashreporter_info_buff__));
- fprintf(stderr, "X11.app: main(): argc=%d\n", argc);
+ ErrorF("X11.app: main(): argc=%d\n", argc);
for(i=0; i < argc; i++) {
- fprintf(stderr, "\targv[%u] = %s\n", (unsigned)i, argv[i]);
+ ErrorF("\targv[%u] = %s\n", (unsigned)i, argv[i]);
if(!strcmp(argv[i], "--listenonly")) {
listenOnly = TRUE;
}
@@ -572,7 +583,7 @@ int main(int argc, char **argv, char **envp) { mp = checkin_or_register(server_bootstrap_name);
if(mp == MACH_PORT_NULL) {
- fprintf(stderr, "NULL mach service: %s", server_bootstrap_name);
+ ErrorF("NULL mach service: %s", server_bootstrap_name);
return EXIT_FAILURE;
}
@@ -621,10 +632,10 @@ int main(int argc, char **argv, char **envp) { }
/* Main event loop */
- fprintf(stderr, "Waiting for startup parameters via Mach IPC.\n");
+ ErrorF("Waiting for startup parameters via Mach IPC.\n");
kr = mach_msg_server(mach_startup_server, mxmsgsz, mp, 0);
if (kr != KERN_SUCCESS) {
- fprintf(stderr, "%s.X11(mp): %s\n", LAUNCHD_ID_PREFIX, mach_error_string(kr));
+ ErrorF("%s.X11(mp): %s\n", BUNDLE_ID_PREFIX, mach_error_string(kr));
return EXIT_FAILURE;
}
@@ -640,9 +651,9 @@ static int execute(const char *command) { newargv[2] = command;
newargv[3] = NULL;
- fprintf(stderr, "X11.app: Launching %s:\n", command);
+ ErrorF("X11.app: Launching %s:\n", command);
for(p=newargv; *p; p++) {
- fprintf(stderr, "\targv[%ld] = %s\n", (long int)(p - newargv), *p);
+ ErrorF("\targv[%ld] = %s\n", (long int)(p - newargv), *p);
}
execvp (newargv[0], (char * const *) newargv);
diff --git a/xorg-server/hw/xquartz/mach-startup/launchd_fd.c b/xorg-server/hw/xquartz/mach-startup/launchd_fd.c index 6dace8ea1..6be4421c2 100644 --- a/xorg-server/hw/xquartz/mach-startup/launchd_fd.c +++ b/xorg-server/hw/xquartz/mach-startup/launchd_fd.c @@ -1,89 +1,89 @@ -/* Copyright (c) 2008 Apple Inc. - * - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <launch.h> -#include <stdio.h> -#include <errno.h> - -#include "launchd_fd.h" - -int launchd_display_fd(void) { - launch_data_t sockets_dict, checkin_request, checkin_response; - launch_data_t listening_fd_array, listening_fd; - - /* Get launchd fd */ - if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) { - fprintf(stderr,"launch_data_new_string(\"" LAUNCH_KEY_CHECKIN "\") Unable to create string.\n"); - return ERROR_FD; - } - - if ((checkin_response = launch_msg(checkin_request)) == NULL) { - fprintf(stderr,"launch_msg(\"" LAUNCH_KEY_CHECKIN "\") IPC failure: %s\n",strerror(errno)); - return ERROR_FD; - } - - if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) { - // ignore EACCES, which is common if we weren't started by launchd - if (launch_data_get_errno(checkin_response) != EACCES) - fprintf(stderr,"launchd check-in failed: %s\n", strerror(launch_data_get_errno(checkin_response))); - return ERROR_FD; - } - - sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS); - if (NULL == sockets_dict) { - fprintf(stderr,"launchd check-in: no sockets found to answer requests on!\n"); - return ERROR_FD; - } - - if (launch_data_dict_get_count(sockets_dict) > 1) { - fprintf(stderr,"launchd check-in: some sockets will be ignored!\n"); - return ERROR_FD; - } - - listening_fd_array = launch_data_dict_lookup(sockets_dict, LAUNCHD_ID_PREFIX":0"); - if (NULL == listening_fd_array) { - listening_fd_array = launch_data_dict_lookup(sockets_dict, ":0"); - if (NULL == listening_fd_array) { - fprintf(stderr,"launchd check-in: No known sockets found to answer requests on! \"%s:0\" and \":0\" failed.\n", LAUNCHD_ID_PREFIX); - return ERROR_FD; - } - } - - if (launch_data_array_get_count(listening_fd_array)!=1) { - fprintf(stderr,"launchd check-in: Expected 1 socket from launchd, got %u)\n", - (unsigned)launch_data_array_get_count(listening_fd_array)); - return ERROR_FD; - } - - listening_fd=launch_data_array_get_index(listening_fd_array, 0); - return launch_data_get_fd(listening_fd); -} +/* Copyright (c) 2008 Apple Inc.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <launch.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "launchd_fd.h"
+
+int launchd_display_fd(void) {
+ launch_data_t sockets_dict, checkin_request, checkin_response;
+ launch_data_t listening_fd_array, listening_fd;
+
+ /* Get launchd fd */
+ if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) {
+ fprintf(stderr,"launch_data_new_string(\"" LAUNCH_KEY_CHECKIN "\") Unable to create string.\n");
+ return ERROR_FD;
+ }
+
+ if ((checkin_response = launch_msg(checkin_request)) == NULL) {
+ fprintf(stderr,"launch_msg(\"" LAUNCH_KEY_CHECKIN "\") IPC failure: %s\n",strerror(errno));
+ return ERROR_FD;
+ }
+
+ if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) {
+ // ignore EACCES, which is common if we weren't started by launchd
+ if (launch_data_get_errno(checkin_response) != EACCES)
+ fprintf(stderr,"launchd check-in failed: %s\n", strerror(launch_data_get_errno(checkin_response)));
+ return ERROR_FD;
+ }
+
+ sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS);
+ if (NULL == sockets_dict) {
+ fprintf(stderr,"launchd check-in: no sockets found to answer requests on!\n");
+ return ERROR_FD;
+ }
+
+ if (launch_data_dict_get_count(sockets_dict) > 1) {
+ fprintf(stderr,"launchd check-in: some sockets will be ignored!\n");
+ return ERROR_FD;
+ }
+
+ listening_fd_array = launch_data_dict_lookup(sockets_dict, BUNDLE_ID_PREFIX":0");
+ if (NULL == listening_fd_array) {
+ listening_fd_array = launch_data_dict_lookup(sockets_dict, ":0");
+ if (NULL == listening_fd_array) {
+ fprintf(stderr,"launchd check-in: No known sockets found to answer requests on! \"%s:0\" and \":0\" failed.\n", BUNDLE_ID_PREFIX);
+ return ERROR_FD;
+ }
+ }
+
+ if (launch_data_array_get_count(listening_fd_array)!=1) {
+ fprintf(stderr,"launchd check-in: Expected 1 socket from launchd, got %u)\n",
+ (unsigned)launch_data_array_get_count(listening_fd_array));
+ return ERROR_FD;
+ }
+
+ listening_fd=launch_data_array_get_index(listening_fd_array, 0);
+ return launch_data_get_fd(listening_fd);
+}
diff --git a/xorg-server/hw/xquartz/mach-startup/stub.c b/xorg-server/hw/xquartz/mach-startup/stub.c index ccf5ab426..8f70eeff7 100644 --- a/xorg-server/hw/xquartz/mach-startup/stub.c +++ b/xorg-server/hw/xquartz/mach-startup/stub.c @@ -1,328 +1,312 @@ -/* Copyright (c) 2008 Apple Inc. - * - * 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. - */ - -#include <CoreServices/CoreServices.h> - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <string.h> -#include <stdio.h> -#include <unistd.h> -#include <errno.h> - -#include <sys/socket.h> -#include <sys/un.h> - -#define kX11AppBundleId LAUNCHD_ID_PREFIX".X11" -#define kX11AppBundlePath "/Contents/MacOS/X11" - -static char *server_bootstrap_name = kX11AppBundleId; - -#include <mach/mach.h> -#include <mach/mach_error.h> -#include <servers/bootstrap.h> -#include "mach_startup.h" - -#include <signal.h> - -#include <AvailabilityMacros.h> - -#include "launchd_fd.h" - -#ifndef BUILD_DATE -#define BUILD_DATE "?" -#endif -#ifndef XSERVER_VERSION -#define XSERVER_VERSION "?" -#endif - -#define DEBUG 1 - -static char x11_path[PATH_MAX + 1]; - -static pid_t x11app_pid = 0; - -static void set_x11_path(void) { -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 - - CFURLRef appURL = NULL; - OSStatus osstatus = LSFindApplicationForInfo(kLSUnknownCreator, CFSTR(kX11AppBundleId), nil, nil, &appURL); - - switch (osstatus) { - case noErr: - if (appURL == NULL) { - fprintf(stderr, "Xquartz: Invalid response from LSFindApplicationForInfo(%s)\n", - kX11AppBundleId); - exit(1); - } - - if (!CFURLGetFileSystemRepresentation(appURL, true, (unsigned char *)x11_path, sizeof(x11_path))) { - fprintf(stderr, "Xquartz: Error resolving URL for %s\n", kX11AppBundleId); - exit(3); - } - - strlcat(x11_path, kX11AppBundlePath, sizeof(x11_path)); -#ifdef DEBUG - fprintf(stderr, "Xquartz: X11.app = %s\n", x11_path); -#endif - break; - case kLSApplicationNotFoundErr: - fprintf(stderr, "Xquartz: Unable to find application for %s\n", kX11AppBundleId); - exit(10); - default: - fprintf(stderr, "Xquartz: Unable to find application for %s, error code = %d\n", - kX11AppBundleId, (int)osstatus); - exit(11); - } -#else - /* TODO: Make Tiger smarter... but TBH, this should never get called on Tiger... */ - strlcpy(x11_path, "/Applications/Utilities/X11.app/Contents/MacOS/X11", sizeof(x11_path)); -#endif -} - -static int connect_to_socket(const char *filename) { - struct sockaddr_un servaddr_un; - struct sockaddr *servaddr; - socklen_t servaddr_len; - int ret_fd; - - /* Setup servaddr_un */ - memset (&servaddr_un, 0, sizeof (struct sockaddr_un)); - servaddr_un.sun_family = AF_UNIX; - strlcpy(servaddr_un.sun_path, filename, sizeof(servaddr_un.sun_path)); - - servaddr = (struct sockaddr *) &servaddr_un; - servaddr_len = sizeof(struct sockaddr_un) - sizeof(servaddr_un.sun_path) + strlen(filename); - - ret_fd = socket(PF_UNIX, SOCK_STREAM, 0); - if(ret_fd == -1) { - fprintf(stderr, "Xquartz: Failed to create socket: %s - %s\n", filename, strerror(errno)); - return -1; - } - - if(connect(ret_fd, servaddr, servaddr_len) < 0) { - fprintf(stderr, "Xquartz: Failed to connect to socket: %s - %d - %s\n", filename, errno, strerror(errno)); - close(ret_fd); - return -1; - } - - return ret_fd; -} - -static void send_fd_handoff(int connected_fd, int launchd_fd) { - char databuf[] = "display"; - struct iovec iov[1]; - - union { - struct cmsghdr hdr; - char bytes[CMSG_SPACE(sizeof(int))]; - } buf; - - struct msghdr msg; - struct cmsghdr *cmsg; - - iov[0].iov_base = databuf; - iov[0].iov_len = sizeof(databuf); - - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_control = buf.bytes; - msg.msg_controllen = sizeof(buf); - msg.msg_name = 0; - msg.msg_namelen = 0; - msg.msg_flags = 0; - - cmsg = CMSG_FIRSTHDR (&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - - msg.msg_controllen = cmsg->cmsg_len; - - *((int*)CMSG_DATA(cmsg)) = launchd_fd; - - if(sendmsg(connected_fd, &msg, 0) < 0) { - fprintf(stderr, "Xquartz: Error sending $DISPLAY file descriptor over fd %d: %d -- %s\n", connected_fd, errno, strerror(errno)); - return; - } - -#ifdef DEBUG - fprintf(stderr, "Xquartz: Message sent. Closing handoff fd.\n"); -#endif - - close(connected_fd); -} - -static void signal_handler(int sig) { - if(x11app_pid) - kill(x11app_pid, sig); - _exit(0); -} - -int main(int argc, char **argv, char **envp) { - int envpc; - kern_return_t kr; - mach_port_t mp; - string_array_t newenvp; - string_array_t newargv; - size_t i; - int launchd_fd; - string_t handoff_socket_filename; - sig_t handler; - - if(argc == 2 && !strcmp(argv[1], "-version")) { - fprintf(stderr, "X.org Release 7.5\n"); - fprintf(stderr, "X.Org X Server %s\n", XSERVER_VERSION); - fprintf(stderr, "Build Date: %s\n", BUILD_DATE); - return EXIT_SUCCESS; - } - - if(getenv("X11_PREFS_DOMAIN")) - server_bootstrap_name = getenv("X11_PREFS_DOMAIN"); - - /* We don't have a mechanism in place to handle this interrupt driven - * server-start notification, so just send the signal now, so xinit doesn't - * time out waiting for it and will just poll for the server. - */ - handler = signal(SIGUSR1, SIG_IGN); - if(handler == SIG_IGN) - kill(getppid(), SIGUSR1); - signal(SIGUSR1, handler); - - /* Pass on SIGs to X11.app */ - signal(SIGINT, signal_handler); - signal(SIGTERM, signal_handler); - - /* Get the $DISPLAY FD */ - launchd_fd = launchd_display_fd(); - - kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp); - if(kr != KERN_SUCCESS) { - pid_t child; - - fprintf(stderr, "Xquartz: Unable to locate waiting server: %s\n", server_bootstrap_name); - set_x11_path(); - - /* This forking is ugly and will be cleaned up later */ - child = fork(); - if(child == -1) { - fprintf(stderr, "Xquartz: Could not fork: %s\n", strerror(errno)); - return EXIT_FAILURE; - } - - if(child == 0) { - char *_argv[3]; - _argv[0] = x11_path; - _argv[1] = "--listenonly"; - _argv[2] = NULL; - fprintf(stderr, "Xquartz: Starting X server: %s --listenonly\n", x11_path); - return execvp(x11_path, _argv); - } - - /* Try connecting for 10 seconds */ - for(i=0; i < 80; i++) { - usleep(250000); - kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp); - if(kr == KERN_SUCCESS) - break; - } - - if(kr != KERN_SUCCESS) { -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 - fprintf(stderr, "Xquartz: bootstrap_look_up(): %s\n", bootstrap_strerror(kr)); -#else - fprintf(stderr, "Xquartz: bootstrap_look_up(): %ul\n", (unsigned long)kr); -#endif - return EXIT_FAILURE; - } - } - - /* Get X11.app's pid */ - request_pid(mp, &x11app_pid); - - /* Handoff the $DISPLAY FD */ - if(launchd_fd != -1) { - size_t try, try_max; - int handoff_fd = -1; - - for(try=0, try_max=5; try < try_max; try++) { - if(request_fd_handoff_socket(mp, handoff_socket_filename) != KERN_SUCCESS) { - fprintf(stderr, "Xquartz: Failed to request a socket from the server to send the $DISPLAY fd over (try %d of %d)\n", (int)try+1, (int)try_max); - continue; - } - - handoff_fd = connect_to_socket(handoff_socket_filename); - if(handoff_fd == -1) { - fprintf(stderr, "Xquartz: Failed to connect to socket (try %d of %d)\n", (int)try+1, (int)try_max); - continue; - } - -#ifdef DEBUG - fprintf(stderr, "Xquartz: Handoff connection established (try %d of %d) on fd %d, \"%s\". Sending message.\n", (int)try+1, (int)try_max, handoff_fd, handoff_socket_filename); -#endif - - send_fd_handoff(handoff_fd, launchd_fd); - close(handoff_fd); - break; - } - } - - /* Count envp */ - for(envpc=0; envp[envpc]; envpc++); - - /* We have fixed-size string lengths due to limitations in IPC, - * so we need to copy our argv and envp. - */ - newargv = (string_array_t)malloc(argc * sizeof(string_t)); - newenvp = (string_array_t)malloc(envpc * sizeof(string_t)); - - if(!newargv || !newenvp) { - fprintf(stderr, "Xquartz: Memory allocation failure\n"); - return EXIT_FAILURE; - } - - for(i=0; i < argc; i++) { - strlcpy(newargv[i], argv[i], STRING_T_SIZE); - } - for(i=0; i < envpc; i++) { - strlcpy(newenvp[i], envp[i], STRING_T_SIZE); - } - - kr = start_x11_server(mp, newargv, argc, newenvp, envpc); - - free(newargv); - free(newenvp); - - if (kr != KERN_SUCCESS) { - fprintf(stderr, "Xquartz: start_x11_server: %s\n", mach_error_string(kr)); - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} +/* Copyright (c) 2008 Apple Inc.
+ *
+ * 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.
+ */
+
+#include <CoreServices/CoreServices.h>
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define kX11AppBundleId BUNDLE_ID_PREFIX".X11"
+#define kX11AppBundlePath "/Contents/MacOS/X11"
+
+static char *server_bootstrap_name = kX11AppBundleId;
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <servers/bootstrap.h>
+#include "mach_startup.h"
+
+#include <signal.h>
+
+#include <AvailabilityMacros.h>
+
+#include "launchd_fd.h"
+
+static char x11_path[PATH_MAX + 1];
+
+static pid_t x11app_pid = 0;
+
+static void set_x11_path(void) {
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+
+ CFURLRef appURL = NULL;
+ OSStatus osstatus = LSFindApplicationForInfo(kLSUnknownCreator, CFSTR(kX11AppBundleId), nil, nil, &appURL);
+
+ switch (osstatus) {
+ case noErr:
+ if (appURL == NULL) {
+ fprintf(stderr, "Xquartz: Invalid response from LSFindApplicationForInfo(%s)\n",
+ kX11AppBundleId);
+ exit(1);
+ }
+
+ if (!CFURLGetFileSystemRepresentation(appURL, true, (unsigned char *)x11_path, sizeof(x11_path))) {
+ fprintf(stderr, "Xquartz: Error resolving URL for %s\n", kX11AppBundleId);
+ exit(3);
+ }
+
+ strlcat(x11_path, kX11AppBundlePath, sizeof(x11_path));
+#ifdef DEBUG
+ fprintf(stderr, "Xquartz: X11.app = %s\n", x11_path);
+#endif
+ break;
+ case kLSApplicationNotFoundErr:
+ fprintf(stderr, "Xquartz: Unable to find application for %s\n", kX11AppBundleId);
+ exit(10);
+ default:
+ fprintf(stderr, "Xquartz: Unable to find application for %s, error code = %d\n",
+ kX11AppBundleId, (int)osstatus);
+ exit(11);
+ }
+#else
+ /* TODO: Make Tiger smarter... but TBH, this should never get called on Tiger... */
+ strlcpy(x11_path, "/Applications/Utilities/X11.app/Contents/MacOS/X11", sizeof(x11_path));
+#endif
+}
+
+static int connect_to_socket(const char *filename) {
+ struct sockaddr_un servaddr_un;
+ struct sockaddr *servaddr;
+ socklen_t servaddr_len;
+ int ret_fd;
+
+ /* Setup servaddr_un */
+ memset (&servaddr_un, 0, sizeof (struct sockaddr_un));
+ servaddr_un.sun_family = AF_UNIX;
+ strlcpy(servaddr_un.sun_path, filename, sizeof(servaddr_un.sun_path));
+
+ servaddr = (struct sockaddr *) &servaddr_un;
+ servaddr_len = sizeof(struct sockaddr_un) - sizeof(servaddr_un.sun_path) + strlen(filename);
+
+ ret_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if(ret_fd == -1) {
+ fprintf(stderr, "Xquartz: Failed to create socket: %s - %s\n", filename, strerror(errno));
+ return -1;
+ }
+
+ if(connect(ret_fd, servaddr, servaddr_len) < 0) {
+ fprintf(stderr, "Xquartz: Failed to connect to socket: %s - %d - %s\n", filename, errno, strerror(errno));
+ close(ret_fd);
+ return -1;
+ }
+
+ return ret_fd;
+}
+
+static void send_fd_handoff(int connected_fd, int launchd_fd) {
+ char databuf[] = "display";
+ struct iovec iov[1];
+
+ union {
+ struct cmsghdr hdr;
+ char bytes[CMSG_SPACE(sizeof(int))];
+ } buf;
+
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+
+ iov[0].iov_base = databuf;
+ iov[0].iov_len = sizeof(databuf);
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = buf.bytes;
+ msg.msg_controllen = sizeof(buf);
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR (&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ *((int*)CMSG_DATA(cmsg)) = launchd_fd;
+
+ if(sendmsg(connected_fd, &msg, 0) < 0) {
+ fprintf(stderr, "Xquartz: Error sending $DISPLAY file descriptor over fd %d: %d -- %s\n", connected_fd, errno, strerror(errno));
+ return;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Xquartz: Message sent. Closing handoff fd.\n");
+#endif
+
+ close(connected_fd);
+}
+
+static void signal_handler(int sig) {
+ if(x11app_pid)
+ kill(x11app_pid, sig);
+ _exit(0);
+}
+
+int main(int argc, char **argv, char **envp) {
+ int envpc;
+ kern_return_t kr;
+ mach_port_t mp;
+ string_array_t newenvp;
+ string_array_t newargv;
+ size_t i;
+ int launchd_fd;
+ string_t handoff_socket_filename;
+ sig_t handler;
+
+ if(getenv("X11_PREFS_DOMAIN"))
+ server_bootstrap_name = getenv("X11_PREFS_DOMAIN");
+
+ /* We don't have a mechanism in place to handle this interrupt driven
+ * server-start notification, so just send the signal now, so xinit doesn't
+ * time out waiting for it and will just poll for the server.
+ */
+ handler = signal(SIGUSR1, SIG_IGN);
+ if(handler == SIG_IGN)
+ kill(getppid(), SIGUSR1);
+ signal(SIGUSR1, handler);
+
+ /* Pass on SIGs to X11.app */
+ signal(SIGINT, signal_handler);
+ signal(SIGTERM, signal_handler);
+
+ /* Get the $DISPLAY FD */
+ launchd_fd = launchd_display_fd();
+
+ kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp);
+ if(kr != KERN_SUCCESS) {
+ pid_t child;
+
+ fprintf(stderr, "Xquartz: Unable to locate waiting server: %s\n", server_bootstrap_name);
+ set_x11_path();
+
+ /* This forking is ugly and will be cleaned up later */
+ child = fork();
+ if(child == -1) {
+ fprintf(stderr, "Xquartz: Could not fork: %s\n", strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ if(child == 0) {
+ char *_argv[3];
+ _argv[0] = x11_path;
+ _argv[1] = "--listenonly";
+ _argv[2] = NULL;
+ fprintf(stderr, "Xquartz: Starting X server: %s --listenonly\n", x11_path);
+ return execvp(x11_path, _argv);
+ }
+
+ /* Try connecting for 10 seconds */
+ for(i=0; i < 80; i++) {
+ usleep(250000);
+ kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp);
+ if(kr == KERN_SUCCESS)
+ break;
+ }
+
+ if(kr != KERN_SUCCESS) {
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+ fprintf(stderr, "Xquartz: bootstrap_look_up(): %s\n", bootstrap_strerror(kr));
+#else
+ fprintf(stderr, "Xquartz: bootstrap_look_up(): %ul\n", (unsigned long)kr);
+#endif
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Get X11.app's pid */
+ request_pid(mp, &x11app_pid);
+
+ /* Handoff the $DISPLAY FD */
+ if(launchd_fd != -1) {
+ size_t try, try_max;
+ int handoff_fd = -1;
+
+ for(try=0, try_max=5; try < try_max; try++) {
+ if(request_fd_handoff_socket(mp, handoff_socket_filename) != KERN_SUCCESS) {
+ fprintf(stderr, "Xquartz: Failed to request a socket from the server to send the $DISPLAY fd over (try %d of %d)\n", (int)try+1, (int)try_max);
+ continue;
+ }
+
+ handoff_fd = connect_to_socket(handoff_socket_filename);
+ if(handoff_fd == -1) {
+ fprintf(stderr, "Xquartz: Failed to connect to socket (try %d of %d)\n", (int)try+1, (int)try_max);
+ continue;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Xquartz: Handoff connection established (try %d of %d) on fd %d, \"%s\". Sending message.\n", (int)try+1, (int)try_max, handoff_fd, handoff_socket_filename);
+#endif
+
+ send_fd_handoff(handoff_fd, launchd_fd);
+ close(handoff_fd);
+ break;
+ }
+ }
+
+ /* Count envp */
+ for(envpc=0; envp[envpc]; envpc++);
+
+ /* We have fixed-size string lengths due to limitations in IPC,
+ * so we need to copy our argv and envp.
+ */
+ newargv = (string_array_t)calloc((1 + argc), sizeof(string_t));
+ newenvp = (string_array_t)calloc((1 + envpc), sizeof(string_t));
+
+ if(!newargv || !newenvp) {
+ fprintf(stderr, "Xquartz: Memory allocation failure\n");
+ return EXIT_FAILURE;
+ }
+
+ for(i=0; i < argc; i++) {
+ strlcpy(newargv[i], argv[i], STRING_T_SIZE);
+ }
+ for(i=0; i < envpc; i++) {
+ strlcpy(newenvp[i], envp[i], STRING_T_SIZE);
+ }
+
+ kr = start_x11_server(mp, newargv, argc, newenvp, envpc);
+
+ free(newargv);
+ free(newenvp);
+
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "Xquartz: start_x11_server: %s\n", mach_error_string(kr));
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/xorg-server/hw/xquartz/pbproxy/Makefile.am b/xorg-server/hw/xquartz/pbproxy/Makefile.am index 188664259..e3782ac61 100644 --- a/xorg-server/hw/xquartz/pbproxy/Makefile.am +++ b/xorg-server/hw/xquartz/pbproxy/Makefile.am @@ -1,28 +1,28 @@ -AM_CPPFLAGS=-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks \ - -DLAUNCHD_ID_PREFIX=\"$(LAUNCHD_ID_PREFIX)\" - -AM_CFLAGS=$(XPBPROXY_CFLAGS) - -noinst_LTLIBRARIES = libxpbproxy.la -libxpbproxy_la_SOURCES = \ - trick_autotools.c \ - main.m \ - x-input.m \ - x-selection.m - -libxpbproxy_la_LDFLAGS=$(XPBPROXY_LIBS) - -if STANDALONE_XPBPROXY - -bin_PROGRAMS = xpbproxy -xpbproxy_SOURCES = app-main.m -xpbproxy_LDADD = libxpbproxy.la -xpbproxy_LDFLAGS = -Wl,-framework,Cocoa - -AM_CPPFLAGS += -DSTANDALONE_XPBPROXY - -endif - -EXTRA_DIST = \ - pbproxy.h \ - x-selection.h +AM_CPPFLAGS=-F/System/Library/Frameworks/ApplicationServices.framework/Frameworks \
+ -DBUNDLE_ID_PREFIX=\"$(BUNDLE_ID_PREFIX)\"
+
+AM_CFLAGS=$(XPBPROXY_CFLAGS)
+
+noinst_LTLIBRARIES = libxpbproxy.la
+libxpbproxy_la_SOURCES = \
+ trick_autotools.c \
+ main.m \
+ x-input.m \
+ x-selection.m
+
+libxpbproxy_la_LDFLAGS=$(XPBPROXY_LIBS)
+
+if STANDALONE_XPBPROXY
+
+bin_PROGRAMS = xpbproxy
+xpbproxy_SOURCES = app-main.m
+xpbproxy_LDADD = libxpbproxy.la
+xpbproxy_LDFLAGS = -Wl,-framework,Cocoa
+
+AM_CPPFLAGS += -DSTANDALONE_XPBPROXY
+
+endif
+
+EXTRA_DIST = \
+ pbproxy.h \
+ x-selection.h
diff --git a/xorg-server/hw/xquartz/pbproxy/app-main.m b/xorg-server/hw/xquartz/pbproxy/app-main.m index b00e90a6d..4e61c05a3 100644 --- a/xorg-server/hw/xquartz/pbproxy/app-main.m +++ b/xorg-server/hw/xquartz/pbproxy/app-main.m @@ -1,93 +1,103 @@ -/* app-main.m - Copyright (c) 2002, 2008 Apple Computer, 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 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. - */ - -#include "pbproxy.h" -#import "x-selection.h" - -#include <pthread.h> -#include <unistd.h> /*for getpid*/ -#include <Cocoa/Cocoa.h> - -static const char *app_prefs_domain = LAUNCHD_ID_PREFIX".xpbproxy"; -CFStringRef app_prefs_domain_cfstr; - -/* Stubs */ -char *display = NULL; -BOOL serverInitComplete = YES; -pthread_mutex_t serverInitCompleteMutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t serverInitCompleteCond = PTHREAD_COND_INITIALIZER; - -static void signal_handler (int sig) { - switch(sig) { - case SIGHUP: - xpbproxy_prefs_reload = YES; - break; - default: - _exit(EXIT_SUCCESS); - } -} - -int main (int argc, const char *argv[]) { - const char *s; - int i; - -#ifdef DEBUG - printf("pid: %u\n", getpid()); -#endif - - xpbproxy_is_standalone = YES; - - if((s = getenv("X11_PREFS_DOMAIN"))) - app_prefs_domain = s; - - for (i = 1; i < argc; i++) { - if(strcmp (argv[i], "--prefs-domain") == 0 && i+1 < argc) { - app_prefs_domain = argv[++i]; - } else if (strcmp (argv[i], "--help") == 0) { - printf("usage: xpbproxy OPTIONS\n" - "Pasteboard proxying for X11.\n\n" - "--prefs-domain <domain> Change the domain used for reading preferences\n" - " (default: %s)\n", app_prefs_domain); - return 0; - } else { - fprintf(stderr, "usage: xpbproxy OPTIONS...\n" - "Try 'xpbproxy --help' for more information.\n"); - return 1; - } - } - - app_prefs_domain_cfstr = CFStringCreateWithCString(NULL, app_prefs_domain, kCFStringEncodingUTF8); - - signal (SIGINT, signal_handler); - signal (SIGTERM, signal_handler); - signal (SIGHUP, signal_handler); - signal (SIGPIPE, SIG_IGN); - - return xpbproxy_run(); -} +/* app-main.m
+ Copyright (c) 2002, 2008 Apple Computer, 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 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.
+ */
+
+#include "pbproxy.h"
+#import "x-selection.h"
+
+#include <pthread.h>
+#include <unistd.h> /*for getpid*/
+#include <Cocoa/Cocoa.h>
+
+static const char *app_prefs_domain = BUNDLE_ID_PREFIX".xpbproxy";
+CFStringRef app_prefs_domain_cfstr;
+
+/* Stubs */
+char *display = NULL;
+BOOL serverInitComplete = YES;
+pthread_mutex_t serverInitCompleteMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t serverInitCompleteCond = PTHREAD_COND_INITIALIZER;
+
+static void signal_handler (int sig) {
+ switch(sig) {
+ case SIGHUP:
+ xpbproxy_prefs_reload = YES;
+ break;
+ default:
+ _exit(EXIT_SUCCESS);
+ }
+}
+
+void
+ErrorF(const char * f, ...)
+{
+ va_list args;
+
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+}
+
+int main (int argc, const char *argv[]) {
+ const char *s;
+ int i;
+
+#ifdef DEBUG
+ ErrorF("pid: %u\n", getpid());
+#endif
+
+ xpbproxy_is_standalone = YES;
+
+ if((s = getenv("X11_PREFS_DOMAIN")))
+ app_prefs_domain = s;
+
+ for (i = 1; i < argc; i++) {
+ if(strcmp (argv[i], "--prefs-domain") == 0 && i+1 < argc) {
+ app_prefs_domain = argv[++i];
+ } else if (strcmp (argv[i], "--help") == 0) {
+ ErrorF("usage: xpbproxy OPTIONS\n"
+ "Pasteboard proxying for X11.\n\n"
+ "--prefs-domain <domain> Change the domain used for reading preferences\n"
+ " (default: %s)\n", app_prefs_domain);
+ return 0;
+ } else {
+ ErrorF("usage: xpbproxy OPTIONS...\n"
+ "Try 'xpbproxy --help' for more information.\n");
+ return 1;
+ }
+ }
+
+ app_prefs_domain_cfstr = CFStringCreateWithCString(NULL, app_prefs_domain, kCFStringEncodingUTF8);
+
+ signal (SIGINT, signal_handler);
+ signal (SIGTERM, signal_handler);
+ signal (SIGHUP, signal_handler);
+ signal (SIGPIPE, SIG_IGN);
+
+ return xpbproxy_run();
+}
diff --git a/xorg-server/hw/xquartz/pbproxy/main.m b/xorg-server/hw/xquartz/pbproxy/main.m index cfdc7696d..bae23dada 100644 --- a/xorg-server/hw/xquartz/pbproxy/main.m +++ b/xorg-server/hw/xquartz/pbproxy/main.m @@ -105,7 +105,7 @@ int xpbproxy_run (void) { }
if (xpbproxy_dpy == NULL) {
- fprintf (stderr, "xpbproxy: can't open default display\n");
+ ErrorF("xpbproxy: can't open default display\n");
[pool release];
return EXIT_FAILURE;
}
@@ -115,7 +115,7 @@ int xpbproxy_run (void) { if (!XAppleWMQueryExtension (xpbproxy_dpy, &xpbproxy_apple_wm_event_base,
&xpbproxy_apple_wm_error_base)) {
- fprintf (stderr, "xpbproxy: can't open AppleWM server extension\n");
+ ErrorF("xpbproxy: can't open AppleWM server extension\n");
[pool release];
return EXIT_FAILURE;
}
@@ -147,19 +147,3 @@ Time xpbproxy_current_timestamp (void) { /* FIXME: may want to fetch a timestamp from the server.. */
return CurrentTime;
}
-
-void debug_printf (const char *fmt, ...) {
- static int spew = -1;
-
- if (spew == -1) {
- char *x = getenv ("DEBUG");
- spew = (x != NULL && atoi (x) != 0);
- }
-
- if (spew) {
- va_list args;
- va_start(args, fmt);
- vfprintf (stderr, fmt, args);
- va_end(args);
- }
-}
diff --git a/xorg-server/hw/xquartz/pbproxy/pbproxy.h b/xorg-server/hw/xquartz/pbproxy/pbproxy.h index 013f981d4..3e5c93926 100644 --- a/xorg-server/hw/xquartz/pbproxy/pbproxy.h +++ b/xorg-server/hw/xquartz/pbproxy/pbproxy.h @@ -1,90 +1,92 @@ -/* pbproxy.h - Copyright (c) 2002, 2008 Apple Computer, 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 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 PBPROXY_H -#define PBPROXY_H 1 - -#import <Foundation/Foundation.h> - -#include <AvailabilityMacros.h> -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 -#if __LP64__ || NS_BUILD_32_LIKE_64 -typedef long NSInteger; -typedef unsigned long NSUInteger; -#else -typedef int NSInteger; -typedef unsigned int NSUInteger; -#endif -#endif - -#define Cursor X_Cursor -#undef _SHAPE_H_ -#include <X11/Xlib.h> -#include <X11/extensions/shape.h> -#undef Cursor - -#ifdef STANDALONE_XPBPROXY -/* Just used for the standalone to respond to SIGHUP to reload prefs */ -extern BOOL xpbproxy_prefs_reload; - -/* Setting this to YES (for the standalone app) causes us to ignore the - * 'sync_pasteboard' defaults preference since we assume it to be on... this is - * mainly useful for debugging/developing xpbproxy with XQuartz still running. - * Just disable the one in the server with X11's preference pane, then run - * the standalone app. - */ -extern BOOL xpbproxy_is_standalone; -#endif - -/* from main.m */ -extern void xpbproxy_set_is_active (BOOL state); -extern BOOL xpbproxy_get_is_active (void); -extern id xpbproxy_selection_object (void); -extern Time xpbproxy_current_timestamp (void); -extern int xpbproxy_run (void); - -extern Display *xpbproxy_dpy; -extern int xpbproxy_apple_wm_event_base, xpbproxy_apple_wm_error_base; -extern int xpbproxy_xfixes_event_base, xpbproxy_xfixes_error_base; -extern BOOL xpbproxy_have_xfixes; - -/* from x-input.m */ -extern BOOL xpbproxy_input_register (void); - -#ifdef DEBUG -/* BEWARE: this can cause a string memory leak, according to the leaks program. */ -# define DB(msg, args...) debug_printf("%s:%s:%d " msg, __FILE__, __FUNCTION__, __LINE__, ##args) -#else -# define DB(msg, args...) do {} while (0) -#endif - -#define TRACE() DB("TRACE\n") -extern void debug_printf (const char *fmt, ...); - -#endif /* PBPROXY_H */ +/* pbproxy.h
+ Copyright (c) 2002, 2008 Apple Computer, 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 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 PBPROXY_H
+#define PBPROXY_H 1
+
+#import <Foundation/Foundation.h>
+
+#include <AvailabilityMacros.h>
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
+#if __LP64__ || NS_BUILD_32_LIKE_64
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+#else
+typedef int NSInteger;
+typedef unsigned int NSUInteger;
+#endif
+#endif
+
+#define Cursor X_Cursor
+#undef _SHAPE_H_
+#include <X11/Xlib.h>
+#include <X11/extensions/shape.h>
+#undef Cursor
+
+#ifdef STANDALONE_XPBPROXY
+/* Just used for the standalone to respond to SIGHUP to reload prefs */
+extern BOOL xpbproxy_prefs_reload;
+
+/* Setting this to YES (for the standalone app) causes us to ignore the
+ * 'sync_pasteboard' defaults preference since we assume it to be on... this is
+ * mainly useful for debugging/developing xpbproxy with XQuartz still running.
+ * Just disable the one in the server with X11's preference pane, then run
+ * the standalone app.
+ */
+extern BOOL xpbproxy_is_standalone;
+#endif
+
+/* from main.m */
+extern void xpbproxy_set_is_active (BOOL state);
+extern BOOL xpbproxy_get_is_active (void);
+extern id xpbproxy_selection_object (void);
+extern Time xpbproxy_current_timestamp (void);
+extern int xpbproxy_run (void);
+
+extern Display *xpbproxy_dpy;
+extern int xpbproxy_apple_wm_event_base, xpbproxy_apple_wm_error_base;
+extern int xpbproxy_xfixes_event_base, xpbproxy_xfixes_error_base;
+extern BOOL xpbproxy_have_xfixes;
+
+/* from x-input.m */
+extern BOOL xpbproxy_input_register (void);
+
+/* os/log.c or app-main.m */
+extern void ErrorF(const char *f, ...) _X_ATTRIBUTE_PRINTF(1,2);
+
+#ifdef DEBUG
+/* BEWARE: this can cause a string memory leak, according to the leaks program. */
+# define DebugF(msg, args...) ErrorF("%s:%s:%d " msg, __FILE__, __FUNCTION__, __LINE__, ##args)
+#else
+# define DebugF(...) /* */
+#endif
+
+#define TRACE() DebugF("TRACE\n")
+
+#endif /* PBPROXY_H */
diff --git a/xorg-server/hw/xquartz/pbproxy/x-input.m b/xorg-server/hw/xquartz/pbproxy/x-input.m index 405ba3c73..7ecc90896 100644 --- a/xorg-server/hw/xquartz/pbproxy/x-input.m +++ b/xorg-server/hw/xquartz/pbproxy/x-input.m @@ -1,173 +1,173 @@ -/* x-input.m -- event handling - Copyright (c) 2002, 2008 Apple Computer, 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 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. - */ - -#include "pbproxy.h" -#import "x-selection.h" - -#include <CoreFoundation/CFSocket.h> -#include <CoreFoundation/CFRunLoop.h> - -#include <X11/Xatom.h> -#include <X11/keysym.h> -#include <X11/extensions/applewm.h> - -#include <unistd.h> - -static CFRunLoopSourceRef xpbproxy_dpy_source; - -#ifdef STANDALONE_XPBPROXY -BOOL xpbproxy_prefs_reload = NO; -#endif - -/* Timestamp when the X server last told us it's active */ -static Time last_activation_time; - -static void x_event_apple_wm_notify(XAppleWMNotifyEvent *e) { - int type = e->type - xpbproxy_apple_wm_event_base; - int kind = e->kind; - - /* We want to reload prefs even if we're not active */ - if(type == AppleWMActivationNotify && - kind == AppleWMReloadPreferences) - [xpbproxy_selection_object() reload_preferences]; - - if(![xpbproxy_selection_object() is_active]) - return; - - switch (type) { - case AppleWMActivationNotify: - switch (kind) { - case AppleWMIsActive: - last_activation_time = e->time; - [xpbproxy_selection_object() x_active:e->time]; - break; - - case AppleWMIsInactive: - [xpbproxy_selection_object() x_inactive:e->time]; - break; - } - break; - - case AppleWMPasteboardNotify: - switch (kind) { - case AppleWMCopyToPasteboard: - [xpbproxy_selection_object() x_copy:e->time]; - } - break; - } -} - -static void xpbproxy_process_xevents(void) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - if(pool == nil) { - fprintf(stderr, "unable to allocate/init auto release pool!\n"); - return; - } - - while (XPending(xpbproxy_dpy) != 0) { - XEvent e; - - XNextEvent (xpbproxy_dpy, &e); - - switch (e.type) { - case SelectionClear: - if([xpbproxy_selection_object() is_active]) - [xpbproxy_selection_object () clear_event:&e.xselectionclear]; - break; - - case SelectionRequest: - [xpbproxy_selection_object () request_event:&e.xselectionrequest]; - break; - - case SelectionNotify: - [xpbproxy_selection_object () notify_event:&e.xselection]; - break; - - case PropertyNotify: - [xpbproxy_selection_object () property_event:&e.xproperty]; - break; - - default: - if(e.type >= xpbproxy_apple_wm_event_base && - e.type < xpbproxy_apple_wm_event_base + AppleWMNumberEvents) { - x_event_apple_wm_notify((XAppleWMNotifyEvent *) &e); - } else if(e.type == xpbproxy_xfixes_event_base + XFixesSelectionNotify) { - [xpbproxy_selection_object() xfixes_selection_notify:(XFixesSelectionNotifyEvent *)&e]; - } - break; - } - - XFlush(xpbproxy_dpy); - } - - [pool release]; -} - -static BOOL add_input_socket (int sock, CFOptionFlags callback_types, - CFSocketCallBack callback, const CFSocketContext *ctx, - CFRunLoopSourceRef *cf_source) { - CFSocketRef cf_sock; - - cf_sock = CFSocketCreateWithNative (kCFAllocatorDefault, sock, - callback_types, callback, ctx); - if (cf_sock == NULL) { - close (sock); - return FALSE; - } - - *cf_source = CFSocketCreateRunLoopSource (kCFAllocatorDefault, - cf_sock, 0); - CFRelease (cf_sock); - - if (*cf_source == NULL) - return FALSE; - - CFRunLoopAddSource (CFRunLoopGetCurrent (), - *cf_source, kCFRunLoopDefaultMode); - return TRUE; -} - -static void x_input_callback (CFSocketRef sock, CFSocketCallBackType type, - CFDataRef address, const void *data, void *info) { - -#ifdef STANDALONE_XPBPROXY - if(xpbproxy_prefs_reload) { - [xpbproxy_selection_object() reload_preferences]; - xpbproxy_prefs_reload = NO; - } -#endif - - xpbproxy_process_xevents(); -} - -BOOL xpbproxy_input_register(void) { - return add_input_socket(ConnectionNumber(xpbproxy_dpy), kCFSocketReadCallBack, - x_input_callback, NULL, &xpbproxy_dpy_source); -} +/* x-input.m -- event handling
+ Copyright (c) 2002, 2008 Apple Computer, 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 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.
+ */
+
+#include "pbproxy.h"
+#import "x-selection.h"
+
+#include <CoreFoundation/CFSocket.h>
+#include <CoreFoundation/CFRunLoop.h>
+
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/extensions/applewm.h>
+
+#include <unistd.h>
+
+static CFRunLoopSourceRef xpbproxy_dpy_source;
+
+#ifdef STANDALONE_XPBPROXY
+BOOL xpbproxy_prefs_reload = NO;
+#endif
+
+/* Timestamp when the X server last told us it's active */
+static Time last_activation_time;
+
+static void x_event_apple_wm_notify(XAppleWMNotifyEvent *e) {
+ int type = e->type - xpbproxy_apple_wm_event_base;
+ int kind = e->kind;
+
+ /* We want to reload prefs even if we're not active */
+ if(type == AppleWMActivationNotify &&
+ kind == AppleWMReloadPreferences)
+ [xpbproxy_selection_object() reload_preferences];
+
+ if(![xpbproxy_selection_object() is_active])
+ return;
+
+ switch (type) {
+ case AppleWMActivationNotify:
+ switch (kind) {
+ case AppleWMIsActive:
+ last_activation_time = e->time;
+ [xpbproxy_selection_object() x_active:e->time];
+ break;
+
+ case AppleWMIsInactive:
+ [xpbproxy_selection_object() x_inactive:e->time];
+ break;
+ }
+ break;
+
+ case AppleWMPasteboardNotify:
+ switch (kind) {
+ case AppleWMCopyToPasteboard:
+ [xpbproxy_selection_object() x_copy:e->time];
+ }
+ break;
+ }
+}
+
+static void xpbproxy_process_xevents(void) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if(pool == nil) {
+ ErrorF("unable to allocate/init auto release pool!\n");
+ return;
+ }
+
+ while (XPending(xpbproxy_dpy) != 0) {
+ XEvent e;
+
+ XNextEvent (xpbproxy_dpy, &e);
+
+ switch (e.type) {
+ case SelectionClear:
+ if([xpbproxy_selection_object() is_active])
+ [xpbproxy_selection_object () clear_event:&e.xselectionclear];
+ break;
+
+ case SelectionRequest:
+ [xpbproxy_selection_object () request_event:&e.xselectionrequest];
+ break;
+
+ case SelectionNotify:
+ [xpbproxy_selection_object () notify_event:&e.xselection];
+ break;
+
+ case PropertyNotify:
+ [xpbproxy_selection_object () property_event:&e.xproperty];
+ break;
+
+ default:
+ if(e.type >= xpbproxy_apple_wm_event_base &&
+ e.type < xpbproxy_apple_wm_event_base + AppleWMNumberEvents) {
+ x_event_apple_wm_notify((XAppleWMNotifyEvent *) &e);
+ } else if(e.type == xpbproxy_xfixes_event_base + XFixesSelectionNotify) {
+ [xpbproxy_selection_object() xfixes_selection_notify:(XFixesSelectionNotifyEvent *)&e];
+ }
+ break;
+ }
+
+ XFlush(xpbproxy_dpy);
+ }
+
+ [pool release];
+}
+
+static BOOL add_input_socket (int sock, CFOptionFlags callback_types,
+ CFSocketCallBack callback, const CFSocketContext *ctx,
+ CFRunLoopSourceRef *cf_source) {
+ CFSocketRef cf_sock;
+
+ cf_sock = CFSocketCreateWithNative (kCFAllocatorDefault, sock,
+ callback_types, callback, ctx);
+ if (cf_sock == NULL) {
+ close (sock);
+ return FALSE;
+ }
+
+ *cf_source = CFSocketCreateRunLoopSource (kCFAllocatorDefault,
+ cf_sock, 0);
+ CFRelease (cf_sock);
+
+ if (*cf_source == NULL)
+ return FALSE;
+
+ CFRunLoopAddSource (CFRunLoopGetCurrent (),
+ *cf_source, kCFRunLoopDefaultMode);
+ return TRUE;
+}
+
+static void x_input_callback (CFSocketRef sock, CFSocketCallBackType type,
+ CFDataRef address, const void *data, void *info) {
+
+#ifdef STANDALONE_XPBPROXY
+ if(xpbproxy_prefs_reload) {
+ [xpbproxy_selection_object() reload_preferences];
+ xpbproxy_prefs_reload = NO;
+ }
+#endif
+
+ xpbproxy_process_xevents();
+}
+
+BOOL xpbproxy_input_register(void) {
+ return add_input_socket(ConnectionNumber(xpbproxy_dpy), kCFSocketReadCallBack,
+ x_input_callback, NULL, &xpbproxy_dpy_source);
+}
diff --git a/xorg-server/hw/xquartz/pbproxy/x-selection.m b/xorg-server/hw/xquartz/pbproxy/x-selection.m index ef84f8bfb..8c099c6c9 100644 --- a/xorg-server/hw/xquartz/pbproxy/x-selection.m +++ b/xorg-server/hw/xquartz/pbproxy/x-selection.m @@ -1,1541 +1,1560 @@ -/* x-selection.m -- proxies between NSPasteboard and X11 selections - - Copyright (c) 2002, 2008 Apple Computer, 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 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. -*/ - -#import "x-selection.h" - -#include <stdio.h> -#include <stdlib.h> -#include <X11/Xatom.h> -#include <X11/Xutil.h> -#import <AppKit/NSGraphics.h> -#import <AppKit/NSImage.h> -#import <AppKit/NSBitmapImageRep.h> - -/* - * The basic design of the pbproxy code is as follows. - * - * When a client selects text, say from an xterm - we only copy it when the - * X11 Edit->Copy menu item is pressed or the shortcut activated. In this - * case we take the PRIMARY selection, and set it as the NSPasteboard data. - * - * When an X11 client copies something to the CLIPBOARD, pbproxy greedily grabs - * the data, sets it as the NSPasteboard data, and finally sets itself as - * owner of the CLIPBOARD. - * - * When an X11 window is activated we check to see if the NSPasteboard has - * changed. If the NSPasteboard has changed, then we set pbproxy as owner - * of the PRIMARY and CLIPBOARD and respond to requests for text and images. - * - * The behavior is now dynamic since the information above was written. - * The behavior is now dependent on the pbproxy_prefs below. - */ - -/* - * TODO: - * 1. handle MULTIPLE - I need to study the ICCCM further, and find a test app. - * 2. Handle NSPasteboard updates immediately, not on active/inactive - * - Open xterm, run 'cat readme.txt | pbcopy' - */ - -static struct { - BOOL active ; - BOOL primary_on_grab; /* This is provided as an option for people who - * want it and has issues that won't ever be - * addressed to make it *always* work. - */ - BOOL clipboard_to_pasteboard; - BOOL pasteboard_to_primary; - BOOL pasteboard_to_clipboard; -} pbproxy_prefs = { YES, NO, YES, YES, YES }; - -@implementation x_selection - -static struct propdata null_propdata = {NULL, 0, 0}; - -#ifdef DEBUG -static void -dump_prefs (FILE *fp) { - fprintf(fp, - "pbproxy preferences:\n" - "\tactive %u\n" - "\tprimary_on_grab %u\n" - "\tclipboard_to_pasteboard %u\n" - "\tpasteboard_to_primary %u\n" - "\tpasteboard_to_clipboard %u\n", - pbproxy_prefs.active, - pbproxy_prefs.primary_on_grab, - pbproxy_prefs.clipboard_to_pasteboard, - pbproxy_prefs.pasteboard_to_primary, - pbproxy_prefs.pasteboard_to_clipboard); -} -#endif - -extern CFStringRef app_prefs_domain_cfstr; - -static BOOL -prefs_get_bool (CFStringRef key, BOOL defaultValue) { - Boolean value, ok; - - value = CFPreferencesGetAppBooleanValue (key, app_prefs_domain_cfstr, &ok); - - return ok ? (BOOL) value : defaultValue; -} - -static void -init_propdata (struct propdata *pdata) -{ - *pdata = null_propdata; -} - -static void -free_propdata (struct propdata *pdata) -{ - free (pdata->data); - *pdata = null_propdata; -} - -/* - * Return True if an error occurs. Return False if pdata has data - * and we finished. - * The property is only deleted when bytesleft is 0 if delete is True. - */ -static Bool -get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Atom *type) -{ - long offset = 0; - unsigned long numitems, bytesleft = 0; -#ifdef TEST - /* This is used to test the growth handling. */ - unsigned long length = 4UL; -#else - unsigned long length = (100000UL + 3) / 4; -#endif - unsigned char *buf = NULL, *chunk = NULL; - size_t buflen = 0, chunkbytesize = 0; - int format; - - TRACE (); - - if(None == property) - return True; - - do - { - unsigned long newbuflen = 0; - unsigned char *newbuf = NULL; - -#ifdef TEST - printf("bytesleft %lu\n", bytesleft); -#endif - - if (Success != XGetWindowProperty (xpbproxy_dpy, win, property, - offset, length, delete, - AnyPropertyType, - type, &format, &numitems, - &bytesleft, &chunk)) - { - DB ("Error while getting window property.\n"); - *pdata = null_propdata; - free (buf); - return True; - } - -#ifdef TEST - printf("format %d numitems %lu bytesleft %lu\n", - format, numitems, bytesleft); - - printf("type %s\n", XGetAtomName (xpbproxy_dpy, *type)); -#endif - - /* Format is the number of bits. */ - chunkbytesize = numitems * (format / 8); - -#ifdef TEST - printf("chunkbytesize %zu\n", chunkbytesize); -#endif - newbuflen = buflen + chunkbytesize; - if (newbuflen > 0) - { - newbuf = realloc (buf, newbuflen); - - if (NULL == newbuf) - { - XFree (chunk); - free (buf); - return True; - } - - memcpy (newbuf + buflen, chunk, chunkbytesize); - XFree (chunk); - buf = newbuf; - buflen = newbuflen; - /* offset is a multiple of 32 bits*/ - offset += chunkbytesize / 4; - } - else - { - if (chunk) - XFree (chunk); - } - -#ifdef TEST - printf("bytesleft %lu\n", bytesleft); -#endif - } while (bytesleft > 0); - - pdata->data = buf; - pdata->length = buflen; - pdata->format = format; - - return /*success*/ False; -} - - -/* Implementation methods */ - -/* This finds the preferred type from a TARGETS list.*/ -- (Atom) find_preferred:(struct propdata *)pdata -{ - Atom a = None; - size_t i, step; - Bool png = False, jpeg = False, utf8 = False, string = False; - - TRACE (); - - if (pdata->format != 32) - { - fprintf(stderr, "Atom list is expected to be formatted as an array of 32bit values.\n"); - return None; - } - - for (i = 0, step = pdata->format >> 3; i < pdata->length; i += step) - { - a = (Atom)*(uint32_t *)(pdata->data + i); - - if (a == atoms->image_png) - { - png = True; - } - else if (a == atoms->image_jpeg) - { - jpeg = True; - } - else if (a == atoms->utf8_string) - { - utf8 = True; - } - else if (a == atoms->string) - { - string = True; - } - else - { - char *type = XGetAtomName(xpbproxy_dpy, a); - if (type) - { - DB("Unhandled X11 mime type: %s", type); - XFree(type); - } - } - } - - /*We prefer PNG over strings, and UTF8 over a Latin-1 string.*/ - if (png) - return atoms->image_png; - - if (jpeg) - return atoms->image_jpeg; - - if (utf8) - return atoms->utf8_string; - - if (string) - return atoms->string; - - /* This is evidently something we don't know how to handle.*/ - return None; -} - -/* Return True if this is an INCR-style transfer. */ -- (Bool) is_incr_type:(XSelectionEvent *)e -{ - Atom seltype; - int format; - unsigned long numitems = 0UL, bytesleft = 0UL; - unsigned char *chunk; - - TRACE (); - - if (Success != XGetWindowProperty (xpbproxy_dpy, e->requestor, e->property, - /*offset*/ 0L, /*length*/ 4UL, - /*Delete*/ False, - AnyPropertyType, &seltype, &format, - &numitems, &bytesleft, &chunk)) - { - return False; - } - - if(chunk) - XFree(chunk); - - return (seltype == atoms->incr) ? True : False; -} - -/* - * This should be called after a selection has been copied, - * or when the selection is unfinished before a transfer completes. - */ -- (void) release_pending -{ - TRACE (); - - free_propdata (&pending.propdata); - pending.requestor = None; - pending.selection = None; -} - -/* Return True if an error occurs during an append.*/ -/* Return False if the append succeeds. */ -- (Bool) append_to_pending:(struct propdata *)pdata requestor:(Window)requestor -{ - unsigned char *newdata; - size_t newlength; - - TRACE (); - - if (requestor != pending.requestor) - { - [self release_pending]; - pending.requestor = requestor; - } - - newlength = pending.propdata.length + pdata->length; - newdata = realloc(pending.propdata.data, newlength); - - if(NULL == newdata) - { - perror("realloc propdata"); - [self release_pending]; - return True; - } - - memcpy(newdata + pending.propdata.length, pdata->data, pdata->length); - pending.propdata.data = newdata; - pending.propdata.length = newlength; - - return False; -} - - - -/* Called when X11 becomes active (i.e. has key focus) */ -- (void) x_active:(Time)timestamp -{ - static NSInteger changeCount; - NSInteger countNow; - NSPasteboard *pb; - - TRACE (); - - pb = [NSPasteboard generalPasteboard]; - - if (nil == pb) - return; - - countNow = [pb changeCount]; - - if (countNow != changeCount) - { - DB ("changed pasteboard!\n"); - changeCount = countNow; - - if (pbproxy_prefs.pasteboard_to_primary) - { - XSetSelectionOwner (xpbproxy_dpy, atoms->primary, _selection_window, CurrentTime); - } - - if (pbproxy_prefs.pasteboard_to_clipboard) { - [self own_clipboard]; - } - } - -#if 0 - /*gstaplin: we should perhaps investigate something like this branch above...*/ - if ([_pasteboard availableTypeFromArray: _known_types] != nil) - { - /* Pasteboard has data we should proxy; I think it makes - sense to put it on both CLIPBOARD and PRIMARY */ - - XSetSelectionOwner (xpbproxy_dpy, atoms->clipboard, - _selection_window, timestamp); - XSetSelectionOwner (xpbproxy_dpy, atoms->primary, - _selection_window, timestamp); - } -#endif -} - -/* Called when X11 loses key focus */ -- (void) x_inactive:(Time)timestamp -{ - TRACE (); -} - -/* This requests the TARGETS list from the PRIMARY selection owner. */ -- (void) x_copy_request_targets -{ - TRACE (); - - request_atom = atoms->targets; - XConvertSelection (xpbproxy_dpy, atoms->primary, atoms->targets, - atoms->primary, _selection_window, CurrentTime); -} - -/* Called when the Edit/Copy item on the main X11 menubar is selected - * and no appkit window claims it. */ -- (void) x_copy:(Time)timestamp -{ - Window w; - - TRACE (); - - w = XGetSelectionOwner (xpbproxy_dpy, atoms->primary); - - if (None != w) - { - ++pending_copy; - - if (1 == pending_copy) { - /* - * There are no other copy operations in progress, so we - * can proceed safely. Otherwise the copy_completed method - * will see that the pending_copy is > 1, and do another copy. - */ - [self x_copy_request_targets]; - } - } -} - -/* Set pbproxy as owner of the SELECTION_MANAGER selection. - * This prevents tools like xclipboard from causing havoc. - * Returns TRUE on success - */ -- (BOOL) set_clipboard_manager_status:(BOOL)value -{ - TRACE (); - - Window owner = XGetSelectionOwner (xpbproxy_dpy, atoms->clipboard_manager); - - if(value) { - if(owner == _selection_window) - return TRUE; - - if(owner != None) { - fprintf (stderr, "A clipboard manager using window 0x%lx " - "already owns the clipboard selection. " - "pbproxy will not sync clipboard to pasteboard.\n", owner); - return FALSE; - } - - XSetSelectionOwner(xpbproxy_dpy, atoms->clipboard_manager, _selection_window, CurrentTime); - return (_selection_window == XGetSelectionOwner(xpbproxy_dpy, atoms->clipboard_manager)); - } else { - if(owner != _selection_window) - return TRUE; - - XSetSelectionOwner(xpbproxy_dpy, atoms->clipboard_manager, None, CurrentTime); - return(None == XGetSelectionOwner(xpbproxy_dpy, atoms->clipboard_manager)); - } - - return FALSE; -} - -/* - * This occurs when we previously owned a selection, - * and then lost it from another client. - */ -- (void) clear_event:(XSelectionClearEvent *)e -{ - - - TRACE (); - - DB ("e->selection %s\n", XGetAtomName (xpbproxy_dpy, e->selection)); - - if(e->selection == atoms->clipboard) { - /* - * We lost ownership of the CLIPBOARD. - */ - ++pending_clipboard; - - if (1 == pending_clipboard) { - /* Claim the clipboard contents from the new owner. */ - [self claim_clipboard]; - } - } else if(e->selection == atoms->clipboard_manager) { - if(pbproxy_prefs.clipboard_to_pasteboard) { - /* Another CLIPBOARD_MANAGER has set itself as owner. Disable syncing - * to avoid a race. - */ - fprintf(stderr, "Another clipboard manager was started! " - "xpbproxy is disabling syncing with clipboard.\n"); - pbproxy_prefs.clipboard_to_pasteboard = NO; - } - } -} - -/* - * We greedily acquire the clipboard after it changes, and on startup. - */ -- (void) claim_clipboard -{ - Window owner; - - TRACE (); - - if (!pbproxy_prefs.clipboard_to_pasteboard) - return; - - owner = XGetSelectionOwner (xpbproxy_dpy, atoms->clipboard); - if (None == owner) { - /* - * The owner probably died or we are just starting up pbproxy. - * Set pbproxy's _selection_window as the owner, and continue. - */ - DB ("No clipboard owner.\n"); - [self copy_completed:atoms->clipboard]; - return; - } else if (owner == _selection_window) { - [self copy_completed:atoms->clipboard]; - return; - } - - DB ("requesting targets\n"); - - request_atom = atoms->targets; - XConvertSelection (xpbproxy_dpy, atoms->clipboard, atoms->targets, - atoms->clipboard, _selection_window, CurrentTime); - XFlush (xpbproxy_dpy); - /* Now we will get a SelectionNotify event in the future. */ -} - -/* Greedily acquire the clipboard. */ -- (void) own_clipboard -{ - - TRACE (); - - /* We should perhaps have a boundary limit on the number of iterations... */ - do - { - XSetSelectionOwner (xpbproxy_dpy, atoms->clipboard, _selection_window, - CurrentTime); - } while (_selection_window != XGetSelectionOwner (xpbproxy_dpy, - atoms->clipboard)); -} - -- (void) init_reply:(XEvent *)reply request:(XSelectionRequestEvent *)e -{ - reply->xselection.type = SelectionNotify; - reply->xselection.selection = e->selection; - reply->xselection.target = e->target; - reply->xselection.requestor = e->requestor; - reply->xselection.time = e->time; - reply->xselection.property = None; -} - -- (void) send_reply:(XEvent *)reply -{ - /* - * We are supposed to use an empty event mask, and not propagate - * the event, according to the ICCCM. - */ - DB ("reply->xselection.requestor 0x%lx\n", reply->xselection.requestor); - - XSendEvent (xpbproxy_dpy, reply->xselection.requestor, False, 0, reply); - XFlush (xpbproxy_dpy); -} - -/* - * This responds to a TARGETS request. - * The result is a list of a ATOMs that correspond to the types available - * for a selection. - * For instance an application might provide a UTF8_STRING and a STRING - * (in Latin-1 encoding). The requestor can then make the choice based on - * the list. - */ -- (void) send_targets:(XSelectionRequestEvent *)e pasteboard:(NSPasteboard *)pb -{ - XEvent reply; - NSArray *pbtypes; - - [self init_reply:&reply request:e]; - - pbtypes = [pb types]; - if (pbtypes) - { - long list[7]; /* Don't forget to increase this if we handle more types! */ - long count = 0; - - /* - * I'm not sure if this is needed, but some toolkits/clients list - * TARGETS in response to targets. - */ - list[count] = atoms->targets; - ++count; - - if ([pbtypes containsObject:NSStringPboardType]) - { - /* We have a string type that we can convert to UTF8, or Latin-1... */ - DB ("NSStringPboardType\n"); - list[count] = atoms->utf8_string; - ++count; - list[count] = atoms->string; - ++count; - list[count] = atoms->compound_text; - ++count; - } - - /* TODO add the NSPICTPboardType back again, once we have conversion - * functionality in send_image. - */ - - if ([pbtypes containsObject:NSPICTPboardType] - || [pbtypes containsObject:NSTIFFPboardType]) - { - /* We can convert a TIFF to a PNG or JPEG. */ - DB ("NSTIFFPboardType\n"); - list[count] = atoms->image_png; - ++count; - list[count] = atoms->image_jpeg; - ++count; - } - - if (count) - { - /* We have a list of ATOMs to send. */ - XChangeProperty (xpbproxy_dpy, e->requestor, e->property, atoms->atom, 32, - PropModeReplace, (unsigned char *) list, count); - - reply.xselection.property = e->property; - } - } - - [self send_reply:&reply]; -} - - -- (void) send_string:(XSelectionRequestEvent *)e utf8:(BOOL)utf8 pasteboard:(NSPasteboard *)pb -{ - XEvent reply; - NSArray *pbtypes; - NSString *data; - const char *bytes; - NSUInteger length; - - TRACE (); - - [self init_reply:&reply request:e]; - - pbtypes = [pb types]; - - if (![pbtypes containsObject:NSStringPboardType]) - { - [self send_reply:&reply]; - return; - } - - DB ("pbtypes retainCount after containsObject: %u\n", [pbtypes retainCount]); - - data = [pb stringForType:NSStringPboardType]; - - if (nil == data) - { - [self send_reply:&reply]; - return; - } - - if (utf8) - { - bytes = [data UTF8String]; - /* - * We don't want the UTF-8 string length here. - * We want the length in bytes. - */ - length = strlen (bytes); - - if (length < 50) { - DB ("UTF-8: %s\n", bytes); - DB ("UTF-8 length: %u\n", length); - } - } - else - { - DB ("Latin-1\n"); - bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding]; - /*WARNING: bytes is not NUL-terminated. */ - length = [data lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding]; - } - - DB ("e->target %s\n", XGetAtomName (xpbproxy_dpy, e->target)); - - XChangeProperty (xpbproxy_dpy, e->requestor, e->property, e->target, - 8, PropModeReplace, (unsigned char *) bytes, length); - - reply.xselection.property = e->property; - - [self send_reply:&reply]; -} - -- (void) send_compound_text:(XSelectionRequestEvent *)e pasteboard:(NSPasteboard *)pb -{ - XEvent reply; - NSArray *pbtypes; - - TRACE (); - - [self init_reply:&reply request:e]; - - pbtypes = [pb types]; - - if ([pbtypes containsObject: NSStringPboardType]) - { - NSString *data = [pb stringForType:NSStringPboardType]; - if (nil != data) - { - /* - * Cast to (void *) to avoid a const warning. - * AFAIK Xutf8TextListToTextProperty does not modify the input memory. - */ - void *utf8 = (void *)[data UTF8String]; - char *list[] = { utf8, NULL }; - XTextProperty textprop; - - textprop.value = NULL; - - if (Success == Xutf8TextListToTextProperty (xpbproxy_dpy, list, 1, - XCompoundTextStyle, - &textprop)) - { - - if (8 != textprop.format) - DB ("textprop.format is unexpectedly not 8 - it's %d instead\n", - textprop.format); - - XChangeProperty (xpbproxy_dpy, e->requestor, e->property, - atoms->compound_text, textprop.format, - PropModeReplace, textprop.value, - textprop.nitems); - - reply.xselection.property = e->property; - } - - if (textprop.value) - XFree (textprop.value); - - } - } - - [self send_reply:&reply]; -} - -/* Finding a test application that uses MULTIPLE has proven to be difficult. */ -- (void) send_multiple:(XSelectionRequestEvent *)e -{ - XEvent reply; - - TRACE (); - - [self init_reply:&reply request:e]; - - if (None != e->property) - { - - } - - [self send_reply:&reply]; -} - -/* Return nil if an error occured. */ -/* DO NOT retain the encdata for longer than the length of an event response. - * The autorelease pool will reuse/free it. - */ -- (NSData *) encode_image_data:(NSData *)data type:(NSBitmapImageFileType)enctype -{ - NSBitmapImageRep *bmimage = nil; - NSData *encdata = nil; - NSDictionary *dict = nil; - - bmimage = [[NSBitmapImageRep alloc] initWithData:data]; - - if (nil == bmimage) - return nil; - - dict = [[NSDictionary alloc] init]; - encdata = [bmimage representationUsingType:enctype properties:dict]; - - if (nil == encdata) - { - [dict autorelease]; - [bmimage autorelease]; - return nil; - } - - [dict autorelease]; - [bmimage autorelease]; - - return encdata; -} - -/* Return YES when an error has occured when trying to send the PICT. */ -/* The caller should send a default reponse with a property of None when an error occurs. */ -- (BOOL) send_image_pict_reply:(XSelectionRequestEvent *)e - pasteboard:(NSPasteboard *)pb - type:(NSBitmapImageFileType)imagetype -{ - XEvent reply; - NSImage *img = nil; - NSData *data = nil, *encdata = nil; - NSUInteger length; - const void *bytes = NULL; - - img = [[NSImage alloc] initWithPasteboard:pb]; - - if (nil == img) - { - return YES; - } - - data = [img TIFFRepresentation]; - - if (nil == data) - { - [img autorelease]; - fprintf(stderr, "unable to convert PICT to TIFF!\n"); - return YES; - } - - encdata = [self encode_image_data:data type:imagetype]; - if(nil == encdata) - { - [img autorelease]; - return YES; - } - - [self init_reply:&reply request:e]; - - length = [encdata length]; - bytes = [encdata bytes]; - - XChangeProperty (xpbproxy_dpy, e->requestor, e->property, e->target, - 8, PropModeReplace, bytes, length); - reply.xselection.property = e->property; - - [self send_reply:&reply]; - - [img autorelease]; - - return NO; /*no error*/ -} - -/* Return YES if an error occured. */ -/* The caller should send a reply with a property of None when an error occurs. */ -- (BOOL) send_image_tiff_reply:(XSelectionRequestEvent *)e - pasteboard:(NSPasteboard *)pb - type:(NSBitmapImageFileType)imagetype -{ - XEvent reply; - NSData *data = nil; - NSData *encdata = nil; - NSUInteger length; - const void *bytes = NULL; - - data = [pb dataForType:NSTIFFPboardType]; - - if (nil == data) - return YES; - - encdata = [self encode_image_data:data type:imagetype]; - - if(nil == encdata) - return YES; - - [self init_reply:&reply request:e]; - - length = [encdata length]; - bytes = [encdata bytes]; - - XChangeProperty (xpbproxy_dpy, e->requestor, e->property, e->target, - 8, PropModeReplace, bytes, length); - reply.xselection.property = e->property; - - [self send_reply:&reply]; - - return NO; /*no error*/ -} - -- (void) send_image:(XSelectionRequestEvent *)e pasteboard:(NSPasteboard *)pb -{ - NSArray *pbtypes = nil; - NSBitmapImageFileType imagetype = NSPNGFileType; - - TRACE (); - - if (e->target == atoms->image_png) - imagetype = NSPNGFileType; - else if (e->target == atoms->image_jpeg) - imagetype = NSJPEGFileType; - else - { - fprintf(stderr, "internal failure in xpbproxy! imagetype being sent isn't PNG or JPEG.\n"); - } - - pbtypes = [pb types]; - - if (pbtypes) - { - if ([pbtypes containsObject:NSTIFFPboardType]) - { - if (NO == [self send_image_tiff_reply:e pasteboard:pb type:imagetype]) - return; - } - else if ([pbtypes containsObject:NSPICTPboardType]) - { - if (NO == [self send_image_pict_reply:e pasteboard:pb type:imagetype]) - return; - - /* Fall through intentionally to the send_none: */ - } - } - - [self send_none:e]; -} - -- (void)send_none:(XSelectionRequestEvent *)e -{ - XEvent reply; - - TRACE (); - - [self init_reply:&reply request:e]; - [self send_reply:&reply]; -} - - -/* Another client requested the data or targets of data available from the clipboard. */ -- (void)request_event:(XSelectionRequestEvent *)e -{ - NSPasteboard *pb; - - TRACE (); - - /* TODO We should also keep track of the time of the selection, and - * according to the ICCCM "refuse the request" if the event timestamp - * is before we owned it. - * What should we base the time on? How can we get the current time just - * before an XSetSelectionOwner? Is it the server's time, or the clients? - * According to the XSelectionRequestEvent manual page, the Time value - * may be set to CurrentTime or a time, so that makes it a bit different. - * Perhaps we should just punt and ignore races. - */ - - /*TODO we need a COMPOUND_TEXT test app*/ - /*TODO we need a MULTIPLE test app*/ - - pb = [NSPasteboard generalPasteboard]; - if (nil == pb) - { - [self send_none:e]; - return; - } - - - if (None != e->target) - DB ("e->target %s\n", XGetAtomName (xpbproxy_dpy, e->target)); - - if (e->target == atoms->targets) - { - /* The paste requestor wants to know what TARGETS we support. */ - [self send_targets:e pasteboard:pb]; - } - else if (e->target == atoms->multiple) - { - /* - * This isn't finished, and may never be, unless I can find - * a good test app. - */ - [self send_multiple:e]; - } - else if (e->target == atoms->utf8_string) - { - [self send_string:e utf8:YES pasteboard:pb]; - } - else if (e->target == atoms->string) - { - [self send_string:e utf8:NO pasteboard:pb]; - } - else if (e->target == atoms->compound_text) - { - [self send_compound_text:e pasteboard:pb]; - } - else if (e->target == atoms->multiple) - { - [self send_multiple:e]; - } - else if (e->target == atoms->image_png || e->target == atoms->image_jpeg) - { - [self send_image:e pasteboard:pb]; - } - else - { - [self send_none:e]; - } -} - -/* This handles the events resulting from an XConvertSelection request. */ -- (void) notify_event:(XSelectionEvent *)e -{ - Atom type; - struct propdata pdata; - - TRACE (); - - [self release_pending]; - - if (None == e->property) { - DB ("e->property is None.\n"); - [self copy_completed:e->selection]; - /* Nothing is selected. */ - return; - } - -#if 0 - printf ("e->selection %s\n", XGetAtomName (xpbproxy_dpy, e->selection)); - printf ("e->property %s\n", XGetAtomName (xpbproxy_dpy, e->property)); -#endif - - if ([self is_incr_type:e]) - { - /* - * This is an INCR-style transfer, which means that we - * will get the data after a series of PropertyNotify events. - */ - DB ("is INCR\n"); - - if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type)) - { - /* - * An error occured, so we should invoke the copy_completed:, but - * not handle_selection:type:propdata: - */ - [self copy_completed:e->selection]; - return; - } - - free_propdata (&pdata); - - pending.requestor = e->requestor; - pending.selection = e->selection; - - DB ("set pending.requestor to 0x%lx\n", pending.requestor); - } - else - { - if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type)) - { - [self copy_completed:e->selection]; - return; - } - - /* We have the complete selection data.*/ - [self handle_selection:e->selection type:type propdata:&pdata]; - - DB ("handled selection with the first notify_event\n"); - } -} - -/* This is used for INCR transfers. See the ICCCM for the details. */ -/* This is used to retrieve PRIMARY and CLIPBOARD selections. */ -- (void) property_event:(XPropertyEvent *)e -{ - struct propdata pdata; - Atom type; - - TRACE (); - - if (None != e->atom) - { -#ifdef DEBUG - char *name = XGetAtomName (xpbproxy_dpy, e->atom); - - if (name) - { - DB ("e->atom %s\n", name); - XFree(name); - } -#endif - } - - if (None != pending.requestor && PropertyNewValue == e->state) - { - DB ("pending.requestor 0x%lx\n", pending.requestor); - - if (get_property (e->window, e->atom, &pdata, /*Delete*/ True, &type)) - { - [self copy_completed:pending.selection]; - [self release_pending]; - return; - } - - if (0 == pdata.length) - { - /* - * We completed the transfer. - * handle_selection will call copy_completed: for us. - */ - [self handle_selection:pending.selection type:type propdata:&pending.propdata]; - free_propdata(&pdata); - pending.propdata = null_propdata; - pending.requestor = None; - pending.selection = None; - } - else - { - [self append_to_pending:&pdata requestor:e->window]; - free_propdata (&pdata); - } - } -} - -- (void) xfixes_selection_notify:(XFixesSelectionNotifyEvent *)e { - if(!pbproxy_prefs.active) - return; - - switch(e->subtype) { - case XFixesSetSelectionOwnerNotify: - if(e->selection == atoms->primary && pbproxy_prefs.primary_on_grab) - [self x_copy:e->timestamp]; - break; - - case XFixesSelectionWindowDestroyNotify: - case XFixesSelectionClientCloseNotify: - default: - fprintf(stderr, "Unhandled XFixesSelectionNotifyEvent: subtype=%d\n", e->subtype); - break; - } -} - -- (void) handle_targets: (Atom)selection propdata:(struct propdata *)pdata -{ - /* Find a type we can handle and prefer from the list of ATOMs. */ - Atom preferred; - char *name; - - TRACE (); - - preferred = [self find_preferred:pdata]; - - if (None == preferred) - { - /* - * This isn't required by the ICCCM, but some apps apparently - * don't respond to TARGETS properly. - */ - preferred = atoms->string; - } - - (void)name; /* Avoid a warning with non-debug compiles. */ -#ifdef DEBUG - name = XGetAtomName (xpbproxy_dpy, preferred); - - if (name) - { - DB ("requesting %s\n", name); - } -#endif - request_atom = preferred; - XConvertSelection (xpbproxy_dpy, selection, preferred, selection, - _selection_window, CurrentTime); -} - -/* This handles the image type of selection (typically in CLIPBOARD). */ -/* We convert to a TIFF, so that other applications can paste more easily. */ -- (void) handle_image: (struct propdata *)pdata pasteboard:(NSPasteboard *)pb -{ - NSArray *pbtypes; - NSUInteger length; - NSData *data, *tiff; - NSBitmapImageRep *bmimage; - - TRACE (); - - length = pdata->length; - data = [[NSData alloc] initWithBytes:pdata->data length:length]; - - if (nil == data) - { - DB ("unable to create NSData object!\n"); - return; - } - - DB ("data retainCount before NSBitmapImageRep initWithData: %u\n", - [data retainCount]); - - bmimage = [[NSBitmapImageRep alloc] initWithData:data]; - - if (nil == bmimage) - { - [data autorelease]; - DB ("unable to create NSBitmapImageRep!\n"); - return; - } - - DB ("data retainCount after NSBitmapImageRep initWithData: %u\n", - [data retainCount]); - - @try - { - tiff = [bmimage TIFFRepresentation]; - } - - @catch (NSException *e) - { - DB ("NSTIFFException!\n"); - [data autorelease]; - [bmimage autorelease]; - return; - } - - DB ("bmimage retainCount after TIFFRepresentation %u\n", [bmimage retainCount]); - - pbtypes = [NSArray arrayWithObjects:NSTIFFPboardType, nil]; - - if (nil == pbtypes) - { - [data autorelease]; - [bmimage autorelease]; - return; - } - - [pb declareTypes:pbtypes owner:nil]; - if (YES != [pb setData:tiff forType:NSTIFFPboardType]) - { - DB ("writing pasteboard data failed!\n"); - } - - [data autorelease]; - - DB ("bmimage retainCount before release %u\n", [bmimage retainCount]); - [bmimage autorelease]; -} - -/* This handles the UTF8_STRING type of selection. */ -- (void) handle_utf8_string:(struct propdata *)pdata pasteboard:(NSPasteboard *)pb -{ - NSString *string; - NSArray *pbtypes; - - TRACE (); - - string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSUTF8StringEncoding]; - - if (nil == string) - return; - - pbtypes = [NSArray arrayWithObjects:NSStringPboardType, nil]; - - if (nil == pbtypes) - { - [string autorelease]; - return; - } - - [pb declareTypes:pbtypes owner:nil]; - - if (YES != [pb setString:string forType:NSStringPboardType]) { - fprintf(stderr, "pasteboard setString:forType: failed!\n"); - } - [string autorelease]; - DB ("done handling utf8 string\n"); -} - -/* This handles the STRING type, which should be in Latin-1. */ -- (void) handle_string: (struct propdata *)pdata pasteboard:(NSPasteboard *)pb -{ - NSString *string; - NSArray *pbtypes; - - TRACE (); - - string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSISOLatin1StringEncoding]; - - if (nil == string) - return; - - pbtypes = [NSArray arrayWithObjects:NSStringPboardType, nil]; - - if (nil == pbtypes) - { - [string autorelease]; - return; - } - - [pb declareTypes:pbtypes owner:nil]; - if (YES != [pb setString:string forType:NSStringPboardType]) { - fprintf(stderr, "pasteboard setString:forType failed in handle_string!\n"); - } - [string autorelease]; -} - -/* This is called when the selection is completely retrieved from another client. */ -/* Warning: this frees the propdata. */ -- (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata -{ - NSPasteboard *pb; - - TRACE (); - - pb = [NSPasteboard generalPasteboard]; - - if (nil == pb) - { - [self copy_completed:selection]; - free_propdata (pdata); - return; - } - - /* - * Some apps it seems set the type to TARGETS instead of ATOM, such as Eterm. - * These aren't ICCCM compliant apps, but we need these to work... - */ - if (request_atom == atoms->targets - && (type == atoms->atom || type == atoms->targets)) - { - [self handle_targets:selection propdata:pdata]; - free_propdata(pdata); - return; - } - else if (type == atoms->image_png) - { - [self handle_image:pdata pasteboard:pb]; - } - else if (type == atoms->image_jpeg) - { - [self handle_image:pdata pasteboard:pb]; - } - else if (type == atoms->utf8_string) - { - [self handle_utf8_string:pdata pasteboard:pb]; - } - else if (type == atoms->string) - { - [self handle_string:pdata pasteboard:pb]; - } - - free_propdata(pdata); - - [self copy_completed:selection]; -} - - -- (void) copy_completed:(Atom)selection -{ - TRACE (); - char *name; - - (void)name; /* Avoid warning with non-debug compiles. */ -#ifdef DEBUG - name = XGetAtomName (xpbproxy_dpy, selection); - if (name) - { - DB ("copy_completed: %s\n", name); - XFree (name); - } -#endif - - if (selection == atoms->primary && pending_copy > 0) - { - --pending_copy; - if (pending_copy > 0) - { - /* Copy PRIMARY again. */ - [self x_copy_request_targets]; - return; - } - } - else if (selection == atoms->clipboard && pending_clipboard > 0) - { - --pending_clipboard; - if (pending_clipboard > 0) - { - /* Copy CLIPBOARD. */ - [self claim_clipboard]; - return; - } - else - { - /* We got the final data. Now set pbproxy as the owner. */ - [self own_clipboard]; - return; - } - } - - /* - * We had 1 or more primary in progress, and the clipboard arrived - * while we were busy. - */ - if (pending_clipboard > 0) - { - [self claim_clipboard]; - } -} - -- (void) reload_preferences -{ - /* - * It's uncertain how we could handle the synchronization failing, so cast to void. - * The prefs_get_bool should fall back to defaults if the org.x.X11 plist doesn't exist or is invalid. - */ - (void)CFPreferencesAppSynchronize(app_prefs_domain_cfstr); -#ifdef STANDALONE_XPBPROXY - if(xpbproxy_is_standalone) - pbproxy_prefs.active = YES; - else -#endif - pbproxy_prefs.active = prefs_get_bool(CFSTR("sync_pasteboard"), pbproxy_prefs.active); - pbproxy_prefs.primary_on_grab = prefs_get_bool(CFSTR("sync_primary_on_select"), pbproxy_prefs.primary_on_grab); - pbproxy_prefs.clipboard_to_pasteboard = prefs_get_bool(CFSTR("sync_clipboard_to_pasteboard"), pbproxy_prefs.clipboard_to_pasteboard); - pbproxy_prefs.pasteboard_to_primary = prefs_get_bool(CFSTR("sync_pasteboard_to_primary"), pbproxy_prefs.pasteboard_to_primary); - pbproxy_prefs.pasteboard_to_clipboard = prefs_get_bool(CFSTR("sync_pasteboard_to_clipboard"), pbproxy_prefs.pasteboard_to_clipboard); - - /* This is used for debugging. */ - //dump_prefs(stdout); - - if(pbproxy_prefs.active && pbproxy_prefs.primary_on_grab && !xpbproxy_have_xfixes) { - fprintf(stderr, "Disabling sync_primary_on_select functionality due to missing XFixes extension.\n"); - pbproxy_prefs.primary_on_grab = NO; - } - - /* Claim or release the CLIPBOARD_MANAGER atom */ - if(![self set_clipboard_manager_status:(pbproxy_prefs.active && pbproxy_prefs.clipboard_to_pasteboard)]) - pbproxy_prefs.clipboard_to_pasteboard = NO; - - if(pbproxy_prefs.active && pbproxy_prefs.clipboard_to_pasteboard) - [self claim_clipboard]; -} - -- (BOOL) is_active -{ - return pbproxy_prefs.active; -} - -/* NSPasteboard-required methods */ - -- (void) paste:(id)sender -{ - TRACE (); -} - -- (void) pasteboard:(NSPasteboard *)pb provideDataForType:(NSString *)type -{ - TRACE (); -} - -- (void) pasteboardChangedOwner:(NSPasteboard *)pb -{ - TRACE (); - - /* Right now we don't care with this. */ -} - -/* Allocation */ - -- init -{ - unsigned long pixel; - - self = [super init]; - if (self == nil) - return nil; - - atoms->primary = XInternAtom (xpbproxy_dpy, "PRIMARY", False); - atoms->clipboard = XInternAtom (xpbproxy_dpy, "CLIPBOARD", False); - atoms->text = XInternAtom (xpbproxy_dpy, "TEXT", False); - atoms->utf8_string = XInternAtom (xpbproxy_dpy, "UTF8_STRING", False); - atoms->string = XInternAtom (xpbproxy_dpy, "STRING", False); - atoms->targets = XInternAtom (xpbproxy_dpy, "TARGETS", False); - atoms->multiple = XInternAtom (xpbproxy_dpy, "MULTIPLE", False); - atoms->cstring = XInternAtom (xpbproxy_dpy, "CSTRING", False); - atoms->image_png = XInternAtom (xpbproxy_dpy, "image/png", False); - atoms->image_jpeg = XInternAtom (xpbproxy_dpy, "image/jpeg", False); - atoms->incr = XInternAtom (xpbproxy_dpy, "INCR", False); - atoms->atom = XInternAtom (xpbproxy_dpy, "ATOM", False); - atoms->clipboard_manager = XInternAtom (xpbproxy_dpy, "CLIPBOARD_MANAGER", False); - atoms->compound_text = XInternAtom (xpbproxy_dpy, "COMPOUND_TEXT", False); - atoms->atom_pair = XInternAtom (xpbproxy_dpy, "ATOM_PAIR", False); - - pixel = BlackPixel (xpbproxy_dpy, DefaultScreen (xpbproxy_dpy)); - _selection_window = XCreateSimpleWindow (xpbproxy_dpy, DefaultRootWindow (xpbproxy_dpy), - 0, 0, 1, 1, 0, pixel, pixel); - - /* This is used to get PropertyNotify events when doing INCR transfers. */ - XSelectInput (xpbproxy_dpy, _selection_window, PropertyChangeMask); - - request_atom = None; - - init_propdata (&pending.propdata); - pending.requestor = None; - pending.selection = None; - - pending_copy = 0; - pending_clipboard = 0; - - if(xpbproxy_have_xfixes) - XFixesSelectSelectionInput(xpbproxy_dpy, _selection_window, atoms->primary, - XFixesSetSelectionOwnerNotifyMask); - - [self reload_preferences]; - - return self; -} - -- (void) dealloc -{ - if (None != _selection_window) - { - XDestroyWindow (xpbproxy_dpy, _selection_window); - _selection_window = None; - } - - free_propdata (&pending.propdata); - - [super dealloc]; -} - -@end +/* x-selection.m -- proxies between NSPasteboard and X11 selections
+
+ Copyright (c) 2002, 2008 Apple Computer, 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 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.
+*/
+
+#import "x-selection.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#import <AppKit/NSGraphics.h>
+#import <AppKit/NSImage.h>
+#import <AppKit/NSBitmapImageRep.h>
+
+/*
+ * The basic design of the pbproxy code is as follows.
+ *
+ * When a client selects text, say from an xterm - we only copy it when the
+ * X11 Edit->Copy menu item is pressed or the shortcut activated. In this
+ * case we take the PRIMARY selection, and set it as the NSPasteboard data.
+ *
+ * When an X11 client copies something to the CLIPBOARD, pbproxy greedily grabs
+ * the data, sets it as the NSPasteboard data, and finally sets itself as
+ * owner of the CLIPBOARD.
+ *
+ * When an X11 window is activated we check to see if the NSPasteboard has
+ * changed. If the NSPasteboard has changed, then we set pbproxy as owner
+ * of the PRIMARY and CLIPBOARD and respond to requests for text and images.
+ *
+ * The behavior is now dynamic since the information above was written.
+ * The behavior is now dependent on the pbproxy_prefs below.
+ */
+
+/*
+ * TODO:
+ * 1. handle MULTIPLE - I need to study the ICCCM further, and find a test app.
+ * 2. Handle NSPasteboard updates immediately, not on active/inactive
+ * - Open xterm, run 'cat readme.txt | pbcopy'
+ */
+
+static struct {
+ BOOL active ;
+ BOOL primary_on_grab; /* This is provided as an option for people who
+ * want it and has issues that won't ever be
+ * addressed to make it *always* work.
+ */
+ BOOL clipboard_to_pasteboard;
+ BOOL pasteboard_to_primary;
+ BOOL pasteboard_to_clipboard;
+} pbproxy_prefs = { YES, NO, YES, YES, YES };
+
+@implementation x_selection
+
+static struct propdata null_propdata = {NULL, 0, 0};
+
+#ifdef DEBUG
+static void
+dump_prefs() {
+ ErrorF(fp,
+ "pbproxy preferences:\n"
+ "\tactive %u\n"
+ "\tprimary_on_grab %u\n"
+ "\tclipboard_to_pasteboard %u\n"
+ "\tpasteboard_to_primary %u\n"
+ "\tpasteboard_to_clipboard %u\n",
+ pbproxy_prefs.active,
+ pbproxy_prefs.primary_on_grab,
+ pbproxy_prefs.clipboard_to_pasteboard,
+ pbproxy_prefs.pasteboard_to_primary,
+ pbproxy_prefs.pasteboard_to_clipboard);
+}
+#endif
+
+extern CFStringRef app_prefs_domain_cfstr;
+
+static BOOL
+prefs_get_bool (CFStringRef key, BOOL defaultValue) {
+ Boolean value, ok;
+
+ value = CFPreferencesGetAppBooleanValue (key, app_prefs_domain_cfstr, &ok);
+
+ return ok ? (BOOL) value : defaultValue;
+}
+
+static void
+init_propdata (struct propdata *pdata)
+{
+ *pdata = null_propdata;
+}
+
+static void
+free_propdata (struct propdata *pdata)
+{
+ free (pdata->data);
+ *pdata = null_propdata;
+}
+
+/*
+ * Return True if an error occurs. Return False if pdata has data
+ * and we finished.
+ * The property is only deleted when bytesleft is 0 if delete is True.
+ */
+static Bool
+get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Atom *type)
+{
+ long offset = 0;
+ unsigned long numitems, bytesleft = 0;
+#ifdef TEST
+ /* This is used to test the growth handling. */
+ unsigned long length = 4UL;
+#else
+ unsigned long length = (100000UL + 3) / 4;
+#endif
+ unsigned char *buf = NULL, *chunk = NULL;
+ size_t buflen = 0, chunkbytesize = 0;
+ int format;
+
+ TRACE ();
+
+ if(None == property)
+ return True;
+
+ do
+ {
+ unsigned long newbuflen = 0;
+ unsigned char *newbuf = NULL;
+
+#ifdef TEST
+ ErrorF("bytesleft %lu\n", bytesleft);
+#endif
+
+ if (Success != XGetWindowProperty (xpbproxy_dpy, win, property,
+ offset, length, delete,
+ AnyPropertyType,
+ type, &format, &numitems,
+ &bytesleft, &chunk))
+ {
+ DebugF ("Error while getting window property.\n");
+ *pdata = null_propdata;
+ free (buf);
+ return True;
+ }
+
+#ifdef TEST
+ ErrorF("format %d numitems %lu bytesleft %lu\n",
+ format, numitems, bytesleft);
+
+ ErrorF("type %s\n", XGetAtomName (xpbproxy_dpy, *type));
+#endif
+
+ /* Format is the number of bits. */
+ if (format == 8)
+ chunkbytesize = numitems;
+ else if (format == 16)
+ chunkbytesize = numitems * sizeof(short);
+ else if (format == 32)
+ chunkbytesize = numitems * sizeof(long);
+
+#ifdef TEST
+ ErrorF("chunkbytesize %zu\n", chunkbytesize);
+#endif
+ newbuflen = buflen + chunkbytesize;
+ if (newbuflen > 0)
+ {
+ newbuf = realloc (buf, newbuflen);
+
+ if (NULL == newbuf)
+ {
+ XFree (chunk);
+ free (buf);
+ return True;
+ }
+
+ memcpy (newbuf + buflen, chunk, chunkbytesize);
+ XFree (chunk);
+ buf = newbuf;
+ buflen = newbuflen;
+ /* offset is a multiple of 32 bits*/
+ offset += chunkbytesize / 4;
+ }
+ else
+ {
+ if (chunk)
+ XFree (chunk);
+ }
+
+#ifdef TEST
+ ErrorF("bytesleft %lu\n", bytesleft);
+#endif
+ } while (bytesleft > 0);
+
+ pdata->data = buf;
+ pdata->length = buflen;
+ pdata->format = format;
+
+ return /*success*/ False;
+}
+
+
+/* Implementation methods */
+
+/* This finds the preferred type from a TARGETS list.*/
+- (Atom) find_preferred:(struct propdata *)pdata
+{
+ Atom a = None;
+ size_t i, step;
+ Bool png = False, jpeg = False, utf8 = False, string = False;
+
+ TRACE ();
+
+ if (pdata->format != 32)
+ {
+ ErrorF("Atom list is expected to be formatted as an array of 32bit values.\n");
+ return None;
+ }
+
+ for (i = 0, step = sizeof(long); i < pdata->length; i += step)
+ {
+ a = (Atom)*(long *)(pdata->data + i);
+
+ if (a == atoms->image_png)
+ {
+ png = True;
+ }
+ else if (a == atoms->image_jpeg)
+ {
+ jpeg = True;
+ }
+ else if (a == atoms->utf8_string)
+ {
+ utf8 = True;
+ }
+ else if (a == atoms->string)
+ {
+ string = True;
+ }
+ else
+ {
+ char *type = XGetAtomName(xpbproxy_dpy, a);
+ if (type)
+ {
+ DebugF("Unhandled X11 mime type: %s", type);
+ XFree(type);
+ }
+ }
+ }
+
+ /*We prefer PNG over strings, and UTF8 over a Latin-1 string.*/
+ if (png)
+ return atoms->image_png;
+
+ if (jpeg)
+ return atoms->image_jpeg;
+
+ if (utf8)
+ return atoms->utf8_string;
+
+ if (string)
+ return atoms->string;
+
+ /* This is evidently something we don't know how to handle.*/
+ return None;
+}
+
+/* Return True if this is an INCR-style transfer. */
+- (Bool) is_incr_type:(XSelectionEvent *)e
+{
+ Atom seltype;
+ int format;
+ unsigned long numitems = 0UL, bytesleft = 0UL;
+ unsigned char *chunk;
+
+ TRACE ();
+
+ if (Success != XGetWindowProperty (xpbproxy_dpy, e->requestor, e->property,
+ /*offset*/ 0L, /*length*/ 4UL,
+ /*Delete*/ False,
+ AnyPropertyType, &seltype, &format,
+ &numitems, &bytesleft, &chunk))
+ {
+ return False;
+ }
+
+ if(chunk)
+ XFree(chunk);
+
+ return (seltype == atoms->incr) ? True : False;
+}
+
+/*
+ * This should be called after a selection has been copied,
+ * or when the selection is unfinished before a transfer completes.
+ */
+- (void) release_pending
+{
+ TRACE ();
+
+ free_propdata (&pending.propdata);
+ pending.requestor = None;
+ pending.selection = None;
+}
+
+/* Return True if an error occurs during an append.*/
+/* Return False if the append succeeds. */
+- (Bool) append_to_pending:(struct propdata *)pdata requestor:(Window)requestor
+{
+ unsigned char *newdata;
+ size_t newlength;
+
+ TRACE ();
+
+ if (requestor != pending.requestor)
+ {
+ [self release_pending];
+ pending.requestor = requestor;
+ }
+
+ newlength = pending.propdata.length + pdata->length;
+ newdata = realloc(pending.propdata.data, newlength);
+
+ if(NULL == newdata)
+ {
+ perror("realloc propdata");
+ [self release_pending];
+ return True;
+ }
+
+ memcpy(newdata + pending.propdata.length, pdata->data, pdata->length);
+ pending.propdata.data = newdata;
+ pending.propdata.length = newlength;
+
+ return False;
+}
+
+
+
+/* Called when X11 becomes active (i.e. has key focus) */
+- (void) x_active:(Time)timestamp
+{
+ static NSInteger changeCount;
+ NSInteger countNow;
+ NSPasteboard *pb;
+
+ TRACE ();
+
+ pb = [NSPasteboard generalPasteboard];
+
+ if (nil == pb)
+ return;
+
+ countNow = [pb changeCount];
+
+ if (countNow != changeCount)
+ {
+ DebugF ("changed pasteboard!\n");
+ changeCount = countNow;
+
+ if (pbproxy_prefs.pasteboard_to_primary)
+ {
+ XSetSelectionOwner (xpbproxy_dpy, atoms->primary, _selection_window, CurrentTime);
+ }
+
+ if (pbproxy_prefs.pasteboard_to_clipboard) {
+ [self own_clipboard];
+ }
+ }
+
+#if 0
+ /*gstaplin: we should perhaps investigate something like this branch above...*/
+ if ([_pasteboard availableTypeFromArray: _known_types] != nil)
+ {
+ /* Pasteboard has data we should proxy; I think it makes
+ sense to put it on both CLIPBOARD and PRIMARY */
+
+ XSetSelectionOwner (xpbproxy_dpy, atoms->clipboard,
+ _selection_window, timestamp);
+ XSetSelectionOwner (xpbproxy_dpy, atoms->primary,
+ _selection_window, timestamp);
+ }
+#endif
+}
+
+/* Called when X11 loses key focus */
+- (void) x_inactive:(Time)timestamp
+{
+ TRACE ();
+}
+
+/* This requests the TARGETS list from the PRIMARY selection owner. */
+- (void) x_copy_request_targets
+{
+ TRACE ();
+
+ request_atom = atoms->targets;
+ XConvertSelection (xpbproxy_dpy, atoms->primary, atoms->targets,
+ atoms->primary, _selection_window, CurrentTime);
+}
+
+/* Called when the Edit/Copy item on the main X11 menubar is selected
+ * and no appkit window claims it. */
+- (void) x_copy:(Time)timestamp
+{
+ Window w;
+
+ TRACE ();
+
+ w = XGetSelectionOwner (xpbproxy_dpy, atoms->primary);
+
+ if (None != w)
+ {
+ ++pending_copy;
+
+ if (1 == pending_copy) {
+ /*
+ * There are no other copy operations in progress, so we
+ * can proceed safely. Otherwise the copy_completed method
+ * will see that the pending_copy is > 1, and do another copy.
+ */
+ [self x_copy_request_targets];
+ }
+ }
+}
+
+/* Set pbproxy as owner of the SELECTION_MANAGER selection.
+ * This prevents tools like xclipboard from causing havoc.
+ * Returns TRUE on success
+ */
+- (BOOL) set_clipboard_manager_status:(BOOL)value
+{
+ TRACE ();
+
+ Window owner = XGetSelectionOwner (xpbproxy_dpy, atoms->clipboard_manager);
+
+ if(value) {
+ if(owner == _selection_window)
+ return TRUE;
+
+ if(owner != None) {
+ ErrorF("A clipboard manager using window 0x%lx already owns the clipboard selection. "
+ "pbproxy will not sync clipboard to pasteboard.\n", owner);
+ return FALSE;
+ }
+
+ XSetSelectionOwner(xpbproxy_dpy, atoms->clipboard_manager, _selection_window, CurrentTime);
+ return (_selection_window == XGetSelectionOwner(xpbproxy_dpy, atoms->clipboard_manager));
+ } else {
+ if(owner != _selection_window)
+ return TRUE;
+
+ XSetSelectionOwner(xpbproxy_dpy, atoms->clipboard_manager, None, CurrentTime);
+ return(None == XGetSelectionOwner(xpbproxy_dpy, atoms->clipboard_manager));
+ }
+
+ return FALSE;
+}
+
+/*
+ * This occurs when we previously owned a selection,
+ * and then lost it from another client.
+ */
+- (void) clear_event:(XSelectionClearEvent *)e
+{
+
+
+ TRACE ();
+
+ DebugF ("e->selection %s\n", XGetAtomName (xpbproxy_dpy, e->selection));
+
+ if(e->selection == atoms->clipboard) {
+ /*
+ * We lost ownership of the CLIPBOARD.
+ */
+ ++pending_clipboard;
+
+ if (1 == pending_clipboard) {
+ /* Claim the clipboard contents from the new owner. */
+ [self claim_clipboard];
+ }
+ } else if(e->selection == atoms->clipboard_manager) {
+ if(pbproxy_prefs.clipboard_to_pasteboard) {
+ /* Another CLIPBOARD_MANAGER has set itself as owner. Disable syncing
+ * to avoid a race.
+ */
+ ErrorF("Another clipboard manager was started! "
+ "xpbproxy is disabling syncing with clipboard.\n");
+ pbproxy_prefs.clipboard_to_pasteboard = NO;
+ }
+ }
+}
+
+/*
+ * We greedily acquire the clipboard after it changes, and on startup.
+ */
+- (void) claim_clipboard
+{
+ Window owner;
+
+ TRACE ();
+
+ if (!pbproxy_prefs.clipboard_to_pasteboard)
+ return;
+
+ owner = XGetSelectionOwner (xpbproxy_dpy, atoms->clipboard);
+ if (None == owner) {
+ /*
+ * The owner probably died or we are just starting up pbproxy.
+ * Set pbproxy's _selection_window as the owner, and continue.
+ */
+ DebugF ("No clipboard owner.\n");
+ [self copy_completed:atoms->clipboard];
+ return;
+ } else if (owner == _selection_window) {
+ [self copy_completed:atoms->clipboard];
+ return;
+ }
+
+ DebugF ("requesting targets\n");
+
+ request_atom = atoms->targets;
+ XConvertSelection (xpbproxy_dpy, atoms->clipboard, atoms->targets,
+ atoms->clipboard, _selection_window, CurrentTime);
+ XFlush (xpbproxy_dpy);
+ /* Now we will get a SelectionNotify event in the future. */
+}
+
+/* Greedily acquire the clipboard. */
+- (void) own_clipboard
+{
+
+ TRACE ();
+
+ /* We should perhaps have a boundary limit on the number of iterations... */
+ do
+ {
+ XSetSelectionOwner (xpbproxy_dpy, atoms->clipboard, _selection_window,
+ CurrentTime);
+ } while (_selection_window != XGetSelectionOwner (xpbproxy_dpy,
+ atoms->clipboard));
+}
+
+- (void) init_reply:(XEvent *)reply request:(XSelectionRequestEvent *)e
+{
+ reply->xselection.type = SelectionNotify;
+ reply->xselection.selection = e->selection;
+ reply->xselection.target = e->target;
+ reply->xselection.requestor = e->requestor;
+ reply->xselection.time = e->time;
+ reply->xselection.property = None;
+}
+
+- (void) send_reply:(XEvent *)reply
+{
+ /*
+ * We are supposed to use an empty event mask, and not propagate
+ * the event, according to the ICCCM.
+ */
+ DebugF ("reply->xselection.requestor 0x%lx\n", reply->xselection.requestor);
+
+ XSendEvent (xpbproxy_dpy, reply->xselection.requestor, False, 0, reply);
+ XFlush (xpbproxy_dpy);
+}
+
+/*
+ * This responds to a TARGETS request.
+ * The result is a list of a ATOMs that correspond to the types available
+ * for a selection.
+ * For instance an application might provide a UTF8_STRING and a STRING
+ * (in Latin-1 encoding). The requestor can then make the choice based on
+ * the list.
+ */
+- (void) send_targets:(XSelectionRequestEvent *)e pasteboard:(NSPasteboard *)pb
+{
+ XEvent reply;
+ NSArray *pbtypes;
+
+ [self init_reply:&reply request:e];
+
+ pbtypes = [pb types];
+ if (pbtypes)
+ {
+ long list[7]; /* Don't forget to increase this if we handle more types! */
+ long count = 0;
+
+ /*
+ * I'm not sure if this is needed, but some toolkits/clients list
+ * TARGETS in response to targets.
+ */
+ list[count] = atoms->targets;
+ ++count;
+
+ if ([pbtypes containsObject:NSStringPboardType])
+ {
+ /* We have a string type that we can convert to UTF8, or Latin-1... */
+ DebugF ("NSStringPboardType\n");
+ list[count] = atoms->utf8_string;
+ ++count;
+ list[count] = atoms->string;
+ ++count;
+ list[count] = atoms->compound_text;
+ ++count;
+ }
+
+ /* TODO add the NSPICTPboardType back again, once we have conversion
+ * functionality in send_image.
+ */
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // NSPICTPboardType
+#endif
+
+ if ([pbtypes containsObject:NSPICTPboardType]
+ || [pbtypes containsObject:NSTIFFPboardType])
+ {
+ /* We can convert a TIFF to a PNG or JPEG. */
+ DebugF ("NSTIFFPboardType\n");
+ list[count] = atoms->image_png;
+ ++count;
+ list[count] = atoms->image_jpeg;
+ ++count;
+ }
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+ if (count)
+ {
+ /* We have a list of ATOMs to send. */
+ XChangeProperty (xpbproxy_dpy, e->requestor, e->property, atoms->atom, 32,
+ PropModeReplace, (unsigned char *) list, count);
+
+ reply.xselection.property = e->property;
+ }
+ }
+
+ [self send_reply:&reply];
+}
+
+
+- (void) send_string:(XSelectionRequestEvent *)e utf8:(BOOL)utf8 pasteboard:(NSPasteboard *)pb
+{
+ XEvent reply;
+ NSArray *pbtypes;
+ NSString *data;
+ const char *bytes;
+ NSUInteger length;
+
+ TRACE ();
+
+ [self init_reply:&reply request:e];
+
+ pbtypes = [pb types];
+
+ if (![pbtypes containsObject:NSStringPboardType])
+ {
+ [self send_reply:&reply];
+ return;
+ }
+
+ DebugF ("pbtypes retainCount after containsObject: %u\n", [pbtypes retainCount]);
+
+ data = [pb stringForType:NSStringPboardType];
+
+ if (nil == data)
+ {
+ [self send_reply:&reply];
+ return;
+ }
+
+ if (utf8)
+ {
+ bytes = [data UTF8String];
+ /*
+ * We don't want the UTF-8 string length here.
+ * We want the length in bytes.
+ */
+ length = strlen (bytes);
+
+ if (length < 50) {
+ DebugF ("UTF-8: %s\n", bytes);
+ DebugF ("UTF-8 length: %u\n", length);
+ }
+ }
+ else
+ {
+ DebugF ("Latin-1\n");
+ bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding];
+ /*WARNING: bytes is not NUL-terminated. */
+ length = [data lengthOfBytesUsingEncoding:NSISOLatin1StringEncoding];
+ }
+
+ DebugF ("e->target %s\n", XGetAtomName (xpbproxy_dpy, e->target));
+
+ XChangeProperty (xpbproxy_dpy, e->requestor, e->property, e->target,
+ 8, PropModeReplace, (unsigned char *) bytes, length);
+
+ reply.xselection.property = e->property;
+
+ [self send_reply:&reply];
+}
+
+- (void) send_compound_text:(XSelectionRequestEvent *)e pasteboard:(NSPasteboard *)pb
+{
+ XEvent reply;
+ NSArray *pbtypes;
+
+ TRACE ();
+
+ [self init_reply:&reply request:e];
+
+ pbtypes = [pb types];
+
+ if ([pbtypes containsObject: NSStringPboardType])
+ {
+ NSString *data = [pb stringForType:NSStringPboardType];
+ if (nil != data)
+ {
+ /*
+ * Cast to (void *) to avoid a const warning.
+ * AFAIK Xutf8TextListToTextProperty does not modify the input memory.
+ */
+ void *utf8 = (void *)[data UTF8String];
+ char *list[] = { utf8, NULL };
+ XTextProperty textprop;
+
+ textprop.value = NULL;
+
+ if (Success == Xutf8TextListToTextProperty (xpbproxy_dpy, list, 1,
+ XCompoundTextStyle,
+ &textprop))
+ {
+
+ if (8 != textprop.format)
+ DebugF ("textprop.format is unexpectedly not 8 - it's %d instead\n",
+ textprop.format);
+
+ XChangeProperty (xpbproxy_dpy, e->requestor, e->property,
+ atoms->compound_text, textprop.format,
+ PropModeReplace, textprop.value,
+ textprop.nitems);
+
+ reply.xselection.property = e->property;
+ }
+
+ if (textprop.value)
+ XFree (textprop.value);
+
+ }
+ }
+
+ [self send_reply:&reply];
+}
+
+/* Finding a test application that uses MULTIPLE has proven to be difficult. */
+- (void) send_multiple:(XSelectionRequestEvent *)e
+{
+ XEvent reply;
+
+ TRACE ();
+
+ [self init_reply:&reply request:e];
+
+ if (None != e->property)
+ {
+
+ }
+
+ [self send_reply:&reply];
+}
+
+/* Return nil if an error occured. */
+/* DO NOT retain the encdata for longer than the length of an event response.
+ * The autorelease pool will reuse/free it.
+ */
+- (NSData *) encode_image_data:(NSData *)data type:(NSBitmapImageFileType)enctype
+{
+ NSBitmapImageRep *bmimage = nil;
+ NSData *encdata = nil;
+ NSDictionary *dict = nil;
+
+ bmimage = [[NSBitmapImageRep alloc] initWithData:data];
+
+ if (nil == bmimage)
+ return nil;
+
+ dict = [[NSDictionary alloc] init];
+ encdata = [bmimage representationUsingType:enctype properties:dict];
+
+ if (nil == encdata)
+ {
+ [dict autorelease];
+ [bmimage autorelease];
+ return nil;
+ }
+
+ [dict autorelease];
+ [bmimage autorelease];
+
+ return encdata;
+}
+
+/* Return YES when an error has occured when trying to send the PICT. */
+/* The caller should send a default reponse with a property of None when an error occurs. */
+- (BOOL) send_image_pict_reply:(XSelectionRequestEvent *)e
+ pasteboard:(NSPasteboard *)pb
+ type:(NSBitmapImageFileType)imagetype
+{
+ XEvent reply;
+ NSImage *img = nil;
+ NSData *data = nil, *encdata = nil;
+ NSUInteger length;
+ const void *bytes = NULL;
+
+ img = [[NSImage alloc] initWithPasteboard:pb];
+
+ if (nil == img)
+ {
+ return YES;
+ }
+
+ data = [img TIFFRepresentation];
+
+ if (nil == data)
+ {
+ [img autorelease];
+ ErrorF("unable to convert PICT to TIFF!\n");
+ return YES;
+ }
+
+ encdata = [self encode_image_data:data type:imagetype];
+ if(nil == encdata)
+ {
+ [img autorelease];
+ return YES;
+ }
+
+ [self init_reply:&reply request:e];
+
+ length = [encdata length];
+ bytes = [encdata bytes];
+
+ XChangeProperty (xpbproxy_dpy, e->requestor, e->property, e->target,
+ 8, PropModeReplace, bytes, length);
+ reply.xselection.property = e->property;
+
+ [self send_reply:&reply];
+
+ [img autorelease];
+
+ return NO; /*no error*/
+}
+
+/* Return YES if an error occured. */
+/* The caller should send a reply with a property of None when an error occurs. */
+- (BOOL) send_image_tiff_reply:(XSelectionRequestEvent *)e
+ pasteboard:(NSPasteboard *)pb
+ type:(NSBitmapImageFileType)imagetype
+{
+ XEvent reply;
+ NSData *data = nil;
+ NSData *encdata = nil;
+ NSUInteger length;
+ const void *bytes = NULL;
+
+ data = [pb dataForType:NSTIFFPboardType];
+
+ if (nil == data)
+ return YES;
+
+ encdata = [self encode_image_data:data type:imagetype];
+
+ if(nil == encdata)
+ return YES;
+
+ [self init_reply:&reply request:e];
+
+ length = [encdata length];
+ bytes = [encdata bytes];
+
+ XChangeProperty (xpbproxy_dpy, e->requestor, e->property, e->target,
+ 8, PropModeReplace, bytes, length);
+ reply.xselection.property = e->property;
+
+ [self send_reply:&reply];
+
+ return NO; /*no error*/
+}
+
+- (void) send_image:(XSelectionRequestEvent *)e pasteboard:(NSPasteboard *)pb
+{
+ NSArray *pbtypes = nil;
+ NSBitmapImageFileType imagetype = NSPNGFileType;
+
+ TRACE ();
+
+ if (e->target == atoms->image_png)
+ imagetype = NSPNGFileType;
+ else if (e->target == atoms->image_jpeg)
+ imagetype = NSJPEGFileType;
+ else
+ {
+ ErrorF("internal failure in xpbproxy! imagetype being sent isn't PNG or JPEG.\n");
+ }
+
+ pbtypes = [pb types];
+
+ if (pbtypes)
+ {
+ if ([pbtypes containsObject:NSTIFFPboardType])
+ {
+ if (NO == [self send_image_tiff_reply:e pasteboard:pb type:imagetype])
+ return;
+ }
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // NSPICTPboardType
+#endif
+ else if ([pbtypes containsObject:NSPICTPboardType])
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ {
+ if (NO == [self send_image_pict_reply:e pasteboard:pb type:imagetype])
+ return;
+
+ /* Fall through intentionally to the send_none: */
+ }
+ }
+
+ [self send_none:e];
+}
+
+- (void)send_none:(XSelectionRequestEvent *)e
+{
+ XEvent reply;
+
+ TRACE ();
+
+ [self init_reply:&reply request:e];
+ [self send_reply:&reply];
+}
+
+
+/* Another client requested the data or targets of data available from the clipboard. */
+- (void)request_event:(XSelectionRequestEvent *)e
+{
+ NSPasteboard *pb;
+
+ TRACE ();
+
+ /* TODO We should also keep track of the time of the selection, and
+ * according to the ICCCM "refuse the request" if the event timestamp
+ * is before we owned it.
+ * What should we base the time on? How can we get the current time just
+ * before an XSetSelectionOwner? Is it the server's time, or the clients?
+ * According to the XSelectionRequestEvent manual page, the Time value
+ * may be set to CurrentTime or a time, so that makes it a bit different.
+ * Perhaps we should just punt and ignore races.
+ */
+
+ /*TODO we need a COMPOUND_TEXT test app*/
+ /*TODO we need a MULTIPLE test app*/
+
+ pb = [NSPasteboard generalPasteboard];
+ if (nil == pb)
+ {
+ [self send_none:e];
+ return;
+ }
+
+
+ if (None != e->target)
+ DebugF ("e->target %s\n", XGetAtomName (xpbproxy_dpy, e->target));
+
+ if (e->target == atoms->targets)
+ {
+ /* The paste requestor wants to know what TARGETS we support. */
+ [self send_targets:e pasteboard:pb];
+ }
+ else if (e->target == atoms->multiple)
+ {
+ /*
+ * This isn't finished, and may never be, unless I can find
+ * a good test app.
+ */
+ [self send_multiple:e];
+ }
+ else if (e->target == atoms->utf8_string)
+ {
+ [self send_string:e utf8:YES pasteboard:pb];
+ }
+ else if (e->target == atoms->string)
+ {
+ [self send_string:e utf8:NO pasteboard:pb];
+ }
+ else if (e->target == atoms->compound_text)
+ {
+ [self send_compound_text:e pasteboard:pb];
+ }
+ else if (e->target == atoms->multiple)
+ {
+ [self send_multiple:e];
+ }
+ else if (e->target == atoms->image_png || e->target == atoms->image_jpeg)
+ {
+ [self send_image:e pasteboard:pb];
+ }
+ else
+ {
+ [self send_none:e];
+ }
+}
+
+/* This handles the events resulting from an XConvertSelection request. */
+- (void) notify_event:(XSelectionEvent *)e
+{
+ Atom type;
+ struct propdata pdata;
+
+ TRACE ();
+
+ [self release_pending];
+
+ if (None == e->property) {
+ DebugF ("e->property is None.\n");
+ [self copy_completed:e->selection];
+ /* Nothing is selected. */
+ return;
+ }
+
+#if 0
+ ErrorF("e->selection %s\n", XGetAtomName (xpbproxy_dpy, e->selection));
+ ErrorF("e->property %s\n", XGetAtomName (xpbproxy_dpy, e->property));
+#endif
+
+ if ([self is_incr_type:e])
+ {
+ /*
+ * This is an INCR-style transfer, which means that we
+ * will get the data after a series of PropertyNotify events.
+ */
+ DebugF ("is INCR\n");
+
+ if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type))
+ {
+ /*
+ * An error occured, so we should invoke the copy_completed:, but
+ * not handle_selection:type:propdata:
+ */
+ [self copy_completed:e->selection];
+ return;
+ }
+
+ free_propdata (&pdata);
+
+ pending.requestor = e->requestor;
+ pending.selection = e->selection;
+
+ DebugF ("set pending.requestor to 0x%lx\n", pending.requestor);
+ }
+ else
+ {
+ if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type))
+ {
+ [self copy_completed:e->selection];
+ return;
+ }
+
+ /* We have the complete selection data.*/
+ [self handle_selection:e->selection type:type propdata:&pdata];
+
+ DebugF ("handled selection with the first notify_event\n");
+ }
+}
+
+/* This is used for INCR transfers. See the ICCCM for the details. */
+/* This is used to retrieve PRIMARY and CLIPBOARD selections. */
+- (void) property_event:(XPropertyEvent *)e
+{
+ struct propdata pdata;
+ Atom type;
+
+ TRACE ();
+
+ if (None != e->atom)
+ {
+#ifdef DEBUG
+ char *name = XGetAtomName (xpbproxy_dpy, e->atom);
+
+ if (name)
+ {
+ DebugF ("e->atom %s\n", name);
+ XFree(name);
+ }
+#endif
+ }
+
+ if (None != pending.requestor && PropertyNewValue == e->state)
+ {
+ DebugF ("pending.requestor 0x%lx\n", pending.requestor);
+
+ if (get_property (e->window, e->atom, &pdata, /*Delete*/ True, &type))
+ {
+ [self copy_completed:pending.selection];
+ [self release_pending];
+ return;
+ }
+
+ if (0 == pdata.length)
+ {
+ /*
+ * We completed the transfer.
+ * handle_selection will call copy_completed: for us.
+ */
+ [self handle_selection:pending.selection type:type propdata:&pending.propdata];
+ free_propdata(&pdata);
+ pending.propdata = null_propdata;
+ pending.requestor = None;
+ pending.selection = None;
+ }
+ else
+ {
+ [self append_to_pending:&pdata requestor:e->window];
+ free_propdata (&pdata);
+ }
+ }
+}
+
+- (void) xfixes_selection_notify:(XFixesSelectionNotifyEvent *)e {
+ if(!pbproxy_prefs.active)
+ return;
+
+ switch(e->subtype) {
+ case XFixesSetSelectionOwnerNotify:
+ if(e->selection == atoms->primary && pbproxy_prefs.primary_on_grab)
+ [self x_copy:e->timestamp];
+ break;
+
+ case XFixesSelectionWindowDestroyNotify:
+ case XFixesSelectionClientCloseNotify:
+ default:
+ ErrorF("Unhandled XFixesSelectionNotifyEvent: subtype=%d\n", e->subtype);
+ break;
+ }
+}
+
+- (void) handle_targets: (Atom)selection propdata:(struct propdata *)pdata
+{
+ /* Find a type we can handle and prefer from the list of ATOMs. */
+ Atom preferred;
+ char *name;
+
+ TRACE ();
+
+ preferred = [self find_preferred:pdata];
+
+ if (None == preferred)
+ {
+ /*
+ * This isn't required by the ICCCM, but some apps apparently
+ * don't respond to TARGETS properly.
+ */
+ preferred = atoms->string;
+ }
+
+ (void)name; /* Avoid a warning with non-debug compiles. */
+#ifdef DEBUG
+ name = XGetAtomName (xpbproxy_dpy, preferred);
+
+ if (name)
+ {
+ DebugF ("requesting %s\n", name);
+ }
+#endif
+ request_atom = preferred;
+ XConvertSelection (xpbproxy_dpy, selection, preferred, selection,
+ _selection_window, CurrentTime);
+}
+
+/* This handles the image type of selection (typically in CLIPBOARD). */
+/* We convert to a TIFF, so that other applications can paste more easily. */
+- (void) handle_image: (struct propdata *)pdata pasteboard:(NSPasteboard *)pb
+{
+ NSArray *pbtypes;
+ NSUInteger length;
+ NSData *data, *tiff;
+ NSBitmapImageRep *bmimage;
+
+ TRACE ();
+
+ length = pdata->length;
+ data = [[NSData alloc] initWithBytes:pdata->data length:length];
+
+ if (nil == data)
+ {
+ DebugF ("unable to create NSData object!\n");
+ return;
+ }
+
+ DebugF ("data retainCount before NSBitmapImageRep initWithData: %u\n",
+ [data retainCount]);
+
+ bmimage = [[NSBitmapImageRep alloc] initWithData:data];
+
+ if (nil == bmimage)
+ {
+ [data autorelease];
+ DebugF ("unable to create NSBitmapImageRep!\n");
+ return;
+ }
+
+ DebugF ("data retainCount after NSBitmapImageRep initWithData: %u\n",
+ [data retainCount]);
+
+ @try
+ {
+ tiff = [bmimage TIFFRepresentation];
+ }
+
+ @catch (NSException *e)
+ {
+ DebugF ("NSTIFFException!\n");
+ [data autorelease];
+ [bmimage autorelease];
+ return;
+ }
+
+ DebugF ("bmimage retainCount after TIFFRepresentation %u\n", [bmimage retainCount]);
+
+ pbtypes = [NSArray arrayWithObjects:NSTIFFPboardType, nil];
+
+ if (nil == pbtypes)
+ {
+ [data autorelease];
+ [bmimage autorelease];
+ return;
+ }
+
+ [pb declareTypes:pbtypes owner:nil];
+ if (YES != [pb setData:tiff forType:NSTIFFPboardType])
+ {
+ DebugF ("writing pasteboard data failed!\n");
+ }
+
+ [data autorelease];
+
+ DebugF ("bmimage retainCount before release %u\n", [bmimage retainCount]);
+ [bmimage autorelease];
+}
+
+/* This handles the UTF8_STRING type of selection. */
+- (void) handle_utf8_string:(struct propdata *)pdata pasteboard:(NSPasteboard *)pb
+{
+ NSString *string;
+ NSArray *pbtypes;
+
+ TRACE ();
+
+ string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSUTF8StringEncoding];
+
+ if (nil == string)
+ return;
+
+ pbtypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
+
+ if (nil == pbtypes)
+ {
+ [string autorelease];
+ return;
+ }
+
+ [pb declareTypes:pbtypes owner:nil];
+
+ if (YES != [pb setString:string forType:NSStringPboardType]) {
+ ErrorF("pasteboard setString:forType: failed!\n");
+ }
+ [string autorelease];
+ DebugF ("done handling utf8 string\n");
+}
+
+/* This handles the STRING type, which should be in Latin-1. */
+- (void) handle_string: (struct propdata *)pdata pasteboard:(NSPasteboard *)pb
+{
+ NSString *string;
+ NSArray *pbtypes;
+
+ TRACE ();
+
+ string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSISOLatin1StringEncoding];
+
+ if (nil == string)
+ return;
+
+ pbtypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
+
+ if (nil == pbtypes)
+ {
+ [string autorelease];
+ return;
+ }
+
+ [pb declareTypes:pbtypes owner:nil];
+ if (YES != [pb setString:string forType:NSStringPboardType]) {
+ ErrorF("pasteboard setString:forType failed in handle_string!\n");
+ }
+ [string autorelease];
+}
+
+/* This is called when the selection is completely retrieved from another client. */
+/* Warning: this frees the propdata. */
+- (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata
+{
+ NSPasteboard *pb;
+
+ TRACE ();
+
+ pb = [NSPasteboard generalPasteboard];
+
+ if (nil == pb)
+ {
+ [self copy_completed:selection];
+ free_propdata (pdata);
+ return;
+ }
+
+ /*
+ * Some apps it seems set the type to TARGETS instead of ATOM, such as Eterm.
+ * These aren't ICCCM compliant apps, but we need these to work...
+ */
+ if (request_atom == atoms->targets
+ && (type == atoms->atom || type == atoms->targets))
+ {
+ [self handle_targets:selection propdata:pdata];
+ free_propdata(pdata);
+ return;
+ }
+ else if (type == atoms->image_png)
+ {
+ [self handle_image:pdata pasteboard:pb];
+ }
+ else if (type == atoms->image_jpeg)
+ {
+ [self handle_image:pdata pasteboard:pb];
+ }
+ else if (type == atoms->utf8_string)
+ {
+ [self handle_utf8_string:pdata pasteboard:pb];
+ }
+ else if (type == atoms->string)
+ {
+ [self handle_string:pdata pasteboard:pb];
+ }
+
+ free_propdata(pdata);
+
+ [self copy_completed:selection];
+}
+
+
+- (void) copy_completed:(Atom)selection
+{
+ TRACE ();
+ char *name;
+
+ (void)name; /* Avoid warning with non-debug compiles. */
+#ifdef DEBUG
+ name = XGetAtomName (xpbproxy_dpy, selection);
+ if (name)
+ {
+ DebugF ("copy_completed: %s\n", name);
+ XFree (name);
+ }
+#endif
+
+ if (selection == atoms->primary && pending_copy > 0)
+ {
+ --pending_copy;
+ if (pending_copy > 0)
+ {
+ /* Copy PRIMARY again. */
+ [self x_copy_request_targets];
+ return;
+ }
+ }
+ else if (selection == atoms->clipboard && pending_clipboard > 0)
+ {
+ --pending_clipboard;
+ if (pending_clipboard > 0)
+ {
+ /* Copy CLIPBOARD. */
+ [self claim_clipboard];
+ return;
+ }
+ else
+ {
+ /* We got the final data. Now set pbproxy as the owner. */
+ [self own_clipboard];
+ return;
+ }
+ }
+
+ /*
+ * We had 1 or more primary in progress, and the clipboard arrived
+ * while we were busy.
+ */
+ if (pending_clipboard > 0)
+ {
+ [self claim_clipboard];
+ }
+}
+
+- (void) reload_preferences
+{
+ /*
+ * It's uncertain how we could handle the synchronization failing, so cast to void.
+ * The prefs_get_bool should fall back to defaults if the org.x.X11 plist doesn't exist or is invalid.
+ */
+ (void)CFPreferencesAppSynchronize(app_prefs_domain_cfstr);
+#ifdef STANDALONE_XPBPROXY
+ if(xpbproxy_is_standalone)
+ pbproxy_prefs.active = YES;
+ else
+#endif
+ pbproxy_prefs.active = prefs_get_bool(CFSTR("sync_pasteboard"), pbproxy_prefs.active);
+ pbproxy_prefs.primary_on_grab = prefs_get_bool(CFSTR("sync_primary_on_select"), pbproxy_prefs.primary_on_grab);
+ pbproxy_prefs.clipboard_to_pasteboard = prefs_get_bool(CFSTR("sync_clipboard_to_pasteboard"), pbproxy_prefs.clipboard_to_pasteboard);
+ pbproxy_prefs.pasteboard_to_primary = prefs_get_bool(CFSTR("sync_pasteboard_to_primary"), pbproxy_prefs.pasteboard_to_primary);
+ pbproxy_prefs.pasteboard_to_clipboard = prefs_get_bool(CFSTR("sync_pasteboard_to_clipboard"), pbproxy_prefs.pasteboard_to_clipboard);
+
+ /* This is used for debugging. */
+ //dump_prefs();
+
+ if(pbproxy_prefs.active && pbproxy_prefs.primary_on_grab && !xpbproxy_have_xfixes) {
+ ErrorF("Disabling sync_primary_on_select functionality due to missing XFixes extension.\n");
+ pbproxy_prefs.primary_on_grab = NO;
+ }
+
+ /* Claim or release the CLIPBOARD_MANAGER atom */
+ if(![self set_clipboard_manager_status:(pbproxy_prefs.active && pbproxy_prefs.clipboard_to_pasteboard)])
+ pbproxy_prefs.clipboard_to_pasteboard = NO;
+
+ if(pbproxy_prefs.active && pbproxy_prefs.clipboard_to_pasteboard)
+ [self claim_clipboard];
+}
+
+- (BOOL) is_active
+{
+ return pbproxy_prefs.active;
+}
+
+/* NSPasteboard-required methods */
+
+- (void) paste:(id)sender
+{
+ TRACE ();
+}
+
+- (void) pasteboard:(NSPasteboard *)pb provideDataForType:(NSString *)type
+{
+ TRACE ();
+}
+
+- (void) pasteboardChangedOwner:(NSPasteboard *)pb
+{
+ TRACE ();
+
+ /* Right now we don't care with this. */
+}
+
+/* Allocation */
+
+- init
+{
+ unsigned long pixel;
+
+ self = [super init];
+ if (self == nil)
+ return nil;
+
+ atoms->primary = XInternAtom (xpbproxy_dpy, "PRIMARY", False);
+ atoms->clipboard = XInternAtom (xpbproxy_dpy, "CLIPBOARD", False);
+ atoms->text = XInternAtom (xpbproxy_dpy, "TEXT", False);
+ atoms->utf8_string = XInternAtom (xpbproxy_dpy, "UTF8_STRING", False);
+ atoms->string = XInternAtom (xpbproxy_dpy, "STRING", False);
+ atoms->targets = XInternAtom (xpbproxy_dpy, "TARGETS", False);
+ atoms->multiple = XInternAtom (xpbproxy_dpy, "MULTIPLE", False);
+ atoms->cstring = XInternAtom (xpbproxy_dpy, "CSTRING", False);
+ atoms->image_png = XInternAtom (xpbproxy_dpy, "image/png", False);
+ atoms->image_jpeg = XInternAtom (xpbproxy_dpy, "image/jpeg", False);
+ atoms->incr = XInternAtom (xpbproxy_dpy, "INCR", False);
+ atoms->atom = XInternAtom (xpbproxy_dpy, "ATOM", False);
+ atoms->clipboard_manager = XInternAtom (xpbproxy_dpy, "CLIPBOARD_MANAGER", False);
+ atoms->compound_text = XInternAtom (xpbproxy_dpy, "COMPOUND_TEXT", False);
+ atoms->atom_pair = XInternAtom (xpbproxy_dpy, "ATOM_PAIR", False);
+
+ pixel = BlackPixel (xpbproxy_dpy, DefaultScreen (xpbproxy_dpy));
+ _selection_window = XCreateSimpleWindow (xpbproxy_dpy, DefaultRootWindow (xpbproxy_dpy),
+ 0, 0, 1, 1, 0, pixel, pixel);
+
+ /* This is used to get PropertyNotify events when doing INCR transfers. */
+ XSelectInput (xpbproxy_dpy, _selection_window, PropertyChangeMask);
+
+ request_atom = None;
+
+ init_propdata (&pending.propdata);
+ pending.requestor = None;
+ pending.selection = None;
+
+ pending_copy = 0;
+ pending_clipboard = 0;
+
+ if(xpbproxy_have_xfixes)
+ XFixesSelectSelectionInput(xpbproxy_dpy, _selection_window, atoms->primary,
+ XFixesSetSelectionOwnerNotifyMask);
+
+ [self reload_preferences];
+
+ return self;
+}
+
+- (void) dealloc
+{
+ if (None != _selection_window)
+ {
+ XDestroyWindow (xpbproxy_dpy, _selection_window);
+ _selection_window = None;
+ }
+
+ free_propdata (&pending.propdata);
+
+ [super dealloc];
+}
+
+@end
diff --git a/xorg-server/hw/xquartz/quartz.c b/xorg-server/hw/xquartz/quartz.c index 158656b6a..4fdf40c89 100644 --- a/xorg-server/hw/xquartz/quartz.c +++ b/xorg-server/hw/xquartz/quartz.c @@ -62,7 +62,7 @@ #include <sys/stat.h>
#include <fcntl.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
-#include <pthread.h>
+#include <libkern/OSAtomic.h>
#include <signal.h>
#include <rootlessCommon.h>
@@ -279,10 +279,10 @@ static void pokeActivityCallback(CFRunLoopTimerRef timer, void *info) { static void QuartzScreenSaver(int state) {
static CFRunLoopTimerRef pokeActivityTimer = NULL;
static CFRunLoopTimerContext pokeActivityContext = { 0, NULL, NULL, NULL, NULL };
- static pthread_mutex_t pokeActivityMutex = PTHREAD_MUTEX_INITIALIZER;
+ static OSSpinLock pokeActivitySpinLock = OS_SPINLOCK_INIT;
+
+ OSSpinLockLock(&pokeActivitySpinLock);
- pthread_mutex_lock(&pokeActivityMutex);
-
if(state) {
if(pokeActivityTimer == NULL)
goto QuartzScreenSaverEnd;
@@ -303,7 +303,7 @@ static void QuartzScreenSaver(int state) { CFRunLoopAddTimer(CFRunLoopGetMain(), pokeActivityTimer, kCFRunLoopCommonModes);
}
QuartzScreenSaverEnd:
- pthread_mutex_unlock(&pokeActivityMutex);
+ OSSpinLockUnlock(&pokeActivitySpinLock);
}
void QuartzShowFullscreen(int state) {
diff --git a/xorg-server/hw/xquartz/quartz.h b/xorg-server/hw/xquartz/quartz.h index d520c1dcb..7fa6d431c 100644 --- a/xorg-server/hw/xquartz/quartz.h +++ b/xorg-server/hw/xquartz/quartz.h @@ -70,7 +70,7 @@ typedef void (*UpdateScreenProc)(ScreenPtr pScreen); /*
* Rootless helper functions
*/
-typedef Bool (*IsX11WindowProc)(void *nsWindow, int windowNumber);
+typedef Bool (*IsX11WindowProc)(int windowNumber);
typedef void (*HideWindowsProc)(Bool hide);
/*
diff --git a/xorg-server/hw/xquartz/quartzKeyboard.c b/xorg-server/hw/xquartz/quartzKeyboard.c index 54f709a8b..368b8a66f 100644 --- a/xorg-server/hw/xquartz/quartzKeyboard.c +++ b/xorg-server/hw/xquartz/quartzKeyboard.c @@ -1,857 +1,874 @@ -/* - quartzKeyboard.c: Keyboard support for Xquartz - - Copyright (c) 2003-2008 Apple Inc. - Copyright (c) 2001-2004 Torrey T. Lyons. All Rights Reserved. - Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved. - - Copyright (C) 1999,2000 by Eric Sunshine <sunshine@sunshineco.com> - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "sanitizedCarbon.h" - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#define HACK_MISSING 1 -#define HACK_KEYPAD 1 -#define HACK_BLACKLIST 1 - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/stat.h> -#include <AvailabilityMacros.h> - -#include "quartz.h" -#include "darwin.h" -#include "darwinEvents.h" - -#include "quartzKeyboard.h" - -#include "X11Application.h" - -#include "threadSafety.h" - -#ifdef NDEBUG -#undef NDEBUG -#include <assert.h> -#define NDEBUG 1 -#else -#include <assert.h> -#endif -#include <pthread.h> - -#include "xkbsrv.h" -#include "exevents.h" -#include "X11/keysym.h" -#include "keysym2ucs.h" - -extern void -CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); - -enum { - MOD_COMMAND = 256, - MOD_SHIFT = 512, - MOD_OPTION = 2048, - MOD_CONTROL = 4096, -}; - -#define UKEYSYM(u) ((u) | 0x01000000) - -#if HACK_MISSING -/* Table of keycode->keysym mappings we use to fallback on for important - keys that are often not in the Unicode mapping. */ - -const static struct { - unsigned short keycode; - KeySym keysym; -} known_keys[] = { - {55, XK_Meta_L}, - {56, XK_Shift_L}, - {57, XK_Caps_Lock}, - {58, XK_Alt_L}, - {59, XK_Control_L}, - - {60, XK_Shift_R}, - {61, XK_Alt_R}, - {62, XK_Control_R}, - {63, XK_Meta_R}, - - {122, XK_F1}, - {120, XK_F2}, - {99, XK_F3}, - {118, XK_F4}, - {96, XK_F5}, - {97, XK_F6}, - {98, XK_F7}, - {100, XK_F8}, - {101, XK_F9}, - {109, XK_F10}, - {103, XK_F11}, - {111, XK_F12}, - {105, XK_F13}, - {107, XK_F14}, - {113, XK_F15}, -}; -#endif - -#if HACK_KEYPAD -/* Table of keycode->old,new-keysym mappings we use to fixup the numeric - keypad entries. */ - -const static struct { - unsigned short keycode; - KeySym normal, keypad; -} known_numeric_keys[] = { - {65, XK_period, XK_KP_Decimal}, - {67, XK_asterisk, XK_KP_Multiply}, - {69, XK_plus, XK_KP_Add}, - {75, XK_slash, XK_KP_Divide}, - {76, 0x01000003, XK_KP_Enter}, - {78, XK_minus, XK_KP_Subtract}, - {81, XK_equal, XK_KP_Equal}, - {82, XK_0, XK_KP_0}, - {83, XK_1, XK_KP_1}, - {84, XK_2, XK_KP_2}, - {85, XK_3, XK_KP_3}, - {86, XK_4, XK_KP_4}, - {87, XK_5, XK_KP_5}, - {88, XK_6, XK_KP_6}, - {89, XK_7, XK_KP_7}, - {91, XK_8, XK_KP_8}, - {92, XK_9, XK_KP_9}, -}; -#endif - -#if HACK_BLACKLIST -/* <rdar://problem/7824370> wine notepad produces wrong characters on shift+arrow - * http://xquartz.macosforge.org/trac/ticket/295 - * http://developer.apple.com/legacy/mac/library/documentation/mac/Text/Text-579.html - * - * legacy Mac keycodes for arrow keys that shift-modify to math symbols - */ -const static unsigned short keycode_blacklist[] = {66, 70, 72, 77}; -#endif - -/* Table mapping normal keysyms to their dead equivalents. - FIXME: all the unicode keysyms (apart from circumflex) were guessed. */ - -const static struct { - KeySym normal, dead; -} dead_keys[] = { - {XK_grave, XK_dead_grave}, - {XK_apostrophe, XK_dead_acute}, /* US:"=" on a Czech keyboard */ - {XK_acute, XK_dead_acute}, - {UKEYSYM (0x384), XK_dead_acute}, /* US:";" on a Greek keyboard */ -// {XK_Greek_accentdieresis, XK_dead_diaeresis}, /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */ - {XK_asciicircum, XK_dead_circumflex}, - {UKEYSYM (0x2c6), XK_dead_circumflex}, /* MODIFIER LETTER CIRCUMFLEX ACCENT */ - {XK_asciitilde, XK_dead_tilde}, - {UKEYSYM (0x2dc), XK_dead_tilde}, /* SMALL TILDE */ - {XK_macron, XK_dead_macron}, - {XK_breve, XK_dead_breve}, - {XK_abovedot, XK_dead_abovedot}, - {XK_diaeresis, XK_dead_diaeresis}, - {UKEYSYM (0x2da), XK_dead_abovering}, /* DOT ABOVE */ - {XK_doubleacute, XK_dead_doubleacute}, - {XK_caron, XK_dead_caron}, - {XK_cedilla, XK_dead_cedilla}, - {XK_ogonek, XK_dead_ogonek}, - {UKEYSYM (0x269), XK_dead_iota}, /* LATIN SMALL LETTER IOTA */ - {UKEYSYM (0x2ec), XK_dead_voiced_sound}, /* MODIFIER LETTER VOICING */ -/* {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */ - {UKEYSYM (0x323), XK_dead_belowdot}, /* COMBINING DOT BELOW */ - {UKEYSYM (0x309), XK_dead_hook}, /* COMBINING HOOK ABOVE */ - {UKEYSYM (0x31b), XK_dead_horn}, /* COMBINING HORN */ -}; - -typedef struct darwinKeyboardInfo_struct { - CARD8 modMap[MAP_LENGTH]; - KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY]; - unsigned char modifierKeycodes[32][2]; -} darwinKeyboardInfo; - -darwinKeyboardInfo keyInfo; -pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER; - -static void DarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl) { - // FIXME: to be implemented - // keyclick, bell volume / pitch, autorepead, LED's -} - -//----------------------------------------------------------------------------- -// Utility functions to help parse Darwin keymap -//----------------------------------------------------------------------------- - -/* - * DarwinBuildModifierMaps - * Use the keyMap field of keyboard info structure to populate - * the modMap and modifierKeycodes fields. - */ -static void DarwinBuildModifierMaps(darwinKeyboardInfo *info) { - int i; - KeySym *k; - - memset(info->modMap, NoSymbol, sizeof(info->modMap)); - memset(info->modifierKeycodes, 0, sizeof(info->modifierKeycodes)); - - for (i = 0; i < NUM_KEYCODES; i++) { - k = info->keyMap + i * GLYPHS_PER_KEY; - - switch (*k) { - case XK_Shift_L: - info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i; - info->modMap[MIN_KEYCODE + i] = ShiftMask; - break; - - case XK_Shift_R: -#ifdef NX_MODIFIERKEY_RSHIFT - info->modifierKeycodes[NX_MODIFIERKEY_RSHIFT][0] = i; -#else - info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i; -#endif - info->modMap[MIN_KEYCODE + i] = ShiftMask; - break; - - case XK_Control_L: - info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i; - info->modMap[MIN_KEYCODE + i] = ControlMask; - break; - - case XK_Control_R: -#ifdef NX_MODIFIERKEY_RCONTROL - info->modifierKeycodes[NX_MODIFIERKEY_RCONTROL][0] = i; -#else - info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i; -#endif - info->modMap[MIN_KEYCODE + i] = ControlMask; - break; - - case XK_Caps_Lock: - info->modifierKeycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i; - info->modMap[MIN_KEYCODE + i] = LockMask; - break; - - case XK_Alt_L: - info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; - info->modMap[MIN_KEYCODE + i] = Mod1Mask; - if(!XQuartzOptionSendsAlt) - *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. - break; - - case XK_Alt_R: -#ifdef NX_MODIFIERKEY_RALTERNATE - info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i; -#else - info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; -#endif - if(!XQuartzOptionSendsAlt) - *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor. - info->modMap[MIN_KEYCODE + i] = Mod1Mask; - break; - - case XK_Mode_switch: - ErrorF("DarwinBuildModifierMaps: XK_Mode_switch encountered, unable to determine side.\n"); - info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i; -#ifdef NX_MODIFIERKEY_RALTERNATE - info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i; -#endif - info->modMap[MIN_KEYCODE + i] = Mod1Mask; - break; - - case XK_Meta_L: - info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i; - info->modMap[MIN_KEYCODE + i] = Mod2Mask; - break; - - case XK_Meta_R: -#ifdef NX_MODIFIERKEY_RCOMMAND - info->modifierKeycodes[NX_MODIFIERKEY_RCOMMAND][0] = i; -#else - info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i; -#endif - info->modMap[MIN_KEYCODE + i] = Mod2Mask; - break; - - case XK_Num_Lock: - info->modMap[MIN_KEYCODE + i] = Mod3Mask; - break; - } - } -} - -/* - * DarwinKeyboardInit - * Get the Darwin keyboard map and compute an equivalent - * X keyboard map and modifier map. Set the new keyboard - * device structure. - */ -void DarwinKeyboardInit(DeviceIntPtr pDev) { - // Open a shared connection to the HID System. - // Note that the Event Status Driver is really just a wrapper - // for a kIOHIDParamConnectType connection. - assert(darwinParamConnect = NXOpenEventStatus()); - - InitKeyboardDeviceStruct(pDev, NULL, NULL, DarwinChangeKeyboardControl); - - DarwinKeyboardReloadHandler(); - - CopyKeyClass(pDev, inputInfo.keyboard); -} - -/* Set the repeat rates based on global preferences and keycodes for modifiers. - * Precondition: Has the keyInfo_mutex lock. - */ -static void DarwinKeyboardSetRepeat(DeviceIntPtr pDev, int initialKeyRepeatValue, int keyRepeatValue) { - if(initialKeyRepeatValue == 300000) { // off - /* Turn off repeats globally */ - XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff); - } else { - int i; - XkbControlsPtr ctrl; - XkbControlsRec old; - - /* Turn on repeats globally */ - XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn); - - /* Setup the bit mask for individual key repeats */ - ctrl = pDev->key->xkbInfo->desc->ctrls; - old= *ctrl; - - ctrl->repeat_delay = initialKeyRepeatValue * 15; - ctrl->repeat_interval = keyRepeatValue * 15; - - /* Turn off key-repeat for modifier keys, on for others */ - /* First set them all on */ - for(i=0; i < XkbPerKeyBitArraySize; i++) - ctrl->per_key_repeat[i] = -1; - - /* Now turn off the modifiers */ - for(i=0; i < 32; i++) { - unsigned char keycode; - - keycode = keyInfo.modifierKeycodes[i][0]; - if(keycode) - ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); - - keycode = keyInfo.modifierKeycodes[i][1]; - if(keycode) - ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE); - } - - /* Hurray for data duplication */ - if (pDev->kbdfeed) - memcpy(pDev->kbdfeed->ctrl.autoRepeats, ctrl->per_key_repeat, XkbPerKeyBitArraySize); - - //fprintf(stderr, "per_key_repeat =\n"); - //for(i=0; i < XkbPerKeyBitArraySize; i++) - // fprintf(stderr, "%02x%s", ctrl->per_key_repeat[i], (i + 1) & 7 ? "" : "\n"); - - /* And now we notify the puppies about the changes */ - XkbDDXChangeControls(pDev, &old, ctrl); - } -} - -void DarwinKeyboardReloadHandler(void) { - KeySymsRec keySyms; - CFIndex initialKeyRepeatValue, keyRepeatValue; - BOOL ok; - DeviceIntPtr pDev; - const char *xmodmap = PROJECTROOT "/bin/xmodmap"; - const char *sysmodmap = PROJECTROOT "/lib/X11/xinit/.Xmodmap"; - const char *homedir = getenv("HOME"); - char usermodmap[PATH_MAX], cmd[PATH_MAX]; - - DEBUG_LOG("DarwinKeyboardReloadHandler\n"); - - /* Get our key repeat settings from GlobalPreferences */ - (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences")); - - initialKeyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"), CFSTR(".GlobalPreferences"), &ok); - if(!ok) - initialKeyRepeatValue = 35; - - keyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("KeyRepeat"), CFSTR(".GlobalPreferences"), &ok); - if(!ok) - keyRepeatValue = 6; - - pthread_mutex_lock(&keyInfo_mutex); { - /* Initialize our keySyms */ - keySyms.map = keyInfo.keyMap; - keySyms.mapWidth = GLYPHS_PER_KEY; - keySyms.minKeyCode = MIN_KEYCODE; - keySyms.maxKeyCode = MAX_KEYCODE; - - // TODO: We should build the entire XkbDescRec and use XkbCopyKeymap - /* Apply the mappings to darwinKeyboard */ - XkbApplyMappingChange(darwinKeyboard, &keySyms, keySyms.minKeyCode, - keySyms.maxKeyCode - keySyms.minKeyCode + 1, - keyInfo.modMap, serverClient); - DarwinKeyboardSetRepeat(darwinKeyboard, initialKeyRepeatValue, keyRepeatValue); - - /* Apply the mappings to the core keyboard */ - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { - if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) { - XkbApplyMappingChange(pDev, &keySyms, keySyms.minKeyCode, - keySyms.maxKeyCode - keySyms.minKeyCode + 1, - keyInfo.modMap, serverClient); - DarwinKeyboardSetRepeat(pDev, initialKeyRepeatValue, keyRepeatValue); - } - } - } pthread_mutex_unlock(&keyInfo_mutex); - - /* Modify with xmodmap */ - if (access(xmodmap, F_OK) == 0) { - /* Check for system .Xmodmap */ - if (access(sysmodmap, F_OK) == 0) { - if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, sysmodmap) < sizeof(cmd)) { - X11ApplicationLaunchClient(cmd); - } else { - ErrorF("X11.app: Unable to create / execute xmodmap command line"); - } - } - - /* Check for user's local .Xmodmap */ - if ((homedir != NULL) && (snprintf (usermodmap, sizeof(usermodmap), "%s/.Xmodmap", homedir) < sizeof(usermodmap))) { - if (access(usermodmap, F_OK) == 0) { - if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, usermodmap) < sizeof(cmd)) { - X11ApplicationLaunchClient(cmd); - } else { - ErrorF("X11.app: Unable to create / execute xmodmap command line"); - } - } - } else { - ErrorF("X11.app: Unable to determine path to user's .Xmodmap"); - } - } -} - -//----------------------------------------------------------------------------- -// Modifier translation functions -// -// There are three different ways to specify a Mac modifier key: -// keycode - specifies hardware key, read from keymapping -// key - NX_MODIFIERKEY_*, really an index -// mask - NX_*MASK, mask for modifier flags in event record -// Left and right side have different keycodes but the same key and mask. -//----------------------------------------------------------------------------- - -/* - * DarwinModifierNXKeyToNXKeycode - * Return the keycode for an NX_MODIFIERKEY_* modifier. - * side = 0 for left or 1 for right. - * Returns 0 if key+side is not a known modifier. - */ -int DarwinModifierNXKeyToNXKeycode(int key, int side) { - int retval; - pthread_mutex_lock(&keyInfo_mutex); - retval = keyInfo.modifierKeycodes[key][side]; - pthread_mutex_unlock(&keyInfo_mutex); - - return retval; -} - -/* - * DarwinModifierNXKeycodeToNXKey - * Returns -1 if keycode+side is not a modifier key - * outSide may be NULL, else it gets 0 for left and 1 for right. - */ -int DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide) { - int key, side; - - keycode += MIN_KEYCODE; - - // search modifierKeycodes for this keycode+side - pthread_mutex_lock(&keyInfo_mutex); - for (key = 0; key < NX_NUMMODIFIERS; key++) { - for (side = 0; side <= 1; side++) { - if (keyInfo.modifierKeycodes[key][side] == keycode) break; - } - } - pthread_mutex_unlock(&keyInfo_mutex); - - if (key == NX_NUMMODIFIERS) { - return -1; - } - if (outSide) *outSide = side; - - return key; -} - -/* - * DarwinModifierNXMaskToNXKey - * Returns -1 if mask is not a known modifier mask. - */ -int DarwinModifierNXMaskToNXKey(int mask) { - switch (mask) { - case NX_ALPHASHIFTMASK: return NX_MODIFIERKEY_ALPHALOCK; - case NX_SHIFTMASK: return NX_MODIFIERKEY_SHIFT; -#ifdef NX_DEVICELSHIFTKEYMASK - case NX_DEVICELSHIFTKEYMASK: return NX_MODIFIERKEY_SHIFT; - case NX_DEVICERSHIFTKEYMASK: return NX_MODIFIERKEY_RSHIFT; -#endif - case NX_CONTROLMASK: return NX_MODIFIERKEY_CONTROL; -#ifdef NX_DEVICELCTLKEYMASK - case NX_DEVICELCTLKEYMASK: return NX_MODIFIERKEY_CONTROL; - case NX_DEVICERCTLKEYMASK: return NX_MODIFIERKEY_RCONTROL; -#endif - case NX_ALTERNATEMASK: return NX_MODIFIERKEY_ALTERNATE; -#ifdef NX_DEVICELALTKEYMASK - case NX_DEVICELALTKEYMASK: return NX_MODIFIERKEY_ALTERNATE; - case NX_DEVICERALTKEYMASK: return NX_MODIFIERKEY_RALTERNATE; -#endif - case NX_COMMANDMASK: return NX_MODIFIERKEY_COMMAND; -#ifdef NX_DEVICELCMDKEYMASK - case NX_DEVICELCMDKEYMASK: return NX_MODIFIERKEY_COMMAND; - case NX_DEVICERCMDKEYMASK: return NX_MODIFIERKEY_RCOMMAND; -#endif - case NX_NUMERICPADMASK: return NX_MODIFIERKEY_NUMERICPAD; - case NX_HELPMASK: return NX_MODIFIERKEY_HELP; - case NX_SECONDARYFNMASK: return NX_MODIFIERKEY_SECONDARYFN; - } - return -1; -} - -/* - * DarwinModifierNXKeyToNXMask - * Returns 0 if key is not a known modifier key. - */ -int DarwinModifierNXKeyToNXMask(int key) { - switch (key) { - case NX_MODIFIERKEY_ALPHALOCK: return NX_ALPHASHIFTMASK; -#ifdef NX_DEVICELSHIFTKEYMASK - case NX_MODIFIERKEY_SHIFT: return NX_DEVICELSHIFTKEYMASK; - case NX_MODIFIERKEY_RSHIFT: return NX_DEVICERSHIFTKEYMASK; - case NX_MODIFIERKEY_CONTROL: return NX_DEVICELCTLKEYMASK; - case NX_MODIFIERKEY_RCONTROL: return NX_DEVICERCTLKEYMASK; - case NX_MODIFIERKEY_ALTERNATE: return NX_DEVICELALTKEYMASK; - case NX_MODIFIERKEY_RALTERNATE: return NX_DEVICERALTKEYMASK; - case NX_MODIFIERKEY_COMMAND: return NX_DEVICELCMDKEYMASK; - case NX_MODIFIERKEY_RCOMMAND: return NX_DEVICERCMDKEYMASK; -#else - case NX_MODIFIERKEY_SHIFT: return NX_SHIFTMASK; - case NX_MODIFIERKEY_CONTROL: return NX_CONTROLMASK; - case NX_MODIFIERKEY_ALTERNATE: return NX_ALTERNATEMASK; - case NX_MODIFIERKEY_COMMAND: return NX_COMMANDMASK; -#endif - case NX_MODIFIERKEY_NUMERICPAD: return NX_NUMERICPADMASK; - case NX_MODIFIERKEY_HELP: return NX_HELPMASK; - case NX_MODIFIERKEY_SECONDARYFN: return NX_SECONDARYFNMASK; - } - return 0; -} - -/* - * DarwinModifierStringToNXMask - * Returns 0 if string is not a known modifier. - */ -int DarwinModifierStringToNXMask(const char *str, int separatelr) { -#ifdef NX_DEVICELSHIFTKEYMASK - if(separatelr) { - if (!strcasecmp(str, "shift")) return NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK; - if (!strcasecmp(str, "control")) return NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK; - if (!strcasecmp(str, "option")) return NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK; - if (!strcasecmp(str, "alt")) return NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK; - if (!strcasecmp(str, "command")) return NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK; - if (!strcasecmp(str, "lshift")) return NX_DEVICELSHIFTKEYMASK; - if (!strcasecmp(str, "rshift")) return NX_DEVICERSHIFTKEYMASK; - if (!strcasecmp(str, "lcontrol")) return NX_DEVICELCTLKEYMASK; - if (!strcasecmp(str, "rcontrol")) return NX_DEVICERCTLKEYMASK; - if (!strcasecmp(str, "loption")) return NX_DEVICELALTKEYMASK; - if (!strcasecmp(str, "roption")) return NX_DEVICERALTKEYMASK; - if (!strcasecmp(str, "lalt")) return NX_DEVICELALTKEYMASK; - if (!strcasecmp(str, "ralt")) return NX_DEVICERALTKEYMASK; - if (!strcasecmp(str, "lcommand")) return NX_DEVICELCMDKEYMASK; - if (!strcasecmp(str, "rcommand")) return NX_DEVICERCMDKEYMASK; - } else { -#endif - if (!strcasecmp(str, "shift")) return NX_SHIFTMASK; - if (!strcasecmp(str, "control")) return NX_CONTROLMASK; - if (!strcasecmp(str, "option")) return NX_ALTERNATEMASK; - if (!strcasecmp(str, "alt")) return NX_ALTERNATEMASK; - if (!strcasecmp(str, "command")) return NX_COMMANDMASK; - if (!strcasecmp(str, "lshift")) return NX_SHIFTMASK; - if (!strcasecmp(str, "rshift")) return NX_SHIFTMASK; - if (!strcasecmp(str, "lcontrol")) return NX_CONTROLMASK; - if (!strcasecmp(str, "rcontrol")) return NX_CONTROLMASK; - if (!strcasecmp(str, "loption")) return NX_ALTERNATEMASK; - if (!strcasecmp(str, "roption")) return NX_ALTERNATEMASK; - if (!strcasecmp(str, "lalt")) return NX_ALTERNATEMASK; - if (!strcasecmp(str, "ralt")) return NX_ALTERNATEMASK; - if (!strcasecmp(str, "lcommand")) return NX_COMMANDMASK; - if (!strcasecmp(str, "rcommand")) return NX_COMMANDMASK; -#ifdef NX_DEVICELSHIFTKEYMASK - } -#endif - if (!strcasecmp(str, "lock")) return NX_ALPHASHIFTMASK; - if (!strcasecmp(str, "fn")) return NX_SECONDARYFNMASK; - if (!strcasecmp(str, "help")) return NX_HELPMASK; - if (!strcasecmp(str, "numlock")) return NX_NUMERICPADMASK; - return 0; -} - -/* - * LegalModifier - * This allows the ddx layer to prevent some keys from being remapped - * as modifier keys. - */ -Bool LegalModifier(unsigned int key, DeviceIntPtr pDev) -{ - return 1; -} - -static inline UniChar macroman2ucs(unsigned char c) { - /* Precalculated table mapping MacRoman-128 to Unicode. Generated - by creating single element CFStringRefs then extracting the - first character. */ - - static const unsigned short table[128] = { - 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, - 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, - 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, - 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, - 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf, - 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8, - 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211, - 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8, - 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab, - 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153, - 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca, - 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02, - 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1, - 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, - 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc, - 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7, - }; - - if (c < 128) return c; - else return table[c - 128]; -} - -static KeySym make_dead_key(KeySym in) { - int i; - - for (i = 0; i < sizeof (dead_keys) / sizeof (dead_keys[0]); i++) - if (dead_keys[i].normal == in) return dead_keys[i].dead; - - return in; -} - -static Bool QuartzReadSystemKeymap(darwinKeyboardInfo *info) { -#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050 - KeyboardLayoutRef key_layout; - int is_uchr = 1; -#endif - const void *chr_data = NULL; - int num_keycodes = NUM_KEYCODES; - UInt32 keyboard_type = LMGetKbdType(); - int i, j; - OSStatus err; - KeySym *k; - CFDataRef currentKeyLayoutDataRef = NULL; - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 - TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource(); - - if (currentKeyLayoutRef) { - currentKeyLayoutDataRef = (CFDataRef )TISGetInputSourceProperty(currentKeyLayoutRef, kTISPropertyUnicodeKeyLayoutData); - if (currentKeyLayoutDataRef) - chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef); - } -#endif - -#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050 - if (chr_data == NULL) { -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 - ErrorF("X11.app: Error detected in determining keyboard layout. If you are using an Apple-provided keyboard layout, please report this error at http://xquartz.macosforge.org and http://bugreport.apple.com\n"); - ErrorF("X11.app: Debug Info: keyboard_type=%u, currentKeyLayoutRef=%p, currentKeyLayoutDataRef=%p, chr_data=%p\n", - (unsigned)keyboard_type, currentKeyLayoutRef, currentKeyLayoutDataRef, chr_data); -#endif - - KLGetCurrentKeyboardLayout (&key_layout); - KLGetKeyboardLayoutProperty (key_layout, kKLuchrData, &chr_data); - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 - if(chr_data != NULL) { - ErrorF("X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n"); - } -#endif - } - - if (chr_data == NULL) { - ErrorF("X11.app: Debug Info: kKLuchrData failed, trying kKLKCHRData.\n"); - ErrorF("If you are using a 3rd party keyboard layout, please see http://xquartz.macosforge.org/trac/ticket/154\n"); - KLGetKeyboardLayoutProperty (key_layout, kKLKCHRData, &chr_data); - is_uchr = 0; - num_keycodes = 128; - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 - if(chr_data != NULL) { - ErrorF("X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n"); - } -#endif - } -#endif - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 - if(currentKeyLayoutRef) - CFRelease(currentKeyLayoutRef); -#endif - - if (chr_data == NULL) { - ErrorF ( "Couldn't get uchr or kchr resource\n"); - return FALSE; - } - - /* Scan the keycode range for the Unicode character that each - key produces in the four shift states. Then convert that to - an X11 keysym (which may just the bit that says "this is - Unicode" if it can't find the real symbol.) */ - - /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate - must be used instead. */ - - for (i = 0; i < num_keycodes; i++) { - static const int mods[4] = {0, MOD_SHIFT, MOD_OPTION, - MOD_OPTION | MOD_SHIFT}; - - k = info->keyMap + i * GLYPHS_PER_KEY; - - for (j = 0; j < 4; j++) { -#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050 - if (is_uchr) { -#endif - UniChar s[8]; - UniCharCount len; - UInt32 dead_key_state = 0, extra_dead = 0; - - err = UCKeyTranslate (chr_data, i, kUCKeyActionDown, - mods[j] >> 8, keyboard_type, 0, - &dead_key_state, 8, &len, s); - if (err != noErr) continue; - - if (len == 0 && dead_key_state != 0) { - /* Found a dead key. Work out which one it is, but - remembering that it's dead. */ - err = UCKeyTranslate (chr_data, i, kUCKeyActionDown, - mods[j] >> 8, keyboard_type, - kUCKeyTranslateNoDeadKeysMask, - &extra_dead, 8, &len, s); - if (err != noErr) continue; - } - - /* Not sure why 0x0010 is there. - * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ... - */ - if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) { - k[j] = ucs2keysym (s[0]); - if (dead_key_state != 0) k[j] = make_dead_key (k[j]); - } -#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050 - } else { // kchr - UInt32 c, state = 0, state2 = 0; - UInt16 code; - - code = i | mods[j]; - c = KeyTranslate (chr_data, code, &state); - - /* Dead keys are only processed on key-down, so ask - to translate those events. When we find a dead key, - translating the matching key up event will give - us the actual dead character. */ - - if (state != 0) - c = KeyTranslate (chr_data, code | 128, &state2); - - /* Characters seem to be in MacRoman encoding. */ - - if (c != 0 && c != 0x0010) { - k[j] = ucs2keysym (macroman2ucs (c & 255)); - - if (state != 0) k[j] = make_dead_key (k[j]); - } - } -#endif - } - - if (k[3] == k[2]) k[3] = NoSymbol; - if (k[1] == k[0]) k[1] = NoSymbol; - if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; - if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol; - } - -#if HACK_MISSING - /* Fix up some things that are normally missing.. */ - - for (i = 0; i < sizeof (known_keys) / sizeof (known_keys[0]); i++) { - k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY; - - if ( k[0] == NoSymbol && k[1] == NoSymbol - && k[2] == NoSymbol && k[3] == NoSymbol) - k[0] = known_keys[i].keysym; - } -#endif - -#if HACK_KEYPAD - /* And some more things. We find the right symbols for the numeric - keypad, but not the KP_ keysyms. So try to convert known keycodes. */ - for (i = 0; i < sizeof (known_numeric_keys) / sizeof (known_numeric_keys[0]); i++) { - k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY; - - if (k[0] == known_numeric_keys[i].normal) - k[0] = known_numeric_keys[i].keypad; - } -#endif - -#if HACK_BLACKLIST - for (i = 0; i < sizeof (keycode_blacklist) / sizeof (keycode_blacklist[0]); i++) { - k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY; - k[0] = k[1] = k[2] = k[3] = NoSymbol; - } -#endif - - DarwinBuildModifierMaps(info); - - return TRUE; -} - -Bool QuartsResyncKeymap(Bool sendDDXEvent) { - Bool retval; - /* Update keyInfo */ - pthread_mutex_lock(&keyInfo_mutex); - memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap)); - retval = QuartzReadSystemKeymap(&keyInfo); - pthread_mutex_unlock(&keyInfo_mutex); - - /* Tell server thread to deal with new keyInfo */ - if(sendDDXEvent) - DarwinSendDDXEvent(kXquartzReloadKeymap, 0); - - return retval; -} +/*
+ quartzKeyboard.c: Keyboard support for Xquartz
+
+ Copyright (c) 2003-2008 Apple Inc.
+ Copyright (c) 2001-2004 Torrey T. Lyons. All Rights Reserved.
+ Copyright 2004 Kaleb S. KEITHLEY. All Rights Reserved.
+
+ Copyright (C) 1999,2000 by Eric Sunshine <sunshine@sunshineco.com>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "sanitizedCarbon.h"
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#define HACK_MISSING 1
+#define HACK_KEYPAD 1
+#define HACK_BLACKLIST 1
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <AvailabilityMacros.h>
+
+#include "quartz.h"
+#include "darwin.h"
+#include "darwinEvents.h"
+
+#include "quartzKeyboard.h"
+
+#include "X11Application.h"
+
+#ifdef NDEBUG
+#undef NDEBUG
+#include <assert.h>
+#define NDEBUG 1
+#else
+#include <assert.h>
+#endif
+#include <pthread.h>
+
+#include "xkbsrv.h"
+#include "exevents.h"
+#include "X11/keysym.h"
+#include "keysym2ucs.h"
+
+extern void
+CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
+
+enum {
+ MOD_COMMAND = 256,
+ MOD_SHIFT = 512,
+ MOD_OPTION = 2048,
+ MOD_CONTROL = 4096,
+};
+
+#define UKEYSYM(u) ((u) | 0x01000000)
+
+#if HACK_MISSING
+/* Table of keycode->keysym mappings we use to fallback on for important
+ keys that are often not in the Unicode mapping. */
+
+const static struct {
+ unsigned short keycode;
+ KeySym keysym;
+} known_keys[] = {
+ {55, XK_Meta_L},
+ {56, XK_Shift_L},
+ {57, XK_Caps_Lock},
+ {58, XK_Alt_L},
+ {59, XK_Control_L},
+
+ {60, XK_Shift_R},
+ {61, XK_Alt_R},
+ {62, XK_Control_R},
+ {63, XK_Meta_R},
+
+ {122, XK_F1},
+ {120, XK_F2},
+ {99, XK_F3},
+ {118, XK_F4},
+ {96, XK_F5},
+ {97, XK_F6},
+ {98, XK_F7},
+ {100, XK_F8},
+ {101, XK_F9},
+ {109, XK_F10},
+ {103, XK_F11},
+ {111, XK_F12},
+ {105, XK_F13},
+ {107, XK_F14},
+ {113, XK_F15},
+};
+#endif
+
+#if HACK_KEYPAD
+/* Table of keycode->old,new-keysym mappings we use to fixup the numeric
+ keypad entries. */
+
+const static struct {
+ unsigned short keycode;
+ KeySym normal, keypad;
+} known_numeric_keys[] = {
+ {65, XK_period, XK_KP_Decimal},
+ {67, XK_asterisk, XK_KP_Multiply},
+ {69, XK_plus, XK_KP_Add},
+ {75, XK_slash, XK_KP_Divide},
+ {76, 0x01000003, XK_KP_Enter},
+ {78, XK_minus, XK_KP_Subtract},
+ {81, XK_equal, XK_KP_Equal},
+ {82, XK_0, XK_KP_0},
+ {83, XK_1, XK_KP_1},
+ {84, XK_2, XK_KP_2},
+ {85, XK_3, XK_KP_3},
+ {86, XK_4, XK_KP_4},
+ {87, XK_5, XK_KP_5},
+ {88, XK_6, XK_KP_6},
+ {89, XK_7, XK_KP_7},
+ {91, XK_8, XK_KP_8},
+ {92, XK_9, XK_KP_9},
+};
+#endif
+
+#if HACK_BLACKLIST
+/* <rdar://problem/7824370> wine notepad produces wrong characters on shift+arrow
+ * http://xquartz.macosforge.org/trac/ticket/295
+ * http://developer.apple.com/legacy/mac/library/documentation/mac/Text/Text-579.html
+ *
+ * legacy Mac keycodes for arrow keys that shift-modify to math symbols
+ */
+const static unsigned short keycode_blacklist[] = {66, 70, 72, 77};
+#endif
+
+/* Table mapping normal keysyms to their dead equivalents.
+ FIXME: all the unicode keysyms (apart from circumflex) were guessed. */
+
+const static struct {
+ KeySym normal, dead;
+} dead_keys[] = {
+ {XK_grave, XK_dead_grave},
+ {XK_apostrophe, XK_dead_acute}, /* US:"=" on a Czech keyboard */
+ {XK_acute, XK_dead_acute},
+ {UKEYSYM (0x384), XK_dead_acute}, /* US:";" on a Greek keyboard */
+// {XK_Greek_accentdieresis, XK_dead_diaeresis}, /* US:"opt+;" on a Greek keyboard ... replace with dead_accentdieresis if there is one */
+ {XK_asciicircum, XK_dead_circumflex},
+ {UKEYSYM (0x2c6), XK_dead_circumflex}, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
+ {XK_asciitilde, XK_dead_tilde},
+ {UKEYSYM (0x2dc), XK_dead_tilde}, /* SMALL TILDE */
+ {XK_macron, XK_dead_macron},
+ {XK_breve, XK_dead_breve},
+ {XK_abovedot, XK_dead_abovedot},
+ {XK_diaeresis, XK_dead_diaeresis},
+ {UKEYSYM (0x2da), XK_dead_abovering}, /* DOT ABOVE */
+ {XK_doubleacute, XK_dead_doubleacute},
+ {XK_caron, XK_dead_caron},
+ {XK_cedilla, XK_dead_cedilla},
+ {XK_ogonek, XK_dead_ogonek},
+ {UKEYSYM (0x269), XK_dead_iota}, /* LATIN SMALL LETTER IOTA */
+ {UKEYSYM (0x2ec), XK_dead_voiced_sound}, /* MODIFIER LETTER VOICING */
+/* {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */
+ {UKEYSYM (0x323), XK_dead_belowdot}, /* COMBINING DOT BELOW */
+ {UKEYSYM (0x309), XK_dead_hook}, /* COMBINING HOOK ABOVE */
+ {UKEYSYM (0x31b), XK_dead_horn}, /* COMBINING HORN */
+};
+
+typedef struct darwinKeyboardInfo_struct {
+ CARD8 modMap[MAP_LENGTH];
+ KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY];
+ unsigned char modifierKeycodes[32][2];
+} darwinKeyboardInfo;
+
+darwinKeyboardInfo keyInfo;
+pthread_mutex_t keyInfo_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void DarwinChangeKeyboardControl(DeviceIntPtr device, KeybdCtrl *ctrl) {
+ // FIXME: to be implemented
+ // keyclick, bell volume / pitch, autorepead, LED's
+}
+
+//-----------------------------------------------------------------------------
+// Utility functions to help parse Darwin keymap
+//-----------------------------------------------------------------------------
+
+/*
+ * DarwinBuildModifierMaps
+ * Use the keyMap field of keyboard info structure to populate
+ * the modMap and modifierKeycodes fields.
+ */
+static void DarwinBuildModifierMaps(darwinKeyboardInfo *info) {
+ int i;
+ KeySym *k;
+
+ memset(info->modMap, NoSymbol, sizeof(info->modMap));
+ memset(info->modifierKeycodes, 0, sizeof(info->modifierKeycodes));
+
+ for (i = 0; i < NUM_KEYCODES; i++) {
+ k = info->keyMap + i * GLYPHS_PER_KEY;
+
+ switch (*k) {
+ case XK_Shift_L:
+ info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
+ info->modMap[MIN_KEYCODE + i] = ShiftMask;
+ break;
+
+ case XK_Shift_R:
+#ifdef NX_MODIFIERKEY_RSHIFT
+ info->modifierKeycodes[NX_MODIFIERKEY_RSHIFT][0] = i;
+#else
+ info->modifierKeycodes[NX_MODIFIERKEY_SHIFT][0] = i;
+#endif
+ info->modMap[MIN_KEYCODE + i] = ShiftMask;
+ break;
+
+ case XK_Control_L:
+ info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
+ info->modMap[MIN_KEYCODE + i] = ControlMask;
+ break;
+
+ case XK_Control_R:
+#ifdef NX_MODIFIERKEY_RCONTROL
+ info->modifierKeycodes[NX_MODIFIERKEY_RCONTROL][0] = i;
+#else
+ info->modifierKeycodes[NX_MODIFIERKEY_CONTROL][0] = i;
+#endif
+ info->modMap[MIN_KEYCODE + i] = ControlMask;
+ break;
+
+ case XK_Caps_Lock:
+ info->modifierKeycodes[NX_MODIFIERKEY_ALPHALOCK][0] = i;
+ info->modMap[MIN_KEYCODE + i] = LockMask;
+ break;
+
+ case XK_Alt_L:
+ info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
+ info->modMap[MIN_KEYCODE + i] = Mod1Mask;
+ if(!XQuartzOptionSendsAlt)
+ *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor.
+ break;
+
+ case XK_Alt_R:
+#ifdef NX_MODIFIERKEY_RALTERNATE
+ info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i;
+#else
+ info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
+#endif
+ if(!XQuartzOptionSendsAlt)
+ *k = XK_Mode_switch; // Yes, this is ugly. This needs to be cleaned up when we integrate quartzKeyboard with this code and refactor.
+ info->modMap[MIN_KEYCODE + i] = Mod1Mask;
+ break;
+
+ case XK_Mode_switch:
+ ErrorF("DarwinBuildModifierMaps: XK_Mode_switch encountered, unable to determine side.\n");
+ info->modifierKeycodes[NX_MODIFIERKEY_ALTERNATE][0] = i;
+#ifdef NX_MODIFIERKEY_RALTERNATE
+ info->modifierKeycodes[NX_MODIFIERKEY_RALTERNATE][0] = i;
+#endif
+ info->modMap[MIN_KEYCODE + i] = Mod1Mask;
+ break;
+
+ case XK_Meta_L:
+ info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
+ info->modMap[MIN_KEYCODE + i] = Mod2Mask;
+ break;
+
+ case XK_Meta_R:
+#ifdef NX_MODIFIERKEY_RCOMMAND
+ info->modifierKeycodes[NX_MODIFIERKEY_RCOMMAND][0] = i;
+#else
+ info->modifierKeycodes[NX_MODIFIERKEY_COMMAND][0] = i;
+#endif
+ info->modMap[MIN_KEYCODE + i] = Mod2Mask;
+ break;
+
+ case XK_Num_Lock:
+ info->modMap[MIN_KEYCODE + i] = Mod3Mask;
+ break;
+ }
+ }
+}
+
+/*
+ * DarwinKeyboardInit
+ * Get the Darwin keyboard map and compute an equivalent
+ * X keyboard map and modifier map. Set the new keyboard
+ * device structure.
+ */
+void DarwinKeyboardInit(DeviceIntPtr pDev) {
+ // Open a shared connection to the HID System.
+ // Note that the Event Status Driver is really just a wrapper
+ // for a kIOHIDParamConnectType connection.
+ assert(darwinParamConnect = NXOpenEventStatus());
+
+ InitKeyboardDeviceStruct(pDev, NULL, NULL, DarwinChangeKeyboardControl);
+
+ DarwinKeyboardReloadHandler();
+
+ CopyKeyClass(pDev, inputInfo.keyboard);
+}
+
+/* Set the repeat rates based on global preferences and keycodes for modifiers.
+ * Precondition: Has the keyInfo_mutex lock.
+ */
+static void DarwinKeyboardSetRepeat(DeviceIntPtr pDev, int initialKeyRepeatValue, int keyRepeatValue) {
+ if(initialKeyRepeatValue == 300000) { // off
+ /* Turn off repeats globally */
+ XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOff);
+ } else {
+ int i;
+ XkbControlsPtr ctrl;
+ XkbControlsRec old;
+
+ /* Turn on repeats globally */
+ XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn);
+
+ /* Setup the bit mask for individual key repeats */
+ ctrl = pDev->key->xkbInfo->desc->ctrls;
+ old= *ctrl;
+
+ ctrl->repeat_delay = initialKeyRepeatValue * 15;
+ ctrl->repeat_interval = keyRepeatValue * 15;
+
+ /* Turn off key-repeat for modifier keys, on for others */
+ /* First set them all on */
+ for(i=0; i < XkbPerKeyBitArraySize; i++)
+ ctrl->per_key_repeat[i] = -1;
+
+ /* Now turn off the modifiers */
+ for(i=0; i < 32; i++) {
+ unsigned char keycode;
+
+ keycode = keyInfo.modifierKeycodes[i][0];
+ if(keycode)
+ ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE);
+
+ keycode = keyInfo.modifierKeycodes[i][1];
+ if(keycode)
+ ClearBit(ctrl->per_key_repeat, keycode + MIN_KEYCODE);
+ }
+
+ /* Hurray for data duplication */
+ if (pDev->kbdfeed)
+ memcpy(pDev->kbdfeed->ctrl.autoRepeats, ctrl->per_key_repeat, XkbPerKeyBitArraySize);
+
+ //ErrorF("per_key_repeat =\n");
+ //for(i=0; i < XkbPerKeyBitArraySize; i++)
+ // ErrorF("%02x%s", ctrl->per_key_repeat[i], (i + 1) & 7 ? "" : "\n");
+
+ /* And now we notify the puppies about the changes */
+ XkbDDXChangeControls(pDev, &old, ctrl);
+ }
+}
+
+void DarwinKeyboardReloadHandler(void) {
+ KeySymsRec keySyms;
+ CFIndex initialKeyRepeatValue, keyRepeatValue;
+ BOOL ok;
+ DeviceIntPtr pDev;
+ const char *xmodmap = PROJECTROOT "/bin/xmodmap";
+ const char *sysmodmap = PROJECTROOT "/lib/X11/xinit/.Xmodmap";
+ const char *homedir = getenv("HOME");
+ char usermodmap[PATH_MAX], cmd[PATH_MAX];
+
+ DEBUG_LOG("DarwinKeyboardReloadHandler\n");
+
+ /* Get our key repeat settings from GlobalPreferences */
+ (void)CFPreferencesAppSynchronize(CFSTR(".GlobalPreferences"));
+
+ initialKeyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("InitialKeyRepeat"), CFSTR(".GlobalPreferences"), &ok);
+ if(!ok)
+ initialKeyRepeatValue = 35;
+
+ keyRepeatValue = CFPreferencesGetAppIntegerValue(CFSTR("KeyRepeat"), CFSTR(".GlobalPreferences"), &ok);
+ if(!ok)
+ keyRepeatValue = 6;
+
+ pthread_mutex_lock(&keyInfo_mutex); {
+ /* Initialize our keySyms */
+ keySyms.map = keyInfo.keyMap;
+ keySyms.mapWidth = GLYPHS_PER_KEY;
+ keySyms.minKeyCode = MIN_KEYCODE;
+ keySyms.maxKeyCode = MAX_KEYCODE;
+
+ // TODO: We should build the entire XkbDescRec and use XkbCopyKeymap
+ /* Apply the mappings to darwinKeyboard */
+ XkbApplyMappingChange(darwinKeyboard, &keySyms, keySyms.minKeyCode,
+ keySyms.maxKeyCode - keySyms.minKeyCode + 1,
+ keyInfo.modMap, serverClient);
+ DarwinKeyboardSetRepeat(darwinKeyboard, initialKeyRepeatValue, keyRepeatValue);
+
+ /* Apply the mappings to the core keyboard */
+ for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
+ if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) {
+ XkbApplyMappingChange(pDev, &keySyms, keySyms.minKeyCode,
+ keySyms.maxKeyCode - keySyms.minKeyCode + 1,
+ keyInfo.modMap, serverClient);
+ DarwinKeyboardSetRepeat(pDev, initialKeyRepeatValue, keyRepeatValue);
+ }
+ }
+ } pthread_mutex_unlock(&keyInfo_mutex);
+
+ /* Modify with xmodmap */
+ if (access(xmodmap, F_OK) == 0) {
+ /* Check for system .Xmodmap */
+ if (access(sysmodmap, F_OK) == 0) {
+ if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, sysmodmap) < sizeof(cmd)) {
+ X11ApplicationLaunchClient(cmd);
+ } else {
+ ErrorF("X11.app: Unable to create / execute xmodmap command line");
+ }
+ }
+
+ /* Check for user's local .Xmodmap */
+ if ((homedir != NULL) && (snprintf (usermodmap, sizeof(usermodmap), "%s/.Xmodmap", homedir) < sizeof(usermodmap))) {
+ if (access(usermodmap, F_OK) == 0) {
+ if(snprintf (cmd, sizeof(cmd), "%s %s", xmodmap, usermodmap) < sizeof(cmd)) {
+ X11ApplicationLaunchClient(cmd);
+ } else {
+ ErrorF("X11.app: Unable to create / execute xmodmap command line");
+ }
+ }
+ } else {
+ ErrorF("X11.app: Unable to determine path to user's .Xmodmap");
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Modifier translation functions
+//
+// There are three different ways to specify a Mac modifier key:
+// keycode - specifies hardware key, read from keymapping
+// key - NX_MODIFIERKEY_*, really an index
+// mask - NX_*MASK, mask for modifier flags in event record
+// Left and right side have different keycodes but the same key and mask.
+//-----------------------------------------------------------------------------
+
+/*
+ * DarwinModifierNXKeyToNXKeycode
+ * Return the keycode for an NX_MODIFIERKEY_* modifier.
+ * side = 0 for left or 1 for right.
+ * Returns 0 if key+side is not a known modifier.
+ */
+int DarwinModifierNXKeyToNXKeycode(int key, int side) {
+ int retval;
+ pthread_mutex_lock(&keyInfo_mutex);
+ retval = keyInfo.modifierKeycodes[key][side];
+ pthread_mutex_unlock(&keyInfo_mutex);
+
+ return retval;
+}
+
+/*
+ * DarwinModifierNXKeycodeToNXKey
+ * Returns -1 if keycode+side is not a modifier key
+ * outSide may be NULL, else it gets 0 for left and 1 for right.
+ */
+int DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide) {
+ int key, side;
+
+ keycode += MIN_KEYCODE;
+
+ // search modifierKeycodes for this keycode+side
+ pthread_mutex_lock(&keyInfo_mutex);
+ for (key = 0; key < NX_NUMMODIFIERS; key++) {
+ for (side = 0; side <= 1; side++) {
+ if (keyInfo.modifierKeycodes[key][side] == keycode) break;
+ }
+ }
+ pthread_mutex_unlock(&keyInfo_mutex);
+
+ if (key == NX_NUMMODIFIERS) {
+ return -1;
+ }
+ if (outSide) *outSide = side;
+
+ return key;
+}
+
+/*
+ * DarwinModifierNXMaskToNXKey
+ * Returns -1 if mask is not a known modifier mask.
+ */
+int DarwinModifierNXMaskToNXKey(int mask) {
+ switch (mask) {
+ case NX_ALPHASHIFTMASK: return NX_MODIFIERKEY_ALPHALOCK;
+ case NX_SHIFTMASK: return NX_MODIFIERKEY_SHIFT;
+#ifdef NX_DEVICELSHIFTKEYMASK
+ case NX_DEVICELSHIFTKEYMASK: return NX_MODIFIERKEY_SHIFT;
+ case NX_DEVICERSHIFTKEYMASK: return NX_MODIFIERKEY_RSHIFT;
+#endif
+ case NX_CONTROLMASK: return NX_MODIFIERKEY_CONTROL;
+#ifdef NX_DEVICELCTLKEYMASK
+ case NX_DEVICELCTLKEYMASK: return NX_MODIFIERKEY_CONTROL;
+ case NX_DEVICERCTLKEYMASK: return NX_MODIFIERKEY_RCONTROL;
+#endif
+ case NX_ALTERNATEMASK: return NX_MODIFIERKEY_ALTERNATE;
+#ifdef NX_DEVICELALTKEYMASK
+ case NX_DEVICELALTKEYMASK: return NX_MODIFIERKEY_ALTERNATE;
+ case NX_DEVICERALTKEYMASK: return NX_MODIFIERKEY_RALTERNATE;
+#endif
+ case NX_COMMANDMASK: return NX_MODIFIERKEY_COMMAND;
+#ifdef NX_DEVICELCMDKEYMASK
+ case NX_DEVICELCMDKEYMASK: return NX_MODIFIERKEY_COMMAND;
+ case NX_DEVICERCMDKEYMASK: return NX_MODIFIERKEY_RCOMMAND;
+#endif
+ case NX_NUMERICPADMASK: return NX_MODIFIERKEY_NUMERICPAD;
+ case NX_HELPMASK: return NX_MODIFIERKEY_HELP;
+ case NX_SECONDARYFNMASK: return NX_MODIFIERKEY_SECONDARYFN;
+ }
+ return -1;
+}
+
+/*
+ * DarwinModifierNXKeyToNXMask
+ * Returns 0 if key is not a known modifier key.
+ */
+int DarwinModifierNXKeyToNXMask(int key) {
+ switch (key) {
+ case NX_MODIFIERKEY_ALPHALOCK: return NX_ALPHASHIFTMASK;
+#ifdef NX_DEVICELSHIFTKEYMASK
+ case NX_MODIFIERKEY_SHIFT: return NX_DEVICELSHIFTKEYMASK;
+ case NX_MODIFIERKEY_RSHIFT: return NX_DEVICERSHIFTKEYMASK;
+ case NX_MODIFIERKEY_CONTROL: return NX_DEVICELCTLKEYMASK;
+ case NX_MODIFIERKEY_RCONTROL: return NX_DEVICERCTLKEYMASK;
+ case NX_MODIFIERKEY_ALTERNATE: return NX_DEVICELALTKEYMASK;
+ case NX_MODIFIERKEY_RALTERNATE: return NX_DEVICERALTKEYMASK;
+ case NX_MODIFIERKEY_COMMAND: return NX_DEVICELCMDKEYMASK;
+ case NX_MODIFIERKEY_RCOMMAND: return NX_DEVICERCMDKEYMASK;
+#else
+ case NX_MODIFIERKEY_SHIFT: return NX_SHIFTMASK;
+ case NX_MODIFIERKEY_CONTROL: return NX_CONTROLMASK;
+ case NX_MODIFIERKEY_ALTERNATE: return NX_ALTERNATEMASK;
+ case NX_MODIFIERKEY_COMMAND: return NX_COMMANDMASK;
+#endif
+ case NX_MODIFIERKEY_NUMERICPAD: return NX_NUMERICPADMASK;
+ case NX_MODIFIERKEY_HELP: return NX_HELPMASK;
+ case NX_MODIFIERKEY_SECONDARYFN: return NX_SECONDARYFNMASK;
+ }
+ return 0;
+}
+
+/*
+ * DarwinModifierStringToNXMask
+ * Returns 0 if string is not a known modifier.
+ */
+int DarwinModifierStringToNXMask(const char *str, int separatelr) {
+#ifdef NX_DEVICELSHIFTKEYMASK
+ if(separatelr) {
+ if (!strcasecmp(str, "shift")) return NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK;
+ if (!strcasecmp(str, "control")) return NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK;
+ if (!strcasecmp(str, "option")) return NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK;
+ if (!strcasecmp(str, "alt")) return NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK;
+ if (!strcasecmp(str, "command")) return NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK;
+ if (!strcasecmp(str, "lshift")) return NX_DEVICELSHIFTKEYMASK;
+ if (!strcasecmp(str, "rshift")) return NX_DEVICERSHIFTKEYMASK;
+ if (!strcasecmp(str, "lcontrol")) return NX_DEVICELCTLKEYMASK;
+ if (!strcasecmp(str, "rcontrol")) return NX_DEVICERCTLKEYMASK;
+ if (!strcasecmp(str, "loption")) return NX_DEVICELALTKEYMASK;
+ if (!strcasecmp(str, "roption")) return NX_DEVICERALTKEYMASK;
+ if (!strcasecmp(str, "lalt")) return NX_DEVICELALTKEYMASK;
+ if (!strcasecmp(str, "ralt")) return NX_DEVICERALTKEYMASK;
+ if (!strcasecmp(str, "lcommand")) return NX_DEVICELCMDKEYMASK;
+ if (!strcasecmp(str, "rcommand")) return NX_DEVICERCMDKEYMASK;
+ } else {
+#endif
+ if (!strcasecmp(str, "shift")) return NX_SHIFTMASK;
+ if (!strcasecmp(str, "control")) return NX_CONTROLMASK;
+ if (!strcasecmp(str, "option")) return NX_ALTERNATEMASK;
+ if (!strcasecmp(str, "alt")) return NX_ALTERNATEMASK;
+ if (!strcasecmp(str, "command")) return NX_COMMANDMASK;
+ if (!strcasecmp(str, "lshift")) return NX_SHIFTMASK;
+ if (!strcasecmp(str, "rshift")) return NX_SHIFTMASK;
+ if (!strcasecmp(str, "lcontrol")) return NX_CONTROLMASK;
+ if (!strcasecmp(str, "rcontrol")) return NX_CONTROLMASK;
+ if (!strcasecmp(str, "loption")) return NX_ALTERNATEMASK;
+ if (!strcasecmp(str, "roption")) return NX_ALTERNATEMASK;
+ if (!strcasecmp(str, "lalt")) return NX_ALTERNATEMASK;
+ if (!strcasecmp(str, "ralt")) return NX_ALTERNATEMASK;
+ if (!strcasecmp(str, "lcommand")) return NX_COMMANDMASK;
+ if (!strcasecmp(str, "rcommand")) return NX_COMMANDMASK;
+#ifdef NX_DEVICELSHIFTKEYMASK
+ }
+#endif
+ if (!strcasecmp(str, "lock")) return NX_ALPHASHIFTMASK;
+ if (!strcasecmp(str, "fn")) return NX_SECONDARYFNMASK;
+ if (!strcasecmp(str, "help")) return NX_HELPMASK;
+ if (!strcasecmp(str, "numlock")) return NX_NUMERICPADMASK;
+ return 0;
+}
+
+/*
+ * LegalModifier
+ * This allows the ddx layer to prevent some keys from being remapped
+ * as modifier keys.
+ */
+Bool LegalModifier(unsigned int key, DeviceIntPtr pDev)
+{
+ return 1;
+}
+
+static inline UniChar macroman2ucs(unsigned char c) {
+ /* Precalculated table mapping MacRoman-128 to Unicode. Generated
+ by creating single element CFStringRefs then extracting the
+ first character. */
+
+ static const unsigned short table[128] = {
+ 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
+ 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
+ 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
+ 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
+ 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
+ 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
+ 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
+ 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
+ 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
+ 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
+ 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
+ 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
+ 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
+ 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
+ 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
+ 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
+ };
+
+ if (c < 128) return c;
+ else return table[c - 128];
+}
+
+static KeySym make_dead_key(KeySym in) {
+ int i;
+
+ for (i = 0; i < sizeof (dead_keys) / sizeof (dead_keys[0]); i++)
+ if (dead_keys[i].normal == in) return dead_keys[i].dead;
+
+ return in;
+}
+
+static Bool QuartzReadSystemKeymap(darwinKeyboardInfo *info) {
+#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
+ KeyboardLayoutRef key_layout;
+ int is_uchr = 1;
+#endif
+ const void *chr_data = NULL;
+ int num_keycodes = NUM_KEYCODES;
+ UInt32 keyboard_type = LMGetKbdType();
+ int i, j;
+ OSStatus err;
+ KeySym *k;
+ CFDataRef currentKeyLayoutDataRef = NULL;
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+ TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource();
+
+ if (currentKeyLayoutRef) {
+ currentKeyLayoutDataRef = (CFDataRef )TISGetInputSourceProperty(currentKeyLayoutRef, kTISPropertyUnicodeKeyLayoutData);
+ if (currentKeyLayoutDataRef)
+ chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef);
+ }
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // KLGetCurrentKeyboardLayout, KLGetKeyboardLayoutProperty
+#endif
+
+#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
+ if (chr_data == NULL) {
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+ ErrorF("X11.app: Error detected in determining keyboard layout. If you are using an Apple-provided keyboard layout, please report this error at http://xquartz.macosforge.org and http://bugreport.apple.com\n");
+ ErrorF("X11.app: Debug Info: keyboard_type=%u, currentKeyLayoutRef=%p, currentKeyLayoutDataRef=%p, chr_data=%p\n",
+ (unsigned)keyboard_type, currentKeyLayoutRef, currentKeyLayoutDataRef, chr_data);
+#endif
+
+ KLGetCurrentKeyboardLayout (&key_layout);
+ KLGetKeyboardLayoutProperty (key_layout, kKLuchrData, &chr_data);
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+ if(chr_data != NULL) {
+ ErrorF("X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n");
+ }
+#endif
+ }
+
+ if (chr_data == NULL) {
+ ErrorF("X11.app: Debug Info: kKLuchrData failed, trying kKLKCHRData.\n");
+ ErrorF("If you are using a 3rd party keyboard layout, please see http://xquartz.macosforge.org/trac/ticket/154\n");
+ KLGetKeyboardLayoutProperty (key_layout, kKLKCHRData, &chr_data);
+ is_uchr = 0;
+ num_keycodes = 128;
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+ if(chr_data != NULL) {
+ ErrorF("X11.app: Fallback succeeded, but this is still a bug. Please report the above information.\n");
+ }
+#endif
+ }
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+ if(currentKeyLayoutRef)
+ CFRelease(currentKeyLayoutRef);
+#endif
+
+ if (chr_data == NULL) {
+ ErrorF ( "Couldn't get uchr or kchr resource\n");
+ return FALSE;
+ }
+
+ /* Scan the keycode range for the Unicode character that each
+ key produces in the four shift states. Then convert that to
+ an X11 keysym (which may just the bit that says "this is
+ Unicode" if it can't find the real symbol.) */
+
+ /* KeyTranslate is not available on 64-bit platforms; UCKeyTranslate
+ must be used instead. */
+
+ for (i = 0; i < num_keycodes; i++) {
+ static const int mods[4] = {0, MOD_SHIFT, MOD_OPTION,
+ MOD_OPTION | MOD_SHIFT};
+
+ k = info->keyMap + i * GLYPHS_PER_KEY;
+
+ for (j = 0; j < 4; j++) {
+#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
+ if (is_uchr) {
+#endif
+ UniChar s[8];
+ UniCharCount len;
+ UInt32 dead_key_state = 0, extra_dead = 0;
+
+ err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
+ mods[j] >> 8, keyboard_type, 0,
+ &dead_key_state, 8, &len, s);
+ if (err != noErr) continue;
+
+ if (len == 0 && dead_key_state != 0) {
+ /* Found a dead key. Work out which one it is, but
+ remembering that it's dead. */
+ err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
+ mods[j] >> 8, keyboard_type,
+ kUCKeyTranslateNoDeadKeysMask,
+ &extra_dead, 8, &len, s);
+ if (err != noErr) continue;
+ }
+
+ /* Not sure why 0x0010 is there.
+ * 0x0000 - <rdar://problem/7793566> 'Unicode Hex Input' ...
+ */
+ if (len > 0 && s[0] != 0x0010 && s[0] != 0x0000) {
+ k[j] = ucs2keysym (s[0]);
+ if (dead_key_state != 0) k[j] = make_dead_key (k[j]);
+ }
+#if !defined(__LP64__) || MAC_OS_X_VERSION_MIN_REQUIRED < 1050
+ } else { // kchr
+ UInt32 c, state = 0, state2 = 0;
+ UInt16 code;
+
+ code = i | mods[j];
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // KeyTranslate
+#endif
+
+ c = KeyTranslate (chr_data, code, &state);
+
+ /* Dead keys are only processed on key-down, so ask
+ to translate those events. When we find a dead key,
+ translating the matching key up event will give
+ us the actual dead character. */
+
+ if (state != 0)
+ c = KeyTranslate (chr_data, code | 128, &state2);
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+ /* Characters seem to be in MacRoman encoding. */
+
+ if (c != 0 && c != 0x0010) {
+ k[j] = ucs2keysym (macroman2ucs (c & 255));
+
+ if (state != 0) k[j] = make_dead_key (k[j]);
+ }
+ }
+#endif
+ }
+
+ if (k[3] == k[2]) k[3] = NoSymbol;
+ if (k[1] == k[0]) k[1] = NoSymbol;
+ if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
+ if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] = NoSymbol;
+ }
+
+#if HACK_MISSING
+ /* Fix up some things that are normally missing.. */
+
+ for (i = 0; i < sizeof (known_keys) / sizeof (known_keys[0]); i++) {
+ k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY;
+
+ if ( k[0] == NoSymbol && k[1] == NoSymbol
+ && k[2] == NoSymbol && k[3] == NoSymbol)
+ k[0] = known_keys[i].keysym;
+ }
+#endif
+
+#if HACK_KEYPAD
+ /* And some more things. We find the right symbols for the numeric
+ keypad, but not the KP_ keysyms. So try to convert known keycodes. */
+ for (i = 0; i < sizeof (known_numeric_keys) / sizeof (known_numeric_keys[0]); i++) {
+ k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY;
+
+ if (k[0] == known_numeric_keys[i].normal)
+ k[0] = known_numeric_keys[i].keypad;
+ }
+#endif
+
+#if HACK_BLACKLIST
+ for (i = 0; i < sizeof (keycode_blacklist) / sizeof (keycode_blacklist[0]); i++) {
+ k = info->keyMap + keycode_blacklist[i] * GLYPHS_PER_KEY;
+ k[0] = k[1] = k[2] = k[3] = NoSymbol;
+ }
+#endif
+
+ DarwinBuildModifierMaps(info);
+
+ return TRUE;
+}
+
+Bool QuartsResyncKeymap(Bool sendDDXEvent) {
+ Bool retval;
+ /* Update keyInfo */
+ pthread_mutex_lock(&keyInfo_mutex);
+ memset(keyInfo.keyMap, 0, sizeof(keyInfo.keyMap));
+ retval = QuartzReadSystemKeymap(&keyInfo);
+ pthread_mutex_unlock(&keyInfo_mutex);
+
+ /* Tell server thread to deal with new keyInfo */
+ if(sendDDXEvent)
+ DarwinSendDDXEvent(kXquartzReloadKeymap, 0);
+
+ return retval;
+}
diff --git a/xorg-server/hw/xquartz/quartzKeyboard.h b/xorg-server/hw/xquartz/quartzKeyboard.h index 1151a0035..bb5e84597 100644 --- a/xorg-server/hw/xquartz/quartzKeyboard.h +++ b/xorg-server/hw/xquartz/quartzKeyboard.h @@ -1,58 +1,56 @@ -/* - * Copyright (c) 2003-2004 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 QUARTZ_KEYBOARD_H -#define QUARTZ_KEYBOARD_H 1 - -#define XK_TECHNICAL // needed to get XK_Escape -#define XK_PUBLISHING -#include "X11/keysym.h" -#include "inputstr.h" - -#include <pthread.h> - -// Each key can generate 4 glyphs. They are, in order: -// unshifted, shifted, modeswitch unshifted, modeswitch shifted -#define GLYPHS_PER_KEY 4 -#define NUM_KEYCODES 248 // NX_NUMKEYCODES might be better -#define MIN_KEYCODE XkbMinLegalKeyCode // unfortunately, this isn't 0... -#define MAX_KEYCODE NUM_KEYCODES + MIN_KEYCODE - 1 - -/* These functions need to be implemented by Xquartz, XDarwin, etc. */ -Bool QuartsResyncKeymap(Bool sendDDXEvent); - -/* Provided for darwinEvents.c */ -void DarwinKeyboardReloadHandler(void); -int DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide); -int DarwinModifierNXKeyToNXKeycode(int key, int side); -int DarwinModifierNXKeyToNXMask(int key); -int DarwinModifierNXMaskToNXKey(int mask); -int DarwinModifierStringToNXMask(const char *string, int separatelr); - -/* Provided for darwin.c */ -void DarwinKeyboardInit(DeviceIntPtr pDev); - -#endif /* QUARTZ_KEYBOARD_H */ +/*
+ * Copyright (c) 2003-2004 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 QUARTZ_KEYBOARD_H
+#define QUARTZ_KEYBOARD_H 1
+
+#define XK_TECHNICAL // needed to get XK_Escape
+#define XK_PUBLISHING
+#include "X11/keysym.h"
+#include "inputstr.h"
+
+// Each key can generate 4 glyphs. They are, in order:
+// unshifted, shifted, modeswitch unshifted, modeswitch shifted
+#define GLYPHS_PER_KEY 4
+#define NUM_KEYCODES 248 // NX_NUMKEYCODES might be better
+#define MIN_KEYCODE XkbMinLegalKeyCode // unfortunately, this isn't 0...
+#define MAX_KEYCODE NUM_KEYCODES + MIN_KEYCODE - 1
+
+/* These functions need to be implemented by Xquartz, XDarwin, etc. */
+Bool QuartsResyncKeymap(Bool sendDDXEvent);
+
+/* Provided for darwinEvents.c */
+void DarwinKeyboardReloadHandler(void);
+int DarwinModifierNXKeycodeToNXKey(unsigned char keycode, int *outSide);
+int DarwinModifierNXKeyToNXKeycode(int key, int side);
+int DarwinModifierNXKeyToNXMask(int key);
+int DarwinModifierNXMaskToNXKey(int mask);
+int DarwinModifierStringToNXMask(const char *string, int separatelr);
+
+/* Provided for darwin.c */
+void DarwinKeyboardInit(DeviceIntPtr pDev);
+
+#endif /* QUARTZ_KEYBOARD_H */
diff --git a/xorg-server/hw/xquartz/quartzStartup.c b/xorg-server/hw/xquartz/quartzStartup.c index 36c8182ae..bc1aa4f68 100644 --- a/xorg-server/hw/xquartz/quartzStartup.c +++ b/xorg-server/hw/xquartz/quartzStartup.c @@ -1,121 +1,118 @@ -/************************************************************** - * - * Startup code for the Quartz Darwin X Server - * - * Copyright (c) 2001-2004 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. - */ - -#include "sanitizedCarbon.h" - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include <fcntl.h> -#include <unistd.h> -#include <CoreFoundation/CoreFoundation.h> -#include "quartzCommon.h" -#include "X11Controller.h" -#include "darwin.h" -#include "darwinEvents.h" -#include "quartz.h" -#include "opaque.h" -#include "micmap.h" - -#include <assert.h> - -#include <pthread.h> - -int dix_main(int argc, char **argv, char **envp); - -struct arg { - int argc; - char **argv; - char **envp; -}; - -static void server_thread (void *arg) { - struct arg args = *((struct arg *)arg); - free(arg); - exit (dix_main(args.argc, args.argv, args.envp)); -} - -static pthread_t create_thread (void *func, void *arg) { - pthread_attr_t attr; - pthread_t tid; - - pthread_attr_init (&attr); - pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); - pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); - pthread_create (&tid, &attr, func, arg); - pthread_attr_destroy (&attr); - - return tid; -} - -void QuartzInitServer(int argc, char **argv, char **envp) { - struct arg *args = (struct arg*)malloc(sizeof(struct arg)); - if(!args) - FatalError("Could not allocate memory.\n"); - - args->argc = argc; - args->argv = argv; - args->envp = envp; - - APPKIT_THREAD_ID = pthread_self(); - SERVER_THREAD_ID = create_thread(server_thread, args); - - if (!SERVER_THREAD_ID) { - FatalError("can't create secondary thread\n"); - } -} - -int server_main(int argc, char **argv, char **envp) { - int i; - int fd[2]; - - /* Unset CFProcessPath, so our children don't inherit this kludge we need - * to load our nib. If an xterm gets this set, then it fails to - * 'open hi.txt' properly. - */ - unsetenv("CFProcessPath"); - - // Make a pipe to pass events - assert( pipe(fd) == 0 ); - darwinEventReadFD = fd[0]; - darwinEventWriteFD = fd[1]; - fcntl(darwinEventReadFD, F_SETFL, O_NONBLOCK); - - for (i = 1; i < argc; i++) { - // Display version info without starting Mac OS X UI if requested - if (!strcmp( argv[i], "-showconfig" ) || !strcmp( argv[i], "-version" )) { - DarwinPrintBanner(); - exit(0); - } - } - - X11ControllerMain(argc, argv, envp); - exit(0); -} +/**************************************************************
+ *
+ * Startup code for the Quartz Darwin X Server
+ *
+ * Copyright (c) 2001-2004 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.
+ */
+
+#include "sanitizedCarbon.h"
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include "quartzCommon.h"
+#include "X11Controller.h"
+#include "darwin.h"
+#include "darwinEvents.h"
+#include "quartz.h"
+#include "opaque.h"
+#include "micmap.h"
+
+#include <assert.h>
+
+#include <pthread.h>
+
+int dix_main(int argc, char **argv, char **envp);
+
+struct arg {
+ int argc;
+ char **argv;
+ char **envp;
+};
+
+static void server_thread (void *arg) {
+ struct arg args = *((struct arg *)arg);
+ free(arg);
+ exit (dix_main(args.argc, args.argv, args.envp));
+}
+
+static pthread_t create_thread (void *func, void *arg) {
+ pthread_attr_t attr;
+ pthread_t tid;
+
+ pthread_attr_init (&attr);
+ pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
+ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create (&tid, &attr, func, arg);
+ pthread_attr_destroy (&attr);
+
+ return tid;
+}
+
+void QuartzInitServer(int argc, char **argv, char **envp) {
+ struct arg *args = (struct arg*)malloc(sizeof(struct arg));
+ if(!args)
+ FatalError("Could not allocate memory.\n");
+
+ args->argc = argc;
+ args->argv = argv;
+ args->envp = envp;
+
+ if (!create_thread(server_thread, args)) {
+ FatalError("can't create secondary thread\n");
+ }
+}
+
+int server_main(int argc, char **argv, char **envp) {
+ int i;
+ int fd[2];
+
+ /* Unset CFProcessPath, so our children don't inherit this kludge we need
+ * to load our nib. If an xterm gets this set, then it fails to
+ * 'open hi.txt' properly.
+ */
+ unsetenv("CFProcessPath");
+
+ // Make a pipe to pass events
+ assert( pipe(fd) == 0 );
+ darwinEventReadFD = fd[0];
+ darwinEventWriteFD = fd[1];
+ fcntl(darwinEventReadFD, F_SETFL, O_NONBLOCK);
+
+ for (i = 1; i < argc; i++) {
+ // Display version info without starting Mac OS X UI if requested
+ if (!strcmp( argv[i], "-showconfig" ) || !strcmp( argv[i], "-version" )) {
+ DarwinPrintBanner();
+ exit(0);
+ }
+ }
+
+ X11ControllerMain(argc, argv, envp);
+ exit(0);
+}
diff --git a/xorg-server/hw/xquartz/threadSafety.c b/xorg-server/hw/xquartz/threadSafety.c deleted file mode 100644 index 85f85bd0a..000000000 --- a/xorg-server/hw/xquartz/threadSafety.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2008 Apple, Inc. - * - * 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. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif - -#include "threadSafety.h" -#include "os.h" - -pthread_t APPKIT_THREAD_ID; -pthread_t SERVER_THREAD_ID; - -#include <AvailabilityMacros.h> - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 -#include <execinfo.h> - -void spewCallStack(void) { - void* callstack[128]; - int i, frames = backtrace(callstack, 128); - char** strs = backtrace_symbols(callstack, frames); - - for (i = 0; i < frames; ++i) { - ErrorF("%s\n", strs[i]); - } - - free(strs); -} -#else -void spewCallStack(void) { - return; -} -#endif - -void _threadSafetyAssert(pthread_t tid, const char *file, const char *fun, int line) { - if(pthread_equal(pthread_self(), tid)) - return; - - /* NOOOO! */ - ErrorF("Thread Assertion Failed: self=%s, expected=%s\n%s:%s:%d\n", - threadSafetyID(pthread_self()), threadSafetyID(tid), - file, fun, line); - spewCallStack(); -} - -const char *threadSafetyID(pthread_t tid) { - if(pthread_equal(tid, APPKIT_THREAD_ID)) { - return "Appkit Thread"; - } else if(pthread_equal(tid, SERVER_THREAD_ID)) { - return "Xserver Thread"; - } else { - return "Unknown Thread"; - } -} diff --git a/xorg-server/hw/xquartz/threadSafety.h b/xorg-server/hw/xquartz/threadSafety.h deleted file mode 100644 index 48602567b..000000000 --- a/xorg-server/hw/xquartz/threadSafety.h +++ /dev/null @@ -1,56 +0,0 @@ -/*
- * Copyright (C) 2008 Apple, Inc.
- *
- * 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 _XQ_THREAD_SAFETY_H_
-#define _XQ_THREAD_SAFETY_H_
-
-#define DEBUG_THREADS 1
-
-#include <pthread.h>
-
-extern pthread_t APPKIT_THREAD_ID;
-extern pthread_t SERVER_THREAD_ID;
-
-/* Dump the call stack */
-void spewCallStack(void);
-
-/* Print message to ErrorF if we're in the wrong thread */
-void _threadSafetyAssert(pthread_t tid, const char *file, const char *fun, int line);
-
-/* Get a string that identifies our thread nicely */
-const char *threadSafetyID(pthread_t tid);
-
-#define threadSafetyAssert(tid) _threadSafetyAssert(tid, __FILE__, __FUNCTION__, __LINE__)
-
-#ifdef DEBUG_THREADS
-#define TA_APPKIT() threadSafetyAssert(APPKIT_THREAD_ID)
-#define TA_SERVER() threadSafetyAssert(SERVER_THREAD_ID)
-#else
-#define TA_SERVER()
-#define TA_APPKIT()
-#endif
-
-#endif /* _XQ_THREAD_SAFETY_H_ */
diff --git a/xorg-server/hw/xquartz/xpr/dri.c b/xorg-server/hw/xquartz/xpr/dri.c index 7b730df8e..cdfe13622 100644 --- a/xorg-server/hw/xquartz/xpr/dri.c +++ b/xorg-server/hw/xquartz/xpr/dri.c @@ -562,7 +562,6 @@ DRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg) (*pScreen->WindowExposures)(pWin, prgn, bsreg);
- pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures;
pScreen->WindowExposures = DRIWindowExposures;
}
@@ -587,7 +586,6 @@ DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
/* rewrap */
- pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow;
pScreen->CopyWindow = DRICopyWindow;
}
@@ -605,7 +603,6 @@ DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind);
/* rewrap */
- pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree;
pScreen->ValidateTree = DRIValidateTree;
return returnValue;
@@ -632,7 +629,6 @@ DRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) (*pScreen->PostValidateTree)(pParent, pChild, kind);
/* rewrap */
- pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree;
pScreen->PostValidateTree = DRIPostValidateTree;
}
}
@@ -653,7 +649,6 @@ DRIClipNotify(WindowPtr pWin, int dx, int dy) (*pScreen->ClipNotify)(pWin, dx, dy);
- pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify;
pScreen->ClipNotify = DRIClipNotify;
}
}
diff --git a/xorg-server/hw/xquartz/xpr/xpr.h b/xorg-server/hw/xquartz/xpr/xpr.h index af1a90ca0..ea06b7eeb 100644 --- a/xorg-server/hw/xquartz/xpr/xpr.h +++ b/xorg-server/hw/xquartz/xpr/xpr.h @@ -1,64 +1,64 @@ -/* - * Xplugin rootless implementation - * - * Copyright (c) 2003 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 XPR_H -#define XPR_H - -#include "windowstr.h" -#include "screenint.h" -#include <Xplugin.h> - -Bool QuartzModeBundleInit(void); - -void AppleDRIExtensionInit(void); -void xprAppleWMInit(void); -Bool xprInit(ScreenPtr pScreen); -Bool xprIsX11Window(void *nsWindow, int windowNumber); -WindowPtr xprGetXWindow(xp_window_id wid); - -void xprHideWindows(Bool hide); - -Bool QuartzInitCursor(ScreenPtr pScreen); -void QuartzSuspendXCursor(ScreenPtr pScreen); -void QuartzResumeXCursor(ScreenPtr pScreen); - -/* If we are rooted, we need the root window and desktop levels to be below - * the menubar (24) but above native windows. Normal window level is 0. - * Floating window level is 3. The rest are filled in as appropriate. - * See CGWindowLevel.h - */ - -#include <X11/extensions/applewmconst.h> -static const int normal_window_levels[AppleWMNumWindowLevels+1] = { -0, 3, 4, 5, INT_MIN + 30, INT_MIN + 29, -}; -static const int rooted_window_levels[AppleWMNumWindowLevels+1] = { -20, 21, 22, 23, 19, 18, -}; - -#endif /* XPR_H */ +/*
+ * Xplugin rootless implementation
+ *
+ * Copyright (c) 2003 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 XPR_H
+#define XPR_H
+
+#include "windowstr.h"
+#include "screenint.h"
+#include <Xplugin.h>
+
+Bool QuartzModeBundleInit(void);
+
+void AppleDRIExtensionInit(void);
+void xprAppleWMInit(void);
+Bool xprInit(ScreenPtr pScreen);
+Bool xprIsX11Window(int windowNumber);
+WindowPtr xprGetXWindow(xp_window_id wid);
+
+void xprHideWindows(Bool hide);
+
+Bool QuartzInitCursor(ScreenPtr pScreen);
+void QuartzSuspendXCursor(ScreenPtr pScreen);
+void QuartzResumeXCursor(ScreenPtr pScreen);
+
+/* If we are rooted, we need the root window and desktop levels to be below
+ * the menubar (24) but above native windows. Normal window level is 0.
+ * Floating window level is 3. The rest are filled in as appropriate.
+ * See CGWindowLevel.h
+ */
+
+#include <X11/extensions/applewmconst.h>
+static const int normal_window_levels[AppleWMNumWindowLevels+1] = {
+0, 3, 4, 5, INT_MIN + 30, INT_MIN + 29,
+};
+static const int rooted_window_levels[AppleWMNumWindowLevels+1] = {
+20, 21, 22, 23, 19, 18,
+};
+
+#endif /* XPR_H */
diff --git a/xorg-server/hw/xquartz/xpr/xprAppleWM.c b/xorg-server/hw/xquartz/xpr/xprAppleWM.c index 1e99a07dc..6f501e201 100644 --- a/xorg-server/hw/xquartz/xpr/xprAppleWM.c +++ b/xorg-server/hw/xquartz/xpr/xprAppleWM.c @@ -114,8 +114,8 @@ static int xprAttachTransient(WindowPtr pWinChild, WindowPtr pWinParent) { static int xprFrameDraw(
WindowPtr pWin,
- int class,
- unsigned int attr,
+ xp_frame_class class,
+ xp_frame_attr attr,
const BoxRec *outer,
const BoxRec *inner,
unsigned int title_len,
diff --git a/xorg-server/hw/xquartz/xpr/xprEvent.c b/xorg-server/hw/xquartz/xpr/xprEvent.c index 38952b091..0ea6540f0 100644 --- a/xorg-server/hw/xquartz/xpr/xprEvent.c +++ b/xorg-server/hw/xquartz/xpr/xprEvent.c @@ -57,8 +57,6 @@ #include "xprEvent.h"
Bool QuartzModeEventHandler(int screenNum, XQuartzEvent *e, DeviceIntPtr dev) {
- TA_SERVER();
-
switch(e->subtype) {
case kXquartzWindowState:
DEBUG_LOG("kXquartzWindowState\n");
diff --git a/xorg-server/hw/xquartz/xpr/xprFrame.c b/xorg-server/hw/xquartz/xpr/xprFrame.c index cddec5ce2..e88019c2d 100644 --- a/xorg-server/hw/xquartz/xpr/xprFrame.c +++ b/xorg-server/hw/xquartz/xpr/xprFrame.c @@ -1,7 +1,7 @@ /*
* Xplugin rootless implementation frame functions
*
- * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2011 Apple Computer, Inc. All rights reserved.
* Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -35,7 +35,6 @@ #include "rootlessCommon.h"
#include <Xplugin.h>
#include "x-hash.h"
-#include "x-list.h"
#include "applewmExt.h"
#include "propertyst.h"
@@ -44,9 +43,11 @@ #include "windowstr.h"
#include "quartz.h"
-#include "threadSafety.h"
-
+#ifdef HAVE_LIBDISPATCH
+#include <dispatch/dispatch.h>
+#else
#include <pthread.h>
+#endif
#define DEFINE_ATOM_HELPER(func,atom_name) \
static Atom func (void) { \
@@ -63,7 +64,13 @@ DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID") /* Maps xp_window_id -> RootlessWindowRec */
static x_hash_table *window_hash;
+
+/* Need to guard window_hash since xprIsX11Window can be called from any thread. */
+#ifdef HAVE_LIBDISPATCH
+static dispatch_queue_t window_hash_serial_q;
+#else
static pthread_mutex_t window_hash_mutex;
+#endif
/* Prototypes for static functions */
static Bool xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
@@ -93,8 +100,6 @@ static inline xp_error xprConfigureWindow(xp_window_id id, unsigned int mask,
const xp_window_changes *values)
{
- TA_SERVER();
-
return xp_configure_window(id, mask, values);
}
@@ -106,8 +111,6 @@ xprSetNativeProperty(RootlessWindowPtr pFrame) unsigned int native_id;
long data;
- TA_SERVER();
-
err = xp_get_native_window(x_cvt_vptr_to_uint(pFrame->wid), &native_id);
if (err == Success)
{
@@ -137,8 +140,6 @@ xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, unsigned int mask = 0;
xp_error err;
- TA_SERVER();
-
wc.x = newX;
wc.y = newY;
wc.width = pFrame->width;
@@ -186,15 +187,15 @@ xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, return FALSE;
}
- if (window_hash == NULL)
- {
- window_hash = x_hash_table_new(NULL, NULL, NULL, NULL);
- pthread_mutex_init(&window_hash_mutex, NULL);
- }
-
+#ifdef HAVE_LIBDISPATCH
+ dispatch_async(window_hash_serial_q, ^{
+ x_hash_table_insert(window_hash, pFrame->wid, pFrame);
+ });
+#else
pthread_mutex_lock(&window_hash_mutex);
x_hash_table_insert(window_hash, pFrame->wid, pFrame);
pthread_mutex_unlock(&window_hash_mutex);
+#endif
xprSetNativeProperty(pFrame);
@@ -209,11 +210,16 @@ static void xprDestroyFrame(RootlessFrameID wid)
{
xp_error err;
- TA_SERVER();
-
+
+#ifdef HAVE_LIBDISPATCH
+ dispatch_async(window_hash_serial_q, ^{
+ x_hash_table_remove(window_hash, wid);
+ });
+#else
pthread_mutex_lock(&window_hash_mutex);
x_hash_table_remove(window_hash, wid);
pthread_mutex_unlock(&window_hash_mutex);
+#endif
err = xp_destroy_window(x_cvt_vptr_to_uint(wid));
if (err != Success)
@@ -229,8 +235,6 @@ xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY) {
xp_window_changes wc;
- TA_SERVER();
-
wc.x = newX;
wc.y = newY;
// ErrorF("xprMoveFrame(%d, %p, %d, %d)\n", wid, pScreen, newX, newY);
@@ -248,8 +252,6 @@ xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, {
xp_window_changes wc;
- TA_SERVER();
-
wc.x = newX;
wc.y = newY;
wc.width = newW;
@@ -269,9 +271,11 @@ xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) {
xp_window_changes wc;
unsigned int mask = XP_STACKING;
+#ifdef HAVE_LIBDISPATCH
+ __block
+#endif
+ RootlessWindowRec *winRec;
- TA_SERVER();
-
/* Stack frame below nextWid it if it exists, or raise
frame above everything otherwise. */
@@ -283,18 +287,24 @@ static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) { wc.sibling = x_cvt_vptr_to_uint(nextWid);
}
- if(window_hash) {
- RootlessWindowRec *winRec = x_hash_table_lookup(window_hash, wid, NULL);
-
- if(winRec) {
- if(XQuartzIsRootless)
- wc.window_level = normal_window_levels[winRec->level];
- else if(XQuartzShieldingWindowLevel)
- wc.window_level = XQuartzShieldingWindowLevel + 1;
- else
- wc.window_level = rooted_window_levels[winRec->level];
- mask |= XP_WINDOW_LEVEL;
- }
+#ifdef HAVE_LIBDISPATCH
+ dispatch_sync(window_hash_serial_q, ^{
+ winRec = x_hash_table_lookup(window_hash, wid, NULL);
+ });
+#else
+ pthread_mutex_lock(&window_hash_mutex);
+ winRec = x_hash_table_lookup(window_hash, wid, NULL);
+ pthread_mutex_unlock(&window_hash_mutex);
+#endif
+
+ if(winRec) {
+ if(XQuartzIsRootless)
+ wc.window_level = normal_window_levels[winRec->level];
+ else if(XQuartzShieldingWindowLevel)
+ wc.window_level = XQuartzShieldingWindowLevel + 1;
+ else
+ wc.window_level = rooted_window_levels[winRec->level];
+ mask |= XP_WINDOW_LEVEL;
}
xprConfigureWindow(x_cvt_vptr_to_uint(wid), mask, &wc);
@@ -309,8 +319,6 @@ xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape) {
xp_window_changes wc;
- TA_SERVER();
-
if (pShape != NULL)
{
wc.shape_nrects = RegionNumRects(pShape);
@@ -336,8 +344,6 @@ xprUnmapFrame(RootlessFrameID wid) {
xp_window_changes wc;
- TA_SERVER();
-
wc.stack_mode = XP_UNMAPPED;
wc.sibling = 0;
@@ -356,8 +362,6 @@ xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow) unsigned int rowbytes[2];
xp_error err;
- TA_SERVER();
-
err = xp_lock_window(x_cvt_vptr_to_uint(wid), NULL, NULL, data, rowbytes, NULL);
if (err != Success)
FatalError("Could not lock window %i for drawing.", (int)x_cvt_vptr_to_uint(wid));
@@ -374,8 +378,7 @@ static void xprStopDrawing(RootlessFrameID wid, Bool flush)
{
xp_error err;
- TA_SERVER();
-
+
err = xp_unlock_window(x_cvt_vptr_to_uint(wid), flush);
if(err != Success)
FatalError("Could not unlock window %i after drawing.", (int)x_cvt_vptr_to_uint(wid));
@@ -388,8 +391,6 @@ xprStopDrawing(RootlessFrameID wid, Bool flush) static void
xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage)
{
- TA_SERVER();
-
xp_flush_window(x_cvt_vptr_to_uint(wid));
}
@@ -401,8 +402,6 @@ static void xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects,
int shift_x, int shift_y)
{
- TA_SERVER();
-
xp_mark_window(x_cvt_vptr_to_uint(wid), nrects, rects, shift_x, shift_y);
}
@@ -416,8 +415,6 @@ xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin) {
DeleteProperty(serverClient, oldWin, xa_native_window_id());
- TA_SERVER();
-
xprSetNativeProperty(pFrame);
}
@@ -429,8 +426,6 @@ static Bool xprDoReorderWindow(RootlessWindowPtr pFrame) {
WindowPtr pWin = pFrame->win;
- TA_SERVER();
-
return AppleWMDoReorderWindow(pWin);
}
@@ -443,8 +438,6 @@ static void xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects,
int dx, int dy)
{
- TA_SERVER();
-
xp_copy_window(x_cvt_vptr_to_uint(wid), x_cvt_vptr_to_uint(wid),
dstNrects, dstRects, dx, dy);
}
@@ -479,11 +472,16 @@ xprInit(ScreenPtr pScreen) {
RootlessInit(pScreen, &xprRootlessProcs);
- TA_SERVER();
-
rootless_CopyBytes_threshold = xp_copy_bytes_threshold;
rootless_CopyWindow_threshold = xp_scroll_area_threshold;
+ assert((window_hash = x_hash_table_new(NULL, NULL, NULL, NULL)));
+#ifdef HAVE_LIBDISPATCH
+ assert((window_hash_serial_q = dispatch_queue_create(BUNDLE_ID_PREFIX".X11.xpr_window_hash", NULL)));
+#else
+ assert(0 == pthread_mutex_init(&window_hash_mutex, NULL));
+#endif
+
return TRUE;
}
@@ -495,73 +493,36 @@ xprInit(ScreenPtr pScreen) WindowPtr
xprGetXWindow(xp_window_id wid)
{
+#ifdef HAVE_LIBDISPATCH
+ RootlessWindowRec *winRec __block;
+ dispatch_sync(window_hash_serial_q, ^{
+ winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL);
+ });
+#else
RootlessWindowRec *winRec;
-
- if (window_hash == NULL)
- return NULL;
-
- winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL);
-
- return winRec != NULL ? winRec->win : NULL;
-}
-
-#ifdef UNUSED_CODE
-/*
- * Given the id of a physical window, try to find the top-level (or root)
- * X window that it represents.
- */
-WindowPtr
-xprGetXWindowFromAppKit(int windowNumber)
-{
- RootlessWindowRec *winRec;
- Bool ret;
- xp_window_id wid;
-
- if (window_hash == NULL)
- return FALSE;
-
- /* need to lock, since this function can be called by any thread */
-
pthread_mutex_lock(&window_hash_mutex);
-
- if (xp_lookup_native_window(windowNumber, &wid))
- ret = xprGetXWindow(wid) != NULL;
- else
- ret = FALSE;
-
- pthread_mutex_unlock(&window_hash_mutex);
-
- if (!ret) return NULL;
winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL);
+ pthread_mutex_unlock(&window_hash_mutex);
+#endif
return winRec != NULL ? winRec->win : NULL;
}
-#endif
/*
* The windowNumber is an AppKit window number. Returns TRUE if xpr is
* displaying a window with that number.
*/
Bool
-xprIsX11Window(void *nsWindow, int windowNumber)
+xprIsX11Window(int windowNumber)
{
Bool ret;
xp_window_id wid;
- if (window_hash == NULL)
- return FALSE;
-
- /* need to lock, since this function can be called by any thread */
-
- pthread_mutex_lock(&window_hash_mutex);
-
if (xp_lookup_native_window(windowNumber, &wid))
ret = xprGetXWindow(wid) != NULL;
else
ret = FALSE;
- pthread_mutex_unlock(&window_hash_mutex);
-
return ret;
}
@@ -578,8 +539,6 @@ xprHideWindows(Bool hide) int screen;
WindowPtr pRoot, pWin;
- TA_SERVER();
-
for (screen = 0; screen < screenInfo.numScreens; screen++) {
RootlessFrameID prevWid = NULL;
pRoot = screenInfo.screens[screen]->root;
|