1/* WIN32Server - Implements window handling for MSWindows 2 3 Copyright (C) 2002, 2005 Free Software Foundation, Inc. 4 5 Written by: Fred Kiefer <FredKiefer@gmx.de> 6 Date: March 2002 7 Part of this code have been re-written by: 8 Tom MacSween <macsweent@sympatico.ca> 9 Date August 2005 10 11 This file is part of the GNU Objective C User Interface Library. 12 13 This library is free software; you can redistribute it and/or 14 modify it under the terms of the GNU Lesser General Public 15 License as published by the Free Software Foundation; either 16 version 2 of the License, or (at your option) any later version. 17 18 This library is distributed in the hope that it will be useful, 19 but WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 Lesser General Public License for more details. 22 23 You should have received a copy of the GNU Lesser General Public 24 License along with this library; see the file COPYING.LIB. 25 If not, see <http://www.gnu.org/licenses/> or write to the 26 Free Software Foundation, 51 Franklin Street, Fifth Floor, 27 Boston, MA 02110-1301, USA. 28*/ 29 30#include "config.h" 31#include <Foundation/NSDebug.h> 32#include <Foundation/NSString.h> 33#include <Foundation/NSArray.h> 34#include <Foundation/NSValue.h> 35#include <Foundation/NSConnection.h> 36#include <Foundation/NSRunLoop.h> 37#include <Foundation/NSTimer.h> 38#include <Foundation/NSUserDefaults.h> 39#include <Foundation/NSException.h> 40#include <AppKit/AppKitExceptions.h> 41#include <AppKit/NSApplication.h> 42#include <AppKit/NSGraphics.h> 43#include <AppKit/NSMenu.h> 44#include <AppKit/NSWindow.h> 45#include <AppKit/NSView.h> 46#include <AppKit/NSEvent.h> 47#include <AppKit/NSCursor.h> 48#include <AppKit/NSText.h> 49#include <AppKit/NSTextField.h> 50#include <AppKit/DPSOperators.h> 51#include <GNUstepGUI/GSTheme.h> 52#include <GNUstepGUI/GSTrackingRect.h> 53 54#include "win32/WIN32Server.h" 55#include "win32/WIN32Geometry.h" 56#ifdef HAVE_WGL 57#include "win32/WIN32OpenGL.h" 58#endif 59 60#ifdef __CYGWIN__ 61#include <sys/file.h> 62#endif 63 64#include <math.h> 65 66// To update the cursor.. 67static BOOL update_cursor = NO; 68static BOOL should_handle_cursor = NO; 69static NSCursor *current_cursor = nil; 70 71 72// Forward declarations... 73static unsigned int mask_for_keystate(BYTE *keyState); 74 75@interface W32DisplayMonitorInfo : NSObject 76{ 77 HMONITOR _hMonitor; 78 RECT _rect; 79 NSRect _frame; 80} 81 82- (id)initWithHMonitor:(HMONITOR)hMonitor rect:(LPRECT)lprcMonitor; 83- (HMONITOR)hMonitor; 84- (RECT)rect; 85- (NSRect)frame; 86- (void)setFrame:(NSRect)frame; 87 88@end 89 90@implementation W32DisplayMonitorInfo 91 92- (id)initWithHMonitor:(HMONITOR)hMonitor rect:(LPRECT)lprcMonitor 93{ 94 self = [self init]; 95 if (self) 96 { 97 CGFloat w = lprcMonitor->right - lprcMonitor->left; 98 CGFloat h = lprcMonitor->bottom - lprcMonitor->top; 99 CGFloat x = lprcMonitor->left; 100 CGFloat y = h - lprcMonitor->bottom; 101 102 _hMonitor = hMonitor; 103 _frame = NSMakeRect(x, y, w, h); 104 memcpy(&_rect, lprcMonitor, sizeof(RECT)); 105 } 106 return self; 107} 108 109- (HMONITOR)hMonitor 110{ 111 return _hMonitor; 112} 113 114- (RECT)rect 115{ 116 return _rect; 117} 118 119- (NSRect)frame 120{ 121 return _frame; 122} 123 124- (void)setFrame:(NSRect)frame 125{ 126 _frame = frame; 127} 128 129@end 130 131 132static BOOL _enableCallbacks = YES; 133 134static NSEvent *process_key_event(WIN32Server *svr, 135 HWND hwnd, WPARAM wParam, 136 LPARAM lParam, NSEventType eventType); 137static NSEvent *process_mouse_event(WIN32Server *svr, 138 HWND hwnd, WPARAM wParam, 139 LPARAM lParam, NSEventType eventType, 140 UINT uMsg); 141 142LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, 143 WPARAM wParam, LPARAM lParam); 144 145BOOL CALLBACK LoadDisplayMonitorInfo(HMONITOR hMonitor, 146 HDC hdcMonitor, 147 LPRECT lprcMonitor, 148 LPARAM dwData) 149{ 150 NSMutableArray *monitors = (NSMutableArray*)dwData; 151 W32DisplayMonitorInfo *info = [[W32DisplayMonitorInfo alloc] initWithHMonitor:hMonitor rect:lprcMonitor]; 152 153 NSDebugLog(@"screen %ld:hdc: %ld frame:top:%ld left:%ld right:%ld bottom:%ld frame:x:%f y:%f w:%f h:%f\n", 154 [monitors count], (long)hMonitor, 155 lprcMonitor->top, lprcMonitor->left, 156 lprcMonitor->right, lprcMonitor->bottom, 157 [info frame].origin.x, [info frame].origin.y, 158 [info frame].size.width, [info frame].size.height); 159 [monitors addObject:info]; 160 161 return TRUE; 162} 163 164 165@implementation WIN32Server 166 167- (BOOL) handlesWindowDecorations 168{ 169 return handlesWindowDecorations; 170} 171 172- (void) setHandlesWindowDecorations: (BOOL) b 173{ 174 handlesWindowDecorations = b; 175} 176 177- (BOOL) usesNativeTaskbar 178{ 179 return usesNativeTaskbar; 180} 181 182- (void) setUsesNativeTaskbar: (BOOL) b 183{ 184 usesNativeTaskbar = b; 185} 186 187- (void) callback: (id)sender 188{ 189 MSG msg; 190 WINBOOL bRet; 191//NSLog(@"Callback"); 192 while ((bRet = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) != 0) 193 { 194 if (msg.message == WM_QUIT) 195 { 196 // Exit the program 197 return; 198 } 199 if (bRet == -1) 200 { 201 // handle the error and possibly exit 202 } 203 else 204 { 205 // Original author disregarded a translate message call here stating 206 // that it would give extra character messages - BUT THIS KILLS IME 207 // MESSAGE PROCESSING!!!!! 208 TranslateMessage(&msg); 209 DispatchMessage(&msg); 210 } 211 } 212} 213 214- (BOOL) hasEvent 215{ 216 return (GetQueueStatus(QS_ALLEVENTS) != 0); 217} 218 219- (void) receivedEvent: (void*)data 220 type: (RunLoopEventType)type 221 extra: (void*)extra 222 forMode: (NSString*)mode 223{ 224#ifdef __CYGWIN__ 225 if (type == ET_RDESC) 226#else 227 if (type == ET_WINMSG) 228#endif 229 { 230 MSG *m = (MSG*)extra; 231 232 if (m->message == WM_QUIT) 233 { 234 [NSApp terminate: nil]; 235 // Exit the program 236 return; 237 } 238 else 239 { 240 TranslateMessage(m); 241 DispatchMessage(m); 242 } 243 } 244// if (mode != nil) [self callback: mode]; 245} 246 247 248- (NSEvent*) getEventMatchingMask: (unsigned)mask 249 beforeDate: (NSDate*)limit 250 inMode: (NSString*)mode 251 dequeue: (BOOL)flag 252{ 253// [self callback: nil]; 254 return [super getEventMatchingMask: mask 255 beforeDate: limit 256 inMode: mode 257 dequeue: flag]; 258} 259 260- (void) discardEventsMatchingMask: (unsigned)mask 261 beforeEvent: (NSEvent*)limit 262{ 263// [self callback: nil]; 264 [super discardEventsMatchingMask: mask 265 beforeEvent: limit]; 266} 267 268 269// server 270 271/* Initialize AppKit backend */ 272+ (void) initializeBackend 273{ 274 NSDebugLog(@"Initializing GNUstep win32 backend.\n"); 275 276 [GSDisplayServer setDefaultServerClass: [WIN32Server class]]; 277} 278 279- (void) _initWin32Context 280{ 281 WNDCLASSEXW wc; 282 hinstance = (HINSTANCE)GetModuleHandle(NULL); 283 284 // Register the main window class. 285 wc.cbSize = sizeof(wc); 286 wc.style = 0; 287 wc.lpfnWndProc = (WNDPROC) MainWndProc; 288 wc.cbClsExtra = 0; 289 // Keep extra space for each window, for OFF_LEVEL and OFF_ORDERED 290 wc.cbWndExtra = WIN_EXTRABYTES; 291 wc.hInstance = hinstance; 292 wc.hIcon = NULL;//currentAppIcon; 293 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 294 wc.hbrBackground = GetStockObject(WHITE_BRUSH); 295 wc.lpszMenuName = NULL; 296 wc.lpszClassName = L"GNUstepWindowClass"; 297 wc.hIconSm = NULL;//currentAppIcon; 298 299 if (!RegisterClassExW(&wc)) 300 return; 301 302 // FIXME We should use GetSysColor to get standard colours from MS Window and 303 // use them in NSColor 304 305 // Should we create a message only window here, so we can get events, even when 306 // no windows are created? 307} 308 309- (void) setupRunLoopInputSourcesForMode: (NSString*)mode 310{ 311 NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; 312 313#ifdef __CYGWIN__ 314 int fdMessageQueue; 315#define WIN_MSG_QUEUE_FNAME "/dev/windows" 316 317 // Open a file descriptor for the windows message queue 318 fdMessageQueue = open (WIN_MSG_QUEUE_FNAME, O_RDONLY); 319 if (fdMessageQueue == -1) 320 { 321 NSLog(@"Failed opening %s\n", WIN_MSG_QUEUE_FNAME); 322 exit(1); 323 } 324 [currentRunLoop addEvent: (void*)fdMessageQueue 325 type: ET_RDESC 326 watcher: (id<RunLoopEvents>)self 327 forMode: mode]; 328#else 329 [currentRunLoop addEvent: (void*)0 330 type: ET_WINMSG 331 watcher: (id<RunLoopEvents>)self 332 forMode: mode]; 333#endif 334} 335 336/** 337 338*/ 339- (id) initWithAttributes: (NSDictionary *)info 340{ 341// NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 342 343 self = [super initWithAttributes: info]; 344 345 if (self) 346 { 347 [self _initWin32Context]; 348 [super initWithAttributes: info]; 349 350 monitorInfo = [[NSMutableArray alloc] init]; 351 EnumDisplayMonitors(NULL, NULL, (MONITORENUMPROC)LoadDisplayMonitorInfo, (LPARAM)monitorInfo); 352 353 [self setupRunLoopInputSourcesForMode: NSDefaultRunLoopMode]; 354 [self setupRunLoopInputSourcesForMode: NSConnectionReplyMode]; 355 [self setupRunLoopInputSourcesForMode: NSModalPanelRunLoopMode]; 356 [self setupRunLoopInputSourcesForMode: NSEventTrackingRunLoopMode]; 357 358 [self setHandlesWindowDecorations: YES]; 359 [self setUsesNativeTaskbar: YES]; 360 361 [GSTheme theme]; 362 { // Check user defaults 363 NSUserDefaults *defs; 364 defs = [NSUserDefaults standardUserDefaults]; 365 366 if ([defs objectForKey: @"GSUseWMStyles"]) 367 { 368 NSWarnLog(@"Usage of 'GSUseWMStyles' as user default option is deprecated. " 369 @"This option will be ignored in future versions. " 370 @"You should use 'GSBackHandlesWindowDecorations' option."); 371 [self setHandlesWindowDecorations: ![defs boolForKey: @"GSUseWMStyles"]]; 372 } 373 if ([defs objectForKey: @"GSUsesWMTaskbar"]) 374 { 375 NSWarnLog(@"Usage of 'GSUseWMTaskbar' as user default option is deprecated. " 376 @"This option will be ignored in future versions. " 377 @"You should use 'GSBackUsesNativeTaskbar' option."); 378 [self setUsesNativeTaskbar: [defs boolForKey: @"GSUseWMTaskbar"]]; 379 } 380 381 if ([defs objectForKey: @"GSBackHandlesWindowDecorations"]) 382 { 383 [self setHandlesWindowDecorations: 384 [defs boolForKey: @"GSBackHandlesWindowDecorations"]]; 385 } 386 if ([defs objectForKey: @"GSBackUsesNativeTaskbar"]) 387 { 388 [self setUsesNativeTaskbar: 389 [defs boolForKey: @"GSBackUsesNativeTaskbar"]]; 390 } 391 } 392 } 393 return self; 394} 395 396- (void) _destroyWin32Context 397{ 398 UnregisterClass("GNUstepWindowClass", hinstance); 399} 400 401- (void) dealloc 402{ 403 [self _destroyWin32Context]; 404 RELEASE(monitorInfo); 405 [super dealloc]; 406} 407 408- (void) restrictWindow: (int)win toImage: (NSImage*)image 409{ 410 //TODO [self subclassResponsibility: _cmd]; 411} 412 413static HWND foundWindowHwnd = 0; 414static POINT findWindowAtPoint; 415 416LRESULT CALLBACK windowEnumCallback(HWND hwnd, LPARAM lParam) 417{ 418 if (foundWindowHwnd == 0 && hwnd != (HWND)lParam) 419 { 420 RECT r; 421 GetWindowRect(hwnd, &r); 422 423 if (PtInRect(&r,findWindowAtPoint) && IsWindowVisible(hwnd)) 424 { 425 NSWindow *window = GSWindowWithNumber((int)hwnd); 426 if (![window ignoresMouseEvents]) 427 foundWindowHwnd = hwnd; 428 } 429 } 430 return true; 431} 432 433- (int) findWindowAt: (NSPoint)screenLocation 434 windowRef: (int*)windowRef 435 excluding: (int)win 436{ 437 HWND hwnd; 438 POINT p; 439 440 p = GSScreenPointToMS(screenLocation); 441 /* 442 * This is insufficient: hwnd = WindowFromPoint(p); 443 * 444 * We must look through all windows until we find one 445 * which contains the specified point, does not have 446 * the ignoresMouseEvents property set, and is not 447 * the excluded window. This is done through the 448 * EnumWindows function which makes a call back to us 449 * for each window. 450 */ 451 foundWindowHwnd = 0; 452 findWindowAtPoint = p; 453 EnumWindows((WNDENUMPROC)windowEnumCallback, win); 454 hwnd = foundWindowHwnd; 455 456 *windowRef = (int)hwnd; // Any windows 457 458 return (int)hwnd; 459} 460 461// FIXME: The following methods wont work for multiple screens. 462// However, GetDeviceCaps docs say that on a system with multiple screens, 463// LOGPIXELSX/Y will be the same for all screens, so the following is OK. 464/* Screen information */ 465- (NSSize) resolutionForScreen: (int)screen 466{ 467 int windowsXRes, windowsYRes; 468 NSSize gnustepRes; 469 HDC hdc; 470 471 hdc = GetDC(NULL); 472 windowsXRes = GetDeviceCaps(hdc, LOGPIXELSX); 473 windowsYRes = GetDeviceCaps(hdc, LOGPIXELSY); 474 ReleaseDC(NULL, hdc); 475 476 // We want to return 72 to indicate no scaling factor, but the default 477 // DPI on Windows is 96. So, multiply the result by (72/96) = 0.75 478 479 gnustepRes = NSMakeSize(0.75 * windowsXRes, 0.75 * windowsYRes); 480 return gnustepRes; 481} 482 483- (NSRect) boundsForScreen: (int)screen 484{ 485 if (screen < [monitorInfo count]) 486 { 487 return [[monitorInfo objectAtIndex: screen] frame]; 488 } 489 return NSZeroRect; 490} 491 492- (HMONITOR) monitorHandleForScreen: (int)screen 493{ 494 if (screen < [monitorInfo count]) 495 { 496 return [[monitorInfo objectAtIndex: screen] hMonitor]; 497 } 498 else 499 { 500 NSWarnMLog(@"invalid screen number: %d", screen); 501 return NULL; 502 } 503} 504 505- (HDC) createHdcForScreen: (int)screen 506{ 507 HDC hdc = NULL; 508 HMONITOR hMonitor = [self monitorHandleForScreen: screen]; 509 510 if (hMonitor == NULL) 511 { 512 NSWarnMLog(@"error obtaining monitor handle for screen: %d", screen); 513 } 514 else 515 { 516 MONITORINFOEX mix = { 0 }; 517 mix.cbSize = sizeof(MONITORINFOEX); 518 519 if (GetMonitorInfo(hMonitor, (LPMONITORINFO)&mix) == 0) 520 { 521 NSWarnMLog(@"error obtaining monitor info for screen: %d status: %d", 522 screen, GetLastError()); 523 } 524 else 525 { 526 hdc = CreateDC("DISPLAY", mix.szDevice, NULL, NULL); 527 if (hdc == NULL) 528 { 529 NSWarnMLog(@"error creating HDC for screen: %d - status: %d", 530 screen, GetLastError()); 531 } 532 } 533 } 534 535 return hdc; 536} 537 538- (void) deleteScreenHdc: (HDC)hdc 539{ 540 if (hdc == NULL) 541 { 542 NSWarnMLog(@"HDC is NULL"); 543 } 544 else 545 { 546 DeleteDC(hdc); 547 } 548} 549 550- (NSWindowDepth) windowDepthForScreen: (int)screen 551{ 552 HDC hdc = [self createHdcForScreen:screen]; 553 int bits = 0; 554 555 if (hdc) 556 { 557 bits = GetDeviceCaps(hdc, BITSPIXEL) / 3; 558 //planes = GetDeviceCaps(hdc, PLANES); 559 //NSLog(@"bits %d planes %d", bits, planes); 560 [self deleteScreenHdc:hdc]; 561 } 562 return (_GSRGBBitValue | bits); 563} 564 565- (const NSWindowDepth *) availableDepthsForScreen: (int)screen 566{ 567 int ndepths = 1; 568 NSZone *defaultZone = NSDefaultMallocZone(); 569 NSWindowDepth *depths = 0; 570 571 depths = NSZoneMalloc(defaultZone, sizeof(NSWindowDepth)*(ndepths + 1)); 572 // FIXME 573 depths[0] = [self windowDepthForScreen: screen]; 574 depths[1] = 0; 575 576 return depths; 577} 578 579- (NSArray *) screenList 580{ 581 NSInteger index; 582 NSInteger nMonitors = [monitorInfo count]; 583 NSMutableArray *screenList = [NSMutableArray arrayWithCapacity:nMonitors]; 584 for (index = 0; index < nMonitors; ++index) 585 [screenList addObject:[NSNumber numberWithInt:index]]; 586 return [[screenList copy] autorelease]; 587} 588 589/** 590 Returns the handle of the module instance. */ 591- (void *) serverDevice 592{ 593 return hinstance; 594} 595 596/** 597 As the number of the window is actually is handle we return this. */ 598- (void *) windowDevice: (int)win 599{ 600 return (void *)win; 601} 602 603- (void) beep 604{ 605 Beep(400, 500); 606} 607 608/* 609 styles are mapped between the two systems 610 611 NSBorderlessWindowMask 0 612 NSTitledWindowMask 1 613 NSClosableWindowMask 2 614 NSMiniaturizableWindowMask 4 615 NSResizableWindowMask 8 616 NSIconWindowMask 64 617 NSMiniWindowMask 128 618 619 NSMenu(style) = NSTitledWindowMask | NSClosableWindowMask =3; 620*/ 621- (DWORD) windowStyleForGSStyle: (unsigned int) style 622{ 623 DWORD wstyle = 0; 624 625 if ([self handlesWindowDecorations] == NO) 626 return WS_POPUP | WS_CLIPCHILDREN; 627 628 if (style == 0) 629 { 630 wstyle = WS_POPUP; 631 } 632 else 633 { 634 if ((style & NSTitledWindowMask) == NSTitledWindowMask) 635 wstyle |= WS_CAPTION; 636 637 if ((style & NSClosableWindowMask) == NSClosableWindowMask) 638 wstyle |= WS_CAPTION | WS_SYSMENU; 639 640 if ((style & NSMiniaturizableWindowMask) == NSMiniaturizableWindowMask) 641 wstyle |= WS_MINIMIZEBOX | WS_SYSMENU; 642 643 if ((style & NSResizableWindowMask) == NSResizableWindowMask) 644 wstyle |= WS_SIZEBOX | WS_MAXIMIZEBOX; 645 646 if (((style & NSMiniWindowMask) == NSMiniWindowMask) 647 || ((style & NSIconWindowMask) == NSIconWindowMask)) 648 wstyle |= WS_ICONIC; 649 650 if (wstyle == 0) 651 wstyle = WS_POPUP; 652 } 653 654 //NSLog(@"Window wstyle %d for style %d", wstyle, style); 655 return wstyle | WS_CLIPCHILDREN; 656} 657 658- (DWORD) exwindowStyleForGSStyle: (unsigned int) style 659{ 660 DWORD estyle = 0; 661 662 if ((style & NSUtilityWindowMask) == NSUtilityWindowMask) 663 { 664 // WS_EX_TOOLWINDOW gives windows a thinner frame, like NSUtilityWindowMask 665 estyle |= WS_EX_TOOLWINDOW; 666 } 667 668 if ([self usesNativeTaskbar]) 669 { 670 // We will put all bordered windows except utility windows in the 671 // taskbar. Utility windows don't need to be in the taskbar since 672 // they are in the floating window level, so always visible. 673 674 if (style == NSBorderlessWindowMask) 675 { 676 // WS_EX_TOOLWINDOW also prevents windows from appearing in the taskbar. 677 estyle |= WS_EX_TOOLWINDOW; 678 } 679 else if ((style & NSUtilityWindowMask) == 0) 680 { 681 // WS_EX_APPWINDOW requests that the window appear in the taskbar 682 estyle |= WS_EX_APPWINDOW; 683 } 684 } 685 else /* (NO == [self usesNativeTaskbar]) */ 686 { 687 // Prevent all windows from appearing in the taskbar. As an undesired 688 // side effect this will give all windows with frames thin "tool window" 689 // frames. We could also get rid of the taskbar buttons by creating 690 // a hidden window, and setting it as the parent of all other windows, 691 // but that would be more complicated to manage. 692 // See http://msdn.microsoft.com/en-us/library/bb776822(v=VS.85).aspx#Managing_Taskbar_But 693 694 estyle |= WS_EX_TOOLWINDOW; 695 } 696 697 return estyle; 698} 699 700- (void) resizeBackingStoreFor: (HWND)hwnd 701{ 702#if (BUILD_GRAPHICS==GRAPHICS_winlib) 703 WIN_INTERN *win = (WIN_INTERN *)GetWindowLong((HWND)hwnd, GWL_USERDATA); 704 705 // FIXME: We should check if the size really did change. 706 if (win->useHDC) 707 { 708 HDC hdc, hdc2; 709 HBITMAP hbitmap; 710 HGDIOBJ old; 711 RECT r; 712 713 old = SelectObject(win->hdc, win->old); 714 DeleteObject(old); 715 DeleteDC(win->hdc); 716 win->hdc = NULL; 717 win->old = NULL; 718 719 GetClientRect((HWND)hwnd, &r); 720 hdc = GetDC((HWND)hwnd); 721 hdc2 = CreateCompatibleDC(hdc); 722 hbitmap = CreateCompatibleBitmap(hdc, r.right - r.left, r.bottom - r.top); 723 win->old = SelectObject(hdc2, hbitmap); 724 win->hdc = hdc2; 725 726 ReleaseDC((HWND)hwnd, hdc); 727 728 // After resizing the backing store, we need to redraw the window 729 win->backingStoreEmpty = YES; 730 } 731#endif 732} 733 734- (BOOL) displayEvent: (unsigned int)uMsg; // diagnotic filter 735{ 736 [self subclassResponsibility: _cmd]; 737 return YES; 738} 739 740// main event loop 741 742/* 743 * Reset all of our flags before the next run through the event switch 744 * 745 */ 746- (void) setFlagsforEventLoop: (HWND)hwnd 747{ 748 flags._eventHandled = NO; 749 750 // future house keeping can go here 751} 752 753- (void) freeCompositionStringForWindow: (HWND)hwnd 754{ 755 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 756 757 // Free any buffer(s)... 758 if (imeInfo->compString) 759 free(imeInfo->compString); 760 imeInfo->compString = NULL; 761 imeInfo->compStringLength = 0; 762} 763 764- (void) freeReadStringForWindow: (HWND)hwnd 765{ 766 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 767 768 // Free any buffer(s)... 769 if (imeInfo->readString) 770 free(imeInfo->readString); 771 imeInfo->readString = NULL; 772 imeInfo->readStringLength = 0; 773} 774 775- (void) freeCompositionInfoForWindow: (HWND)hwnd 776{ 777 // Clear information... 778 [self freeCompositionStringForWindow: hwnd]; 779 [self freeReadStringForWindow: hwnd]; 780} 781 782- (void) getCompositionStringForWindow: (HWND)hwnd 783{ 784 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 785 HIMC immc = ImmGetContext(hwnd); 786 787 // Current composition string... 788 imeInfo->compStringLength = ImmGetCompositionStringW(immc, GCS_COMPSTR, NULL, 0); 789 imeInfo->compString = malloc(imeInfo->compStringLength+sizeof(TCHAR)); 790 ImmGetCompositionStringW(immc, GCS_COMPSTR, imeInfo->compString, imeInfo->compStringLength); 791 792 // Cleanup... 793 ImmReleaseContext(hwnd, immc); 794} 795 796- (void) getReadStringForWindow: (HWND)hwnd 797{ 798 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 799 HIMC immc = ImmGetContext(hwnd); 800 801 // Current read string... 802 imeInfo->readStringLength = ImmGetCompositionStringW(immc, GCS_COMPREADSTR, NULL, 0); 803 imeInfo->readString = malloc(imeInfo->readStringLength+sizeof(TCHAR)); 804 ImmGetCompositionStringW(immc, GCS_COMPREADSTR, imeInfo->readString, imeInfo->readStringLength); 805 806 // Cleanup... 807 ImmReleaseContext(hwnd, immc); 808} 809 810- (void) saveCompositionInfoForWindow: (HWND)hwnd 811{ 812 // First, ensure we've cleared out any saved information... 813 [self freeCompositionInfoForWindow: hwnd]; 814 815 // Current composition string... 816 [self getCompositionStringForWindow: hwnd]; 817 818 // Current read string... 819 [self getReadStringForWindow: hwnd]; 820} 821 822- (void) setCompositionStringForWindow: (HWND)hwnd 823{ 824 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 825 HIMC immc = ImmGetContext(hwnd); 826 827 // Restore the state... 828 ImmSetCompositionStringW(immc, SCS_SETSTR, imeInfo->compString, imeInfo->compStringLength, NULL, 0); 829 830 // Clear out any saved information... 831 [self freeCompositionInfoForWindow: hwnd]; 832 833 // Cleanup... 834 ImmReleaseContext(hwnd, immc); 835} 836 837- (void) setReadStringForWindow: (HWND)hwnd 838{ 839 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 840 HIMC immc = ImmGetContext(hwnd); 841 842 // Restore the state... 843 ImmSetCompositionStringW(immc, SCS_SETSTR, NULL, 0, imeInfo->readString, imeInfo->readStringLength); 844 845 // Clear out any saved information... 846 [self freeReadStringForWindow: hwnd]; 847 848 // Cleanup... 849 ImmReleaseContext(hwnd, immc); 850} 851 852- (void) restoreCompositionInfoForWindow: (HWND)hwnd 853{ 854 // Restore the state... 855 [self setCompositionStringForWindow: hwnd]; 856 857 // Restore the read string... 858 [self setReadStringForWindow: hwnd]; 859} 860 861- (LRESULT) imnMessage: (HWND)hwnd : (WPARAM)wParam : (LPARAM)lParam 862{ 863 HIMC immc = ImmGetContext(hwnd); 864 switch (wParam) 865 { 866 case IMN_CLOSESTATUSWINDOW: 867 { 868 NSDebugLog(@"IMN_CLOSESTATUSWINDOW: hwnd: %p wParam: %p lParam: %p immc: %p\n", 869 hwnd, wParam, lParam, immc); 870 if (immc) 871 { 872 ImmNotifyIME(immc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 873 HideCaret(hwnd); 874 DestroyCaret(); 875 } 876 break; 877 } 878 879 case IMN_SETOPENSTATUS: 880 { 881 NSDebugLog(@"IMN_SETOPENSTATUS: hwnd: %p wParam: %p lParam: %p immc: %p\n", 882 hwnd, wParam, lParam, immc); 883 if (immc) 884 { 885 NSDebugLog(@"IMN_SETOPENSTATUS: openstatus: %d\n", ImmGetOpenStatus(immc)); 886 887 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 888 if (imeInfo == NULL) 889 { 890 NSDebugLog(@"IMN_SETOPENSTATUS: IME info pointer is NULL\n"); 891 } 892 else 893 { 894 if (ImmGetOpenStatus(immc)) 895 { 896 if (imeInfo->isOpened == NO) 897 { 898 // Restore previous information... 899#if defined(IME_SAVERESTORE_COMPOSITIONINFO) 900 [self restoreCompositionInfoForWindow: hwnd]; 901#else 902 ImmNotifyIME(immc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 903#endif 904 } 905 } 906 else if (imeInfo->isOpened == YES) 907 { 908 // Save current information... 909 [self saveCompositionInfoForWindow: hwnd]; 910 } 911 912 // Save state... 913 imeInfo->isOpened = ImmGetOpenStatus(immc); 914 } 915 916#if defined(USE_SYSTEM_CARET) 917 if (ImmGetOpenStatus(immc)) 918 ShowCaret(hwnd); 919 else 920 HideCaret(hwnd); 921#endif 922 923#if defined(IME_SETCOMPOSITIONFONT) 924 { 925 LOGFONT logFont; 926 ImmGetCompositionFont(immc, &logFont); 927 LOGFONT newFont = logFont; 928 newFont.lfCharSet = ((logFont.lfCharSet == DEFAULT_CHARSET) ? OEM_CHARSET : DEFAULT_CHARSET); 929 ImmSetCompositionFont(immc, &newFont); 930 NSDebugLog(@"IMN_SETOPENSTATUS: changing logfont from: %d to: %d\n", logFont.lfCharSet, newFont.lfCharSet); 931 } 932#endif 933 } 934 break; 935 } 936 937 case IMN_OPENSTATUSWINDOW: 938 { 939 NSDebugLog(@"IMN_OPENSTATUSWINDOW: hwnd: %p wParam: %p lParam: %p immc: %p\n", 940 hwnd, wParam, lParam, immc); 941 if (immc) 942 { 943 NSDebugLog(@"IMN_OPENSTATUSWINDOW: openstatus: %d\n", ImmGetOpenStatus(immc)); 944 LOGFONT logFont; 945 { 946 ImmGetCompositionFont(immc, &logFont); 947 NSDebugLog(@"IMN_OPENSTATUSWINDOW: logfont - width: %d height: %d\n", 948 logFont.lfWidth, logFont.lfHeight); 949 } 950#if defined(USE_SYSTEM_CARET) 951 CreateCaret(hwnd, NULL, logFont.lfWidth, logFont.lfHeight); 952 if (ImmGetOpenStatus(immc)) 953 ShowCaret(hwnd); 954 else 955 HideCaret(hwnd); 956#endif 957 } 958 break; 959 } 960 961 case IMN_CHANGECANDIDATE: 962 NSDebugLog(@"IMN_CHANGECANDIDATE: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 963 break; 964 965 case IMN_CLOSECANDIDATE: 966 NSDebugLog(@"IMN_CLOSECANDIDATE: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 967 break; 968 969 case IMN_OPENCANDIDATE: 970 NSDebugLog(@"IMN_OPENCANDIDATE: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 971 break; 972 973 case IMN_SETCONVERSIONMODE: 974 { 975 NSDebugLog(@"IMN_SETCONVERSIONMODE: hwnd: %p wParam: %p lParam: %p immc: %p\n", 976 hwnd, wParam, lParam, immc); 977 if (immc) 978 { 979 DWORD conversion; 980 DWORD sentence; 981 if (ImmGetConversionStatus(immc, &conversion, &sentence) == 0) 982 NSDebugLog(@"IMN_SETCONVERSIONMODE: error getting conversion status: %d\n", GetLastError()); 983 else 984 NSDebugLog(@"IMN_SETCONVERSIONMODE: conversion: %p sentence: %p\n", conversion, sentence); 985 } 986 break; 987 } 988 989 case IMN_SETSENTENCEMODE: 990 { 991 NSDebugLog(@"IMN_SETSENTENCEMODE: hwnd: %p wParam: %p lParam: %p immc: %p\n", 992 hwnd, wParam, lParam, immc); 993 if (immc) 994 { 995 DWORD conversion; 996 DWORD sentence; 997 if (ImmGetConversionStatus(immc, &conversion, &sentence) == 0) 998 NSDebugLog(@"IMN_SETSENTENCEMODE: error getting conversion status: %d\n", GetLastError()); 999 else 1000 NSDebugLog(@"IMN_SETSENTENCEMODE: conversion: %p sentence: %p\n", conversion, sentence); 1001 } 1002 break; 1003 } 1004 1005 case IMN_SETCANDIDATEPOS: 1006 NSDebugLog(@"IMN_SETCANDIDATEPOS: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1007 break; 1008 1009 case IMN_SETCOMPOSITIONFONT: 1010 { 1011 NSDebugLog(@"IMN_SETCOMPOSITIONFONT: hwnd: %p wParam: %p lParam: %p immc: %p\n", 1012 hwnd, wParam, lParam, immc); 1013 if (immc) 1014 { 1015#if defined(IME_SETCOMPOSITIONFONT) 1016 { 1017 LOGFONT logFont; 1018 ImmGetCompositionFont(immc, &logFont); 1019 NSDebugLog(@"IMN_SETCOMPOSITIONFONT: new character set: %d\n", logFont.lfCharSet); 1020 } 1021#endif 1022 } 1023 break; 1024 } 1025 1026 case IMN_SETCOMPOSITIONWINDOW: 1027 NSDebugLog(@"IMN_SETCOMPOSITIONWINDOW: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1028 break; 1029 1030 case IMN_SETSTATUSWINDOWPOS: 1031 NSDebugLog(@"IMN_SETSTATUSWINDOWPOS: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1032 break; 1033 1034 case IMN_GUIDELINE: 1035 NSDebugLog(@"IMN_GUIDELINE: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1036 break; 1037 1038 case IMN_PRIVATE: 1039 NSDebugLog(@"IMN_PRIVATE: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1040 break; 1041 1042 default: 1043 NSDebugLog(@"Unknown IMN message: %p hwnd: %p\n", wParam, hwnd); 1044 break; 1045 } 1046 1047 // Release the IME context... 1048 ImmReleaseContext(hwnd, immc); 1049 1050 return 0; 1051} 1052 1053- (NSEvent*)imeCompositionMessage: (HWND)hwnd : (WPARAM)wParam : (LPARAM)lParam 1054{ 1055 NSDebugLog(@"WM_IME_COMPOSITION: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1056 HIMC immc = ImmGetContext(hwnd); 1057 if (immc == 0) 1058 { 1059 NSWarnMLog(@"IMMContext is NULL\n"); 1060 } 1061 else if (lParam & GCS_RESULTSTR) 1062 { 1063 // Update our composition string information... 1064 LONG length = ImmGetCompositionStringW(immc, GCS_RESULTSTR, NULL, 0); 1065 NSDebugLog(@"length: %d\n", length); 1066 if (length) 1067 { 1068 TCHAR composition[length+sizeof(TCHAR)]; 1069 length = ImmGetCompositionStringW(immc, GCS_RESULTSTR, &composition, length); 1070 { 1071 int index; 1072 for (index = 0; index < length; ++index) 1073 NSDebugLog(@"%2.2X ", composition[index]); 1074 } 1075 NSDebugLog(@"composition (uKeys): %@\n", 1076 [NSString stringWithCharacters: (unichar*)composition length: length]); 1077 } 1078 ImmReleaseContext(hwnd, immc); 1079 } 1080 1081 return 0; 1082} 1083 1084- (LRESULT) imeCharacter: (HWND)hwnd : (WPARAM)wParam : (LPARAM)lParam 1085{ 1086 BYTE keyState[256]; 1087 1088 // Get the current key states... 1089 GetKeyboardState(keyState); 1090 1091 // key events should go to the key window if we have one (Windows' focus window isn't always appropriate) 1092 int windowNumber = [[NSApp keyWindow] windowNumber]; 1093 if (windowNumber == 0) 1094 windowNumber = (int)hwnd; 1095 1096 /* FIXME: How do you guarentee a context is associated with an event? */ 1097 NSGraphicsContext *gcontext = GSCurrentContext(); 1098 LONG ltime = GetMessageTime(); 1099 NSTimeInterval time = ltime / 1000.0f; 1100 BOOL repeat = (lParam & 0xFFFF) != 0; 1101 unsigned int eventFlags = mask_for_keystate(keyState); 1102 DWORD pos = GetMessagePos(); 1103 NSPoint eventLocation = MSWindowPointToGS(self, hwnd, GET_X_LPARAM(pos), GET_Y_LPARAM(pos)); 1104 NSString *keys = [NSString stringWithCharacters: (unichar*)&wParam length: 1]; 1105 NSString *ukeys = [NSString stringWithCharacters: (unichar*)&wParam length: 1]; 1106 1107 // Create a NSKeyDown message... 1108 NSEvent *ev = [NSEvent keyEventWithType: NSKeyDown 1109 location: eventLocation 1110 modifierFlags: eventFlags 1111 timestamp: time 1112 windowNumber: windowNumber 1113 context: gcontext 1114 characters: keys 1115 charactersIgnoringModifiers: ukeys 1116 isARepeat: repeat 1117 keyCode: wParam]; 1118 1119 // Post it... 1120 [GSCurrentServer() postEvent: ev atStart: NO]; 1121 1122 // then an associated NSKeyUp message... 1123 ev = [NSEvent keyEventWithType: NSKeyUp 1124 location: eventLocation 1125 modifierFlags: eventFlags 1126 timestamp: time 1127 windowNumber: windowNumber 1128 context: gcontext 1129 characters: keys 1130 charactersIgnoringModifiers: ukeys 1131 isARepeat: repeat 1132 keyCode: wParam]; 1133 1134 // Post it... 1135 [GSCurrentServer() postEvent: ev atStart: NO]; 1136 1137 return 0; 1138} 1139 1140- (LRESULT) windowEventProc: (HWND)hwnd : (UINT)uMsg 1141 : (WPARAM)wParam : (LPARAM)lParam 1142{ 1143 NSEvent *ev = nil; 1144 1145 [self setFlagsforEventLoop: hwnd]; 1146 1147 switch (uMsg) 1148 { 1149 case WM_MOUSELEAVE: 1150 { 1151 /* If the cursor leave the window remove the GNUstep cursors, send 1152 * the appropriate message and tell GNUstep stop handling 1153 * the cursor. 1154 */ 1155 NSEvent *e; 1156 e = [NSEvent otherEventWithType: NSAppKitDefined 1157 location: NSMakePoint(-1,-1) 1158 modifierFlags: 0 1159 timestamp: 0 1160 windowNumber: (int)hwnd 1161 context: GSCurrentContext() 1162 subtype: GSAppKitWindowLeave 1163 data1: 0 1164 data2: 0]; 1165 [GSCurrentServer() postEvent: e atStart: YES]; 1166 should_handle_cursor = NO; 1167 } 1168 break; 1169 case WM_SIZING: 1170 return [self decodeWM_SIZINGParams: hwnd : wParam : lParam]; 1171 break; 1172 case WM_NCCREATE: 1173 return [self decodeWM_NCCREATEParams: wParam : lParam : hwnd]; 1174 break; 1175 case WM_NCCALCSIZE: 1176 [self decodeWM_NCCALCSIZEParams: wParam : lParam : hwnd]; 1177 break; 1178 case WM_NCACTIVATE: 1179 [self decodeWM_NCACTIVATEParams: wParam : lParam : hwnd]; 1180 break; 1181 case WM_NCPAINT: 1182 if ([self handlesWindowDecorations]) 1183 [self decodeWM_NCPAINTParams: wParam : lParam : hwnd]; 1184 break; 1185 case WM_SHOWWINDOW: 1186 //[self decodeWM_SHOWWINDOWParams: wParam : lParam : hwnd]; 1187 break; 1188 case WM_NCDESTROY: 1189 [self decodeWM_NCDESTROYParams: wParam : lParam : hwnd]; 1190 break; 1191 case WM_GETTEXT: 1192 [self decodeWM_GETTEXTParams: wParam : lParam : hwnd]; 1193 break; 1194 case WM_STYLECHANGING: 1195 break; 1196 case WM_STYLECHANGED: 1197 break; 1198 case WM_GETMINMAXINFO: 1199 return [self decodeWM_GETMINMAXINFOParams: wParam : lParam : hwnd]; 1200 break; 1201 case WM_CREATE: 1202 return [self decodeWM_CREATEParams: wParam : lParam : hwnd]; 1203 break; 1204 case WM_WINDOWPOSCHANGING: 1205 [self decodeWM_WINDOWPOSCHANGINGParams: wParam : lParam : hwnd]; 1206 break; 1207 case WM_WINDOWPOSCHANGED: 1208 [self decodeWM_WINDOWPOSCHANGEDParams: wParam : lParam : hwnd]; 1209 break; 1210 case WM_MOVE: 1211 return [self decodeWM_MOVEParams: hwnd : wParam : lParam]; 1212 break; 1213 case WM_MOVING: 1214 return [self decodeWM_MOVINGParams: hwnd : wParam : lParam]; 1215 break; 1216 case WM_SIZE: 1217 return [self decodeWM_SIZEParams: hwnd : wParam : lParam]; 1218 break; 1219 case WM_ENTERSIZEMOVE: 1220 return [self decodeWM_ENTERSIZEMOVEParams: wParam : lParam : hwnd]; 1221 break; 1222 case WM_EXITSIZEMOVE: 1223 return [self decodeWM_EXITSIZEMOVEParams: wParam : lParam : hwnd]; 1224 break; 1225 case WM_ACTIVATE: 1226 if ((int)lParam !=0) 1227 [self decodeWM_ACTIVEParams: wParam : lParam : hwnd]; 1228 break; 1229 case WM_ACTIVATEAPP: 1230 return [self decodeWM_ACTIVEAPPParams: hwnd : wParam : lParam]; 1231 break; 1232 case WM_SETFOCUS: 1233 return [self decodeWM_SETFOCUSParams: wParam : lParam : hwnd]; 1234 break; 1235 case WM_KILLFOCUS: 1236 if (wParam == (int)hwnd) 1237 return 0; 1238 else 1239 [self decodeWM_KILLFOCUSParams: wParam : lParam : hwnd]; 1240 break; 1241 case WM_SETCURSOR: 1242 if (wParam == (int)hwnd) 1243 { 1244 // Check if GNUstep should handle the cursor. 1245 if (should_handle_cursor) 1246 { 1247 flags._eventHandled = YES; 1248 } 1249 } 1250 break; 1251 case WM_QUERYOPEN: 1252 [self decodeWM_QUERYOPENParams: wParam : lParam : hwnd]; 1253 break; 1254 case WM_CAPTURECHANGED: 1255 [self decodeWM_CAPTURECHANGEDParams: wParam : lParam : hwnd]; 1256 break; 1257 case WM_ERASEBKGND: 1258 return [self decodeWM_ERASEBKGNDParams: wParam : lParam : hwnd]; 1259 break; 1260 case WM_PAINT: 1261 [self decodeWM_PAINTParams: (WPARAM)wParam : (LPARAM)lParam : (HWND)hwnd]; 1262 break; 1263 case WM_SYNCPAINT: 1264 if ([self handlesWindowDecorations]) 1265 [self decodeWM_SYNCPAINTParams: wParam : lParam : hwnd]; 1266 break; 1267 case WM_CLOSE: 1268 [self decodeWM_CLOSEParams: wParam : lParam : hwnd]; 1269 break; 1270 case WM_DESTROY: 1271 [self decodeWM_DESTROYParams: wParam : lParam : hwnd]; 1272 break; 1273 case WM_QUIT: 1274 break; 1275 case WM_USER: 1276 break; 1277 case WM_APP: 1278 break; 1279 case WM_ENTERMENULOOP: 1280 /* If the user open a native contextual menu (a non GNUstep window) 1281 * send the appropriate message and tell GNUstep stop handling 1282 * the cursor. 1283 */ 1284 if (wParam) 1285 { 1286 NSEvent *e; 1287 [GSWindowWithNumber((int)hwnd) resetCursorRects]; 1288 e = [NSEvent otherEventWithType: NSAppKitDefined 1289 location: NSMakePoint(-1,-1) 1290 modifierFlags: 0 1291 timestamp: 0 1292 windowNumber: (int)hwnd 1293 context: GSCurrentContext() 1294 subtype: GSAppKitWindowLeave 1295 data1: 0 1296 data2: 0]; 1297 [GSCurrentServer() postEvent: e atStart: YES]; 1298 should_handle_cursor = NO; 1299 } 1300 break; 1301 case WM_EXITMENULOOP: 1302 break; 1303 case WM_INITMENU: 1304 break; 1305 case WM_MENUSELECT: 1306 break; 1307 case WM_ENTERIDLE: 1308 break; 1309 case WM_COMMAND: 1310 [self decodeWM_COMMANDParams: wParam : lParam : hwnd]; 1311 break; 1312 case WM_THEMECHANGED: 1313 [self decodeWM_THEMECHANGEDParams: wParam : lParam : hwnd]; 1314 break; 1315 case WM_SYSKEYDOWN: //KEYBOARD 1316 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "SYSKEYDOWN", hwnd); 1317 ev = process_key_event(self, hwnd, wParam, lParam, NSKeyDown); 1318 break; 1319 case WM_SYSKEYUP: //KEYBOARD 1320 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "SYSKEYUP", hwnd); 1321 ev = process_key_event(self, hwnd, wParam, lParam, NSKeyUp); 1322 break; 1323 case WM_SYSCOMMAND: 1324 [self decodeWM_SYSCOMMANDParams: wParam : lParam : hwnd]; 1325 break; 1326 case WM_HELP: 1327 break; 1328 //case WM_GETICON: 1329 //return [self decodeWM_GETICONParams: wParam : lParam : hwnd]; 1330 //break; 1331 //case WM_SETICON: 1332 //return [self decodeWM_SETICONParams: wParam : lParam : hwnd]; 1333 //break; 1334 case WM_CANCELMODE: 1335 break; 1336 case WM_ENABLE: 1337 case WM_CHILDACTIVATE: 1338 break; 1339 case WM_NULL: 1340 break; 1341 1342 case WM_NCHITTEST: //MOUSE 1343 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCHITTEST", hwnd); 1344 break; 1345 case WM_NCMOUSEMOVE: //MOUSE 1346 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCMOUSEMOVE", hwnd); 1347 break; 1348 case WM_NCLBUTTONDOWN: //MOUSE 1349 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCLBUTTONDOWN", hwnd); 1350 break; 1351 case WM_NCLBUTTONUP: //MOUSE 1352 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCLBUTTONUP", hwnd); 1353 break; 1354 case WM_MOUSEACTIVATE: //MOUSE 1355 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "MOUSEACTIVATE", hwnd); 1356 break; 1357 case WM_MOUSEMOVE: //MOUSE 1358 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "MOUSEMOVE", hwnd); 1359 ev = process_mouse_event(self, hwnd, wParam, lParam, NSMouseMoved, uMsg); 1360 break; 1361 case WM_LBUTTONDOWN: //MOUSE 1362 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "LBUTTONDOWN", hwnd); 1363 //[self decodeWM_LBUTTONDOWNParams: (WPARAM)wParam : (LPARAM)lParam : (HWND)hwnd]; 1364 ev = process_mouse_event(self, hwnd, wParam, lParam, NSLeftMouseDown, uMsg); 1365 break; 1366 case WM_LBUTTONUP: //MOUSE 1367 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "LBUTTONUP", hwnd); 1368 ev = process_mouse_event(self, hwnd, wParam, lParam, NSLeftMouseUp, uMsg); 1369 break; 1370 case WM_LBUTTONDBLCLK: //MOUSE 1371 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "LBUTTONDBLCLK", hwnd); 1372 break; 1373 case WM_MBUTTONDOWN: //MOUSE 1374 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "MBUTTONDOWN", hwnd); 1375 ev = process_mouse_event(self, hwnd, wParam, lParam, NSOtherMouseDown, uMsg); 1376 break; 1377 case WM_MBUTTONUP: //MOUSE 1378 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "MBUTTONUP", hwnd); 1379 ev = process_mouse_event(self, hwnd, wParam, lParam, NSOtherMouseUp, uMsg); 1380 break; 1381 case WM_MBUTTONDBLCLK: //MOUSE 1382 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "MBUTTONDBLCLK", hwnd); 1383 break; 1384 case WM_RBUTTONDOWN: //MOUSE 1385 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "RBUTTONDOWN", hwnd); 1386 ev = process_mouse_event(self, hwnd, wParam, lParam, NSRightMouseDown, uMsg); 1387 break; 1388 case WM_RBUTTONUP: //MOUSE 1389 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "RBUTTONUP", hwnd); 1390 ev = process_mouse_event(self, hwnd, wParam, lParam, NSRightMouseUp, uMsg); 1391 break; 1392 case WM_RBUTTONDBLCLK: //MOUSE 1393 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "RBUTTONDBLCLK", hwnd); 1394 break; 1395 case WM_MOUSEHWHEEL: //MOUSE 1396 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "MOUSEHWHEEL", hwnd); 1397 ev = process_mouse_event(self, hwnd, wParam, lParam, NSScrollWheel, uMsg); 1398 break; 1399 1400 case WM_MOUSEWHEEL: //MOUSE 1401 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "MOUSEWHEEL", hwnd); 1402 ev = process_mouse_event(self, hwnd, wParam, lParam, NSScrollWheel, uMsg); 1403 break; 1404 1405 // WINDOWS IME PROCESSING MESSAGES... 1406 case WM_IME_NOTIFY: 1407 [self imnMessage: hwnd : wParam : lParam]; 1408 break; 1409 case WM_IME_REQUEST: 1410 NSDebugLog(@"WM_IME_REQUEST: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1411 break; 1412 case WM_IME_SELECT: 1413 NSDebugLog(@"WM_IME_SELECT: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1414 break; 1415 case WM_IME_SETCONTEXT: 1416 NSDebugLog(@"WM_IME_SETCONTEXT: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1417 break; 1418 case WM_IME_STARTCOMPOSITION: 1419 { 1420 NSDebugLog(@"WM_IME_STARTCOMPOSITION: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1421 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 1422 if (imeInfo) 1423 imeInfo->isComposing = YES; 1424 break; 1425 } 1426 case WM_IME_ENDCOMPOSITION: 1427 { 1428 NSDebugLog(@"WM_IME_ENDCOMPOSITION: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1429 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 1430 if (imeInfo) 1431 imeInfo->isComposing = NO; 1432 break; 1433 } 1434 case WM_IME_COMPOSITION: 1435 { 1436 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 1437 if (imeInfo && imeInfo->isComposing) 1438 ev = [self imeCompositionMessage: hwnd : wParam : lParam]; 1439 break; 1440 } 1441 case WM_IME_COMPOSITIONFULL: 1442 NSDebugLog(@"WM_IME_COMPOSITIONFULL: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1443 break; 1444 case WM_IME_KEYDOWN: 1445 NSDebugLog(@"WM_IME_KEYDOWN: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1446 if (wParam == 0xd) // Carriage return... 1447 { 1448 HIMC immc = ImmGetContext(hwnd); 1449 if (immc) 1450 { 1451 // If currently in a composition sequence in the IMM... 1452 ImmNotifyIME(immc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); 1453 1454 // Release the context... 1455 ImmReleaseContext(hwnd, immc); 1456 } 1457 } 1458 1459 // Don't pass this message on for processing... 1460 flags._eventHandled = YES; 1461 break; 1462 case WM_IME_KEYUP: 1463 NSDebugLog(@"WM_IME_KEYUP: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1464 break; 1465 case WM_IME_CHAR: 1466 return [self imeCharacter: hwnd : wParam : lParam]; 1467 break; 1468 1469 case WM_CHAR: 1470 NSDebugLog(@"WM_CHAR: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1471 break; 1472 1473 case WM_INPUTLANGCHANGEREQUEST: 1474 NSDebugLog(@"WM_INPUTLANGCHANGEREQUEST: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1475 break; 1476 case WM_INPUTLANGCHANGE: 1477 NSDebugLog(@"WM_INPUTLANGCHANGE: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1478 break; 1479 1480 case WM_KEYDOWN: //KEYBOARD 1481 NSDebugLog(@"WM_KEYDOWN: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1482 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "KEYDOWN", hwnd); 1483 ev = process_key_event(self, hwnd, wParam, lParam, NSKeyDown); 1484 break; 1485 case WM_KEYUP: //KEYBOARD 1486 NSDebugLog(@"WM_KEYUP: hwnd: %p wParam: %p lParam: %p\n", hwnd, wParam, lParam); 1487 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "KEYUP", hwnd); 1488 ev = process_key_event(self, hwnd, wParam, lParam, NSKeyUp); 1489 break; 1490 1491 case WM_POWERBROADCAST: //SYSTEM 1492 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "POWERBROADCAST", hwnd); 1493 break; 1494 case WM_TIMECHANGE: //SYSTEM 1495 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "TIMECHANGE", hwnd); 1496 break; 1497 case WM_DEVICECHANGE: //SYSTEM 1498 NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "DEVICECHANGE", hwnd); 1499 break; 1500 1501 default: 1502 // Process all other messages. 1503 NSDebugLLog(@"NSEvent", @"Got unhandled Message %d for %d", uMsg, hwnd); 1504 break; 1505 } 1506 1507 /* 1508 * see if the event was handled in the the main loop or in the 1509 * menu loop. if eventHandled = YES then we are done and need to 1510 * tell the windows event handler we are finished 1511 */ 1512 if (flags._eventHandled == YES) 1513 return 0; 1514 1515 if (ev != nil) 1516 { 1517 [GSCurrentServer() postEvent: ev atStart: NO]; 1518 return 0; 1519 } 1520 1521 /* 1522 * We did not care about the event, return it back to the windows 1523 * event handler 1524 */ 1525 return DefWindowProcW(hwnd, uMsg, wParam, lParam); 1526} 1527 1528- glContextClass 1529{ 1530#ifdef HAVE_WGL 1531 return [Win32GLContext class]; 1532#else 1533 return nil; 1534#endif 1535} 1536 1537- glPixelFormatClass 1538{ 1539#ifdef HAVE_WGL 1540 return [Win32GLPixelFormat class]; 1541#else 1542 return nil; 1543#endif 1544} 1545 1546@end 1547 1548 1549 1550@implementation WIN32Server (WindowOps) 1551 1552/* 1553 styleMask specifies the receiver's style. It can either be 1554 NSBorderlessWindowMask, or it can contain any of the following 1555 options, combined using the C bitwise OR operator: Option Meaning 1556 1557 NSTitledWindowMask The NSWindow displays a title bar. 1558 NSClosableWindowMask The NSWindow displays a close button. 1559 NSMiniaturizableWindowMask The NSWindow displays a miniaturize button. 1560 NSResizableWindowMask The NSWindow displays a resize bar or border. 1561 NSBorderlessWindowMask 1562 1563 NSBorderlessWindowMask 0 1564 NSTitledWindowMask 1 1565 NSClosableWindowMask 2 1566 NSMiniaturizableWindowMask 4 1567 NSResizableWindowMask 8 1568 NSIconWindowMask 64 1569 NSMiniWindowMask 128 1570 1571 Borderless windows display none of the usual peripheral elements and 1572 are generally useful only for display or caching purposes; you 1573 should normally not need to create them. Also, note that an 1574 NSWindow's style mask should include NSTitledWindowMask if it 1575 includes any of the others. 1576 1577 backingType specifies how the drawing done in the receiver is 1578 buffered by the object's window device: NSBackingStoreBuffered 1579 NSBackingStoreRetained NSBackingStoreNonretained 1580 1581 1582 flag determines whether the Window Server creates a window device 1583 for the new object immediately. If flag is YES, it defers creating 1584 the window until the receiver is moved on screen. All display 1585 messages sent to the NSWindow or its NSViews are postponed until the 1586 window is created, just before it's moved on screen. Deferring the 1587 creation of the window improves launch time and minimizes the 1588 virtual memory load on the Window Server. The new NSWindow creates 1589 an instance of NSView to be its default content view. You can 1590 replace it with your own object by using the setContentView: method. 1591 1592*/ 1593 1594- (int) window: (NSRect)frame : (NSBackingStoreType)type : (unsigned int)style 1595 : (int) screen 1596{ 1597 HWND hwnd; 1598 RECT r; 1599 DWORD wstyle; 1600 DWORD estyle; 1601 1602 wstyle = [self windowStyleForGSStyle: style]; 1603 estyle = [self exwindowStyleForGSStyle: style]; 1604 1605 r = GSScreenRectToMS(frame); 1606 1607 NSDebugLLog(@"WTrace", @"window: %@ : %d : %d : %d", NSStringFromRect(frame), 1608 type, style, screen); 1609 NSDebugLLog(@"WTrace", @" device frame: %d, %d, %d, %d", 1610 r.left, r.top, r.right - r.left, r.bottom - r.top); 1611 hwnd = CreateWindowEx(estyle | WS_EX_LAYERED, 1612 "GNUstepWindowClass", 1613 "GNUstepWindow", 1614#if (BUILD_GRAPHICS==GRAPHICS_cairo) 1615 ((wstyle & WS_POPUP) ? ((wstyle & ~WS_POPUP) | WS_OVERLAPPED) : wstyle), 1616#else 1617 wstyle, 1618#endif 1619 r.left, 1620 r.top, 1621 r.right - r.left, 1622 r.bottom - r.top, 1623 (HWND)NULL, 1624 (HMENU)NULL, 1625 hinstance, 1626 (void*)type); 1627 NSDebugLLog(@"WCTrace", @" num/handle: %d", hwnd); 1628 if (hwnd == NULL) 1629 { 1630 NSLog(@"CreateWindowEx Failed %d", GetLastError()); 1631 } 1632 else 1633 { 1634#if (BUILD_GRAPHICS==GRAPHICS_cairo) 1635 // Borderless window request... 1636 if (wstyle & WS_POPUP) 1637 { 1638 LONG wstyleOld = GetWindowLong(hwnd, GWL_STYLE); 1639 LONG estyleOld = GetWindowLong(hwnd, GWL_EXSTYLE); 1640 LONG wstyleNew = (wstyleOld & ~WS_OVERLAPPEDWINDOW); 1641 LONG estyleNew = estyleOld | WS_EX_TOOLWINDOW; 1642 1643 NSDebugMLLog(@"WCTrace", @"wstyles - old: %8.8X new: %8.8X\n", 1644 wstyleOld, wstyleNew); 1645 NSDebugMLLog(@"WCTrace", @"estyles - old: %8.8X new: %8.8X\n", 1646 estyleOld, estyleNew); 1647 1648 // Modify window style parameters and update the window information... 1649 SetWindowLong(hwnd, GWL_STYLE, wstyleNew); 1650 SetWindowLong(hwnd, GWL_EXSTYLE, estyleNew); 1651 SetWindowPos(hwnd, NULL, 0, 0, 0, 0, 1652 SWP_FRAMECHANGED | SWP_NOSENDCHANGING | SWP_NOREPOSITION | 1653 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); 1654 } 1655#endif 1656 1657 SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA); 1658 1659 [self _setWindowOwnedByServer: (int)hwnd]; 1660 } 1661 return (int)hwnd; 1662} 1663 1664- (void) termwindow: (int) winNum 1665{ 1666 NSDebugLLog(@"WCTrace", @"termwindow: %d", winNum); 1667 if (!DestroyWindow((HWND)winNum)) { 1668 NSLog(@"DestroyWindow Failed %d", GetLastError()); 1669 } 1670} 1671 1672- (void) stylewindow: (unsigned int)style : (int) winNum 1673{ 1674 DWORD wstyle = [self windowStyleForGSStyle: style]; 1675 DWORD estyle = [self exwindowStyleForGSStyle: style]; 1676 1677 NSAssert([self handlesWindowDecorations], 1678 @"-stylewindow: : called when [self handlesWindowDecorations] == NO"); 1679 1680 NSDebugLLog(@"WTrace", @"stylewindow: %d : %d", style, winNum); 1681 SetWindowLong((HWND)winNum, GWL_STYLE, wstyle); 1682 SetWindowLong((HWND)winNum, GWL_EXSTYLE, estyle); 1683} 1684 1685- (void) setbackgroundcolor: (NSColor *)color : (int)win 1686{ 1687} 1688 1689/** Changes window's the backing store to type */ 1690- (void) windowbacking: (NSBackingStoreType)type : (int) winNum 1691{ 1692 WIN_INTERN *win = (WIN_INTERN *)GetWindowLong((HWND)winNum, GWL_USERDATA); 1693 1694 NSDebugLLog(@"WTrace", @"windowbacking: %d : %d", type, winNum); 1695#if (BUILD_GRAPHICS==GRAPHICS_winlib) 1696 if (win->useHDC) 1697 { 1698 HGDIOBJ old; 1699 1700 old = SelectObject(win->hdc, win->old); 1701 DeleteObject(old); 1702 DeleteDC(win->hdc); 1703 win->hdc = NULL; 1704 win->old = NULL; 1705 win->useHDC = NO; 1706 } 1707 1708 if (type != NSBackingStoreNonretained) 1709 { 1710 HDC hdc, hdc2; 1711 HBITMAP hbitmap; 1712 RECT r; 1713 1714 GetClientRect((HWND)winNum, &r); 1715 hdc = GetDC((HWND)winNum); 1716 hdc2 = CreateCompatibleDC(hdc); 1717 hbitmap = CreateCompatibleBitmap(hdc, r.right - r.left, r.bottom - r.top); 1718 win->old = SelectObject(hdc2, hbitmap); 1719 win->hdc = hdc2; 1720 win->useHDC = YES; 1721 win->backingStoreEmpty = YES; 1722 1723 ReleaseDC((HWND)winNum, hdc); 1724 } 1725 else 1726#endif 1727 { 1728 win->useHDC = NO; 1729 win->hdc = NULL; 1730 } 1731 1732 // Save updated window backing store type... 1733 win->type = type; 1734} 1735 1736- (void) titlewindow: (NSString*)window_title : (int) winNum 1737{ 1738 NSDebugLLog(@"WTrace", @"titlewindow: %@ : %d", window_title, winNum); 1739 SetWindowTextW((HWND)winNum, (const unichar*) 1740 [window_title cStringUsingEncoding: NSUnicodeStringEncoding]); 1741} 1742 1743- (void) miniwindow: (int) winNum 1744{ 1745 NSDebugLLog(@"WTrace", @"miniwindow: %d", winNum); 1746 ShowWindow((HWND)winNum, SW_MINIMIZE); 1747} 1748 1749/** Returns NO as we don't provide mini windows on MS Windows */ 1750- (BOOL) appOwnsMiniwindow 1751{ 1752 return NO; 1753} 1754 1755- (void) setWindowdevice: (int)winNum forContext: (NSGraphicsContext *)ctxt 1756{ 1757 RECT rect; 1758 float h, l, r, t, b; 1759 NSWindow *window; 1760 1761 NSDebugLLog(@"WTrace", @"windowdevice: %d", winNum); 1762 window = GSWindowWithNumber(winNum); 1763 1764 /* FIXME: 1765 * The windows with autodisplay set to NO aren't displayed correctly on 1766 * Windows, no matter the backing store type used. And trying to redisplay 1767 * these windows here in the server not takes effect. So if the window 1768 * have set autodisplay to NO, we change it to YES before create the window. 1769 * This problem affects the tooltips, but this solution is different to 1770 * the one used in the TestPlant branch. Because that solution involves 1771 * changes in the side of GUI. 1772 */ 1773 if (![window isAutodisplay]) 1774 { 1775 [window setAutodisplay: YES]; 1776 } 1777 1778 GetClientRect((HWND)winNum, &rect); 1779 h = rect.bottom - rect.top; 1780 [self styleoffsets: &l : &r : &t : &b : [window styleMask]]; 1781 GSSetDevice(ctxt, (void*)winNum, l, h + b); 1782 DPSinitmatrix(ctxt); 1783 DPSinitclip(ctxt); 1784} 1785 1786- (void) orderwindow: (int) op : (int) otherWin : (int) winNum 1787{ 1788 int flag = 0; 1789 int foreground = 0; 1790 int otherLevel; 1791 int level; 1792 NSWindow *window = GSWindowWithNumber(winNum); 1793 1794 NSDebugLLog(@"WTrace", @"orderwindow: %d : %d : %d", op, otherWin, winNum); 1795 1796 if ([self usesNativeTaskbar]) 1797 { 1798 /* When using this policy, we make these changes: 1799 - don't show the application icon window 1800 - Never order out the main menu, just minimize it, so that 1801 when the user clicks on it in the taskbar it will activate the 1802 application. 1803 */ 1804 int special; 1805 special = [[NSApp iconWindow] windowNumber]; 1806 if (winNum == special) 1807 { 1808 return; 1809 } 1810 special = [[[NSApp mainMenu] window] windowNumber]; 1811 if (winNum == special && op == NSWindowOut) 1812 { 1813 ShowWindow((HWND)winNum, SW_MINIMIZE); 1814 return; 1815 } 1816 } 1817 1818 if (op == NSWindowOut) 1819 { 1820 SetWindowLong((HWND)winNum, OFF_ORDERED, 0); 1821 ShowWindow((HWND)winNum, SW_HIDE); 1822 return; 1823 } 1824 1825 if (![window canBecomeMainWindow] && ![window canBecomeKeyWindow]) 1826 { 1827 // Bring front, but do not activate, eg - tooltips 1828 flag = SW_SHOWNA; 1829 } 1830 else 1831 { 1832 flag = SW_SHOW; 1833 if (IsIconic((HWND)winNum)) 1834 flag = SW_RESTORE; 1835 } 1836 1837 ShowWindow((HWND)winNum, flag); 1838 SetWindowLong((HWND)winNum, OFF_ORDERED, 1); 1839 1840 // Process window leveling... 1841 level = GetWindowLong((HWND)winNum, OFF_LEVEL); 1842 1843 if (otherWin <= 0) 1844 { 1845 if (otherWin == 0 && op == NSWindowAbove) 1846 { 1847 /* This combination means we should move to the top of the current 1848 * window level but stay below the key window, so if we have a key 1849 * window (other than the current window), we store it's id for 1850 * testing later. 1851 */ 1852 foreground = (int)GetForegroundWindow(); 1853 if (foreground < 0 || foreground == winNum) 1854 { 1855 foreground = 0; 1856 } 1857 } 1858 otherWin = 0; 1859 } 1860 1861 if (otherWin > 0) 1862 { 1863 /* Put this on the same window level as the window we are ordering 1864 * it against. 1865 */ 1866 otherLevel = GetWindowLong((HWND)otherWin, OFF_LEVEL); 1867 if (level != otherLevel) 1868 { 1869 NSDebugLLog(@"WTrace", 1870 @"orderwindow: implicitly set level of %d (%d) to that of %d (%d)", 1871 winNum, level, otherWin, otherLevel); 1872 level = otherLevel; 1873 SetWindowLong((HWND)winNum, OFF_LEVEL, level); 1874 } 1875 } 1876 1877 if (level <= NSDesktopWindowLevel) 1878 { 1879 HWND desktop = GetDesktopWindow(); 1880 1881 // For desktop level, put this at the bottom of the z-order 1882 SetParent((HWND)winNum, desktop); 1883 otherWin = (int)HWND_BOTTOM; 1884 NSDebugLLog(@"WTrace", @"orderwindow: set %i (%i) to bottom", winNum, level); 1885 } 1886 else if (otherWin == 0 || op == NSWindowAbove) 1887 { 1888 if (otherWin == 0) 1889 { 1890 /* Start searching from bottom of window list... 1891 * The last child of the desktop. 1892 */ 1893 otherWin = (int)GetDesktopWindow(); 1894 otherWin = (int)GetWindow((HWND)otherWin, GW_CHILD); 1895 if (otherWin > 0) 1896 { 1897 otherWin = (int)GetWindow((HWND)otherWin, GW_HWNDLAST); 1898 } 1899 } 1900 NSDebugLLog(@"WTrace", @"orderwindow: traverse for %d (%d) starting at %d", 1901 winNum, level, otherWin); 1902 while (otherWin > 0) 1903 { 1904 TCHAR buf[32]; 1905 1906 otherWin = (int)GetNextWindow((HWND)otherWin, GW_HWNDPREV); 1907 1908 /* We only look at gnustep windows (other than the one being 1909 * ordered) to decide where to place our window. 1910 * The assumption is, that if we are ordering a window in, 1911 * we want it to be above any non-gnustep window. 1912 * FIXME ... perhaps we should move all non-gnustep windows 1913 * to be lower than the lowest (excluding gnustep desktop 1914 * level windows I suppose) gnustep window. 1915 */ 1916 if (otherWin > 0 && otherWin != winNum 1917 && GetClassName((HWND)otherWin, buf, 32) == 18 1918 && strncmp(buf, "GNUstepWindowClass", 18) == 0) 1919 { 1920 if (GetWindowLong((HWND)otherWin, OFF_ORDERED) == 1) 1921 { 1922 otherLevel = GetWindowLong((HWND)otherWin, OFF_LEVEL); 1923 NSDebugLLog(@"WTrace", @"orderwindow: found gnustep window %d (%d)", 1924 otherWin, otherLevel); 1925 if (otherLevel >= level) 1926 { 1927 if (otherLevel > level) 1928 { 1929 /* On windows, there is no notion of levels, so 1930 * native apps will automatically move to the 1931 * very top of the stack (above our alert panels etc) 1932 * 1933 * So to cope with this, when we move to the top 1934 * of a level, we assume there may be native apps 1935 * above us and we set otherWin=0 to move to the 1936 * very top of the stack past them. 1937 * 1938 * We rely on the fact that we have code in the 1939 * window positioning notification to rearrange 1940 * (sort) all the windows into level order if 1941 * moving this window to the top messes up the 1942 * level ordering. 1943 */ 1944 otherWin = 0; 1945 break; 1946 } 1947 if (op == NSWindowBelow || foreground == otherWin) 1948 { 1949 break; 1950 } 1951 } 1952 } 1953 } 1954 } 1955 } 1956 1957 if (otherWin == 0) 1958 { 1959 otherWin = (int)HWND_TOP; 1960 NSDebugLLog(@"WTrace", @"orderwindow: set %i (%i) to top", winNum, level); 1961 } 1962 else if (otherWin == (int)HWND_BOTTOM) 1963 { 1964 NSDebugLLog(@"WTrace", @"orderwindow: set %i (%i) to bottom", winNum, level); 1965 } 1966 else 1967 { 1968 NSDebugLLog(@"WTrace", @"orderwindow: set %i (%i) below %d", winNum, level, otherWin); 1969 } 1970 1971 SetWindowPos((HWND)winNum, (HWND)otherWin, 0, 0, 0, 0, 1972 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); 1973 1974 if (otherWin == (int)HWND_TOP) 1975 { 1976 _enableCallbacks = NO; 1977 if (SetForegroundWindow((HWND)winNum) == 0) 1978 NSDebugMLLog(@"WError", @"SetForegroundWindow error for HWND: %p\n", winNum); 1979 _enableCallbacks = YES; 1980 } 1981 /* For debug log window stack. 1982 */ 1983 if (GSDebugSet(@"WTrace") == YES) 1984 { 1985 NSString *s = @"Window list:\n"; 1986 1987 otherWin = (int)GetDesktopWindow(); 1988 otherWin = (int)GetWindow((HWND)otherWin, GW_CHILD); 1989 if (otherWin > 0) 1990 { 1991 otherWin = (int)GetWindow((HWND)otherWin, GW_HWNDLAST); 1992 } 1993 while (otherWin > 0) 1994 { 1995 TCHAR buf[32]; 1996 1997 otherWin = (int)GetNextWindow((HWND)otherWin, GW_HWNDPREV); 1998 1999 if (otherWin > 0 2000 && GetClassName((HWND)otherWin, buf, 32) == 18 2001 && strncmp(buf, "GNUstepWindowClass", 18) == 0) 2002 { 2003 if (GetWindowLong((HWND)otherWin, OFF_ORDERED) == 1) 2004 { 2005 otherLevel = GetWindowLong((HWND)otherWin, OFF_LEVEL); 2006 s = [s stringByAppendingFormat: 2007 @"%d (%d)\n", otherWin, otherLevel]; 2008 } 2009 } 2010 } 2011 NSDebugLLog(@"WTrace", @"orderwindow: %@", s); 2012 } 2013} 2014 2015- (void) movewindow: (NSPoint)loc : (int)winNum 2016{ 2017 POINT p; 2018 2019 NSDebugLLog(@"WTrace", @"movewindow: %@ : %d", NSStringFromPoint(loc), 2020 winNum); 2021 p = GSWindowOriginToMS((HWND)winNum, loc); 2022 2023 SetWindowPos((HWND)winNum, NULL, p.x, p.y, 0, 0, 2024 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING); 2025} 2026 2027- (void) placewindow: (NSRect)frame : (int) winNum 2028{ 2029 RECT r; 2030 RECT r2; 2031 2032 NSDebugLLog(@"WTrace", @"placewindow: %@ : %d", NSStringFromRect(frame), 2033 winNum); 2034 r = GSScreenRectToMS(frame); 2035 GetWindowRect((HWND)winNum, &r2); 2036 2037 SetWindowPos((HWND)winNum, NULL, 2038 r.left, r.top, r.right - r.left, r.bottom - r.top, 2039 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING); 2040 2041#if (BUILD_GRAPHICS==GRAPHICS_winlib) 2042 WIN_INTERN *win = (WIN_INTERN *)GetWindowLong((HWND)winNum, GWL_USERDATA); 2043 2044 if ((win->useHDC) 2045 && (r.right - r.left != r2.right - r2.left) 2046 && (r.bottom - r.top != r2.bottom - r2.top)) 2047 { 2048 HDC hdc, hdc2; 2049 HBITMAP hbitmap; 2050 HGDIOBJ old; 2051 2052 old = SelectObject(win->hdc, win->old); 2053 DeleteObject(old); 2054 DeleteDC(win->hdc); 2055 win->hdc = NULL; 2056 win->old = NULL; 2057 2058 GetClientRect((HWND)winNum, &r); 2059 hdc = GetDC((HWND)winNum); 2060 hdc2 = CreateCompatibleDC(hdc); 2061 hbitmap = CreateCompatibleBitmap(hdc, r.right - r.left, r.bottom - r.top); 2062 win->old = SelectObject(hdc2, hbitmap); 2063 win->hdc = hdc2; 2064 2065 ReleaseDC((HWND)winNum, hdc); 2066 } 2067#endif 2068} 2069 2070- (BOOL) findwindow: (NSPoint)loc : (int) op : (int) otherWin 2071 : (NSPoint *)floc : (int*) winFound 2072{ 2073 return NO; 2074} 2075 2076- (NSRect) windowbounds: (int) winNum 2077{ 2078 RECT r; 2079 2080 GetWindowRect((HWND)winNum, &r); 2081 return MSScreenRectToGS(r); 2082} 2083 2084- (void) setwindowlevel: (int) level : (int) winNum 2085{ 2086 NSDebugLLog(@"WTrace", @"setwindowlevel: %d : %d", level, winNum); 2087 if (GetWindowLong((HWND)winNum, OFF_LEVEL) != level) 2088 { 2089 SetWindowLong((HWND)winNum, OFF_LEVEL, level); 2090 if (GetWindowLong((HWND)winNum, OFF_ORDERED) == YES) 2091 { 2092 [self orderwindow: NSWindowAbove : 0 : winNum]; 2093 } 2094 } 2095} 2096 2097- (int) windowlevel: (int) winNum 2098{ 2099 return GetWindowLong((HWND)winNum, OFF_LEVEL); 2100} 2101 2102- (NSArray *) windowlist 2103{ 2104 NSMutableArray *list = [NSMutableArray arrayWithCapacity: 100]; 2105 HWND w; 2106 HWND next; 2107 2108 w = GetForegroundWindow(); // Try to start with frontmost window 2109 if (w == NULL) 2110 { 2111 w = GetDesktopWindow(); // This should always succeed. 2112 w = GetWindow(w, GW_CHILD); 2113 } 2114 2115 /* Step up to the frontmost window. 2116 */ 2117 while ((next = GetNextWindow(w, GW_HWNDPREV)) != NULL) 2118 { 2119 w = next; 2120 } 2121 2122 /* Now walk down the window list populating the array. 2123 */ 2124 while (w != NULL) 2125 { 2126 /* Only add windows we own. 2127 * FIXME We should improve the API to support all windows on server. 2128 */ 2129 if (GSWindowWithNumber((int)w) != nil) 2130 { 2131 [list addObject: [NSNumber numberWithInt: (int)w]]; 2132 } 2133 w = GetNextWindow(w, GW_HWNDNEXT); 2134 } 2135 2136 return list; 2137} 2138 2139- (int) windowdepth: (int) winNum 2140{ 2141 return 0; 2142} 2143 2144/** Set the maximum size of the window */ 2145- (void) setmaxsize: (NSSize)size : (int) winNum 2146{ 2147 WIN_INTERN *win = (WIN_INTERN *)GetWindowLong((HWND)winNum, GWL_USERDATA); 2148 POINT p; 2149 2150 p.x = size.width; 2151 p.y = size.height; 2152 win->minmax.ptMaxTrackSize = p; 2153 2154 // Disable the maximize box if a maximum size is set 2155 if (size.width < 10000 || size.height < 10000) 2156 { 2157 SetWindowLong((HWND)winNum, GWL_STYLE, 2158 GetWindowLong((HWND)winNum, GWL_STYLE) ^ WS_MAXIMIZEBOX); 2159 } 2160 else 2161 { 2162 SetWindowLong((HWND)winNum, GWL_STYLE, 2163 GetWindowLong((HWND)winNum, GWL_STYLE) | WS_MAXIMIZEBOX); 2164 } 2165} 2166 2167/** Set the minimum size of the window */ 2168- (void) setminsize: (NSSize)size : (int) winNum 2169{ 2170 WIN_INTERN *win = (WIN_INTERN *)GetWindowLong((HWND)winNum, GWL_USERDATA); 2171 POINT p; 2172 2173 p.x = size.width; 2174 p.y = size.height; 2175 win->minmax.ptMinTrackSize = p; 2176} 2177 2178/** Set the resize incremenet of the window */ 2179- (void) setresizeincrements: (NSSize)size : (int) winNum 2180{ 2181} 2182/** Causes buffered graphics to be flushed to the screen */ 2183- (void) flushwindowrect: (NSRect)rect : (int)winNum 2184{ 2185 HWND hwnd = (HWND)winNum; 2186 WIN_INTERN *win = (WIN_INTERN *)GetWindowLong(hwnd, GWL_USERDATA); 2187 2188 if (win) 2189 { 2190#if (BUILD_GRAPHICS==GRAPHICS_winlib) 2191 if (win->useHDC) 2192 { 2193 HDC hdc = GetDC(hwnd); 2194 RECT r = GSWindowRectToMS(self, hwnd, rect); 2195 WINBOOL result; 2196 2197 result = BitBlt(hdc, r.left, r.top, 2198 (r.right - r.left), (r.bottom - r.top), 2199 win->hdc, r.left, r.top, SRCCOPY); 2200 if (!result) 2201 { 2202 NSLog(@"Flush window %d %@", hwnd, 2203 NSStringFromRect(MSWindowRectToGS(self, hwnd, r))); 2204 NSLog(@"Flush window failed with %d", GetLastError()); 2205 } 2206 ReleaseDC(hwnd, hdc); 2207 } 2208#elif (BUILD_GRAPHICS==GRAPHICS_cairo) 2209 if (win->surface == NULL) 2210 { 2211 NSWarnMLog(@"NULL surface for window %p", hwnd); 2212 } 2213 else 2214 { 2215 [[GSCurrentContext() class] handleExposeRect: rect forDriver: (void*)win->surface]; 2216 } 2217#else 2218#error INVALID build graphics type 2219#endif 2220 } 2221} 2222 2223- (void) styleoffsets: (float *) l : (float *) r : (float *) t : (float *) b 2224 : (unsigned int) style 2225{ 2226 if ([self handlesWindowDecorations]) 2227 { 2228 DWORD wstyle = [self windowStyleForGSStyle: style]; 2229 DWORD estyle = [self exwindowStyleForGSStyle: style]; 2230 RECT rect = {100, 100, 200, 200}; 2231 2232 AdjustWindowRectEx(&rect, wstyle, NO, estyle); 2233 2234 *l = 100 - rect.left; 2235 *r = rect.right - 200; 2236 *t = 100 - rect.top; 2237 *b = rect.bottom - 200; 2238 //NSLog(@"Style 0x%X offset %f %f %f %f", wstyle, *l, *r, *t, *b); 2239 } 2240 else 2241 { 2242 /* 2243 If we don't handle decorations, all our windows are going to be 2244 border- and decorationless. In that case, -gui won't call this method, 2245 but we still use it internally. 2246 */ 2247 *l = *r = *t = *b = 0.0; 2248 } 2249} 2250 2251- (void) docedited: (int) edited : (int) winNum 2252{ 2253} 2254 2255- (void) setinputstate: (int)state : (int)winNum 2256{ 2257 if ([self handlesWindowDecorations] == NO) 2258 { 2259 return; 2260 } 2261 if (state == GSTitleBarMain) 2262 { 2263 _enableCallbacks = NO; 2264 SetActiveWindow((HWND)winNum); 2265 _enableCallbacks = YES; 2266 } 2267} 2268 2269/** Forces focus to the window so that all key events are sent to this 2270 window */ 2271- (void) setinputfocus: (int) winNum 2272{ 2273 NSDebugLLog(@"WTrace", @"setinputfocus: %d", winNum); 2274 NSDebugLLog(@"Focus", @"Setting input focus to %d", winNum); 2275 if (winNum == 0) 2276 { 2277 NSDebugLLog(@"Focus", @" invalid focus window"); 2278 return; 2279 } 2280 if (currentFocus == (HWND)winNum) 2281 { 2282 NSDebugLLog(@"Focus", @" window already has focus"); 2283 return; 2284 } 2285 desiredFocus = (HWND)winNum; 2286 SetFocus((HWND)winNum); 2287} 2288 2289- (void) setalpha: (float)alpha: (int) win 2290{ 2291 if (alpha > 0.99) 2292 { 2293 SetWindowLong((HWND)win, GWL_EXSTYLE, 2294 GetWindowLong((HWND)win, GWL_EXSTYLE) & ~WS_EX_LAYERED); 2295 RedrawWindow((HWND)win, NULL, NULL, 2296 RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); 2297 } 2298 else 2299 { 2300 SetWindowLong((HWND)win, GWL_EXSTYLE, 2301 GetWindowLong((HWND)win, GWL_EXSTYLE) | WS_EX_LAYERED); 2302 SetLayeredWindowAttributes((HWND)win, 0, 255 * alpha, LWA_ALPHA); 2303 } 2304} 2305 2306- (NSPoint) mouselocation 2307{ 2308 POINT p; 2309 2310 if (!GetCursorPos(&p)) 2311 { 2312 // Try using cursorInfo which should work in more situations 2313 CURSORINFO cursorInfo; 2314 cursorInfo.cbSize = sizeof(CURSORINFO); 2315 if (!GetCursorInfo(&cursorInfo)) { 2316 NSLog(@"GetCursorInfo failed with %d", GetLastError()); 2317 return NSZeroPoint; 2318 } 2319 p = cursorInfo.ptScreenPos; 2320 } 2321 2322 return MSScreenPointToGS(p.x, p.y); 2323} 2324 2325- (NSPoint) mouseLocationOnScreen: (int)screen window: (int *)win 2326{ 2327 return [self mouselocation]; 2328} 2329 2330- (BOOL) capturemouse: (int) winNum 2331{ 2332 NSDebugLLog(@"WTrace", @"capturemouse: %d", winNum); 2333 SetCapture((HWND)winNum); 2334 return YES; 2335} 2336 2337- (void) releasemouse 2338{ 2339 NSDebugLLog(@"WTrace", @"releasemouse"); 2340 ReleaseCapture(); 2341} 2342 2343- (void) hidecursor 2344{ 2345 NSDebugLLog(@"WTrace", @"hidecursor"); 2346 ShowCursor(NO); 2347} 2348 2349- (void) showcursor 2350{ 2351 ShowCursor(YES); 2352} 2353 2354- (void) standardcursor: (int)style : (void **)cid 2355{ 2356 HCURSOR hCursor = 0; 2357 2358 NSDebugLLog(@"WTrace", @"standardcursor: %d", style); 2359 switch (style) 2360 { 2361 case GSArrowCursor: 2362 hCursor = LoadCursor(NULL, IDC_ARROW); 2363 break; 2364 case GSIBeamCursor: 2365 hCursor = LoadCursor(NULL, IDC_IBEAM); 2366 break; 2367 case GSCrosshairCursor: 2368 hCursor = LoadCursor(NULL, IDC_CROSS); 2369 break; 2370 case GSPointingHandCursor: 2371 hCursor = LoadCursor(NULL, IDC_HAND); 2372 break; 2373 case GSResizeLeftRightCursor: 2374 hCursor = LoadCursor(NULL, IDC_SIZEWE); 2375 break; 2376 case GSResizeUpDownCursor: 2377 hCursor = LoadCursor(NULL, IDC_SIZENS); 2378 break; 2379 default: 2380 return; 2381 } 2382 *cid = (void*)hCursor; 2383} 2384 2385- (void) imagecursor: (NSPoint)hotp : (NSImage *)image : (void **)cid 2386{ 2387 /* 2388 HCURSOR cur; 2389 BYTE *and; 2390 BYTE *xor; 2391 int w, h; 2392 2393 xor = image; 2394 cur = CreateCursor(hinstance, (int)hotp.x, (int)hotp.y, (int)w, (int)h, and, xor); 2395 *cid = (void*)hCursor; 2396 */ 2397} 2398 2399- (void) recolorcursor: (NSColor *)fg : (NSColor *)bg : (void*) cid 2400{ 2401 /* FIXME The colour is currently ignored 2402 if (fg != nil) 2403 { 2404 ICONINFO iconinfo; 2405 2406 if (GetIconInfo((HCURSOR)cid, &iconinfo)) 2407 { 2408 iconinfo.hbmColor = ; 2409 } 2410 } 2411 */ 2412} 2413 2414- (void) setcursor: (void*) cid 2415{ 2416 SetCursor((HCURSOR)cid); 2417} 2418 2419- (void) freecursor: (void*) cid 2420{ 2421 // This is only allowed on non-shared cursors and we have no way of knowing that. 2422 //DestroyCursor((HCURSOR)cid); 2423} 2424 2425- (void) setParentWindow: (int)parentWin 2426 forChildWindow: (int)childWin 2427{ 2428 //SetParent((HWND)childWin, (HWND)parentWin); 2429} 2430 2431- (void) setIgnoreMouse: (BOOL)ignoreMouse : (int)win 2432{ 2433 int extendedStyle = GetWindowLong((HWND)win, GWL_EXSTYLE); 2434 2435 if (ignoreMouse) 2436 { 2437 SetWindowLong((HWND)win, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT); 2438 } 2439 else 2440 { 2441 SetWindowLong((HWND)win, GWL_EXSTYLE, extendedStyle & ~WS_EX_TRANSPARENT); 2442 } 2443} 2444 2445@end 2446 2447static unichar 2448process_char(WPARAM wParam, unsigned *eventModifierFlags) 2449{ 2450 switch (wParam) 2451 { 2452 case VK_RETURN: return NSCarriageReturnCharacter; 2453 case VK_TAB: return NSTabCharacter; 2454 case VK_ESCAPE: return 0x1b; 2455 case VK_BACK: return NSDeleteCharacter; 2456 2457 /* The following keys need to be reported as function keys */ 2458 #define WIN_FUNCTIONKEY \ 2459 *eventModifierFlags = *eventModifierFlags | NSFunctionKeyMask; 2460 case VK_F1: WIN_FUNCTIONKEY return NSF1FunctionKey; 2461 case VK_F2: WIN_FUNCTIONKEY return NSF2FunctionKey; 2462 case VK_F3: WIN_FUNCTIONKEY return NSF3FunctionKey; 2463 case VK_F4: WIN_FUNCTIONKEY return NSF4FunctionKey; 2464 case VK_F5: WIN_FUNCTIONKEY return NSF5FunctionKey; 2465 case VK_F6: WIN_FUNCTIONKEY return NSF6FunctionKey; 2466 case VK_F7: WIN_FUNCTIONKEY return NSF7FunctionKey; 2467 case VK_F8: WIN_FUNCTIONKEY return NSF8FunctionKey; 2468 case VK_F9: WIN_FUNCTIONKEY return NSF9FunctionKey; 2469 case VK_F10: WIN_FUNCTIONKEY return NSF10FunctionKey; 2470 case VK_F11: WIN_FUNCTIONKEY return NSF11FunctionKey; 2471 case VK_F12: WIN_FUNCTIONKEY return NSF12FunctionKey; 2472 case VK_F13: WIN_FUNCTIONKEY return NSF13FunctionKey; 2473 case VK_F14: WIN_FUNCTIONKEY return NSF14FunctionKey; 2474 case VK_F15: WIN_FUNCTIONKEY return NSF15FunctionKey; 2475 case VK_F16: WIN_FUNCTIONKEY return NSF16FunctionKey; 2476 case VK_F17: WIN_FUNCTIONKEY return NSF17FunctionKey; 2477 case VK_F18: WIN_FUNCTIONKEY return NSF18FunctionKey; 2478 case VK_F19: WIN_FUNCTIONKEY return NSF19FunctionKey; 2479 case VK_F20: WIN_FUNCTIONKEY return NSF20FunctionKey; 2480 case VK_F21: WIN_FUNCTIONKEY return NSF21FunctionKey; 2481 case VK_F22: WIN_FUNCTIONKEY return NSF22FunctionKey; 2482 case VK_F23: WIN_FUNCTIONKEY return NSF23FunctionKey; 2483 case VK_F24: WIN_FUNCTIONKEY return NSF24FunctionKey; 2484 2485 case VK_DELETE: WIN_FUNCTIONKEY return NSDeleteFunctionKey; 2486 case VK_HOME: WIN_FUNCTIONKEY return NSHomeFunctionKey; 2487 case VK_LEFT: WIN_FUNCTIONKEY return NSLeftArrowFunctionKey; 2488 case VK_RIGHT: WIN_FUNCTIONKEY return NSRightArrowFunctionKey; 2489 case VK_UP: WIN_FUNCTIONKEY return NSUpArrowFunctionKey; 2490 case VK_DOWN: WIN_FUNCTIONKEY return NSDownArrowFunctionKey; 2491 case VK_PRIOR: WIN_FUNCTIONKEY return NSPageUpFunctionKey; 2492 case VK_NEXT: WIN_FUNCTIONKEY return NSPageDownFunctionKey; 2493 case VK_END: WIN_FUNCTIONKEY return NSEndFunctionKey; 2494 case VK_SELECT: WIN_FUNCTIONKEY return NSSelectFunctionKey; 2495 case VK_PRINT: WIN_FUNCTIONKEY return NSPrintFunctionKey; 2496 case VK_SNAPSHOT: WIN_FUNCTIONKEY return NSPrintScreenFunctionKey; 2497 case VK_EXECUTE: WIN_FUNCTIONKEY return NSExecuteFunctionKey; 2498 case VK_INSERT: WIN_FUNCTIONKEY return NSInsertFunctionKey; 2499 case VK_HELP: WIN_FUNCTIONKEY return NSHelpFunctionKey; 2500 case VK_CANCEL: WIN_FUNCTIONKEY return NSBreakFunctionKey; 2501 case VK_MODECHANGE: WIN_FUNCTIONKEY return NSModeSwitchFunctionKey; 2502 case VK_SCROLL: WIN_FUNCTIONKEY return NSScrollLockFunctionKey; 2503 case VK_PAUSE: WIN_FUNCTIONKEY return NSPauseFunctionKey; 2504 case VK_OEM_CLEAR: WIN_FUNCTIONKEY return NSClearDisplayFunctionKey; 2505 case VK_CLEAR: WIN_FUNCTIONKEY return NSClearLineFunctionKey; 2506 #undef WIN_FUNCTIONKEY 2507 default: 2508 return 0; 2509 } 2510} 2511 2512static unsigned int 2513mask_for_keystate(BYTE *keyState) 2514{ 2515 unsigned int eventFlags = 0; 2516 NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 2517 NSString *firstCommand = [defs stringForKey: @"GSFirstCommandKey"]; 2518 NSString *firstControl = [defs stringForKey: @"GSFirstControlKey"]; 2519 NSString *firstAlt = [defs stringForKey: @"GSFirstAlternateKey"]; 2520 NSString *secondCommand = [defs stringForKey: @"GSSecondCommandKey"]; 2521 NSString *secondControl = [defs stringForKey: @"GSSecondControlKey"]; 2522 NSString *secondAlt = [defs stringForKey: @"GSSecondAlternateKey"]; 2523 2524 /* AltGr is mapped to right alt + left control */ 2525 if (keyState[VK_RCONTROL] & 128) // && !((keyState[VK_LCONTROL] & 128) && (keyState[VK_RMENU] & 128))) 2526 { 2527 if([@"Control_R" isEqualToString: firstAlt] || 2528 [@"Control_R" isEqualToString: secondAlt]) 2529 eventFlags |= NSAlternateKeyMask; 2530 else if([@"Control_R" isEqualToString: firstCommand] || 2531 [@"Control_R" isEqualToString: secondCommand]) 2532 eventFlags |= NSCommandKeyMask; 2533 else 2534 eventFlags |= NSControlKeyMask; 2535 } 2536 2537 if (keyState[VK_SHIFT] & 128) 2538 eventFlags |= NSShiftKeyMask; 2539 if (keyState[VK_CAPITAL] & 128) 2540 eventFlags |= NSShiftKeyMask; 2541 2542 if (keyState[VK_MENU] & 128) 2543 { 2544 if([@"Alt_R" isEqualToString: firstControl] || 2545 [@"Alt_R" isEqualToString: secondControl]) 2546 eventFlags |= NSControlKeyMask; 2547 else if([@"Alt_R" isEqualToString: firstCommand] || 2548 [@"Alt_R" isEqualToString: secondCommand]) 2549 eventFlags |= NSCommandKeyMask; 2550 else 2551 eventFlags |= NSAlternateKeyMask; 2552 } 2553 2554 if (keyState[VK_HELP] & 128) 2555 eventFlags |= NSHelpKeyMask; 2556 2557 if ((keyState[VK_LCONTROL] & 128) || (keyState[VK_RWIN] & 128)) 2558 { 2559 if([@"Control_L" isEqualToString: firstAlt] || 2560 [@"Control_L" isEqualToString: secondAlt]) 2561 eventFlags |= NSAlternateKeyMask; 2562 else if([@"Control_L" isEqualToString: firstControl] || 2563 [@"Control_L" isEqualToString: secondControl]) 2564 eventFlags |= NSControlKeyMask; 2565 else 2566 eventFlags |= NSCommandKeyMask; 2567 } 2568 return eventFlags; 2569} 2570 2571static NSEvent* 2572process_key_event(WIN32Server *svr, HWND hwnd, WPARAM wParam, LPARAM lParam, NSEventType eventType) 2573{ 2574 NSEvent *event; 2575 BOOL repeat; 2576 DWORD pos; 2577 NSPoint eventLocation; 2578 unsigned int eventFlags; 2579 NSTimeInterval time; 2580 LONG ltime; 2581 unichar unicode[5]; 2582 unsigned int scan; 2583 int result; 2584 BYTE keyState[256]; 2585 NSString *keys, *ukeys; 2586 NSGraphicsContext *gcontext; 2587 unichar uChar = 0; 2588 2589 /* FIXME: How do you guarentee a context is associated with an event? */ 2590 gcontext = GSCurrentContext(); 2591 2592 repeat = (lParam & 0xFFFF) != 0; 2593 2594 pos = GetMessagePos(); 2595 eventLocation 2596 = MSWindowPointToGS(svr, hwnd, GET_X_LPARAM(pos), GET_Y_LPARAM(pos)); 2597 2598 ltime = GetMessageTime(); 2599 time = ltime / 1000.0f; 2600 2601 GetKeyboardState(keyState); 2602 eventFlags = mask_for_keystate(keyState); 2603 2604 switch(wParam) 2605 { 2606 case VK_SHIFT: 2607 case VK_CAPITAL: 2608 case VK_CONTROL: 2609 case VK_MENU: 2610 case VK_HELP: 2611 case VK_NUMLOCK: 2612 eventType = NSFlagsChanged; 2613 break; 2614 case VK_NUMPAD0: 2615 case VK_NUMPAD1: 2616 case VK_NUMPAD2: 2617 case VK_NUMPAD3: 2618 case VK_NUMPAD4: 2619 case VK_NUMPAD5: 2620 case VK_NUMPAD6: 2621 case VK_NUMPAD7: 2622 case VK_NUMPAD8: 2623 case VK_NUMPAD9: 2624 eventFlags |= NSNumericPadKeyMask; 2625 break; 2626 default: 2627 break; 2628 } 2629 2630 if (wParam == VK_PROCESSKEY) 2631 { 2632 // Ignore VK_PROCESSKEY for IME processing... 2633 return 0; 2634 } 2635 else 2636 { 2637 // Ignore if currently in IME composition processing... 2638 IME_INFO_T *imeInfo = (IME_INFO_T*)GetWindowLongPtr(hwnd, IME_INFO); 2639 if (imeInfo && (imeInfo->isComposing)) 2640 return 0; 2641 uChar = process_char(wParam, &eventFlags); 2642 } 2643 2644 if (uChar) 2645 { 2646 keys = [NSString stringWithCharacters: &uChar length: 1]; 2647 ukeys = [NSString stringWithCharacters: &uChar length: 1]; 2648 } 2649 else 2650 { 2651 BYTE blankKeyState[256]; 2652 int i = 0; 2653 2654 // initialize blank key state array.... 2655 for(i = 0; i < 256; i++) 2656 blankKeyState[i] = 0; 2657 2658 scan = ((lParam >> 16) & 0xFF); 2659 result = ToUnicodeEx(wParam, scan, keyState, unicode, 5, 0, GetKeyboardLayout(0)); 2660 if (result == -1) 2661 { 2662 // A non spacing accent key was found, we still try to use the result 2663 result = 1; 2664 } 2665 keys = [NSString stringWithCharacters: unicode length: result]; 2666 2667 // Now get the characters with a blank keyboard state so that 2668 // no modifiers are applied. 2669 result = ToUnicodeEx(wParam, scan, blankKeyState, unicode, 5, 0, GetKeyboardLayout(0)); 2670 //NSLog(@"To Unicode resulted in %d with %d", result, unicode[0]); 2671 if (result == -1) 2672 { 2673 // A non spacing accent key was found, we still try to use the result 2674 result = 1; 2675 NSWarnMLog(@"To Unicode resulted in -1 with: 0x%4.4X\n", unicode[0]); 2676 } 2677 ukeys = [NSString stringWithCharacters: unicode length: result]; 2678 } 2679 2680 if (eventFlags & NSShiftKeyMask) 2681 ukeys = [ukeys uppercaseString]; 2682 2683 // key events should go to the key window if we have one (Windows' focus window isn't always appropriate) 2684 int windowNumber = [[NSApp keyWindow] windowNumber]; 2685 if (windowNumber == 0) 2686 windowNumber = (int)hwnd; 2687 2688 event = [NSEvent keyEventWithType: eventType 2689 location: eventLocation 2690 modifierFlags: eventFlags 2691 timestamp: time 2692 windowNumber: windowNumber 2693 context: gcontext 2694 characters: keys 2695 charactersIgnoringModifiers: ukeys 2696 isARepeat: repeat 2697 keyCode: wParam]; 2698 2699 return event; 2700} 2701 2702static NSEvent* 2703process_mouse_event(WIN32Server *svr, HWND hwnd, WPARAM wParam, LPARAM lParam, 2704 NSEventType eventType, UINT uMsg) 2705{ 2706 NSEvent *event; 2707 NSPoint eventLocation; 2708 static NSPoint lastLocation = {0.0, 0.0}; 2709 unsigned int eventFlags; 2710 NSTimeInterval time; 2711 LONG ltime; 2712 DWORD tick; 2713 NSGraphicsContext *gcontext; 2714 float deltaX = 0.0, deltaY = 0.0; 2715 static int clickCount = 1; 2716 static LONG lastTime = 0; 2717 int clientX, clientY; 2718/* 2719 * Occasionally the mouse down events are lost ... don't know why. 2720 * So we track the mouse status and simulate mouse down or up events 2721 * if the button states appear to have changed when we get a move. 2722 */ 2723 static BOOL lDown = NO; 2724 static BOOL oDown = NO; 2725 static BOOL rDown = NO; 2726 2727 gcontext = GSCurrentContext(); 2728 2729/* 2730 * Some events give screen coordinates - we must convert those to client 2731 * coordinates. 2732 */ 2733 if (eventType == NSScrollWheel) 2734 { 2735 POINT point; 2736 point.x = GET_X_LPARAM(lParam); 2737 point.y = GET_Y_LPARAM(lParam); 2738 ScreenToClient(hwnd, &point); 2739 clientX = point.x; 2740 clientY = point.y; 2741 } 2742 else 2743 { 2744 clientX = GET_X_LPARAM(lParam); 2745 clientY = GET_Y_LPARAM(lParam); 2746 } 2747 2748 eventLocation = MSWindowPointToGS(svr, hwnd, clientX, clientY); 2749 ltime = GetMessageTime(); 2750 time = ltime / 1000.0f; 2751 tick = GetTickCount(); 2752 eventFlags = 0; 2753 if (wParam & MK_CONTROL) 2754 { 2755 eventFlags |= NSControlKeyMask; 2756 } 2757 if (wParam & MK_SHIFT) 2758 { 2759 eventFlags |= NSShiftKeyMask; 2760 } 2761 if (GetKeyState(VK_MENU) < 0) 2762 { 2763 eventFlags |= NSAlternateKeyMask; 2764 } 2765 if (GetKeyState(VK_HELP) < 0) 2766 { 2767 eventFlags |= NSHelpKeyMask; 2768 } 2769 // What about other modifiers? 2770 2771 /* Currently GNUstep only proccess events inside the windows (contentview). 2772 * So we should check if this is the first movement inside the window. 2773 * And should consider also the case when this is the last movement inside 2774 * the window. 2775 */ 2776 if (!should_handle_cursor) 2777 { 2778 /* If this is the first movement inside the window, tell GNUstep 2779 * that should handle the cursor and that should check if the 2780 * cursor needs be updated. 2781 */ 2782 should_handle_cursor = YES; 2783 update_cursor = YES; 2784 2785 /* We also starts tracking the mouse, so we receive the 2786 * message WM_MOUSELEAVE when the mouse leaves the client area. 2787 */ 2788 TRACKMOUSEEVENT tme; 2789 tme.cbSize = sizeof(tme); 2790 tme.dwFlags = TME_LEAVE; 2791 tme.hwndTrack = hwnd; 2792 TrackMouseEvent(&tme); 2793 2794 /* If there are a previous cursor available (maybe a cursor that 2795 * represent a tool) set it as the cursor. If not, set an arrow 2796 * cursor (this is necessary because if the cursor is updated to, 2797 * for example, an I Beam cursor, there will not be a default cursor 2798 * to display when the user moves the mouse over, for example, an 2799 * scrollbar). 2800 */ 2801 if (current_cursor != nil) 2802 { 2803 [current_cursor set]; 2804 current_cursor = nil; 2805 } 2806 else 2807 { 2808 [[NSCursor arrowCursor] set]; 2809 } 2810 } 2811 else 2812 { 2813 /* If the cursor is not associated to a tracking rectangle, not in 2814 * the push/pop stack, save this. We do this for the case when, for 2815 * example, the user choose a tool in a Tools window which sets a 2816 * cursor for the tool and this cursor should be preserved between 2817 * different windows. 2818 */ 2819 if ([NSCursor count] == 0 && 2820 ![current_cursor isEqual: [NSCursor currentCursor]]) 2821 { 2822 ASSIGN(current_cursor, [NSCursor currentCursor]); 2823 } 2824 } 2825 2826 // Check if we need update the cursor. 2827 if (update_cursor) 2828 { 2829 NSView *subview = nil; 2830 NSWindow *gswin = GSWindowWithNumber((int)hwnd); 2831 2832 subview = [[gswin contentView] hitTest: eventLocation]; 2833 2834 if (subview != nil && subview->_rFlags.valid_rects) 2835 { 2836 NSArray *tr = subview->_cursor_rects; 2837 NSUInteger count = [tr count]; 2838 2839 // Loop through cursor rectangles 2840 if (count > 0) 2841 { 2842 GSTrackingRect *rects[count]; 2843 NSUInteger i; 2844 2845 [tr getObjects: rects]; 2846 2847 for (i = 0; i < count; ++i) 2848 { 2849 GSTrackingRect *r = rects[i]; 2850 BOOL now; 2851 2852 if ([r isValid] == NO) 2853 continue; 2854 2855 /* 2856 * Check for presence of point in rectangle. 2857 */ 2858 now = NSMouseInRect(eventLocation, r->rectangle, NO); 2859 2860 // Mouse inside 2861 if (now) 2862 { 2863 NSEvent *e; 2864 2865 e = [NSEvent enterExitEventWithType: NSCursorUpdate 2866 location: eventLocation 2867 modifierFlags: eventFlags 2868 timestamp: 0 2869 windowNumber: (int)hwnd 2870 context: gcontext 2871 eventNumber: 0 2872 trackingNumber: (int)YES 2873 userData: (void*)r]; 2874 [GSCurrentServer() postEvent: e atStart: YES]; 2875 //NSLog(@"Add enter event %@ for view %@ rect %@", e, theView, NSStringFromRect(r->rectangle)); 2876 } 2877 } 2878 } 2879 } 2880 update_cursor = NO; 2881 } 2882 2883 if (eventType == NSScrollWheel) 2884 { 2885 float delta = GET_WHEEL_DELTA_WPARAM(wParam) / 120.0; 2886 if (uMsg == WM_MOUSEWHEEL) 2887 deltaY = delta; 2888 else 2889 deltaX = delta; 2890 //NSLog(@"Scroll event with deltaX %f deltaY %f", deltaX, deltaY); 2891 } 2892 else if (eventType == NSMouseMoved) 2893 { 2894 NSEvent *e; 2895 deltaX = eventLocation.x - lastLocation.x; 2896 deltaY = -(eventLocation.y - lastLocation.y); 2897 2898 if (wParam & MK_LBUTTON) 2899 { 2900 if (lDown == NO) 2901 { 2902 e = process_mouse_event(svr, hwnd, wParam, lParam, 2903 NSLeftMouseDown, uMsg); 2904 if (e != nil) 2905 [GSCurrentServer() postEvent: e atStart: NO]; 2906 } 2907 eventType = NSLeftMouseDragged; 2908 } 2909 else if (wParam & MK_RBUTTON) 2910 { 2911 if (lDown == YES) 2912 { 2913 e = process_mouse_event(svr, hwnd, wParam, lParam, 2914 NSLeftMouseUp, uMsg); 2915 if (e != nil) 2916 [GSCurrentServer() postEvent: e atStart: NO]; 2917 } 2918 if (rDown == NO) 2919 { 2920 e = process_mouse_event(svr, hwnd, wParam, lParam, 2921 NSRightMouseDown, uMsg); 2922 if (e != nil) 2923 [GSCurrentServer() postEvent: e atStart: NO]; 2924 } 2925 eventType = NSRightMouseDragged; 2926 } 2927 else if (wParam & MK_MBUTTON) 2928 { 2929 if (lDown == YES) 2930 { 2931 e = process_mouse_event(svr, hwnd, wParam, lParam, 2932 NSLeftMouseUp, uMsg); 2933 if (e != nil) 2934 [GSCurrentServer() postEvent: e atStart: NO]; 2935 } 2936 if (rDown == YES) 2937 { 2938 e = process_mouse_event(svr, hwnd, wParam, lParam, 2939 NSRightMouseUp, uMsg); 2940 if (e != nil) 2941 [GSCurrentServer() postEvent: e atStart: NO]; 2942 } 2943 if (oDown == NO) 2944 { 2945 e = process_mouse_event(svr, hwnd, wParam, lParam, 2946 NSOtherMouseDown, uMsg); 2947 if (e != nil) 2948 [GSCurrentServer() postEvent: e atStart: NO]; 2949 } 2950 eventType = NSOtherMouseDragged; 2951 } 2952 else 2953 { 2954 if (lDown == YES) 2955 { 2956 e = process_mouse_event(svr, hwnd, wParam, lParam, 2957 NSLeftMouseUp, uMsg); 2958 if (e != nil) 2959 [GSCurrentServer() postEvent: e atStart: NO]; 2960 } 2961 if (rDown == YES) 2962 { 2963 e = process_mouse_event(svr, hwnd, wParam, lParam, 2964 NSRightMouseUp, uMsg); 2965 if (e != nil) 2966 [GSCurrentServer() postEvent: e atStart: NO]; 2967 } 2968 if (oDown == YES) 2969 { 2970 e = process_mouse_event(svr, hwnd, wParam, lParam, 2971 NSOtherMouseUp, uMsg); 2972 if (e != nil) 2973 [GSCurrentServer() postEvent: e atStart: NO]; 2974 } 2975 } 2976 } 2977 else if ((eventType == NSLeftMouseDown) 2978 || (eventType == NSRightMouseDown) 2979 || (eventType == NSOtherMouseDown)) 2980 { 2981 // It seems Windows generates duplicate mouse down events on first click in a window 2982 if (ltime == lastTime) // duplicate event has identical time 2983 return nil; // ignore it 2984 2985 static NSPoint lastClick = {0.0, 0.0}; 2986 2987 if (lastTime + GetDoubleClickTime() > ltime 2988 && fabs(eventLocation.x - lastClick.x) < GetSystemMetrics(SM_CXDOUBLECLK) 2989 && fabs(eventLocation.y - lastClick.y) < GetSystemMetrics(SM_CYDOUBLECLK)) 2990 { 2991 clickCount += 1; 2992 } 2993 else 2994 { 2995 clickCount = 1; 2996 } 2997 lastTime = ltime; 2998 lastClick = eventLocation; 2999 3000 SetCapture(hwnd); // capture the mouse to get mouse moved events outside of window 3001 } 3002 else if ( ((eventType == NSLeftMouseUp) 3003 || (eventType == NSRightMouseUp) 3004 || (eventType == NSOtherMouseUp)) 3005 && !((wParam & MK_LBUTTON) || (wParam & MK_MBUTTON) || (wParam & MK_RBUTTON)) ) 3006 { 3007 ReleaseCapture(); // release capture when all mouse buttons are up 3008 } 3009 3010 if (eventType == NSLeftMouseDown) lDown = YES; 3011 if (eventType == NSRightMouseDown) rDown = YES; 3012 if (eventType == NSOtherMouseDown) oDown = YES; 3013 if (eventType == NSLeftMouseUp) lDown = NO; 3014 if (eventType == NSRightMouseUp) rDown = NO; 3015 if (eventType == NSOtherMouseUp) oDown = NO; 3016 3017 if (eventType == NSMouseMoved) { 3018 static HWND lastHwnd = 0; 3019 if (hwnd == lastHwnd && NSEqualPoints(eventLocation, lastLocation)) 3020 return nil; // mouse hasn't actually moved -- don't generate another event 3021 // record window and location of this event, to check next mouseMoved event against 3022 lastHwnd = hwnd; 3023 } 3024 3025 lastLocation = eventLocation; 3026 3027 event = [NSEvent mouseEventWithType: eventType 3028 location: eventLocation 3029 modifierFlags: eventFlags 3030 timestamp: time 3031 windowNumber: (int)hwnd 3032 context: gcontext 3033 eventNumber: tick 3034 clickCount: clickCount 3035 pressure: 1.0 3036 buttonNumber: 0 /* FIXME */ 3037 deltaX: deltaX 3038 deltaY: deltaY 3039 deltaZ: 0.]; 3040 3041 return event; 3042} 3043 3044 3045LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, 3046 WPARAM wParam, LPARAM lParam) 3047{ 3048 WIN32Server *ctxt = (WIN32Server *)GSCurrentServer(); 3049 3050 if(_enableCallbacks == NO) 3051 { 3052 return (LRESULT)NULL; 3053 } 3054 3055 return [ctxt windowEventProc: hwnd : uMsg : wParam : lParam]; 3056} 3057 3058