1/* 2 XGServerEvent - Window/Event code for X11 backends. 3 4 Copyright (C) 1998-2015 Free Software Foundation, Inc. 5 6 Written by: Adam Fedor <fedor@boulder.colorado.edu> 7 Date: Nov 1998 8 9 This file is part of the GNU Objective C User Interface Library. 10 11 This library is free software; you can redistribute it and/or 12 modify it under the terms of the GNU Lesser General Public 13 License as published by the Free Software Foundation; either 14 version 2 of the License, or (at your option) any later version. 15 16 This library is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 Lesser General Public License for more details. 20 21 You should have received a copy of the GNU Lesser General Public 22 License along with this library; see the file COPYING.LIB. 23 If not, see <http://www.gnu.org/licenses/> or write to the 24 Free Software Foundation, 51 Franklin Street, Fifth Floor, 25*/ 26 27#include "config.h" 28 29#include <AppKit/AppKitExceptions.h> 30#include <AppKit/NSApplication.h> 31#include <AppKit/NSGraphics.h> 32#include <AppKit/NSMenu.h> 33#include <AppKit/NSPasteboard.h> 34#include <AppKit/NSWindow.h> 35#include <AppKit/NSScreen.h> 36#include <Foundation/NSException.h> 37#include <Foundation/NSArray.h> 38#include <Foundation/NSDictionary.h> 39#include <Foundation/NSData.h> 40#include <Foundation/NSNotification.h> 41#include <Foundation/NSValue.h> 42#include <Foundation/NSString.h> 43#include <Foundation/NSUserDefaults.h> 44#include <Foundation/NSRunLoop.h> 45#include <Foundation/NSDebug.h> 46#include <Foundation/NSDistributedNotificationCenter.h> 47 48#include "x11/XGServerWindow.h" 49#include "x11/XGInputServer.h" 50#include "x11/XGDragView.h" 51#include "x11/XGGeneric.h" 52#include "x11/xdnd.h" 53 54#ifdef HAVE_WRASTER_H 55#include "wraster.h" 56#else 57#include "x11/wraster.h" 58#endif 59#ifdef HAVE_XRANDR 60#include <X11/extensions/Xrandr.h> 61#endif 62 63#include "math.h" 64#include <X11/keysym.h> 65#include <X11/Xproto.h> 66 67#if LIB_FOUNDATION_LIBRARY 68# include <Foundation/NSPosixFileDescriptor.h> 69#elif defined(NeXT_PDO) 70# include <Foundation/NSFileHandle.h> 71# include <Foundation/NSNotification.h> 72#endif 73 74#define cWin ((gswindow_device_t*)generic.cachedWindow) 75 76// NumLock's mask (it depends on the keyboard mapping) 77static unsigned int _num_lock_mask; 78// Modifier state 79static char _shift_pressed = 0; 80static char _control_pressed = 0; 81static char _command_pressed = 0; 82static char _alt_pressed = 0; 83static char _help_pressed = 0; 84/* 85Keys used for the modifiers (you may set them with user preferences). 86Note that the first and second key sym for a modifier must be different. 87Otherwise, the _*_pressed tracking will be confused. 88*/ 89static KeySym _control_keysyms[2]; 90static KeySym _command_keysyms[2]; 91static KeySym _alt_keysyms[2]; 92static KeySym _help_keysyms[2]; 93 94static BOOL _is_keyboard_initialized = NO; 95static BOOL _mod_ignore_shift = NO; 96 97/* 98 Mouse properties. In comments below specified defaults key and default value. 99*/ 100static NSInteger clickTime; // "GSDoubleClickTime" - milisecond (250) 101static NSInteger clickMove; // "GSMouseMoveThreshold" - in pixels (3) 102static NSInteger mouseScrollMultiplier; // "GSMouseScrollMultiplier" - times (1) 103static NSEventType menuMouseButton; // "GSMenuButtonEvent" - (NSRightMouseButon) 104static BOOL menuButtonEnabled; // "GSMenuButtonEnabled" - BOOL 105static BOOL swapMouseButtons; // YES if "GSMenuButtonEvent" == NSLeftMouseButton 106 107void __objc_xgcontextevent_linking (void) 108{ 109} 110 111static SEL procSel = 0; 112static void (*procEvent)(id, SEL, XEvent*) = 0; 113 114#ifdef XSHM 115@interface NSGraphicsContext (SharedMemory) 116-(void) gotShmCompletion: (Drawable)d; 117@end 118#endif 119 120@interface XGServer (Private) 121- (void) receivedEvent: (void*)data 122 type: (RunLoopEventType)type 123 extra: (void*)extra 124 forMode: (NSString*)mode; 125- (void) setupRunLoopInputSourcesForMode: (NSString*)mode; 126- (NSDate*) timedOutEvent: (void*)data 127 type: (RunLoopEventType)type 128 forMode: (NSString*)mode; 129- (int) XGErrorHandler: (Display*)display : (XErrorEvent*)err; 130- (void) processEvent: (XEvent *) event; 131- (NSEvent *)_handleTakeFocusAtom: (XEvent)xEvent 132 forContext: (NSGraphicsContext *)gcontext; 133@end 134 135 136int 137XGErrorHandler(Display *display, XErrorEvent *err) 138{ 139 XGServer *ctxt = (XGServer*)GSCurrentServer(); 140 141 return [ctxt XGErrorHandler: display : err]; 142} 143 144static NSEvent*process_key_event (XEvent* xEvent, XGServer* ctxt, 145 NSEventType eventType, 146 NSMutableArray *event_queue, BOOL keyRepeat); 147 148static unichar process_char (KeySym keysym, unsigned *eventModifierFlags); 149 150static unsigned process_modifier_flags(unsigned int state); 151 152static void initialize_keyboard (void); 153 154static void set_up_num_lock (void); 155 156// checks whether a GNUstep modifier (key_sym) is pressed when we're only able 157// to check whether X keycodes are pressed in xEvent->xkeymap; 158static int check_modifier (XEvent *xEvent, KeySym key_sym) 159{ 160 char *key_vector; 161 int by,bi; 162 int key_code = XKeysymToKeycode(xEvent->xkeymap.display, key_sym); 163 164 if (key_code != NoSymbol) 165 { 166 by = key_code / 8; 167 bi = key_code % 8; 168 key_vector = xEvent->xkeymap.key_vector; 169 return (key_vector[by] & (1 << bi)); 170 } 171 return 0; 172} 173 174@interface XGServer (WindowOps) 175- (void) styleoffsets: (float *) l : (float *) r : (float *) t : (float *) b 176 : (unsigned int) style : (Window) win; 177- (NSRect) _XWinRectToOSWinRect: (NSRect)r for: (void*)windowNumber; 178@end 179 180@implementation XGServer (EventOps) 181 182- (int) XGErrorHandler: (Display*)display : (XErrorEvent*)err 183{ 184 int length = 1024; 185 char buffer[length+1]; 186 187 /* 188 * Ignore attempts to set input focus to unmapped window, except for noting 189 * if the most recent request failed (mark the request serial number to 0) 190 * in which case we should repeat the request when the window becomes 191 * mapped again. 192 */ 193 if (err->error_code == BadMatch && err->request_code == X_SetInputFocus) 194 { 195 if (err->serial == generic.focusRequestNumber) 196 { 197 generic.focusRequestNumber = 0; 198 } 199 return 0; 200 } 201 202 XGetErrorText(display, err->error_code, buffer, length); 203 if (err->type == 0 204 && GSDebugSet(@"XSynchronize") == NO) 205 { 206 NSLog(@"X-Windows error - %s\n\ 207 on display: %s\n\ 208 type: %d\n\ 209 serial number: %lu\n\ 210 request code: %d\n", 211 buffer, 212 XDisplayName(DisplayString(display)), 213 err->type, err->serial, err->request_code); 214 return 0; 215 } 216 [NSException raise: NSWindowServerCommunicationException 217 format: @"X-Windows error - %s\n\ 218 on display: %s\n\ 219 type: %d\n\ 220 serial number: %lu\n\ 221 request code: %d\n", 222 buffer, 223 XDisplayName(DisplayString(display)), 224 err->type, err->serial, err->request_code]; 225 return 0; 226} 227 228- (void) setupRunLoopInputSourcesForMode: (NSString*)mode 229{ 230 int xEventQueueFd = XConnectionNumber(dpy); 231 NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; 232 233#if defined(LIB_FOUNDATION_LIBRARY) 234 { 235 id fileDescriptor = [[[NSPosixFileDescriptor alloc] 236 initWithFileDescriptor: xEventQueueFd] 237 autorelease]; 238 239 // Invoke limitDateForMode: to setup the current 240 // mode of the run loop (the doc says that this 241 // method and acceptInputForMode: beforeDate: are 242 // the only ones that setup the current mode). 243 244 [currentRunLoop limitDateForMode: mode]; 245 246 [fileDescriptor setDelegate: self]; 247 [fileDescriptor monitorFileActivity: NSPosixReadableActivity]; 248 } 249#elif defined(NeXT_PDO) 250 { 251 id fileDescriptor = [[[NSFileHandle alloc] 252 initWithFileDescriptor: xEventQueueFd] 253 autorelease]; 254 255 [[NSNotificationCenter defaultCenter] addObserver: self 256 selector: @selector(activityOnFileHandle:) 257 name: NSFileHandleDataAvailableNotification 258 object: fileDescriptor]; 259 [fileDescriptor waitForDataInBackgroundAndNotifyForModes: 260 [NSArray arrayWithObject: mode]]; 261 } 262#else 263 [currentRunLoop addEvent: (void*)(gsaddr)xEventQueueFd 264 type: ET_RDESC 265 watcher: (id<RunLoopEvents>)self 266 forMode: mode]; 267#endif 268 if (procSel == 0) 269 { 270 procSel = @selector(processEvent:); 271 procEvent = (void (*)(id, SEL, XEvent*)) 272 [self methodForSelector: procSel]; 273 } 274} 275 276#if LIB_FOUNDATION_LIBRARY 277- (void) activity: (NSPosixFileActivities)activity 278posixFileDescriptor: (NSPosixFileDescriptor*)fileDescriptor 279{ 280 [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; 281} 282#elif defined(NeXT_PDO) 283- (void) activityOnFileHandle: (NSNotification*)notification 284{ 285 id fileDescriptor = [notification object]; 286 id runLoopMode = [[NSRunLoop currentRunLoop] currentMode]; 287 288 [fileDescriptor waitForDataInBackgroundAndNotifyForModes: 289 [NSArray arrayWithObject: runLoopMode]]; 290 [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; 291} 292#endif 293 294- (BOOL) runLoopShouldBlock: (BOOL*)trigger 295{ 296 *trigger = YES; // Should trigger this event 297 if (XPending(dpy) > 0) 298 { 299 return NO; // Don't block 300 } 301 return YES; 302} 303 304- (void) receivedEvent: (void*)data 305 type: (RunLoopEventType)type 306 extra: (void*)extra 307 forMode: (NSString*)mode 308{ 309 XEvent xEvent; 310 311 // loop and grab all of the events from the X queue 312 while (XPending(dpy) > 0) 313 { 314 XNextEvent(dpy, &xEvent); 315 316#ifdef USE_XIM 317 if (XFilterEvent(&xEvent, None)) 318 { 319 NSDebugLLog(@"NSKeyEvent", @"Event filtered (by XIM?)\n"); 320 continue; 321 } 322#endif 323 324 (*procEvent)(self, procSel, &xEvent); 325 } 326} 327 328/* 329 */ 330- (NSPoint) _XPointToOSPoint: (NSPoint)x for: (void*)window 331{ 332 gswindow_device_t *win = (gswindow_device_t*)window; 333 unsigned int style = win->win_attrs.window_style; 334 NSPoint o; 335 float t, b, l, r; 336 337 [self styleoffsets: &l : &r : &t : &b : style : win->ident]; 338 o.x = x.x + l; 339 o.y = NSHeight(win->xframe) - x.y + b; 340 341 NSDebugLLog(@"Frame", @"X2OP %lu, %x, %@, %@", win->number, style, 342 NSStringFromPoint(x), NSStringFromPoint(o)); 343 return o; 344} 345 346- (void) mouseOptionsChanged: (NSNotification *)aNotif 347{ 348 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 349 350 clickTime = [defs integerForKey:@"GSDoubleClickTime"]; 351 if (clickTime < 200) 352 clickTime = 300; 353 354 clickMove = [defs integerForKey:@"GSMouseMoveThreshold"]; 355 if (clickMove < 3) 356 clickMove = 3; 357 358 mouseScrollMultiplier = [defs integerForKey:@"GSMouseScrollMultiplier"]; 359 if (mouseScrollMultiplier == 0) 360 mouseScrollMultiplier = 1; 361 362 if ([defs objectForKey:@"GSMenuButtonEnabled"]) 363 menuButtonEnabled = [defs boolForKey:@"GSMenuButtonEnabled"]; 364 else 365 menuButtonEnabled = YES; 366 367 if ([defs objectForKey:@"GSMenuButtonEvent"]) 368 menuMouseButton = [defs integerForKey:@"GSMenuButtonEvent"]; 369 else 370 menuMouseButton = NSRightMouseDown; 371 372 switch (menuMouseButton) 373 { 374 case NSLeftMouseDown: 375 swapMouseButtons = YES; 376 break; 377 default: 378 swapMouseButtons = NO; 379 break; 380 } 381} 382 383- (void) initializeMouse 384{ 385 [self mouseOptionsChanged: nil]; 386 [[NSDistributedNotificationCenter defaultCenter] 387 addObserver: self 388 selector: @selector(mouseOptionsChanged:) 389 name: NSUserDefaultsDidChangeNotification 390 object: nil]; 391} 392 393- (void) processEvent: (XEvent *) event 394{ 395 static int clickCount = 1; 396 static unsigned int eventFlags; 397 static NSPoint eventLocation; 398 NSEvent *e = nil; 399 XEvent xEvent; 400 NSWindow *nswin; 401 Window xWin; 402 NSEventType eventType; 403 NSGraphicsContext *gcontext; 404 float deltaX; 405 float deltaY; 406 int buttonNumber; 407 408 gcontext = GSCurrentContext(); 409 xEvent = *event; 410 411 switch (xEvent.type) 412 { 413 // mouse button events 414 case ButtonPress: 415 NSDebugLLog(@"NSEvent", @"%lu ButtonPress: \ 416 xEvent.xbutton.time %lu timeOfLastClick %lu \n", 417 xEvent.xbutton.window, xEvent.xbutton.time, 418 generic.lastClick); 419 /* 420 * hardwired test for a double click 421 * 422 * For multiple clicks, the clicks must remain in the same 423 * region of the same window and must occur in a limited time. 424 * 425 * default time of 300 should be user set; 426 * perhaps the movement of 3 should also be a preference? 427 */ 428 { 429 BOOL incrementCount = YES; 430 431 if (clickTime == 0) [self initializeMouse]; 432 433 if (xEvent.xbutton.time 434 >= (unsigned long)(generic.lastClick + clickTime)) 435 incrementCount = NO; 436 else if (generic.lastClickWindow != xEvent.xbutton.window) 437 incrementCount = NO; 438 else if ((generic.lastClickX - xEvent.xbutton.x) > clickMove) 439 incrementCount = NO; 440 else if ((generic.lastClickX - xEvent.xbutton.x) < -clickMove) 441 incrementCount = NO; 442 else if ((generic.lastClickY - xEvent.xbutton.y) > clickMove) 443 incrementCount = NO; 444 else if ((generic.lastClickY - xEvent.xbutton.y) < -clickMove) 445 incrementCount = NO; 446 447 if (incrementCount == YES) 448 { 449 clickCount++; 450 } 451 else 452 { 453 /* 454 * Not a multiple-click, so we must set the stored 455 * location of the click to the new values and 456 * reset the counter. 457 */ 458 clickCount = 1; 459 generic.lastClickWindow = xEvent.xbutton.window; 460 generic.lastClickX = xEvent.xbutton.x; 461 generic.lastClickY = xEvent.xbutton.y; 462 } 463 } 464 generic.lastClick = xEvent.xbutton.time; 465 [self setLastTime: generic.lastClick]; 466 deltaX = 0.0; 467 deltaY = 0.0; 468 469 if (xEvent.xbutton.button == generic.lMouse) 470 { 471 if (swapMouseButtons) 472 { 473 eventType = NSRightMouseDown; 474 buttonNumber = generic.rMouse; 475 } 476 else 477 { 478 eventType = NSLeftMouseDown; 479 buttonNumber = generic.lMouse; 480 } 481 } 482 else if (xEvent.xbutton.button == generic.rMouse 483 && generic.rMouse != 0) 484 { 485 if (swapMouseButtons) 486 { 487 eventType = NSLeftMouseDown; 488 buttonNumber = generic.lMouse; 489 } 490 else 491 { 492 eventType = NSRightMouseDown; 493 buttonNumber = generic.rMouse; 494 } 495 } 496 else if (xEvent.xbutton.button == generic.mMouse 497 && generic.mMouse != 0) 498 { 499 eventType = NSOtherMouseDown; 500 buttonNumber = generic.mMouse; 501 } 502 else if (xEvent.xbutton.button == generic.upMouse 503 && generic.upMouse != 0) 504 { 505 deltaY = 1. * mouseScrollMultiplier; 506 eventType = NSScrollWheel; 507 buttonNumber = generic.upMouse; 508 } 509 else if (xEvent.xbutton.button == generic.downMouse 510 && generic.downMouse != 0) 511 { 512 deltaY = -1. * mouseScrollMultiplier; 513 eventType = NSScrollWheel; 514 buttonNumber = generic.downMouse; 515 } 516 else if (xEvent.xbutton.button == generic.scrollLeftMouse 517 && generic.scrollLeftMouse != 0) 518 { 519 deltaX = -1. * mouseScrollMultiplier; 520 eventType = NSScrollWheel; 521 buttonNumber = generic.scrollLeftMouse; 522 } 523 else if (xEvent.xbutton.button == generic.scrollRightMouse 524 && generic.scrollRightMouse != 0) 525 { 526 deltaX = 1. * mouseScrollMultiplier; 527 eventType = NSScrollWheel; 528 buttonNumber = generic.scrollRightMouse; 529 } 530 else 531 { 532 break; /* Unknown button */ 533 } 534 535 if (menuButtonEnabled == NO && eventType == menuMouseButton) 536 break; // disabled menu button was pressed 537 538 eventFlags = process_modifier_flags(xEvent.xbutton.state); 539 // if pointer is grabbed use grab window 540 xWin = (grabWindow == 0) ? xEvent.xbutton.window : grabWindow; 541 if (cWin == 0 || xWin != cWin->ident) 542 generic.cachedWindow = [XGServer _windowForXWindow: xWin]; 543 if (cWin == 0) 544 break; 545 eventLocation.x = xEvent.xbutton.x; 546 eventLocation.y = xEvent.xbutton.y; 547 eventLocation = [self _XPointToOSPoint: eventLocation 548 for: cWin]; 549 550 if (generic.flags.useWindowMakerIcons == 1) 551 { 552 /* 553 * We must hand over control of our icon/miniwindow 554 * to Window Maker. 555 */ 556 if ((cWin->win_attrs.window_style 557 & (NSMiniWindowMask | NSIconWindowMask)) != 0 558 && eventType == NSLeftMouseDown) 559 { 560 if (cWin->parent == None) 561 break; 562 xEvent.xbutton.window = cWin->parent; 563 XUngrabPointer(dpy, CurrentTime); 564 XSendEvent(dpy, cWin->parent, True, 565 ButtonPressMask, &xEvent); 566 XFlush(dpy); 567 if (clickCount == 1) 568 break; 569 } 570 } 571 572 // create NSEvent 573 e = [NSEvent mouseEventWithType: eventType 574 location: eventLocation 575 modifierFlags: eventFlags 576 timestamp: (NSTimeInterval)generic.lastClick / 1000.0 577 windowNumber: cWin->number 578 context: gcontext 579 eventNumber: xEvent.xbutton.serial 580 clickCount: clickCount 581 pressure: 1.0 582 buttonNumber: buttonNumber /* FIXME */ 583 deltaX: deltaX 584 deltaY: deltaY 585 deltaZ: 0.]; 586 break; 587 588 case ButtonRelease: 589 NSDebugLLog(@"NSEvent", @"%lu ButtonRelease\n", 590 xEvent.xbutton.window); 591 [self setLastTime: xEvent.xbutton.time]; 592 if (xEvent.xbutton.button == generic.lMouse) 593 { 594 if (swapMouseButtons) 595 { 596 eventType = NSRightMouseUp; 597 buttonNumber = generic.rMouse; 598 } 599 else 600 { 601 eventType = NSLeftMouseUp; 602 buttonNumber = generic.lMouse; 603 } 604 } 605 else if (xEvent.xbutton.button == generic.rMouse 606 && generic.rMouse != 0) 607 { 608 if (swapMouseButtons) 609 { 610 eventType = NSLeftMouseUp; 611 buttonNumber = generic.lMouse; 612 } 613 else 614 { 615 eventType = NSRightMouseUp; 616 buttonNumber = generic.rMouse; 617 } 618 } 619 else if (xEvent.xbutton.button == generic.mMouse 620 && generic.mMouse != 0) 621 { 622 eventType = NSOtherMouseUp; 623 buttonNumber = generic.mMouse; 624 } 625 else 626 { 627 // we ignore release of scrollUp or scrollDown 628 break; /* Unknown button */ 629 } 630 631 if (menuButtonEnabled == NO && eventType == menuMouseButton) 632 break; // disabled menu button was released 633 634 eventFlags = process_modifier_flags(xEvent.xbutton.state); 635 // if pointer is grabbed use grab window 636 xWin = (grabWindow == 0) ? xEvent.xbutton.window : grabWindow; 637 if (cWin == 0 || xWin != cWin->ident) 638 generic.cachedWindow = [XGServer _windowForXWindow: xWin]; 639 if (cWin == 0) 640 break; 641 eventLocation.x = xEvent.xbutton.x; 642 eventLocation.y = xEvent.xbutton.y; 643 eventLocation = [self _XPointToOSPoint: eventLocation 644 for: cWin]; 645 646 e = [NSEvent mouseEventWithType: eventType 647 location: eventLocation 648 modifierFlags: eventFlags 649 timestamp: (NSTimeInterval)generic.lastTime / 1000.0 650 windowNumber: cWin->number 651 context: gcontext 652 eventNumber: xEvent.xbutton.serial 653 clickCount: clickCount 654 pressure: 1.0 655 buttonNumber: buttonNumber /* FIXMME */ 656 deltaX: 0.0 657 deltaY: 0.0 658 deltaZ: 0.0]; 659 break; 660 661 case CirculateNotify: 662 NSDebugLLog(@"NSEvent", @"%lu CirculateNotify\n", 663 xEvent.xcirculate.window); 664 break; 665 666 case CirculateRequest: 667 NSDebugLLog(@"NSEvent", @"%lu CirculateRequest\n", 668 xEvent.xcirculaterequest.window); 669 break; 670 671 case ClientMessage: 672 { 673 NSTimeInterval time; 674 DndClass dnd = xdnd (); 675 676 NSDebugLLog(@"NSEvent", @"%lu ClientMessage - %s\n", 677 xEvent.xclient.window, 678 XGetAtomName(dpy, xEvent.xclient.message_type)); 679 if (cWin == 0 || xEvent.xclient.window != cWin->ident) 680 { 681 generic.cachedWindow 682 = [XGServer _windowForXWindow: xEvent.xclient.window]; 683 } 684 if (cWin == 0) 685 break; 686 if (xEvent.xclient.message_type == generic.WM_PROTOCOLS_ATOM) 687 { 688 [self setLastTime: (Time)xEvent.xclient.data.l[1]]; 689 NSDebugLLog(@"NSEvent", @"WM Protocol - %s\n", 690 XGetAtomName(dpy, xEvent.xclient.data.l[0])); 691 692 if ((Atom)xEvent.xclient.data.l[0] == generic.WM_DELETE_WINDOW_ATOM) 693 { 694 /* 695 * WM is asking us to close a window 696 */ 697 eventLocation = NSMakePoint(0,0); 698 e = [NSEvent otherEventWithType: NSAppKitDefined 699 location: eventLocation 700 modifierFlags: 0 701 timestamp: 0 702 windowNumber: cWin->number 703 context: gcontext 704 subtype: GSAppKitWindowClose 705 data1: 0 706 data2: 0]; 707 } 708 else if ((Atom)xEvent.xclient.data.l[0] 709 == generic._GNUSTEP_WM_MINIATURIZE_WINDOW_ATOM) 710 { 711 NSDebugLLog(@"Miniaturize", @"%lu miniaturized", cWin->number); 712 eventLocation = NSMakePoint(0,0); 713 e = [NSEvent otherEventWithType: NSAppKitDefined 714 location: eventLocation 715 modifierFlags: 0 716 timestamp: 0 717 windowNumber: cWin->number 718 context: gcontext 719 subtype: GSAppKitWindowMiniaturize 720 data1: 0 721 data2: 0]; 722 } 723 else if ((Atom)xEvent.xclient.data.l[0] 724 == generic._GNUSTEP_WM_HIDE_APP_ATOM) 725 { 726 NSDebugLLog(@"Hide", @"%lu application will be hidden", cWin->number); 727 eventLocation = NSMakePoint(0,0); 728 e = [NSEvent otherEventWithType: NSAppKitDefined 729 location: eventLocation 730 modifierFlags: 0 731 timestamp: 0 732 windowNumber: cWin->number 733 context: gcontext 734 subtype: GSAppKitAppHide 735 data1: 0 736 data2: 0]; 737 } 738 else if ((Atom)xEvent.xclient.data.l[0] 739 == generic.WM_TAKE_FOCUS_ATOM) 740 { 741 e = [self _handleTakeFocusAtom: xEvent 742 forContext: gcontext]; 743 } 744 else if ((Atom)xEvent.xclient.data.l[0] 745 == generic._NET_WM_PING_ATOM) 746 { 747 xEvent.xclient.window = RootWindow(dpy, cWin->screen_id); 748 XSendEvent(dpy, xEvent.xclient.window, False, 749 (SubstructureRedirectMask | SubstructureNotifyMask), 750 &xEvent); 751 } 752#ifdef HAVE_X11_EXTENSIONS_SYNC_H 753 else if ((Atom)xEvent.xclient.data.l[0] 754 == generic._NET_WM_SYNC_REQUEST_ATOM) 755 { 756 cWin->net_wm_sync_request_counter_value_low = (Atom)xEvent.xclient.data.l[2]; 757 cWin->net_wm_sync_request_counter_value_high = (Atom)xEvent.xclient.data.l[3]; 758 } 759#endif 760 } 761 else if (xEvent.xclient.message_type == dnd.XdndEnter) 762 { 763 Window source; 764 765 NSDebugLLog(@"NSDragging", @" XdndEnter message\n"); 766 source = XDND_ENTER_SOURCE_WIN(&xEvent); 767 eventLocation = NSMakePoint(0,0); 768 e = [NSEvent otherEventWithType: NSAppKitDefined 769 location: eventLocation 770 modifierFlags: 0 771 timestamp: 0 772 windowNumber: cWin->number 773 context: gcontext 774 subtype: GSAppKitDraggingEnter 775 data1: source 776 data2: 0]; 777 /* If this is a non-local drag, set the dragInfo */ 778 if ([XGServer _windowForXWindow: source] == NULL) 779 { 780 [[XGDragView sharedDragView] setupDragInfoFromXEvent: 781 &xEvent]; 782 } 783 } 784 else if (xEvent.xclient.message_type == dnd.XdndPosition) 785 { 786 Window source; 787 Atom action; 788 NSDragOperation operation; 789 int root_x, root_y; 790 Window root_child; 791 792 NSDebugLLog(@"NSDragging", @" XdndPosition message\n"); 793 source = XDND_POSITION_SOURCE_WIN(&xEvent); 794 /* 795 Work around a bug/feature in WindowMaker that does not 796 send ConfigureNotify events for app icons. 797 */ 798 XTranslateCoordinates(dpy, xEvent.xclient.window, 799 RootWindow(dpy, cWin->screen_id), 800 0, 0, 801 &root_x, &root_y, 802 &root_child); 803 cWin->xframe.origin.x = root_x; 804 cWin->xframe.origin.y = root_y; 805 806 eventLocation.x = XDND_POSITION_ROOT_X(&xEvent) - 807 NSMinX(cWin->xframe); 808 eventLocation.y = XDND_POSITION_ROOT_Y(&xEvent) - 809 NSMinY(cWin->xframe); 810 eventLocation = [self _XPointToOSPoint: eventLocation 811 for: cWin]; 812 time = XDND_POSITION_TIME(&xEvent); 813 action = XDND_POSITION_ACTION(&xEvent); 814 operation = GSDragOperationForAction(action); 815 e = [NSEvent otherEventWithType: NSAppKitDefined 816 location: eventLocation 817 modifierFlags: 0 818 timestamp: time / 1000.0 819 windowNumber: cWin->number 820 context: gcontext 821 subtype: GSAppKitDraggingUpdate 822 data1: source 823 data2: operation]; 824 /* If this is a non-local drag, update the dragInfo */ 825 if ([XGServer _windowForXWindow: source] == NULL) 826 { 827 [[XGDragView sharedDragView] updateDragInfoFromEvent: 828 e]; 829 } 830 } 831 else if (xEvent.xclient.message_type == dnd.XdndStatus) 832 { 833 Window target; 834 Atom action; 835 NSDragOperation operation; 836 837 NSDebugLLog(@"NSDragging", @" XdndStatus message\n"); 838 target = XDND_STATUS_TARGET_WIN(&xEvent); 839 eventLocation = NSMakePoint(0, 0); 840 if (XDND_STATUS_WILL_ACCEPT (&xEvent)) 841 { 842 action = XDND_STATUS_ACTION(&xEvent); 843 } 844 else 845 { 846 action = NSDragOperationNone; 847 } 848 849 operation = GSDragOperationForAction(action); 850 e = [NSEvent otherEventWithType: NSAppKitDefined 851 location: eventLocation 852 modifierFlags: 0 853 timestamp: 0 854 windowNumber: cWin->number 855 context: gcontext 856 subtype: GSAppKitDraggingStatus 857 data1: target 858 data2: operation]; 859 } 860 else if (xEvent.xclient.message_type == dnd.XdndLeave) 861 { 862 Window source; 863 864 NSDebugLLog(@"NSDragging", @" XdndLeave message\n"); 865 source = XDND_LEAVE_SOURCE_WIN(&xEvent); 866 eventLocation = NSMakePoint(0, 0); 867 e = [NSEvent otherEventWithType: NSAppKitDefined 868 location: eventLocation 869 modifierFlags: 0 870 timestamp: 0 871 windowNumber: cWin->number 872 context: gcontext 873 subtype: GSAppKitDraggingExit 874 data1: 0 875 data2: 0]; 876 /* If this is a non-local drag, reset the dragInfo */ 877 if ([XGServer _windowForXWindow: source] == NULL) 878 { 879 [[XGDragView sharedDragView] resetDragInfo]; 880 } 881 } 882 else if (xEvent.xclient.message_type == dnd.XdndDrop) 883 { 884 Window source; 885 886 NSDebugLLog(@"NSDragging", @" XdndDrop message\n"); 887 source = XDND_DROP_SOURCE_WIN(&xEvent); 888 eventLocation = NSMakePoint(0, 0); 889 time = XDND_DROP_TIME(&xEvent); 890 e = [NSEvent otherEventWithType: NSAppKitDefined 891 location: eventLocation 892 modifierFlags: 0 893 timestamp: time / 1000.0 894 windowNumber: cWin->number 895 context: gcontext 896 subtype: GSAppKitDraggingDrop 897 data1: source 898 data2: 0]; 899 } 900 else if (xEvent.xclient.message_type == dnd.XdndFinished) 901 { 902 Window target; 903 904 NSDebugLLog(@"NSDragging", @" XdndFinished message\n"); 905 target = XDND_FINISHED_TARGET_WIN(&xEvent); 906 eventLocation = NSMakePoint(0, 0); 907 e = [NSEvent otherEventWithType: NSAppKitDefined 908 location: eventLocation 909 modifierFlags: 0 910 timestamp: 0 911 windowNumber: cWin->number 912 context: gcontext 913 subtype: GSAppKitDraggingFinished 914 data1: target 915 data2: 0]; 916 } 917 } 918 break; 919 920 case ColormapNotify: 921 // colormap attribute 922 NSDebugLLog(@"NSEvent", @"%lu ColormapNotify\n", 923 xEvent.xcolormap.window); 924 break; 925 926 // the window has been resized, change the width and height 927 // and update the window so the changes get displayed 928 case ConfigureNotify: 929 NSDebugLLog(@"NSEvent", @"%lu ConfigureNotify " 930 @"x:%d y:%d w:%d h:%d b:%d %c", xEvent.xconfigure.window, 931 xEvent.xconfigure.x, xEvent.xconfigure.y, 932 xEvent.xconfigure.width, xEvent.xconfigure.height, 933 xEvent.xconfigure.border_width, 934 xEvent.xconfigure.send_event ? 'T' : 'F'); 935 if (cWin == 0 || xEvent.xconfigure.window != cWin->ident) 936 { 937 generic.cachedWindow 938 = [XGServer _windowForXWindow:xEvent.xconfigure.window]; 939 } 940 941 if (cWin != 0) 942 { 943 NSRect r, x, n, h; 944 NSTimeInterval ts = (NSTimeInterval)generic.lastMotion; 945 946 r = cWin->xframe; 947 948 x = NSMakeRect(xEvent.xconfigure.x, 949 xEvent.xconfigure.y, 950 xEvent.xconfigure.width, 951 xEvent.xconfigure.height); 952 953 /* 954 According to the ICCCM, coordinates in synthetic events 955 (ie. non-zero send_event) are in root space, while coordinates 956 in real events are in the parent window's space. The parent 957 window might be some window manager window, so we can't 958 directly use those coordinates. 959 960 Thus, if the event is real, we use XTranslateCoordinates to 961 get the root space coordinates. 962 */ 963 if (xEvent.xconfigure.send_event == 0) 964 { 965 int root_x, root_y; 966 Window root_child; 967 XTranslateCoordinates(dpy, xEvent.xconfigure.window, 968 RootWindow(dpy, cWin->screen_id), 969 0, 0, 970 &root_x, &root_y, 971 &root_child); 972 x.origin.x = root_x; 973 x.origin.y = root_y; 974 } 975 976 cWin->xframe = x; 977 n = [self _XFrameToOSFrame: x for: cWin]; 978 NSDebugLLog(@"Moving", 979 @"Update win %lu:\n original:%@\n new:%@", 980 cWin->number, NSStringFromRect(r), 981 NSStringFromRect(x)); 982 /* 983 * Set size hints info to be up to date with new size. 984 */ 985 h = [self _XFrameToXHints: x for: cWin]; 986 cWin->siz_hints.width = h.size.width; 987 cWin->siz_hints.height = h.size.height; 988 989 /* 990 We only update the position hints if we're on the screen. 991 Otherwise, the window manager might not have added decorations 992 (if any) to the window yet. Since we compensate for decorations 993 when we set the position, this will confuse us and we'll end 994 up compensating twice, which makes windows drift. 995 */ 996 if (cWin->map_state == IsViewable) 997 { 998 cWin->siz_hints.x = h.origin.x; 999 cWin->siz_hints.y = h.origin.y; 1000 } 1001 1002 /* 1003 * create GNUstep event(s) 1004 */ 1005 if (!NSEqualSizes(r.size, x.size)) 1006 { 1007 NSEvent *r; 1008 1009 /* Resize events move the origin. There's no good 1010 place to pass this info back, so we put it in 1011 the event location field */ 1012 r = [NSEvent otherEventWithType: NSAppKitDefined 1013 location: n.origin 1014 modifierFlags: eventFlags 1015 timestamp: ts / 1000.0 1016 windowNumber: cWin->number 1017 context: gcontext 1018 subtype: GSAppKitWindowResized 1019 data1: n.size.width 1020 data2: n.size.height]; 1021 1022 /* We don't add this event in event_queue, to don't delay 1023 * its sent. Instead, send it directly to the window. If not, 1024 * the programa can move/resize the window while we send 1025 * this event, causing a confusion. 1026 */ 1027 [[NSApp windowWithWindowNumber: cWin->number] sendEvent: r]; 1028 } 1029 if (!NSEqualPoints(r.origin, x.origin)) 1030 { 1031 NSEvent *r; 1032 NSWindow *window; 1033 1034 r = [NSEvent otherEventWithType: NSAppKitDefined 1035 location: eventLocation 1036 modifierFlags: eventFlags 1037 timestamp: ts / 1000.0 1038 windowNumber: cWin->number 1039 context: gcontext 1040 subtype: GSAppKitWindowMoved 1041 data1: n.origin.x 1042 data2: n.origin.y]; 1043 1044 /* We don't add this event in event_queue, to don't delay 1045 * its sent. Instead, send it directly to the window. If not, 1046 * the programa can move/resize the window while we send 1047 * this event, causing a confusion. 1048 */ 1049 window = [NSApp windowWithWindowNumber: cWin->number]; 1050 [window sendEvent: r]; 1051 /* Update monitor_id of the backend window. 1052 NSWindow may change screen pointer while processing 1053 the event. */ 1054 cWin->monitor_id = [[window screen] screenNumber]; 1055 } 1056 } 1057 break; 1058 1059 // same as ConfigureNotify but we get this event 1060 // before the change has actually occurred 1061 case ConfigureRequest: 1062 NSDebugLLog(@"NSEvent", @"%lu ConfigureRequest\n", 1063 xEvent.xconfigurerequest.window); 1064 break; 1065 1066 // a window has been created 1067 case CreateNotify: 1068 NSDebugLLog(@"NSEvent", @"%lu CreateNotify\n", 1069 xEvent.xcreatewindow.window); 1070 break; 1071 1072 // a window has been destroyed 1073 case DestroyNotify: 1074 NSDebugLLog(@"NSEvent", @"%lu DestroyNotify\n", 1075 xEvent.xdestroywindow.window); 1076 break; 1077 1078 // when the pointer enters a window 1079 case EnterNotify: 1080 NSDebugLLog(@"NSEvent", @"%lu EnterNotify\n", 1081 xEvent.xcrossing.window); 1082 break; 1083 1084 // when the pointer leaves a window 1085 case LeaveNotify: 1086 NSDebugLLog(@"NSEvent", @"%lu LeaveNotify\n", 1087 xEvent.xcrossing.window); 1088 if (cWin == 0 || xEvent.xcrossing.window != cWin->ident) 1089 { 1090 generic.cachedWindow 1091 = [XGServer _windowForXWindow: xEvent.xcrossing.window]; 1092 } 1093 if (cWin == 0) 1094 break; 1095 eventLocation = NSMakePoint(-1,-1); 1096 e = [NSEvent otherEventWithType: NSAppKitDefined 1097 location: eventLocation 1098 modifierFlags: 0 1099 timestamp: 0 1100 windowNumber: cWin->number 1101 context: gcontext 1102 subtype: GSAppKitWindowLeave 1103 data1: 0 1104 data2: 0]; 1105 break; 1106 1107 // the visibility of a window has changed 1108 case VisibilityNotify: 1109 NSDebugLLog(@"NSEvent", @"%lu VisibilityNotify %d\n", 1110 xEvent.xvisibility.window, xEvent.xvisibility.state); 1111 if (cWin == 0 || xEvent.xvisibility.window != cWin->ident) 1112 { 1113 generic.cachedWindow 1114 = [XGServer _windowForXWindow:xEvent.xvisibility.window]; 1115 } 1116 // sub-window ? 1117 /* 1118 { 1119 Window xw; 1120 xw = xEvent.xvisibility.window; 1121 while (cWin == 0) 1122 { 1123 Window rw, *cw; unsigned int nc; 1124 if ( !XQueryTree(dpy, xw, &rw, &xw, &cw, &nc) ) 1125 continue; 1126 if ( cw != NULL ) 1127 XFree(cw); 1128 generic.cachedWindow 1129 = [XGServer _windowForXWindow:xw]; 1130 } 1131 } 1132 */ 1133 if (cWin != 0) 1134 cWin->visibility = xEvent.xvisibility.state; 1135 break; 1136 1137 // a portion of the window has become visible and 1138 // we must redisplay it 1139 case Expose: 1140 NSDebugLLog(@"NSEvent", @"%lu Expose\n", 1141 xEvent.xexpose.window); 1142 { 1143 if (cWin == 0 || xEvent.xexpose.window != cWin->ident) 1144 { 1145 generic.cachedWindow 1146 = [XGServer _windowForXWindow:xEvent.xexpose.window]; 1147 } 1148 // sub-window ? 1149 /* 1150 BOOL isSubWindow = NO; 1151 1152 { 1153 Window xw; 1154 xw = xEvent.xexpose.window; 1155 XWindowAttributes wa; 1156 // We should not found more than one level, but who knows ? 1157 while (cWin == 0) 1158 { 1159 Window rw, *cw; unsigned int nc; 1160 XGetWindowAttributes(dpy,xEvent.xexpose.window,&wa); 1161 xEvent.xexpose.x += wa.x; 1162 xEvent.xexpose.y += wa.y; 1163 if ( !XQueryTree(dpy, xw, &rw, &xw, &cw, &nc) ) 1164 continue; 1165 if ( cw != NULL ) 1166 XFree(cw); 1167 generic.cachedWindow 1168 = [XGServer _windowForXWindow:xw]; 1169 } 1170 if ( xw != xEvent.xexpose.window ) 1171 { 1172 isSubWindow = YES; 1173 } 1174 } 1175 */ 1176 if (cWin != 0) 1177 { 1178 XRectangle rectangle; 1179 1180 rectangle.x = xEvent.xexpose.x; 1181 rectangle.y = xEvent.xexpose.y; 1182 rectangle.width = xEvent.xexpose.width; 1183 rectangle.height = xEvent.xexpose.height; 1184 1185 NSDebugLLog(@"NSEvent", @"Expose frame %d %d %d %d\n", 1186 rectangle.x, rectangle.y, 1187 rectangle.width, rectangle.height); 1188#if 0 1189 // ignore backing if sub-window 1190 [self _addExposedRectangle: rectangle : cWin->number : isSubWindow]; 1191 1192 if (xEvent.xexpose.count == 0) 1193 [self _processExposedRectangles: cWin->number]; 1194#else 1195 { 1196 NSRect rect; 1197 NSTimeInterval ts = (NSTimeInterval)generic.lastMotion; 1198 1199 rect = [self _XWinRectToOSWinRect: NSMakeRect( 1200 rectangle.x, rectangle.y, rectangle.width, rectangle.height) 1201 for: cWin]; 1202 e = [NSEvent otherEventWithType: NSAppKitDefined 1203 location: rect.origin 1204 modifierFlags: eventFlags 1205 timestamp: ts / 1000.0 1206 windowNumber: cWin->number 1207 context: gcontext 1208 subtype: GSAppKitRegionExposed 1209 data1: rect.size.width 1210 data2: rect.size.height]; 1211 } 1212 1213#endif 1214 } 1215 break; 1216 } 1217 1218 // keyboard focus entered a window 1219 case FocusIn: 1220 NSDebugLLog(@"NSEvent", @"%lu FocusIn\n", 1221 xEvent.xfocus.window); 1222 if (cWin == 0 || xEvent.xfocus.window != cWin->ident) 1223 { 1224 generic.cachedWindow 1225 = [XGServer _windowForXWindow:xEvent.xfocus.window]; 1226 } 1227 if (cWin == 0) 1228 break; 1229 NSDebugLLog(@"Focus", @"%lu got focus on %lu\n", 1230 xEvent.xfocus.window, cWin->number); 1231 // Store this for debugging, may not be the real focus window 1232 generic.currentFocusWindow = cWin->number; 1233 if (xEvent.xfocus.serial == generic.focusRequestNumber) 1234 { 1235 /* 1236 * This is a response to our own request - so we mark the 1237 * request as complete. 1238 */ 1239 generic.desiredFocusWindow = 0; 1240 generic.focusRequestNumber = 0; 1241 } 1242 break; 1243 1244 // keyboard focus left a window 1245 case FocusOut: 1246 { 1247 Window fw; 1248 int rev; 1249 1250 /* 1251 * See where the focus has moved to - 1252 * If it has gone to 'none' or 'PointerRoot' then 1253 * it's not one of ours. 1254 * If it has gone to our root window - use the icon window. 1255 * If it has gone to a window - we see if it is one of ours. 1256 */ 1257 XGetInputFocus(xEvent.xfocus.display, &fw, &rev); 1258 NSDebugLLog(@"NSEvent", @"%lu FocusOut\n", 1259 xEvent.xfocus.window); 1260 if (fw != None && fw != PointerRoot) 1261 { 1262 generic.cachedWindow = [XGServer _windowForXWindow: fw]; 1263 if (cWin == 0) 1264 { 1265 generic.cachedWindow = [XGServer _windowForXParent: fw]; 1266 } 1267 if (cWin == 0) 1268 { 1269 nswin = nil; 1270 } 1271 else 1272 { 1273 nswin = GSWindowWithNumber(cWin->number); 1274 } 1275 } 1276 else 1277 { 1278 nswin = nil; 1279 } 1280 NSDebugLLog(@"Focus", @"Focus went to %lu (xwin %lu)\n", 1281 (nswin != nil) ? cWin->number : 0, fw); 1282 1283 // Focus went to a window not in this application. 1284 if (nswin == nil) 1285 { 1286 [NSApp deactivate]; 1287 } 1288 1289 // Clean up old focus request 1290 generic.cachedWindow 1291 = [XGServer _windowForXWindow: xEvent.xfocus.window]; 1292 NSDebugLLog(@"Focus", @"%lu lost focus on %lu\n", 1293 xEvent.xfocus.window, (cWin) ? cWin->number : 0); 1294 generic.currentFocusWindow = 0; 1295 if (cWin && generic.desiredFocusWindow == cWin->number) 1296 { 1297 /* Request not valid anymore since we lost focus */ 1298 generic.focusRequestNumber = 0; 1299 } 1300 } 1301 break; 1302 1303 case GraphicsExpose: 1304 NSDebugLLog(@"NSEvent", @"%lu GraphicsExpose\n", 1305 xEvent.xexpose.window); 1306 break; 1307 1308 case NoExpose: 1309 NSDebugLLog(@"NSEvent", @"NoExpose\n"); 1310 break; 1311 1312 // window is moved because of a change in the size of its parent 1313 case GravityNotify: 1314 NSDebugLLog(@"NSEvent", @"%lu GravityNotify\n", 1315 xEvent.xgravity.window); 1316 break; 1317 1318 // a key has been pressed 1319 case KeyPress: 1320 NSDebugLLog(@"NSEvent", @"%lu KeyPress\n", 1321 xEvent.xkey.window); 1322 [self setLastTime: xEvent.xkey.time]; 1323 e = process_key_event (&xEvent, self, NSKeyDown, event_queue, NO); 1324 break; 1325 1326 // a key has been released 1327 case KeyRelease: 1328 NSDebugLLog(@"NSEvent", @"%lu KeyRelease\n", 1329 xEvent.xkey.window); 1330 [self setLastTime: xEvent.xkey.time]; 1331 1332 /* 1333 For key repeats X creates two corresponding KeyRelease/KeyPress events. 1334 So, first we check for the KeyRelease event, take a look at the next 1335 event in the queue and look if they are a matching KeyRelease/KeyPress 1336 pair. If so, we ignore the current KeyRelease event. 1337 */ 1338 if (XEventsQueued(dpy, QueuedAfterReading)) 1339 { 1340 XEvent nev; 1341 XPeekEvent(dpy, &nev); 1342 1343 if (nev.type == KeyPress && 1344 nev.xkey.window == xEvent.xkey.window && 1345 nev.xkey.time == xEvent.xkey.time && 1346 nev.xkey.keycode == xEvent.xkey.keycode) 1347 { 1348 // Ignore the current KeyRelease event. 1349 } 1350 else 1351 { 1352 /* 1353 if (nev.type == ClientMessage) 1354 { 1355 NSDebugLLog(@"NSEvent", @"Next event ClientMessage type %ld %s", 1356 xEvent.xclient.message_type, 1357 XGetAtomName(dpy, xEvent.xclient.message_type)); 1358 } 1359 */ 1360 e = process_key_event(&xEvent, self, NSKeyUp, event_queue, NO); 1361 } 1362 } 1363 else 1364 { 1365 e = process_key_event(&xEvent, self, NSKeyUp, event_queue, NO); 1366 } 1367 break; 1368 1369 // reports the state of the keyboard when pointer or 1370 // focus enters a window 1371 case KeymapNotify: 1372 { 1373 if (_is_keyboard_initialized == NO) 1374 initialize_keyboard (); 1375 1376 NSDebugLLog(@"NSEvent", @"%lu KeymapNotify\n", 1377 xEvent.xkeymap.window); 1378 1379 // Check if shift is pressed 1380 _shift_pressed = 0; 1381 if (check_modifier (&xEvent, XK_Shift_L)) 1382 { 1383 _shift_pressed |= 1; 1384 } 1385 if (check_modifier (&xEvent, XK_Shift_R)) 1386 { 1387 _shift_pressed |= 2; 1388 } 1389 1390 // Check if control is pressed 1391 _control_pressed = 0; 1392 if ((_control_keysyms[0] != NoSymbol) 1393 && check_modifier (&xEvent, _control_keysyms[0])) 1394 { 1395 _control_pressed |= 1; 1396 } 1397 if ((_control_keysyms[1] != NoSymbol) 1398 && check_modifier (&xEvent, _control_keysyms[1])) 1399 { 1400 _control_pressed |= 2; 1401 } 1402 1403 // Check if command is pressed 1404 _command_pressed = 0; 1405 if ((_command_keysyms[0] != NoSymbol) 1406 && check_modifier (&xEvent, _command_keysyms[0])) 1407 { 1408 _command_pressed |= 1; 1409 } 1410 if ((_command_keysyms[1] != NoSymbol) 1411 && check_modifier (&xEvent, _command_keysyms[1])) 1412 { 1413 _command_pressed |= 2; 1414 } 1415 1416 // Check if alt is pressed 1417 _alt_pressed = 0; 1418 if ((_alt_keysyms[0] != NoSymbol) 1419 && check_modifier (&xEvent, _alt_keysyms[0])) 1420 { 1421 _alt_pressed |= 1; 1422 } 1423 if ((_alt_keysyms[1] != NoSymbol) 1424 && check_modifier (&xEvent, _alt_keysyms[1])) 1425 { 1426 _alt_pressed |= 2; 1427 } 1428 1429 // Check if help is pressed 1430 _help_pressed = 0; 1431 if ((_help_keysyms[0] != NoSymbol) 1432 && check_modifier (&xEvent, _help_keysyms[0])) 1433 { 1434 _help_pressed |= 1; 1435 } 1436 if ((_help_keysyms[1] != NoSymbol) 1437 && check_modifier (&xEvent, _help_keysyms[1])) 1438 { 1439 _help_pressed |= 2; 1440 } 1441 } 1442 break; 1443 1444 // when a window changes state from ummapped to 1445 // mapped or vice versa 1446 case MapNotify: 1447 NSDebugLLog(@"NSEvent", @"%lu MapNotify\n", 1448 xEvent.xmap.window); 1449 if (cWin == 0 || xEvent.xmap.window != cWin->ident) 1450 { 1451 generic.cachedWindow 1452 = [XGServer _windowForXWindow:xEvent.xmap.window]; 1453 } 1454 if (cWin != 0) 1455 { 1456 cWin->map_state = IsViewable; 1457 /* 1458 * if the window that was just mapped wants the input 1459 * focus, re-do the request. 1460 */ 1461 if (generic.desiredFocusWindow == cWin->number 1462 && generic.focusRequestNumber == 0) 1463 { 1464 NSDebugLLog(@"Focus", @"Refocusing %lu on map notify", 1465 cWin->number); 1466 [self setinputfocus: cWin->number]; 1467 } 1468 /* 1469 * Make sure that the newly mapped window displays. 1470 */ 1471 nswin = GSWindowWithNumber(cWin->number); 1472 [nswin update]; 1473 } 1474 break; 1475 1476 // Window is no longer visible. 1477 case UnmapNotify: 1478 NSDebugLLog(@"NSEvent", @"%lu UnmapNotify\n", 1479 xEvent.xunmap.window); 1480 if (cWin == 0 || xEvent.xunmap.window != cWin->ident) 1481 { 1482 generic.cachedWindow 1483 = [XGServer _windowForXWindow:xEvent.xunmap.window]; 1484 } 1485 if (cWin != 0) 1486 { 1487 cWin->map_state = IsUnmapped; 1488 cWin->visibility = -1; 1489 } 1490 break; 1491 1492 // like MapNotify but occurs before the request is carried out 1493 case MapRequest: 1494 NSDebugLLog(@"NSEvent", @"%lu MapRequest\n", 1495 xEvent.xmaprequest.window); 1496 break; 1497 1498 // keyboard or mouse mapping has been changed by another client 1499 case MappingNotify: 1500 NSDebugLLog(@"NSEvent", @"%lu MappingNotify\n", 1501 xEvent.xmapping.window); 1502 if ((xEvent.xmapping.request == MappingModifier) 1503 || (xEvent.xmapping.request == MappingKeyboard)) 1504 { 1505 XRefreshKeyboardMapping (&xEvent.xmapping); 1506 set_up_num_lock (); 1507 } 1508 break; 1509 1510 case MotionNotify: 1511 NSDebugLLog(@"NSMotionEvent", @"%lu MotionNotify - %d %d\n", 1512 xEvent.xmotion.window, xEvent.xmotion.x, xEvent.xmotion.y); 1513 { 1514 unsigned int state; 1515 1516 /* 1517 * Compress motion events to avoid flooding. 1518 */ 1519 while (XPending(xEvent.xmotion.display)) 1520 { 1521 XEvent peek; 1522 1523 XPeekEvent(xEvent.xmotion.display, &peek); 1524 if (peek.type == MotionNotify 1525 && xEvent.xmotion.window == peek.xmotion.window 1526 && xEvent.xmotion.subwindow == peek.xmotion.subwindow) 1527 { 1528 XNextEvent(xEvent.xmotion.display, &xEvent); 1529 } 1530 else 1531 { 1532 break; 1533 } 1534 } 1535 1536 generic.lastMotion = xEvent.xmotion.time; 1537 [self setLastTime: generic.lastMotion]; 1538 state = xEvent.xmotion.state; 1539 if (state & generic.lMouseMask) 1540 { 1541 eventType = NSLeftMouseDragged; 1542 } 1543 else if (state & generic.rMouseMask) 1544 { 1545 eventType = NSRightMouseDragged; 1546 } 1547 else if (state & generic.mMouseMask) 1548 { 1549 eventType = NSOtherMouseDragged; 1550 } 1551 else 1552 { 1553 eventType = NSMouseMoved; 1554 } 1555 1556 eventFlags = process_modifier_flags(state); 1557 // if pointer is grabbed use grab window instead 1558 xWin = (grabWindow == 0) 1559 ? xEvent.xmotion.window : grabWindow; 1560 if (cWin == 0 || xWin != cWin->ident) 1561 generic.cachedWindow = [XGServer _windowForXWindow: xWin]; 1562 if (cWin == 0) 1563 break; 1564 1565 deltaX = - eventLocation.x; 1566 deltaY = - eventLocation.y; 1567 eventLocation = NSMakePoint(xEvent.xmotion.x, xEvent.xmotion.y); 1568 eventLocation = [self _XPointToOSPoint: eventLocation 1569 for: cWin]; 1570 deltaX += eventLocation.x; 1571 deltaY += eventLocation.y; 1572 1573 e = [NSEvent mouseEventWithType: eventType 1574 location: eventLocation 1575 modifierFlags: eventFlags 1576 timestamp: (NSTimeInterval)generic.lastTime / 1000.0 1577 windowNumber: cWin->number 1578 context: gcontext 1579 eventNumber: xEvent.xbutton.serial 1580 clickCount: clickCount 1581 pressure: 1.0 1582 buttonNumber: 0 /* FIXME */ 1583 deltaX: deltaX 1584 deltaY: deltaY 1585 deltaZ: 0]; 1586 break; 1587 } 1588 1589 // a window property has changed or been deleted 1590 case PropertyNotify: 1591 NSDebugLLog(@"NSEvent", @"%lu PropertyNotify - '%s'\n", 1592 xEvent.xproperty.window, 1593 XGetAtomName(dpy, xEvent.xproperty.atom)); 1594 if (xEvent.xproperty.atom == generic.WM_STATE_ATOM) 1595 { 1596 if (cWin == 0 || xEvent.xproperty.window != cWin->ident) 1597 { 1598 generic.cachedWindow 1599 = [XGServer _windowForXWindow: xEvent.xproperty.window]; 1600 } 1601 if (cWin != 0) 1602 { 1603 int new_state; 1604 1605 /* Get the new window state */ 1606 if (xEvent.xproperty.state == PropertyNewValue) 1607 new_state = [self _wm_state: xEvent.xproperty.window]; 1608 else 1609 new_state = WithdrawnState; 1610 1611 switch (new_state) 1612 { 1613 case IconicState: 1614 /* Post miniaturize event upon transition from NormalState 1615 to IconicState. If the window manager supports the ewmh 1616 specification, also check that the _NET_WM_STATE 1617 property includes _NET_WM_STATE_HIDDEN. */ 1618 /* Note: Don't rely on WM_STATE (nor on _NET_WM_STATE) with 1619 Window Maker, since it is impossible to distinguish 1620 miniaturized windows from hidden windows by their window 1621 properties. Fortunately, Window Maker sends us a client 1622 message when a window is miniaturized. */ 1623 if ((generic.wm & XGWM_WINDOWMAKER) == 0 && 1624 cWin->wm_state == NormalState && 1625 ((generic.wm & XGWM_EWMH) == 0 || 1626 [self _ewmh_isHidden: xEvent.xproperty.window] == YES)) 1627 { 1628 /* Same event as when we get ClientMessage with the 1629 * atom equal to generic._GNUSTEP_WM_MINIATURIZE_WINDOW_ATOM 1630 */ 1631 NSDebugLLog(@"Miniaturize", @"%lu miniaturized", 1632 cWin->number); 1633 eventLocation = NSMakePoint(0,0); 1634 e = [NSEvent otherEventWithType: NSAppKitDefined 1635 location: eventLocation 1636 modifierFlags: 0 1637 timestamp: xEvent.xproperty.time / 1000 1638 windowNumber: cWin->number 1639 context: gcontext 1640 subtype: GSAppKitWindowMiniaturize 1641 data1: 0 1642 data2: 0]; 1643 } 1644 break; 1645 1646 case NormalState: 1647 /* Post deminiaturize event upon transition from IconicState 1648 to NormalState, but only if our window is actually 1649 miniaturized. */ 1650 if (cWin->wm_state == IconicState && 1651 [GSWindowWithNumber(cWin->number) isMiniaturized]) 1652 { 1653 NSDebugLLog(@"Miniaturize", @"%lu deminiaturized", 1654 cWin->number); 1655 eventLocation = NSMakePoint(0,0); 1656 e = [NSEvent otherEventWithType: NSAppKitDefined 1657 location: eventLocation 1658 modifierFlags: 0 1659 timestamp: xEvent.xproperty.time / 1000 1660 windowNumber: cWin->number 1661 context: gcontext 1662 subtype: GSAppKitWindowDeminiaturize 1663 data1: 0 1664 data2: 0]; 1665 } 1666 break; 1667 } 1668 1669 /* save the new state */ 1670 cWin->wm_state = new_state; 1671 } 1672 } 1673 break; 1674 1675 // a client successfully reparents a window 1676 case ReparentNotify: 1677 NSDebugLLog(@"NSEvent", @"%lu ReparentNotify - offset %d %d\n", 1678 xEvent.xreparent.window, xEvent.xreparent.x, 1679 xEvent.xreparent.y); 1680 if (cWin == 0 || xEvent.xreparent.window != cWin->ident) 1681 { 1682 generic.cachedWindow 1683 = [XGServer _windowForXWindow:xEvent.xreparent.window]; 1684 } 1685 if (cWin != 0) 1686 { 1687 cWin->parent = xEvent.xreparent.parent; 1688 } 1689 1690 if (cWin != 0 && xEvent.xreparent.parent != cWin->root 1691 && (xEvent.xreparent.x != 0 || xEvent.xreparent.y != 0)) 1692 { 1693 Window parent = xEvent.xreparent.parent; 1694 XWindowAttributes wattr; 1695 float l; 1696 float r; 1697 float t; 1698 float b; 1699 Offsets *o; 1700 1701 /* Get the WM offset info which we hope is the same 1702 * for all parented windows with the same style. 1703 * The coordinates in the event are insufficient to determine 1704 * the offsets as the new parent window may have a border, 1705 * so we must get the attributes of that window and use them 1706 * to determine our offsets. 1707 */ 1708 XGetWindowAttributes(dpy, parent, &wattr); 1709 NSDebugLLog(@"NSEvent", @"Parent border,width,height %d,%d,%d\n", 1710 wattr.border_width, wattr.width, wattr.height); 1711 l = xEvent.xreparent.x + wattr.border_width; 1712 t = xEvent.xreparent.y + wattr.border_width; 1713 1714 /* Find total parent size and subtract window size and 1715 * top-left-corner offset to determine bottom-right-corner 1716 * offset. 1717 */ 1718 r = wattr.width + wattr.border_width * 2; 1719 r -= (cWin->xframe.size.width + l); 1720 b = wattr.height + wattr.border_width * 2; 1721 b -= (cWin->xframe.size.height + t); 1722 1723 // Some window manager e.g. KDE2 put in multiple windows, 1724 // so we have to find the right parent, closest to root 1725 /* FIXME: This section of code has caused problems with 1726 certain users. An X error occurs in XQueryTree and 1727 later a seg fault in XFree. It's 'commented' out for 1728 now unless you set the default 'GSDoubleParentWindows' 1729 */ 1730 if (generic.flags.doubleParentWindow) 1731 { 1732 Window new_parent = parent; 1733 1734 r = wattr.width + wattr.border_width * 2; 1735 b = wattr.height + wattr.border_width * 2; 1736 while (new_parent && (new_parent != cWin->root)) 1737 { 1738 Window root; 1739 Window *children; 1740 unsigned int nchildren; 1741 1742 parent = new_parent; 1743 NSLog(@"QueryTree window is %lu (cwin root %lu)", 1744 parent, cWin->root); 1745 if (!XQueryTree(dpy, parent, &root, &new_parent, 1746 &children, &nchildren)) 1747 { 1748 new_parent = None; 1749 if (children) 1750 { 1751 NSLog(@"Bad pointer from failed X call?"); 1752 children = 0; 1753 } 1754 } 1755 if (children) 1756 { 1757 XFree(children); 1758 } 1759 if (new_parent && new_parent != cWin->root) 1760 { 1761 XWindowAttributes pattr; 1762 1763 XGetWindowAttributes(dpy, parent, &pattr); 1764 l += pattr.x + pattr.border_width; 1765 t += pattr.y + pattr.border_width; 1766 r = pattr.width + pattr.border_width * 2; 1767 b = pattr.height + pattr.border_width * 2; 1768 } 1769 } /* while */ 1770 r -= (cWin->xframe.size.width + l); 1771 b -= (cWin->xframe.size.height + t); 1772 } /* generic.flags.doubleParentWindow */ 1773 1774 o = generic.offsets + (cWin->win_attrs.window_style & 15); 1775 if (o->known == NO) 1776 { 1777 o->l = l; 1778 o->r = r; 1779 o->t = t; 1780 o->b = b; 1781 o->known = YES; 1782 /* FIXME: if offsets have changed, from previously guessed 1783 * versions, we should go through window list and fix up 1784 * hints. 1785 */ 1786 } 1787 else 1788 { 1789 BOOL changed = NO; 1790 1791 if (l != o->l) 1792 { 1793 NSLog(@"Ignore left offset change from %d to %d", 1794 (int)o->l, (int)l); 1795 changed = YES; 1796 } 1797 if (r != o->r) 1798 { 1799 NSLog(@"Ignore right offset change from %d to %d", 1800 (int)o->r, (int)r); 1801 changed = YES; 1802 } 1803 if (t != o->t) 1804 { 1805 NSLog(@"Ignore top offset change from %d to %d", 1806 (int)o->t, (int)t); 1807 changed = YES; 1808 } 1809 if (b != o->b) 1810 { 1811 NSLog(@"Ignore bottom offset change from %d to %d", 1812 (int)o->b, (int)b); 1813 changed = YES; 1814 } 1815 if (changed == YES) 1816 { 1817 NSLog(@"Reparent was with offset %d %d\n", 1818 xEvent.xreparent.x, xEvent.xreparent.y); 1819 NSLog(@"Parent border,width,height %d,%d,%d\n", 1820 wattr.border_width, wattr.width, wattr.height); 1821 } 1822 } 1823 1824 /* Work around a bug in Window Maker, which does not preserve 1825 * the document edited status and uses the wrong close button 1826 * when a window is shown again after hiding it 1827 */ 1828 if (generic.wm & XGWM_WINDOWMAKER) 1829 { 1830/* Warning ... X-bug .. when we specify 32bit data X actually expects data 1831 * of type 'long' or 'unsigned long' even on machines where those types 1832 * hold 64bit values. 1833 */ 1834 XChangeProperty(dpy, cWin->ident, generic._GNUSTEP_WM_ATTR_ATOM, 1835 generic._GNUSTEP_WM_ATTR_ATOM, 32, PropModeReplace, 1836 (unsigned char *)&cWin->win_attrs, 1837 sizeof(GNUstepWMAttributes)/sizeof(CARD32)); 1838 } 1839 } 1840 break; 1841 1842 // another client attempts to change the size of a window 1843 case ResizeRequest: 1844 NSDebugLLog(@"NSEvent", @"%lu ResizeRequest\n", 1845 xEvent.xresizerequest.window); 1846 break; 1847 1848 // events dealing with the selection 1849 case SelectionClear: 1850 NSDebugLLog(@"NSEvent", @"%lu SelectionClear\n", 1851 xEvent.xselectionclear.window); 1852 break; 1853 1854 case SelectionNotify: 1855 NSDebugLLog(@"NSEvent", @"%lu SelectionNotify\n", 1856 xEvent.xselection.requestor); 1857 break; 1858 1859 case SelectionRequest: 1860 NSDebugLLog(@"NSEvent", @"%lu SelectionRequest\n", 1861 xEvent.xselectionrequest.requestor); 1862 { 1863 NSPasteboard *pb = [NSPasteboard pasteboardWithName: NSDragPboard]; 1864 NSArray *types = [pb types]; 1865 NSData *data = nil; 1866 Atom xType = xEvent.xselectionrequest.target; 1867 1868 if (((xType == generic.UTF8_STRING_ATOM) || 1869 (xType == XA_STRING) || 1870 (xType == generic.TEXT_ATOM)) && 1871 [types containsObject: NSStringPboardType]) 1872 { 1873 NSString *s = [pb stringForType: NSStringPboardType]; 1874 1875 if (xType == generic.UTF8_STRING_ATOM) 1876 { 1877 data = [s dataUsingEncoding: NSUTF8StringEncoding]; 1878 } 1879 else if ((xType == XA_STRING) || (xType == generic.TEXT_ATOM)) 1880 { 1881 data = [s dataUsingEncoding: NSISOLatin1StringEncoding]; 1882 } 1883 } 1884 // FIXME: Add support for more types. See: xpbs.m 1885 1886 if (data != nil) 1887 { 1888 DndClass dnd = xdnd(); 1889 1890 // Send the data to the other process 1891 xdnd_selection_send(&dnd, &xEvent.xselectionrequest, 1892 (unsigned char *)[data bytes], [data length]); 1893 } 1894 } 1895 break; 1896 1897 // We shouldn't get here unless we forgot to trap an event above 1898 default: 1899#ifdef XSHM 1900 if (xEvent.type == XShmGetEventBase(dpy)+ShmCompletion 1901 && [gcontext respondsToSelector: @selector(gotShmCompletion:)]) 1902 { 1903 [gcontext gotShmCompletion: 1904 ((XShmCompletionEvent *)&xEvent)->drawable]; 1905 break; 1906 } 1907#endif 1908#ifdef HAVE_XRANDR 1909 int randr_event_type = randrEventBase + RRScreenChangeNotify; 1910 if (xEvent.type == randr_event_type 1911 && (xEvent.xconfigure.window == RootWindow(dpy, defScreen))) 1912 { 1913 // Check if other RandR events are waiting in the queue. 1914 XSync(dpy, 0); 1915 while (XCheckTypedEvent(dpy, randr_event_type, &xEvent)) {;} 1916 1917 XRRUpdateConfiguration(event); 1918 // Regenerate NSScreens 1919 [NSScreen resetScreens]; 1920 // Notify application about screen parameters change 1921 [[NSNotificationCenter defaultCenter] 1922 postNotificationName: NSApplicationDidChangeScreenParametersNotification 1923 object: NSApp]; 1924 } 1925 break; 1926#endif 1927 NSLog(@"Received an untrapped event\n"); 1928 break; 1929 } 1930 if (e) 1931 { 1932 [event_queue addObject: e]; 1933 } 1934 e = nil; 1935} 1936 1937/* 1938 * WM is asking us to take the keyboard focus 1939 */ 1940- (NSEvent *)_handleTakeFocusAtom: (XEvent)xEvent 1941 forContext: (NSGraphicsContext *)gcontext 1942{ 1943 NSWindow *keyWindow = [NSApp keyWindow]; 1944 int key_num = [keyWindow windowNumber]; 1945 NSEvent *e = nil; 1946 1947 NSDebugLLog(@"Focus", 1948 @"TakeFocus received by: %li (%lu) (focused = %lu, key = %d)", 1949 cWin->number, xEvent.xfocus.window, 1950 generic.currentFocusWindow, key_num); 1951 1952 /* Invalidate the previous request. It's possible the app lost focus 1953 before this request was fufilled and we are being focused again, 1954 or ??? */ 1955 { 1956 generic.focusRequestNumber = 0; 1957 generic.desiredFocusWindow = 0; 1958 } 1959 1960 /* Sometimes window managers lose the setinputfocus on the key window 1961 * e.g. when ordering out a window with focus then ordering in the key window. 1962 * it might search for a window until one accepts its take focus request. 1963 */ 1964 if (key_num == 0) 1965 { 1966 cWin->ignore_take_focus = NO; 1967 } 1968 else if (cWin->number == [[[NSApp mainMenu] window] windowNumber]) 1969 { 1970 cWin->ignore_take_focus = NO; 1971 } 1972 1973 /* We'd like to send this event directly to the front-end to handle, 1974 but the front-end polls events so slowly compared the speed at 1975 which X events could potentially come that we could easily get 1976 out of sync, particularly when there are a lot of window 1977 events */ 1978 if ([NSApp isHidden]) 1979 { 1980 /* This often occurs when hidding an app, since a bunch of 1981 windows get hidden at once, and the WM is searching for a 1982 window to take focus after each one gets hidden. */ 1983 NSDebugLLog(@"Focus", @"WM take focus while hiding"); 1984 } 1985 else if (cWin->ignore_take_focus == YES) 1986 { 1987 NSDebugLLog(@"Focus", @"Ignoring window focus request"); 1988 cWin->ignore_take_focus = NO; 1989 } 1990 else if (cWin->number == key_num) 1991 { 1992 NSDebugLLog(@"Focus", @"Reasserting key window"); 1993 [GSServerForWindow(keyWindow) setinputfocus: key_num]; 1994 } 1995 else if (key_num 1996 && cWin->number == [[[NSApp mainMenu] window] windowNumber]) 1997 { 1998 gswindow_device_t *key_window = [XGServer _windowWithTag:key_num]; 1999 /* This might occur when the window manager just wants someone 2000 to become key, so it tells the main menu (typically the first 2001 menu in the list), but since we already have a window that 2002 was key before, use that instead */ 2003 NSDebugLLog(@"Focus", @"Key window is already %d", key_num); 2004 if (key_window->map_state == IsUnmapped) { 2005 /* `key_window` was unmapped by window manager. 2006 this window and `key_window` are on the different workspace. */ 2007 [GSServerForWindow(keyWindow) setinputfocus: cWin->number]; 2008 } 2009 else { 2010 [GSServerForWindow(keyWindow) setinputfocus: key_num]; 2011 } 2012 } 2013 else 2014 { 2015 NSPoint eventLocation; 2016 /* 2017 * Here the app asked for this (if keyWindow==nil) or there was a 2018 * click on the title bar or some other reason (window mapped, 2019 * etc). We don't necessarily want to forward the event for the 2020 * last reason but we just have to deal with that since we can 2021 * never be sure if it's necessary. 2022 */ 2023 eventLocation = NSMakePoint(0,0); 2024 e = [NSEvent otherEventWithType:NSAppKitDefined 2025 location: eventLocation 2026 modifierFlags: 0 2027 timestamp: 0 2028 windowNumber: cWin->number 2029 context: gcontext 2030 subtype: GSAppKitWindowFocusIn 2031 data1: 0 2032 data2: 0]; 2033 } 2034 return e; 2035} 2036 2037 2038// Return the key_sym corresponding to the user defaults string given, 2039// or fallback if no default is registered. 2040static KeySym 2041key_sym_from_defaults (Display *display, NSUserDefaults *defaults, 2042 NSString *keyDefaultKey, KeySym fallback) 2043{ 2044 NSString *keyDefaultName; 2045 KeySym key_sym; 2046 2047 keyDefaultName = [defaults stringForKey: keyDefaultKey]; 2048 if (keyDefaultName == nil) 2049 return fallback; 2050 2051 key_sym = XStringToKeysym ([keyDefaultName cString]); 2052#if 0 2053 if (key_sym == NoSymbol && [keyDefaultName intValue] > 0) 2054 { 2055 key_sym = [keyDefaultName intValue]; 2056 } 2057#endif 2058 if (key_sym == NoSymbol) 2059 { 2060 // This is not necessarily an error. 2061 // If you want on purpose to disable a key, 2062 // set its default to 'NoSymbol'. 2063 NSLog (@"KeySym %@ not found; disabling %@", keyDefaultName, 2064 keyDefaultKey); 2065 } 2066 2067 return key_sym; 2068} 2069 2070// This function should be called before any keyboard event is dealed with. 2071static void 2072initialize_keyboard (void) 2073{ 2074 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 2075 Display *display = [XGServer xDisplay]; 2076 2077 // Below must be stored and checked as keysyms, not keycodes, since 2078 // more than one keycode may be mapped t the same keysym 2079 // Initialize Control 2080 _control_keysyms[0] = key_sym_from_defaults(display, defaults, 2081 @"GSFirstControlKey", 2082 XK_Control_L); 2083 2084 _control_keysyms[1] = key_sym_from_defaults(display, defaults, 2085 @"GSSecondControlKey", 2086 XK_Control_R); 2087 2088 if (_control_keysyms[0] == _control_keysyms[1]) 2089 _control_keysyms[1] = NoSymbol; 2090 2091 // Initialize Command 2092 _command_keysyms[0] = key_sym_from_defaults(display, defaults, 2093 @"GSFirstCommandKey", 2094 XK_Alt_L); 2095 2096 _command_keysyms[1] = key_sym_from_defaults(display, defaults, 2097 @"GSSecondCommandKey", 2098 NoSymbol); 2099 2100 if (_command_keysyms[0] == _command_keysyms[1]) 2101 _command_keysyms[1] = NoSymbol; 2102 2103 // Initialize Alt 2104 _alt_keysyms[0] = key_sym_from_defaults(display, defaults, 2105 @"GSFirstAlternateKey", 2106 XK_Alt_R); 2107 if (XKeysymToKeycode(display, _alt_keysyms[0]) == 0) 2108 _alt_keysyms[0] = XK_Mode_switch; 2109 2110 _alt_keysyms[1] = key_sym_from_defaults(display, defaults, 2111 @"GSSecondAlternateKey", 2112 NoSymbol); 2113 2114 if (_alt_keysyms[0] == _alt_keysyms[1]) 2115 _alt_keysyms[1] = NoSymbol; 2116 2117 // Initialize Help 2118 _help_keysyms[0] = key_sym_from_defaults(display, defaults, 2119 @"GSFirstHelpKey", 2120 XK_Help); 2121 if (XKeysymToKeycode(display, _help_keysyms[0]) == 0) 2122 _help_keysyms[0] = NoSymbol; 2123 2124 _help_keysyms[1] = key_sym_from_defaults(display, defaults, 2125 @"GSSecondHelpKey", 2126 XK_Super_L); 2127 2128 if (_help_keysyms[0] == _help_keysyms[1]) 2129 _help_keysyms[1] = NoSymbol; 2130 2131 2132 set_up_num_lock (); 2133 _mod_ignore_shift = ![defaults boolForKey: @"GSModifiersAreNotKeys"]; 2134 2135 _is_keyboard_initialized = YES; 2136} 2137 2138 2139static void 2140set_up_num_lock (void) 2141{ 2142 XModifierKeymap *modifier_map; 2143 int i, j; 2144 unsigned int modifier_masks[8] = 2145 { 2146 ShiftMask, LockMask, ControlMask, Mod1Mask, 2147 Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask 2148 }; 2149 Display *display = [XGServer xDisplay]; 2150 KeyCode _num_lock_keycode; 2151 2152 // Get NumLock keycode 2153 _num_lock_keycode = XKeysymToKeycode (display, XK_Num_Lock); 2154 if (_num_lock_keycode == 0) 2155 { 2156 // Weird. There is no NumLock in this keyboard. 2157 _num_lock_mask = 0; 2158 return; 2159 } 2160 2161 // Get the current modifier mapping 2162 modifier_map = XGetModifierMapping (display); 2163 2164 // Scan the modifiers for NumLock 2165 for (j = 0; j < 8; j++) 2166 for (i = 0; i < (modifier_map->max_keypermod); i++) 2167 { 2168 if ((modifier_map->modifiermap)[i + j*modifier_map->max_keypermod] 2169 == _num_lock_keycode) 2170 { 2171 _num_lock_mask = modifier_masks[j]; 2172 XFreeModifiermap (modifier_map); 2173 return; 2174 } 2175 } 2176 // Weird. NumLock is not among the modifiers 2177 _num_lock_mask = 0; 2178 XFreeModifiermap (modifier_map); 2179 return; 2180} 2181 2182static BOOL 2183keysym_is_X_modifier (KeySym keysym) 2184{ 2185 switch (keysym) 2186 { 2187 case XK_Num_Lock: 2188 case XK_Caps_Lock: 2189 case XK_Shift_Lock: 2190 return YES; 2191 2192 default: 2193 return NO; 2194 } 2195} 2196 2197static NSEvent* 2198process_key_event (XEvent* xEvent, XGServer* context, NSEventType eventType, 2199 NSMutableArray *event_queue, BOOL keyRepeat) 2200{ 2201 NSString *keys, *ukeys; 2202 KeySym keysym; 2203 NSPoint eventLocation; 2204 unsigned short keyCode; 2205 unsigned int eventFlags; 2206 unichar unicode; 2207 NSEvent *event = nil; 2208 NSEventType originalType; 2209 gswindow_device_t *window; 2210 int shift_key = 0; 2211 int control_key = 0; 2212 int command_key = 0; 2213 int alt_key = 0; 2214 int help_key = 0; 2215 KeySym modKeysym; // process modifier independently of shift, etc. 2216 2217 if (_is_keyboard_initialized == NO) 2218 initialize_keyboard (); 2219 2220 window = [XGServer _windowWithTag: [[NSApp keyWindow] windowNumber]]; 2221 if (!window) 2222 { 2223 // No key event if we don't have a key window 2224 return nil; 2225 } 2226 2227 /* Process location */ 2228 eventLocation.x = xEvent->xbutton.x; 2229 eventLocation.y = xEvent->xbutton.y; 2230 eventLocation = [context _XPointToOSPoint: eventLocation 2231 for: window]; 2232 2233 /* Process characters */ 2234 keys = [context->inputServer lookupStringForEvent: (XKeyEvent *)xEvent 2235 window: window 2236 keysym: &keysym]; 2237 2238 /* Process keycode */ 2239 keyCode = ((XKeyEvent *)xEvent)->keycode; 2240 //ximKeyCode = XKeysymToKeycode([XGServer currentXDisplay],keysym); 2241 2242 /* Process NSFlagsChanged events. We can't use a switch because we 2243 are not comparing to constants. Make sure keySym is not NoSymbol since 2244 XIM events can potentially return this. */ 2245 /* Possibly ignore shift/other modifier state in determining KeySym to 2246 work around correct but undesired behavior with shifted modifiers. 2247 See Back defaults documentation for "GSModifiersAreNotKeys". */ 2248 modKeysym = (_mod_ignore_shift == YES) ? 2249 XLookupKeysym((XKeyEvent *)xEvent, 0) : keysym; 2250 if (modKeysym != NoSymbol) 2251 { 2252 if (modKeysym == XK_Shift_L) 2253 { 2254 shift_key = 1; 2255 } 2256 else if (modKeysym == XK_Shift_R) 2257 { 2258 shift_key = 2; 2259 } 2260 else if (modKeysym == _control_keysyms[0]) 2261 { 2262 control_key = 1; 2263 } 2264 else if (modKeysym == _control_keysyms[1]) 2265 { 2266 control_key = 2; 2267 } 2268 else if (modKeysym == _command_keysyms[0]) 2269 { 2270 command_key = 1; 2271 } 2272 else if (modKeysym == _command_keysyms[1]) 2273 { 2274 command_key = 2; 2275 } 2276 else if (modKeysym == _alt_keysyms[0]) 2277 { 2278 alt_key = 1; 2279 } 2280 else if (modKeysym == _alt_keysyms[1]) 2281 { 2282 alt_key = 2; 2283 } 2284 else if (modKeysym == _help_keysyms[0]) 2285 { 2286 help_key = 1; 2287 } 2288 else if (modKeysym == _help_keysyms[1]) 2289 { 2290 help_key = 2; 2291 } 2292 } 2293 2294 originalType = eventType; 2295 if (shift_key || control_key || command_key || alt_key || help_key) 2296 { 2297 eventType = NSFlagsChanged; 2298 if (xEvent->xkey.type == KeyPress) 2299 { 2300 if (shift_key) 2301 _shift_pressed |= shift_key; 2302 if (control_key) 2303 _control_pressed |= control_key; 2304 if (command_key) 2305 _command_pressed |= command_key; 2306 if (alt_key) 2307 _alt_pressed |= alt_key; 2308 if (help_key) 2309 _help_pressed |= help_key; 2310 } 2311 else if (xEvent->xkey.type == KeyRelease) 2312 { 2313 if (shift_key) 2314 _shift_pressed &= ~shift_key; 2315 if (control_key) 2316 _control_pressed &= ~control_key; 2317 if (command_key) 2318 _command_pressed &= ~command_key; 2319 if (alt_key) 2320 _alt_pressed &= ~alt_key; 2321 if (help_key) 2322 _help_pressed &= ~help_key; 2323 } 2324 } 2325 2326 /* Process modifiers */ 2327 eventFlags = process_modifier_flags (xEvent->xkey.state); 2328 2329 /* Add NSNumericPadKeyMask if the key is in the KeyPad */ 2330 if (IsKeypadKey (keysym)) 2331 eventFlags = eventFlags | NSNumericPadKeyMask; 2332 2333 NSDebugLLog (@"NSKeyEvent", @"keysym=%lu, keyCode=%d flags=%d (state=%d)", 2334 keysym, keyCode, eventFlags, ((XKeyEvent *)xEvent)->state); 2335 2336 /* Add NSFunctionKeyMask if the key is a function or a misc function key */ 2337 /* We prefer not to do this and do it manually in process_char 2338 because X's idea of what is a function key seems to be different 2339 from OPENSTEP's one */ 2340 /* if (IsFunctionKey (keysym) || IsMiscFunctionKey (keysym)) 2341 eventFlags = eventFlags | NSFunctionKeyMask; */ 2342 2343 /* First, check to see if the key event if a Shift, NumLock or 2344 CapsLock or ShiftLock keypress/keyrelease. If it is, then use a 2345 NSFlagsChanged event type. This will generate a NSFlagsChanged 2346 event each time you press/release a shift key, even if the flags 2347 haven't actually changed. I don't see this as a problem - if we 2348 didn't, the shift keypress/keyrelease event would never be 2349 notified to the application. 2350 2351 NB - to know if shift was pressed, we need to check the X keysym 2352 - it doesn't work to compare the X modifier flags of this 2353 keypress X event with the ones of the previous one, because when 2354 you press Shift, the X shift keypress event has the *same* X 2355 modifiers flags as the X keypress event before it - only 2356 keypresses coming *after* the shift keypress will get a different 2357 X modifier mask. */ 2358 if (keysym_is_X_modifier (keysym)) 2359 { 2360 eventType = NSFlagsChanged; 2361 } 2362 2363 2364 if (help_key) 2365 { 2366 unicode = NSHelpFunctionKey; 2367 keys = [NSString stringWithCharacters: &unicode length: 1]; 2368 if (originalType == NSKeyDown) 2369 { 2370 event = [NSEvent keyEventWithType: NSKeyDown 2371 location: eventLocation 2372 modifierFlags: eventFlags 2373 timestamp: (NSTimeInterval)xEvent->xkey.time / 1000.0 2374 windowNumber: window->number 2375 context: GSCurrentContext() 2376 characters: keys 2377 charactersIgnoringModifiers: keys 2378 isARepeat: keyRepeat 2379 keyCode: keyCode]; 2380 [event_queue addObject: event]; 2381 event = [NSEvent keyEventWithType: NSFlagsChanged 2382 location: eventLocation 2383 modifierFlags: eventFlags 2384 timestamp: (NSTimeInterval)xEvent->xkey.time / 1000.0 2385 windowNumber: window->number 2386 context: GSCurrentContext() 2387 characters: keys 2388 charactersIgnoringModifiers: keys 2389 isARepeat: NO 2390 keyCode: keyCode]; 2391 return event; 2392 } 2393 else 2394 { 2395 event = [NSEvent keyEventWithType: NSFlagsChanged 2396 location: eventLocation 2397 modifierFlags: eventFlags 2398 timestamp: (NSTimeInterval)xEvent->xkey.time / 1000.0 2399 windowNumber: window->number 2400 context: GSCurrentContext() 2401 characters: keys 2402 charactersIgnoringModifiers: keys 2403 isARepeat: NO 2404 keyCode: keyCode]; 2405 [event_queue addObject: event]; 2406 event = [NSEvent keyEventWithType: NSKeyUp 2407 location: eventLocation 2408 modifierFlags: eventFlags 2409 timestamp: (NSTimeInterval)xEvent->xkey.time / 1000.0 2410 windowNumber: window->number 2411 context: GSCurrentContext() 2412 characters: keys 2413 charactersIgnoringModifiers: keys 2414 isARepeat: keyRepeat 2415 keyCode: keyCode]; 2416 return event; 2417 } 2418 } 2419 else 2420 { 2421 /* Now we get the unicode character for the pressed key using our 2422 * internal table. 2423 */ 2424 unicode = process_char (keysym, &eventFlags); 2425 2426 /* If that didn't work, we use what X gave us */ 2427 if (unicode != 0) 2428 { 2429 keys = [NSString stringWithCharacters: &unicode length: 1]; 2430 } 2431 2432 // Now the same ignoring modifiers, except Shift, ShiftLock, NumLock. 2433 xEvent->xkey.state = (xEvent->xkey.state & (ShiftMask | LockMask 2434 | _num_lock_mask)); 2435 ukeys = [context->inputServer lookupStringForEvent: (XKeyEvent *)xEvent 2436 window: window 2437 keysym: &keysym]; 2438 unicode = process_char (keysym, &eventFlags); 2439 if (unicode != 0) 2440 { 2441 ukeys = [NSString stringWithCharacters: &unicode length: 1]; 2442 } 2443 2444 event = [NSEvent keyEventWithType: eventType 2445 location: eventLocation 2446 modifierFlags: eventFlags 2447 timestamp: (NSTimeInterval)xEvent->xkey.time / 1000.0 2448 windowNumber: window->number 2449 context: GSCurrentContext() 2450 characters: keys 2451 charactersIgnoringModifiers: ukeys 2452 isARepeat: keyRepeat 2453 keyCode: keyCode]; 2454 2455 return event; 2456 } 2457} 2458 2459static unichar 2460process_char (KeySym keysym, unsigned *eventModifierFlags) 2461{ 2462 switch (keysym) 2463 { 2464 /* NB: Whatever is explicitly put in this conversion table takes 2465 precedence over what is returned by XLookupString. Not sure 2466 this is a good idea for latin-1 character input. */ 2467 case XK_Return: return NSCarriageReturnCharacter; 2468 case XK_KP_Enter: return NSEnterCharacter; 2469 case XK_Linefeed: return NSFormFeedCharacter; 2470 case XK_Tab: return NSTabCharacter; 2471#ifdef XK_XKB_KEYS 2472 case XK_ISO_Left_Tab: return NSBackTabCharacter; 2473#endif 2474 /* FIXME: The following line ? */ 2475 case XK_Escape: return 0x1b; 2476 case XK_BackSpace: return NSDeleteCharacter; 2477 2478 /* The following keys need to be reported as function keys */ 2479#define XGPS_FUNCTIONKEY \ 2480*eventModifierFlags = *eventModifierFlags | NSFunctionKeyMask; 2481 2482 case XK_F1: XGPS_FUNCTIONKEY return NSF1FunctionKey; 2483 case XK_F2: XGPS_FUNCTIONKEY return NSF2FunctionKey; 2484 case XK_F3: XGPS_FUNCTIONKEY return NSF3FunctionKey; 2485 case XK_F4: XGPS_FUNCTIONKEY return NSF4FunctionKey; 2486 case XK_F5: XGPS_FUNCTIONKEY return NSF5FunctionKey; 2487 case XK_F6: XGPS_FUNCTIONKEY return NSF6FunctionKey; 2488 case XK_F7: XGPS_FUNCTIONKEY return NSF7FunctionKey; 2489 case XK_F8: XGPS_FUNCTIONKEY return NSF8FunctionKey; 2490 case XK_F9: XGPS_FUNCTIONKEY return NSF9FunctionKey; 2491 case XK_F10: XGPS_FUNCTIONKEY return NSF10FunctionKey; 2492 case XK_F11: XGPS_FUNCTIONKEY return NSF11FunctionKey; 2493 case XK_F12: XGPS_FUNCTIONKEY return NSF12FunctionKey; 2494 case XK_F13: XGPS_FUNCTIONKEY return NSF13FunctionKey; 2495 case XK_F14: XGPS_FUNCTIONKEY return NSF14FunctionKey; 2496 case XK_F15: XGPS_FUNCTIONKEY return NSF15FunctionKey; 2497 case XK_F16: XGPS_FUNCTIONKEY return NSF16FunctionKey; 2498 case XK_F17: XGPS_FUNCTIONKEY return NSF17FunctionKey; 2499 case XK_F18: XGPS_FUNCTIONKEY return NSF18FunctionKey; 2500 case XK_F19: XGPS_FUNCTIONKEY return NSF19FunctionKey; 2501 case XK_F20: XGPS_FUNCTIONKEY return NSF20FunctionKey; 2502 case XK_F21: XGPS_FUNCTIONKEY return NSF21FunctionKey; 2503 case XK_F22: XGPS_FUNCTIONKEY return NSF22FunctionKey; 2504 case XK_F23: XGPS_FUNCTIONKEY return NSF23FunctionKey; 2505 case XK_F24: XGPS_FUNCTIONKEY return NSF24FunctionKey; 2506 case XK_F25: XGPS_FUNCTIONKEY return NSF25FunctionKey; 2507 case XK_F26: XGPS_FUNCTIONKEY return NSF26FunctionKey; 2508 case XK_F27: XGPS_FUNCTIONKEY return NSF27FunctionKey; 2509 case XK_F28: XGPS_FUNCTIONKEY return NSF28FunctionKey; 2510 case XK_F29: XGPS_FUNCTIONKEY return NSF29FunctionKey; 2511 case XK_F30: XGPS_FUNCTIONKEY return NSF30FunctionKey; 2512 case XK_F31: XGPS_FUNCTIONKEY return NSF31FunctionKey; 2513 case XK_F32: XGPS_FUNCTIONKEY return NSF32FunctionKey; 2514 case XK_F33: XGPS_FUNCTIONKEY return NSF33FunctionKey; 2515 case XK_F34: XGPS_FUNCTIONKEY return NSF34FunctionKey; 2516 case XK_F35: XGPS_FUNCTIONKEY return NSF35FunctionKey; 2517 case XK_Delete: XGPS_FUNCTIONKEY return NSDeleteFunctionKey; 2518 case XK_Home: XGPS_FUNCTIONKEY return NSHomeFunctionKey; 2519 case XK_Left: XGPS_FUNCTIONKEY return NSLeftArrowFunctionKey; 2520 case XK_Right: XGPS_FUNCTIONKEY return NSRightArrowFunctionKey; 2521 case XK_Up: XGPS_FUNCTIONKEY return NSUpArrowFunctionKey; 2522 case XK_Down: XGPS_FUNCTIONKEY return NSDownArrowFunctionKey; 2523// case XK_Prior: XGPS_FUNCTIONKEY return NSPrevFunctionKey; 2524// case XK_Next: XGPS_FUNCTIONKEY return NSNextFunctionKey; 2525 case XK_End: XGPS_FUNCTIONKEY return NSEndFunctionKey; 2526 case XK_Begin: XGPS_FUNCTIONKEY return NSBeginFunctionKey; 2527 case XK_Select: XGPS_FUNCTIONKEY return NSSelectFunctionKey; 2528 case XK_Print: XGPS_FUNCTIONKEY return NSPrintFunctionKey; 2529 case XK_Execute: XGPS_FUNCTIONKEY return NSExecuteFunctionKey; 2530 case XK_Insert: XGPS_FUNCTIONKEY return NSInsertFunctionKey; 2531 case XK_Undo: XGPS_FUNCTIONKEY return NSUndoFunctionKey; 2532 case XK_Redo: XGPS_FUNCTIONKEY return NSRedoFunctionKey; 2533 case XK_Menu: XGPS_FUNCTIONKEY return NSMenuFunctionKey; 2534 case XK_Find: XGPS_FUNCTIONKEY return NSFindFunctionKey; 2535 case XK_Help: XGPS_FUNCTIONKEY return NSHelpFunctionKey; 2536 case XK_Break: XGPS_FUNCTIONKEY return NSBreakFunctionKey; 2537 case XK_Mode_switch: XGPS_FUNCTIONKEY return NSModeSwitchFunctionKey; 2538 case XK_Scroll_Lock: XGPS_FUNCTIONKEY return NSScrollLockFunctionKey; 2539 case XK_Pause: XGPS_FUNCTIONKEY return NSPauseFunctionKey; 2540 case XK_Clear: XGPS_FUNCTIONKEY return NSClearDisplayFunctionKey; 2541#ifndef NeXT 2542 case XK_Page_Up: XGPS_FUNCTIONKEY return NSPageUpFunctionKey; 2543 case XK_Page_Down: XGPS_FUNCTIONKEY return NSPageDownFunctionKey; 2544 case XK_Sys_Req: XGPS_FUNCTIONKEY return NSSysReqFunctionKey; 2545#endif 2546 case XK_KP_F1: XGPS_FUNCTIONKEY return NSF1FunctionKey; 2547 case XK_KP_F2: XGPS_FUNCTIONKEY return NSF2FunctionKey; 2548 case XK_KP_F3: XGPS_FUNCTIONKEY return NSF3FunctionKey; 2549 case XK_KP_F4: XGPS_FUNCTIONKEY return NSF4FunctionKey; 2550#ifndef NeXT 2551 case XK_KP_Home: XGPS_FUNCTIONKEY return NSHomeFunctionKey; 2552 case XK_KP_Left: XGPS_FUNCTIONKEY return NSLeftArrowFunctionKey; 2553 case XK_KP_Up: XGPS_FUNCTIONKEY return NSUpArrowFunctionKey; 2554 case XK_KP_Right: XGPS_FUNCTIONKEY return NSRightArrowFunctionKey; 2555 case XK_KP_Down: XGPS_FUNCTIONKEY return NSDownArrowFunctionKey; 2556// case XK_KP_Prior: return NSPrevFunctionKey; 2557 case XK_KP_Page_Up: XGPS_FUNCTIONKEY return NSPageUpFunctionKey; 2558// case XK_KP_Next: return NSNextFunctionKey; 2559 case XK_KP_Page_Down: XGPS_FUNCTIONKEY return NSPageDownFunctionKey; 2560 case XK_KP_End: XGPS_FUNCTIONKEY return NSEndFunctionKey; 2561 case XK_KP_Begin: XGPS_FUNCTIONKEY return NSBeginFunctionKey; 2562 case XK_KP_Insert: XGPS_FUNCTIONKEY return NSInsertFunctionKey; 2563 case XK_KP_Delete: XGPS_FUNCTIONKEY return NSDeleteFunctionKey; 2564#endif 2565#undef XGPS_FUNCTIONKEY 2566 default: return 0; 2567 } 2568} 2569 2570// process_modifier_flags() determines which modifier keys (Command, Control, 2571// Shift, and so forth) were held down while the event occured. 2572static unsigned int 2573process_modifier_flags(unsigned int state) 2574{ 2575 unsigned int eventModifierFlags = 0; 2576 2577 if (_shift_pressed != 0) 2578 eventModifierFlags = eventModifierFlags | NSShiftKeyMask; 2579 2580 if (state & LockMask) 2581 eventModifierFlags = eventModifierFlags | NSAlphaShiftKeyMask; 2582 2583 if (_control_pressed != 0) 2584 eventModifierFlags = eventModifierFlags | NSControlKeyMask; 2585 2586 if (_command_pressed != 0) 2587 eventModifierFlags = eventModifierFlags | NSCommandKeyMask; 2588 2589 if (_alt_pressed != 0) 2590 eventModifierFlags = eventModifierFlags | NSAlternateKeyMask; 2591 2592 if (_help_pressed != 0) 2593 eventModifierFlags = eventModifierFlags | NSHelpKeyMask; 2594 2595 // Other modifiers ignored for now. 2596 2597 return eventModifierFlags; 2598} 2599 2600 2601- (NSDate*) timedOutEvent: (void*)data 2602 type: (RunLoopEventType)type 2603 forMode: (NSString*)mode 2604{ 2605 return nil; 2606} 2607 2608/* Drag and Drop */ 2609- (id <NSDraggingInfo>)dragInfo 2610{ 2611 return [XGDragView sharedDragView]; 2612} 2613 2614@end 2615 2616@implementation XGServer (XSync) 2617- (BOOL) xSyncMap: (void*)windowHandle 2618{ 2619 gswindow_device_t *window = (gswindow_device_t*)windowHandle; 2620 2621 /* 2622 * if the window is not mapped, make sure we have sent all requests to the 2623 * X-server, it may be that our mapping request was buffered. 2624 */ 2625 if (window->map_state != IsViewable) 2626 { 2627 XSync(dpy, False); 2628 [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; 2629 } 2630 /* 2631 * If the window is still not mapped, it may be that the window-manager 2632 * intercepted our mapping request, and hasn't dealt with it yet. 2633 * Listen for input for up to a second, in the hope of getting the mapping. 2634 */ 2635 if (window->map_state != IsViewable) 2636 { 2637 NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 1.0]; 2638 NSRunLoop *l = [NSRunLoop currentRunLoop]; 2639 NSString *m = [l currentMode]; 2640 2641 while (window->map_state != IsViewable && [d timeIntervalSinceNow] > 0) 2642 { 2643 [l runMode: m beforeDate: d]; 2644 } 2645 } 2646 if (window->map_state != IsViewable) 2647 { 2648 NSLog(@"Window still not mapped a second after mapping request made"); 2649 return NO; 2650 } 2651 return YES; 2652} 2653@end 2654 2655@implementation XGServer (X11Ops) 2656 2657/* 2658 * Return mouse location in base coords ignoring the event loop 2659 */ 2660- (NSPoint) mouselocation 2661{ 2662 return [self mouseLocationOnScreen: defScreen window: NULL]; 2663} 2664 2665- (NSPoint) mouseLocationOnScreen: (int)screen window: (int *)win 2666{ 2667 Window rootWin; 2668 Window childWin; 2669 int currentX; 2670 int currentY; 2671 int winX; 2672 int winY; 2673 unsigned mask; 2674 BOOL ok; 2675 NSPoint p; 2676 int height; 2677 int screen_id; 2678 2679 ok = XQueryPointer (dpy, [self xDisplayRootWindow], 2680 &rootWin, &childWin, ¤tX, ¤tY, 2681 &winX, &winY, &mask); 2682 p = NSMakePoint(-1,-1); 2683 /* FIXME: After multi-monitor support will be implemented `screen` method 2684 parameter doesn't make sense. The `if{}` block should be removed since 2685 we have only one screen and mouse can't be placed on "wrong" screen. 2686 Also actually we need `height` of the whole Xlib screen (defScreen). */ 2687 if (ok == False) 2688 { 2689 /* Mouse not on the specified screen_number */ 2690 XWindowAttributes attribs; 2691 ok = XGetWindowAttributes(dpy, rootWin, &attribs); 2692 if (ok == False) 2693 { 2694 return p; 2695 } 2696 screen_id = XScreenNumberOfScreen(attribs.screen); 2697 if (screen >= 0 && screen != screen_id) 2698 { 2699 /* Mouse not on the requred screen, return an invalid point */ 2700 return p; 2701 } 2702 height = attribs.height; 2703 } 2704 else 2705 { 2706 height = xScreenSize.height; 2707 } 2708 p = NSMakePoint(currentX, height - currentY); 2709 if (win) 2710 { 2711 gswindow_device_t *w = [XGServer _windowForXWindow: childWin]; 2712 2713 if (w == NULL) 2714 w = [XGServer _windowForXParent: childWin]; 2715 if (w) 2716 *win = w->number; 2717 else 2718 *win = 0; 2719 } 2720 return p; 2721} 2722 2723- (NSEvent*) getEventMatchingMask: (unsigned)mask 2724 beforeDate: (NSDate*)limit 2725 inMode: (NSString*)mode 2726 dequeue: (BOOL)flag 2727{ 2728 [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; 2729 return [super getEventMatchingMask: mask 2730 beforeDate: limit 2731 inMode: mode 2732 dequeue: flag]; 2733} 2734 2735- (void) discardEventsMatchingMask: (unsigned)mask 2736 beforeEvent: (NSEvent*)limit 2737{ 2738 [self receivedEvent: 0 type: 0 extra: 0 forMode: nil]; 2739 [super discardEventsMatchingMask: mask 2740 beforeEvent: limit]; 2741} 2742 2743@end 2744 2745@implementation XGServer (TimeKeeping) 2746// Sync time with X server every 10 seconds 2747#define MAX_TIME_DIFF 10 2748// Regard an X time stamp as valid for half a second 2749#define OUT_DATE_TIME_DIFF 0.5 2750 2751- (void) setLastTime: (Time)last 2752{ 2753 if (generic.lastTimeStamp == 0 2754 || generic.baseXServerTime + MAX_TIME_DIFF * 1000 < last) 2755 { 2756 // We have not sync'ed with the clock for at least 2757 // MAX_TIME_DIFF seconds ... so we do it now. 2758 generic.lastTimeStamp = [NSDate timeIntervalSinceReferenceDate]; 2759 generic.baseXServerTime = last; 2760 } 2761 else 2762 { 2763 // Optimisation to compute the new time stamp instead. 2764 generic.lastTimeStamp += (last - generic.lastTime) / 1000.0; 2765 } 2766 2767 generic.lastTime = last; 2768} 2769 2770- (Time) lastTime 2771{ 2772 // In the case of activation via DO the lastTime is outdated and cannot be used. 2773 if (generic.lastTimeStamp == 0 2774 || ((generic.lastTimeStamp + OUT_DATE_TIME_DIFF) 2775 < [NSDate timeIntervalSinceReferenceDate])) 2776 { 2777 return CurrentTime; 2778 } 2779 else 2780 { 2781 return generic.lastTime; 2782 } 2783} 2784 2785@end 2786 2787