4 #include <X11/keysymdef.h>
7 /* a crude method to avoid losing the selection when
8 calling EmptyClipboard, which is necessary to do
9 every time the selection content changes, otherwise
10 windows apps use a cached copy of the selection */
11 static volatile int destroyClipboardCatcher = 0;
12 static NT_window *NT_CWIN = NULL;
14 catchNextDestroyClipboard()
16 destroyClipboardCatcher=1;
19 typedef struct WinEvent_
28 typedef struct WinEventQ_
35 proto_W11EventHandler *handler;
36 WinEvent list[W11_QSIZE];
39 static WinEventQ *wineventq = NULL;
44 WinEventQ *q = (WinEventQ *)allocateMemory(sizeof(WinEventQ));
51 for (i=0; i<W11_QSIZE; i++) {
53 q->list[i].window = NULL;
59 getQdEvent(WinEventQ *q, XEvent *ev)
63 cjh_printf("Queue is empty\n");
66 we = q->list[q->next];
67 WinEventToXEvent(&we,ev);
70 if (q->next>q->num) q->next=0;
75 QSendEvent(WinEventQ *q)
78 if (q->handler != NULL) {
79 if (getQdEvent(q,&e)) (q->handler)(&e);
84 QEvent(WinEventQ *q, NT_window *window,UINT message,UINT wParam,LONG lParam)
86 q->list[q->avail].window=window;
87 q->list[q->avail].message=message;
88 q->list[q->avail].wParam=wParam;
89 q->list[q->avail].lParam=lParam;
90 q->avail++; q->count++;
91 if (q->avail>q->num) q->avail=0;
92 if (q->dispatch) QSendEvent(q);
97 /* Allow application to install an event handler call back.
98 This will make some actions such as moving the window work
101 The event handler should look like:
102 void process_xevent(XEvent *ev) { }
105 W11AddEventHandler(display,process_xevent);
107 The specific problem is that calling DefWindowProc()
108 in response to a WM_SYSCOMMAND will cause windows to run its
109 own event loop waiting for the mouse up event. The application
110 therefore cannot rely on it's main event loop to get run for
111 each event. Without running multiple threads, or setjmp, there
112 is little recourse for alerting the application in the
113 traditional X manner to Expose events while the window is
117 void W11AddEventHandler(Display *d, proto_W11EventHandler *ev)
119 wineventq->handler = ev;
124 doTranslateMessage(MSG *m)
126 if ((m->message == WM_KEYDOWN) &&
127 ((m->wParam == VK_BACK) ||
128 (((m->wParam == VK_ADD) || (m->wParam == VK_SUBTRACT)) &&
129 (GetKeyState(VK_SHIFT) & 0x8000)))) return;
130 if ((m->message == WM_SYSKEYDOWN) && (m->wParam == VK_F10))
132 m->message = WM_KEYDOWN;
139 NT_default(HWND hWnd,UINT message,UINT wParam,LONG lParam)
141 return DefWindowProc(hWnd, message, wParam, lParam);
147 PostMessage(hWnd,USR_WakeUp,0,0L);
150 /*****************************************************************\
152 Function: MainWndProc
153 Inputs: Window handle, message, message parameters.
155 Comments: This is called when messages are sent to the application
156 but not to the application's message queue. If an
157 event can be processed, it is done here. The equivalent
158 XEvent is filled out in l_event, which is picked up
159 in the X event routines. Some events are not received
160 from Windows, eg Enter/LeaveNotify, so these are made
163 Caution: The application does not see HWND, but Window.
165 \*****************************************************************/
179 HWND hWnd, /* window handle */
180 UINT message, /* type of message */
181 UINT wParam, /* additional information */
182 LONG lParam) /* additional information */
185 WINDOWPOS *posStruct;
186 unsigned long int st=0L;
189 PAINTSTRUCT paintStruct;
191 /* if (message == WM_CLOSE) exit(0); */
193 window = NT_find_window_from_id(hWnd);
194 if (window == NULL) return (NT_default(hWnd, message, wParam, lParam));
199 /* we'll handle these, later */
201 QEvent(wineventq,window,message,wParam,lParam);
208 case WM_SYSCHAR: /* alt-keys go here */
210 case WM_LBUTTONDBLCLK:
211 case WM_MBUTTONDBLCLK:
212 case WM_RBUTTONDBLCLK:
214 case USR_EnterNotify:
220 QEvent(wineventq,window,message,wParam,lParam);
222 case WM_DESTROYCLIPBOARD:
223 if (destroyClipboardCatcher)
224 destroyClipboardCatcher=0;
226 QEvent(wineventq,window,message,wParam,lParam);
231 BeginPaint(hWnd,&paintStruct);
232 FillRect(paintStruct.hdc, &paintStruct.rcPaint,window->bg);
233 QEvent(wineventq,window,message,
234 (((paintStruct.rcPaint.right-paintStruct.rcPaint.left)&0xffff) |
235 (((paintStruct.rcPaint.bottom-paintStruct.rcPaint.top)&0xffff)<<16)),
236 (((paintStruct.rcPaint.left)&0xffff) | (((paintStruct.rcPaint.top)&0xffff)<<16)));
238 EndPaint(hWnd,&paintStruct);
240 /* capture the mouse on button down to emulate x */
245 QEvent(wineventq,window,message,wParam,lParam);
251 QEvent(wineventq,window,message,wParam,lParam);
254 if ((mask&PointerMotionMask) ||
255 ((mask&Button1MotionMask)&& (wParam&MK_LBUTTON)) ||
256 ((mask&Button2MotionMask)&& (wParam&MK_MBUTTON)) ||
257 ((mask&Button3MotionMask)&& (wParam&MK_RBUTTON)) ||
258 ((mask&ButtonMotionMask)&&((wParam&(MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))))
260 QEvent(wineventq,window,message,wParam,lParam);
262 return (NT_default(hWnd, message, wParam, lParam));
265 /* this event only seems to go to the top most window.
266 see if child windows accept it. */
267 window = NT_find_child(window,ButtonPressMask|Button2MotionMask|Button3MotionMask,
268 ButtonPressMask|Button3MotionMask );
269 if (window && ((window->mask)&ButtonPressMask))
270 QEvent(wineventq,window,message,wParam,lParam);
272 return (NT_default(hWnd, message, wParam, lParam));
275 /* don't erase the background */
279 wineventq->dispatch++;
280 NT_default(hWnd, message, wParam, lParam);
281 wineventq->dispatch--;
320 QEvent(wineventq,window,message,wParam,lParam);
323 return (NT_default(hWnd, message, wParam, lParam));
328 default: /* Passes it on if unproccessed */
329 return (NT_default(hWnd, message, wParam, lParam));
334 /*****************************************************************\
336 Function: NT_get_state
339 Comments: Get the keyboard state
341 \*****************************************************************/
346 unsigned int state = 0;
347 if (GetKeyState(VK_SHIFT) & 0x8000) state |= ShiftMask;
348 if (GetKeyState(VK_CONTROL) & 0x8000)
350 if (!(GetKeyState(VK_MENU) & 0x8000))
351 state |= ControlMask;
353 else if (GetKeyState(VK_MENU) & 0x8000)
355 if (GetKeyState(VK_CAPITAL) & 0x0001) state |= LockMask;
356 if (GetKeyState(VK_NUMLOCK) & 0x0001) state |= Mod5Mask;
357 if (GetKeyState(VK_SCROLL) & 0x0001) state |= Mod3Mask;
358 if (GetKeyState(VK_LBUTTON) & 0x8000) state |= Button1Mask;
359 if (GetKeyState(VK_MBUTTON) & 0x8000) state |= Button2Mask;
360 if (GetKeyState(VK_RBUTTON) & 0x8000) state |= Button3Mask;
371 unsigned long int st=0L;
379 if (event==NULL) break;
380 if (we == NULL) break;
387 event->xbutton.subwindow = None;
390 switch (we->message) {
393 event->xfocus.window=(Window)window;
396 event->type=FocusOut;
397 event->xfocus.window=(Window)window;
399 /* case WM_ERASEBKGND: */
402 event->xexpose.x=LOWORD(lParam); /* right */
403 event->xexpose.y=HIWORD(lParam); /* top */
404 event->xexpose.width=LOWORD(wParam);
405 event->xexpose.height=HIWORD(wParam);
406 event->xexpose.count=0;
407 event->xexpose.window=(Window)window;
410 case WM_LBUTTONDBLCLK:
411 event->type = ButtonPress;
412 event->xbutton.x = LOWORD (lParam);
413 event->xbutton.y = HIWORD (lParam);
414 if ( wParam & MK_SHIFT )
415 event->xbutton.button=Button2;
417 event->xbutton.button=Button1;
418 event->xbutton.window = (Window)window;
419 event->xbutton.time=GetTickCount();
422 event->type=ButtonRelease;
423 event->xbutton.x=LOWORD(lParam);
424 event->xbutton.y=HIWORD (lParam);
425 if ( wParam & MK_SHIFT )
426 event->xbutton.button=Button2;
428 event->xbutton.button=Button1;
429 event->xbutton.window=(Window)window;
430 event->xbutton.time=GetTickCount();
433 case WM_MBUTTONDBLCLK:
434 event->type=ButtonPress;
435 event->xbutton.x=LOWORD(lParam);
436 event->xbutton.y=HIWORD (lParam);
437 event->xbutton.button=Button2;
438 event->xbutton.window=(Window)window;
439 event->xbutton.time=GetTickCount();
442 event->type=ButtonRelease;
443 event->xbutton.x=LOWORD(lParam);
444 event->xbutton.y=HIWORD (lParam);
445 event->xbutton.button=Button2;
446 event->xbutton.window=(Window)window;
447 event->xbutton.time=GetTickCount();
450 case WM_RBUTTONDBLCLK:
451 event->type=ButtonPress;
452 event->xbutton.x=LOWORD(lParam);
453 event->xbutton.y=HIWORD (lParam);
454 event->xbutton.button=Button3;
455 event->xbutton.window=(Window)window;
456 event->xbutton.time=GetTickCount();
459 event->type=ButtonRelease;
460 event->xbutton.x=LOWORD(lParam);
461 event->xbutton.y=HIWORD (lParam);
462 event->xbutton.button=Button3;
463 event->xbutton.window=(Window)window;
464 event->xbutton.time=GetTickCount();
467 if (hWnd!=(HWND)NT_CWIN) /* Mouse in different window? */
469 if (NT_CWIN==NULL) /* No previous window */
471 event->type = EnterNotify;
472 event->xcrossing.x = LOWORD(lParam);
473 event->xcrossing.y = HIWORD(lParam);
474 event->xcrossing.window = (Window)window;
478 event->type=LeaveNotify;
479 event->xcrossing.x=LOWORD(lParam);
480 event->xcrossing.y=HIWORD(lParam);
481 event->xcrossing.window = (Window)NT_find_window_from_id(NT_CWIN);
486 event->type=MotionNotify; /* Fill out mouse event */
487 event->xmotion.window=(Window)window;
488 event->xmotion.x=pt.x=LOWORD(lParam);
489 event->xmotion.y=pt.y=HIWORD(lParam);
490 event->xmotion.time=GetTickCount();
491 ClientToScreen(hWnd,&pt); /* Translate coordinates */
492 event->xmotion.x_root=pt.x;
493 event->xmotion.y_root=pt.y;
494 if (wParam&MK_CONTROL)
498 if (wParam&MK_LBUTTON)
500 if (wParam&MK_MBUTTON)
502 if (wParam&MK_RBUTTON)
504 event->xmotion.state=st;
506 NT_CWIN=(NT_window *)hWnd;
509 event->type=ButtonRelease;
510 event->xbutton.x=LOWORD(lParam);
511 event->xbutton.y=HIWORD (lParam);
512 event->xbutton.button=HIWORD(wParam)>32768?Button5:Button4;
513 event->xbutton.window=(Window)window;
514 event->xbutton.time=GetTickCount();
515 if (wParam&MK_CONTROL)
519 if (wParam&MK_LBUTTON)
521 if (wParam&MK_MBUTTON)
523 if (wParam&MK_RBUTTON)
525 event->xbutton.state=st;
529 event->type=KeyPress;
530 event->xkey.state=NT_get_state();
531 event->xkey.x=event->xkey.y=0; /* Inside the window */
532 event->xkey.keycode=LOWORD(wParam);
533 if (GetKeyState(VK_CONTROL) & 0x8000) {
534 if (event->xkey.keycode == 32) { event->xkey.keycode=0; }
535 if (event->xkey.keycode >255 ) { event->xkey.keycode=0; }
537 event->xkey.window=(Window)window;
540 event->type=KeyPress;
543 case VK_CANCEL: key=XK_Cancel; break;
544 case VK_CLEAR: key=XK_Clear; break;
545 /* causes AltGr to create a keypress */
546 /* case VK_MENU: key=XK_Alt_L; break;*/
547 case VK_PAUSE: key=XK_Pause; break;
548 case VK_PRIOR: key=XK_Prior; break;
549 case VK_NEXT: key=XK_Next; break;
550 case VK_END: key=XK_End; break;
551 case VK_HOME: key=XK_Home; break;
552 case VK_LEFT: key=XK_Left; break;
553 case VK_UP: key=XK_Up; break;
554 case VK_RIGHT: key=XK_Right; break;
555 case VK_DOWN: key=XK_Down; break;
556 case VK_SELECT: key=XK_Select; break;
557 case VK_PRINT: key=XK_Print; break;
558 case VK_EXECUTE: key=XK_Execute; break;
559 case VK_INSERT: key=XK_Insert; break;
560 case VK_DELETE: key=XK_Delete; break;
561 case VK_HELP: key=XK_Help; break;
562 case VK_NUMLOCK: key=XK_Num_Lock; break;
563 case VK_SCROLL: key=XK_Scroll_Lock; break;
564 case VK_BACK: key=XK_BackSpace; break;
565 case VK_F1: key=XK_F1; break;
566 case VK_F2: key=XK_F2; break;
567 case VK_F3: key=XK_F3; break;
568 case VK_F4: key=XK_F4; break;
569 case VK_F5: key=XK_F5; break;
570 case VK_F6: key=XK_F6; break;
571 case VK_F7: key=XK_F7; break;
572 case VK_F8: key=XK_F8; break;
573 case VK_F9: key=XK_F9; break;
574 case VK_F10: key=XK_F10; break;
575 case VK_F11: key=XK_F11; break;
576 case VK_F12: key=XK_F12; break;
577 case VK_ADD: key=XK_KP_Add; break;
578 case VK_SUBTRACT:key=XK_KP_Subtract; break;
579 default: key=0; break;
586 event->xkey.keycode=key;
587 event->xkey.window=(Window)window;
588 event->xkey.state=NT_get_state();
589 event->xkey.x=event->xkey.y=0; /* Inside the window */
595 event->type = ClientMessage;
596 event->xclient.format = 32;
597 event->xclient.data.l[0] = XInternAtom(NULL,"WM_DELETE_WINDOW", FALSE);
599 case USR_EnterNotify:
600 event->type = EnterNotify;
601 event->xcrossing.x = LOWORD(lParam);
602 event->xcrossing.y = HIWORD(lParam);
603 event->xcrossing.window = (Window)window;
608 window->x = LOWORD(lParam);
609 window->y = HIWORD(lParam);
610 NT_configureNotify(window,window->x,window->y);
611 event->type = ConfigureNotify;
612 event->xconfigure.window = (Window)window;
613 event->xconfigure.x = 0; /* client area is always @ 0 */
614 event->xconfigure.y = 0;
615 event->xconfigure.width = window->wdth;
616 event->xconfigure.height = window->hght;
617 event->xconfigure.above = Above;
621 event->type = ConfigureNotify;
622 window->wdth = LOWORD(lParam);
623 if (window->wdth<window->minx)
624 window->wdth = window->minx;
625 window->hght = HIWORD(lParam);
626 if (window->hght<window->minx)
627 window->hght = window->miny;
628 NT_configureNotify(window,window->x,window->y);
629 event->xconfigure.window = (Window)window;
630 event->xconfigure.x = 0;
631 event->xconfigure.y = 0;
632 event->xconfigure.width = window->wdth;
633 event->xconfigure.height = window->hght;
634 event->xconfigure.above = Above;
640 event->type=UnmapNotify;
644 event->type = ConfigureNotify;
645 window->wdth = LOWORD(lParam);
646 if (window->wdth<window->minx)
647 window->wdth = window->minx;
648 window->hght = HIWORD(lParam);
649 if (window->hght<window->minx)
650 window->hght = window->miny;
651 event->xconfigure.window = (Window)window;
652 event->xconfigure.x = 0;
653 event->xconfigure.y = 0;
654 event->xconfigure.width = window->wdth;
655 event->xconfigure.height = window->hght;
656 event->xconfigure.above = Above;
658 if (window->min) event->type=MapNotify;
664 case WM_DESTROYCLIPBOARD:
665 event->type = SelectionClear;
666 event->xselectionclear.time = GetTickCount();
669 event->type=MapNotify;
671 case USR_ConvertSelection:
672 event->type=SelectionNotify;
673 event->xselection.requestor = (Window)window;
674 event->xselection.property = XA_CUT_BUFFER0;
680 return (event==NULL?0: (event->type==-1?0:1));
682 /*****************************************************************\
685 Function: XCheckWindowEvent
686 Inputs: display, window, event mask.
687 Returned: pointer to filled in event structure, status.
689 Comments: This is fudged at the moment to work with the toolkit.
690 The event system needs rewriting to account properly for
693 \*****************************************************************/
696 XCheckTypedEvent(display,ev,rep)
701 xtrace("XCheckTypedEvent\n");
706 XCheckWindowEvent(display,w,emask,ev)
712 NT_window *ntw=(NT_window *)w;
716 xtrace("XCheckWindowEvent\n");
718 if (PeekMessage(&msg,ntw->w,USR_MapNotify,
719 USR_MapNotify,PM_REMOVE)||
720 PeekMessage(&msg,ntw->w,WM_PAINT,WM_PAINT,PM_REMOVE))
722 cjh_printf("removed message\n");
723 ev->type=ConfigureNotify;
730 XPending checks for x events pending.
731 We don't know if we have x events until we process
739 /* xtrace("XPending\n"); */
740 while(wineventq->count<=0 && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
742 doTranslateMessage(&msg);
743 DispatchMessage(&msg);
745 return wineventq->count;
749 XPutBackEvent(display,event)
753 xtrace("XPutBackEvent\n");
759 XSendEvent(display,w,prop,emask,event)
766 xtrace("XSendEvent\n");
770 /* I'm tempted to flush the windows queue
771 ** before checking, but I think that would
772 ** break the assumtion that most of the WM_PAINT
773 ** messges are only going to be dispatched when
774 ** the app is directly calling us.
778 XCheckTypedWindowEvent(
782 XEvent* event_return)
785 xtrace("XCheckTypedWindowEvent\n");
789 while(i != wineventq->avail)
791 if (wineventq->list[i].window==(NT_window*)w)
793 WinEventToXEvent(&wineventq->list[i],event_return);
794 if (event_return->type == event_type)
800 if (i>wineventq->num) i=0;
802 if (i != wineventq->avail)
804 while(i != wineventq->next)
807 if (j<0) j= wineventq->num;
808 copyWinEvent(&wineventq->list[i],&wineventq->list[j]);
813 cjh_printf("removed an event\n");
820 /*****************************************************************\
823 Function: XWindowEvent
824 Inputs: display, window, event mask.
825 Returned: pointer to filled in event structure.
827 Comments: This is fudged at the moment to work with the toolkit.
828 The event system needs rewriting to account properly for
831 \*****************************************************************/
834 XWindowEvent(display,w,emask,rep)
840 NT_window *ntw=(NT_window *)w;
843 xtrace("XWindowEvent\n");
844 if (emask&ExposureMask)
846 GetMessage(&msg,ntw->w,USR_MapNotify,USR_MapNotify);
847 rep->type=ConfigureNotify;
854 /*****************************************************************\
857 Inputs: display, event structure pointer.
859 Comments: Windows routines receive messages (events) in two ways:
860 firstly by GetMessage, which takes messages from the
861 calling thread's message queue, and secondly by the
862 window function being called with events as arguments.
863 To simulate the X system, we get messages from the queue
864 and pass them to the window function anyway, which
865 processes them and fills out the local XEvent structure.
866 DispatchMessage calls the window procedure and waits until
867 it returns. Translate message turns WM_KEYUP/DOWN messages
870 \*****************************************************************/
873 XNextEvent(Display *display,XEvent *event)
877 xtrace("XNextEvent\n");
879 /* if there isn't already an event in the pipe, this will block */
880 while(wineventq->count <= 0 && GetMessage(&msg, NULL, 0, 0)>0)
882 doTranslateMessage(&msg);
883 DispatchMessage(&msg);
885 if (wineventq->count>0)
887 getQdEvent(wineventq,event);
891 /* hmm, GetMessage failed, maybe we're supposed to quit */
892 event->type=ClientMessage;
893 event->xclient.format = 32;
894 event->xclient.data.l[0] = XInternAtom(NULL,"WM_DELETE_WINDOW", FALSE);
901 XFilterEvent(XEvent* event,Window window)
903 xtrace("XFilterEvent\n");
912 Window* child_return,
917 unsigned int* mask_return)
921 xtrace("XQueryPointer\n");
922 GetCursorPos(&point);
923 *root_x_return = point.x;
924 *root_y_return = point.y;
925 GetWindowRect(((NT_window*)w)->w,&rect);
926 *win_x_return= point.x - rect.left;
927 *win_y_return= point.y - rect.top;
928 *mask_return = NT_get_state();
935 Atom sel, Atom target, Atom prop,
939 xtrace("XConvertSelection\n");
940 QEvent(wineventq,(NT_window*)req,USR_ConvertSelection,0,0L);
941 NT_wakeup(((NT_window*)req)->w);