106 applicationActive = toplevel.isFocused();
107 }
108 }
109
110 void deinstallActivateListener() {
111 Window toplevel = getTopLevel(target);
112 if (toplevel != null) {
113 toplevel.removeWindowFocusListener(this);
114 }
115 }
116
117 boolean isXEmbedActive() {
118 return xembed.handle != 0;
119 }
120
121 boolean isApplicationActive() {
122 return applicationActive;
123 }
124
125 void initDispatching() {
126 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("Init embedding for " + Long.toHexString(xembed.handle));
127 XToolkit.awtLock();
128 try {
129 XToolkit.addEventDispatcher(xembed.handle, xembed);
130 XlibWrapper.XSelectInput(XToolkit.getDisplay(), xembed.handle,
131 XConstants.StructureNotifyMask | XConstants.PropertyChangeMask);
132
133 XDropTargetRegistry.getRegistry().registerXEmbedClient(getWindow(), xembed.handle);
134 } finally {
135 XToolkit.awtUnlock();
136 }
137 xembed.processXEmbedInfo();
138
139 notifyChildEmbedded();
140 }
141
142 void endDispatching() {
143 xembedLog.fine("End dispatching for " + Long.toHexString(xembed.handle));
144 XToolkit.awtLock();
145 try {
146 XDropTargetRegistry.getRegistry().unregisterXEmbedClient(getWindow(), xembed.handle);
147 // We can't deselect input since someone else might be interested in it
148 XToolkit.removeEventDispatcher(xembed.handle, xembed);
149 } finally {
150 XToolkit.awtUnlock();
151 }
152 }
153
154 void embedChild(long child) {
155 if (xembed.handle != 0) {
156 detachChild();
157 }
158 xembed.handle = child;
159 initDispatching();
160 }
161
162 void childDestroyed() {
163 xembedLog.fine("Child " + Long.toHexString(xembed.handle) + " has self-destroyed.");
164 endDispatching();
165 xembed.handle = 0;
166 }
167
168 public void handleEvent(AWTEvent e) {
169 super.handleEvent(e);
170 if (isXEmbedActive()) {
171 switch (e.getID()) {
172 case FocusEvent.FOCUS_GAINED:
173 canvasFocusGained((FocusEvent)e);
174 break;
175 case FocusEvent.FOCUS_LOST:
176 canvasFocusLost((FocusEvent)e);
177 break;
178 case KeyEvent.KEY_PRESSED:
179 case KeyEvent.KEY_RELEASED:
180 if (!((InputEvent)e).isConsumed()) {
181 forwardKeyEvent((KeyEvent)e);
182 }
183 break;
365 }
366 }));
367 } else {
368 xembedLog.fine("XEmbed is not active - denying request focus");
369 }
370 }
371
372 void notifyChildEmbedded() {
373 xembed.sendMessage(xembed.handle, XEMBED_EMBEDDED_NOTIFY, getWindow(), Math.min(xembed.version, XEMBED_VERSION), 0);
374 if (isApplicationActive()) {
375 xembedLog.fine("Sending WINDOW_ACTIVATE during initialization");
376 xembed.sendMessage(xembed.handle, XEMBED_WINDOW_ACTIVATE);
377 if (hasFocus()) {
378 xembedLog.fine("Sending FOCUS_GAINED during initialization");
379 xembed.sendMessage(xembed.handle, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0);
380 }
381 }
382 }
383
384 void detachChild() {
385 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("Detaching child " + Long.toHexString(xembed.handle));
386 /**
387 * XEmbed specification:
388 * "The embedder can unmap the client and reparent the client window to the root window. If the
389 * client receives an ReparentNotify event, it should check the parent field of the XReparentEvent
390 * structure. If this is the root window of the window's screen, then the protocol is finished and
391 * there is no further interaction. If it is a window other than the root window, then the protocol
392 * continues with the new parent acting as the embedder window."
393 */
394 XToolkit.awtLock();
395 try {
396 XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), xembed.handle);
397 XlibWrapper.XReparentWindow(XToolkit.getDisplay(), xembed.handle, XToolkit.getDefaultRootWindow(), 0, 0);
398 } finally {
399 XToolkit.awtUnlock();
400 }
401 endDispatching();
402 xembed.handle = 0;
403 }
404
405 public void windowGainedFocus(WindowEvent e) {
446 }
447 }
448 xembed.sendMessage(xembed.handle, XEMBED_FOCUS_OUT, num, 0, 0);
449 }
450 }
451
452 static byte[] getBData(KeyEvent e) {
453 return AWTAccessor.getAWTEventAccessor().getBData(e);
454 }
455
456 void forwardKeyEvent(KeyEvent e) {
457 xembedLog.fine("Try to forward key event");
458 byte[] bdata = getBData(e);
459 long data = Native.toData(bdata);
460 if (data == 0) {
461 return;
462 }
463 try {
464 XKeyEvent ke = new XKeyEvent(data);
465 ke.set_window(xembed.handle);
466 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("Forwarding native key event: " + ke);
467 XToolkit.awtLock();
468 try {
469 XlibWrapper.XSendEvent(XToolkit.getDisplay(), xembed.handle, false, XConstants.NoEventMask, data);
470 } finally {
471 XToolkit.awtUnlock();
472 }
473 } finally {
474 XlibWrapper.unsafe.freeMemory(data);
475 }
476 }
477
478
479 /**
480 * Grab/ungrab key functionality is an unofficial API supported by
481 * GTK. Unfortunately, it doesn't support accelerator API, so,
482 * since this is the ONLY shortcut-processing API available, we
483 * must support it. See XEmbed.NON_STANDARD_XEMBED_GTK_*
484 * messages. The format of these messages is as follows:
485 * - request from client:
486 * data[1] = NON_STANDARD_XEMBED_GTK_GRAB_KEY or NON_STANDARD_XEMBED_GTK_UNGRAB_KEY
487 * data[3] = X keysym
488 * data[4] = X modifiers
489 *
490 * - response from server (in case the grabbed key has been pressed):
491 * forwarded XKeyEvent that matches keysym/modifiers pair
492 */
493 void grabKey(final long keysym, final long modifiers) {
494 postEvent(new InvocationEvent(target, new Runnable() {
495 public void run() {
496 GrabbedKey grab = new GrabbedKey(keysym, modifiers);
497 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("Grabbing key: " + grab);
498 synchronized(GRAB_LOCK) {
499 grabbed_keys.add(grab);
500 }
501 }
502 }));
503 }
504
505 void ungrabKey(final long keysym, final long modifiers) {
506 postEvent(new InvocationEvent(target, new Runnable() {
507 public void run() {
508 GrabbedKey grab = new GrabbedKey(keysym, modifiers);
509 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("UnGrabbing key: " + grab);
510 synchronized(GRAB_LOCK) {
511 grabbed_keys.remove(grab);
512 }
513 }
514 }));
515 }
516
517 void registerAccelerator(final long accel_id, final long keysym, final long modifiers) {
518 postEvent(new InvocationEvent(target, new Runnable() {
519 public void run() {
520 AWTKeyStroke stroke = xembed.getKeyStrokeForKeySym(keysym, modifiers);
521 if (stroke != null) {
522 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("Registering accelerator " + accel_id + " for " + stroke);
523 synchronized(ACCEL_LOCK) {
524 accelerators.put(accel_id, stroke);
525 accel_lookup.put(stroke, accel_id);
526 }
527 }
528 propogateRegisterAccelerator(stroke);
529 }
530 }));
531 }
532
533 void unregisterAccelerator(final long accel_id) {
534 postEvent(new InvocationEvent(target, new Runnable() {
535 public void run() {
536 AWTKeyStroke stroke = null;
537 synchronized(ACCEL_LOCK) {
538 stroke = accelerators.get(accel_id);
539 if (stroke != null) {
540 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("Unregistering accelerator: " + accel_id);
541 accelerators.remove(accel_id);
542 accel_lookup.remove(stroke); // FIXME: How about several accelerators with the same stroke?
543 }
544 }
545 propogateUnRegisterAccelerator(stroke);
546 }
547 }));
548 }
549
550 void propogateRegisterAccelerator(AWTKeyStroke stroke) {
551 // Find the top-level and see if it is XEmbed client. If so, ask him to
552 // register the accelerator
553 XWindowPeer parent = getToplevelXWindow();
554 if (parent != null && parent instanceof XEmbeddedFramePeer) {
555 XEmbeddedFramePeer embedded = (XEmbeddedFramePeer)parent;
556 embedded.registerAccelerator(stroke);
557 }
558 }
559
560 void propogateUnRegisterAccelerator(AWTKeyStroke stroke) {
566 embedded.unregisterAccelerator(stroke);
567 }
568 }
569
570 public boolean postProcessKeyEvent(KeyEvent e) {
571 // Processing events only if we are in the focused window but
572 // we are not focus owner since otherwise we will get
573 // duplicate shortcut events in the client - one is from
574 // activate_accelerator, another from forwarded event
575 // FIXME: This is probably an incompatibility, protocol
576 // doesn't say anything about disable accelerators when client
577 // is focused.
578
579 XWindowPeer parent = getToplevelXWindow();
580 if (parent == null || !((Window)parent.getTarget()).isFocused() || target.isFocusOwner()) {
581 return false;
582 }
583
584 boolean result = false;
585
586 if (xembedLog.isLoggable(PlatformLogger.FINER)) xembedLog.finer("Post-processing event " + e);
587
588 // Process ACCELERATORS
589 AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e);
590 long accel_id = 0;
591 boolean exists = false;
592 synchronized(ACCEL_LOCK) {
593 exists = accel_lookup.containsKey(stroke);
594 if (exists) {
595 accel_id = accel_lookup.get(stroke).longValue();
596 }
597 }
598 if (exists) {
599 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("Activating accelerator " + accel_id);
600 xembed.sendMessage(xembed.handle, XEMBED_ACTIVATE_ACCELERATOR, accel_id, 0, 0); // FIXME: How about overloaded?
601 result = true;
602 }
603
604 // Process Grabs, unofficial GTK feature
605 exists = false;
606 GrabbedKey key = new GrabbedKey(e);
607 synchronized(GRAB_LOCK) {
608 exists = grabbed_keys.contains(key);
609 }
610 if (exists) {
611 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine("Forwarding grabbed key " + e);
612 forwardKeyEvent(e);
613 result = true;
614 }
615
616 return result;
617 }
618
619 public void modalityPushed(ModalityEvent ev) {
620 xembed.sendMessage(xembed.handle, XEMBED_MODALITY_ON);
621 }
622
623 public void modalityPopped(ModalityEvent ev) {
624 xembed.sendMessage(xembed.handle, XEMBED_MODALITY_OFF);
625 }
626
627 public void handleClientMessage(XEvent xev) {
628 super.handleClientMessage(xev);
629 XClientMessageEvent msg = xev.get_xclient();
630 if (xembedLog.isLoggable(PlatformLogger.FINER)) xembedLog.finer("Client message to embedder: " + msg);
631 if (msg.get_message_type() == xembed.XEmbed.getAtom()) {
632 if (xembedLog.isLoggable(PlatformLogger.FINE)) xembedLog.fine(xembed.XEmbedMessageToString(msg));
633 }
634 if (isXEmbedActive()) {
635 switch ((int)msg.get_data(1)) {
636 case XEMBED_REQUEST_FOCUS:
637 requestXEmbedFocus();
638 break;
639 case XEMBED_FOCUS_NEXT:
640 focusNext();
641 break;
642 case XEMBED_FOCUS_PREV:
643 focusPrev();
644 break;
645 case XEMBED_REGISTER_ACCELERATOR:
646 registerAccelerator(msg.get_data(2), msg.get_data(3), msg.get_data(4));
647 break;
648 case XEMBED_UNREGISTER_ACCELERATOR:
649 unregisterAccelerator(msg.get_data(2));
650 break;
651 case NON_STANDARD_XEMBED_GTK_GRAB_KEY:
652 grabKey(msg.get_data(3), msg.get_data(4));
713 long handle; // Handle to XEmbed client
714 long version;
715 long flags;
716
717 boolean processXEmbedInfo() {
718 long xembed_info_data = Native.allocateLongArray(2);
719 try {
720 if (!XEmbedInfo.getAtomData(handle, xembed_info_data, 2)) {
721 // No more XEMBED_INFO? This is not XEmbed client!
722 // Unfortunately this is the initial state of the most clients
723 // FIXME: add 5-state processing
724 //childDestroyed();
725 xembedLog.finer("Unable to get XEMBED_INFO atom data");
726 return false;
727 }
728 version = Native.getCard32(xembed_info_data, 0);
729 flags = Native.getCard32(xembed_info_data, 1);
730 boolean new_mapped = (flags & XEMBED_MAPPED) != 0;
731 boolean currently_mapped = XlibUtil.getWindowMapState(handle) != XConstants.IsUnmapped;
732 if (new_mapped != currently_mapped) {
733 if (xembedLog.isLoggable(PlatformLogger.FINER))
734 xembedLog.fine("Mapping state of the client has changed, old state: " + currently_mapped + ", new state: " + new_mapped);
735 if (new_mapped) {
736 XToolkit.awtLock();
737 try {
738 XlibWrapper.XMapWindow(XToolkit.getDisplay(), handle);
739 } finally {
740 XToolkit.awtUnlock();
741 }
742 } else {
743 XToolkit.awtLock();
744 try {
745 XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), handle);
746 } finally {
747 XToolkit.awtUnlock();
748 }
749 }
750 } else {
751 xembedLog.finer("Mapping state didn't change, mapped: " + currently_mapped);
752 }
753 return true;
754 } finally {
755 XlibWrapper.unsafe.freeMemory(xembed_info_data);
756 }
757 }
758
759 public void handlePropertyNotify(XEvent xev) {
760 if (isXEmbedActive()) {
761 XPropertyEvent ev = xev.get_xproperty();
762 if (xembedLog.isLoggable(PlatformLogger.FINER)) xembedLog.finer("Property change on client: " + ev);
763 if (ev.get_atom() == XAtom.XA_WM_NORMAL_HINTS) {
764 childResized();
765 } else if (ev.get_atom() == XEmbedInfo.getAtom()) {
766 processXEmbedInfo();
767 } else if (ev.get_atom() ==
768 XDnDConstants.XA_XdndAware.getAtom()) {
769 XDropTargetRegistry.getRegistry().unregisterXEmbedClient(getWindow(),
770 xembed.handle);
771 if (ev.get_state() == XConstants.PropertyNewValue) {
772 XDropTargetRegistry.getRegistry().registerXEmbedClient(getWindow(),
773 xembed.handle);
774 }
775 }
776 } else {
777 xembedLog.finer("XEmbed is not active");
778 }
779 }
780 void handleConfigureNotify(XEvent xev) {
781 if (isXEmbedActive()) {
782 XConfigureEvent ev = xev.get_xconfigure();
783 if (xembedLog.isLoggable(PlatformLogger.FINER)) xembedLog.finer("Bounds change on client: " + ev);
784 if (xev.get_xany().get_window() == handle) {
785 childResized();
786 }
787 }
788 }
789 public void dispatchEvent(XEvent xev) {
790 int type = xev.get_type();
791 switch (type) {
792 case XConstants.PropertyNotify:
793 handlePropertyNotify(xev);
794 break;
795 case XConstants.ConfigureNotify:
796 handleConfigureNotify(xev);
797 break;
798 case XConstants.ClientMessage:
799 handleClientMessage(xev);
800 break;
801 }
802 }
803 }
814 init(ev);
815 }
816
817 private void init(KeyEvent e) {
818 byte[] bdata = getBData(e);
819 long data = Native.toData(bdata);
820 if (data == 0) {
821 return;
822 }
823 try {
824 XToolkit.awtLock();
825 try {
826 keysym = XWindow.getKeySymForAWTKeyCode(e.getKeyCode());
827 } finally {
828 XToolkit.awtUnlock();
829 }
830 XKeyEvent ke = new XKeyEvent(data);
831
832 // We recognize only these masks
833 modifiers = ke.get_state() & (XConstants.ShiftMask | XConstants.ControlMask | XConstants.LockMask);
834 if (xembedLog.isLoggable(PlatformLogger.FINEST)) xembedLog.finest("Mapped " + e + " to " + this);
835 } finally {
836 XlibWrapper.unsafe.freeMemory(data);
837 }
838 }
839
840 public int hashCode() {
841 return (int)keysym & 0xFFFFFFFF;
842 }
843
844 public boolean equals(Object o) {
845 if (!(o instanceof GrabbedKey)) {
846 return false;
847 }
848 GrabbedKey key = (GrabbedKey)o;
849 return (keysym == key.keysym && modifiers == key.modifiers);
850 }
851
852 public String toString() {
853 return "Key combination[keysym=" + keysym + ", mods=" + modifiers + "]";
854 }
|
106 applicationActive = toplevel.isFocused();
107 }
108 }
109
110 void deinstallActivateListener() {
111 Window toplevel = getTopLevel(target);
112 if (toplevel != null) {
113 toplevel.removeWindowFocusListener(this);
114 }
115 }
116
117 boolean isXEmbedActive() {
118 return xembed.handle != 0;
119 }
120
121 boolean isApplicationActive() {
122 return applicationActive;
123 }
124
125 void initDispatching() {
126 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
127 xembedLog.fine("Init embedding for " + Long.toHexString(xembed.handle));
128 }
129 XToolkit.awtLock();
130 try {
131 XToolkit.addEventDispatcher(xembed.handle, xembed);
132 XlibWrapper.XSelectInput(XToolkit.getDisplay(), xembed.handle,
133 XConstants.StructureNotifyMask | XConstants.PropertyChangeMask);
134
135 XDropTargetRegistry.getRegistry().registerXEmbedClient(getWindow(), xembed.handle);
136 } finally {
137 XToolkit.awtUnlock();
138 }
139 xembed.processXEmbedInfo();
140
141 notifyChildEmbedded();
142 }
143
144 void endDispatching() {
145 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
146 xembedLog.fine("End dispatching for " + Long.toHexString(xembed.handle));
147 }
148 XToolkit.awtLock();
149 try {
150 XDropTargetRegistry.getRegistry().unregisterXEmbedClient(getWindow(), xembed.handle);
151 // We can't deselect input since someone else might be interested in it
152 XToolkit.removeEventDispatcher(xembed.handle, xembed);
153 } finally {
154 XToolkit.awtUnlock();
155 }
156 }
157
158 void embedChild(long child) {
159 if (xembed.handle != 0) {
160 detachChild();
161 }
162 xembed.handle = child;
163 initDispatching();
164 }
165
166 void childDestroyed() {
167 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
168 xembedLog.fine("Child " + Long.toHexString(xembed.handle) + " has self-destroyed.");
169 }
170 endDispatching();
171 xembed.handle = 0;
172 }
173
174 public void handleEvent(AWTEvent e) {
175 super.handleEvent(e);
176 if (isXEmbedActive()) {
177 switch (e.getID()) {
178 case FocusEvent.FOCUS_GAINED:
179 canvasFocusGained((FocusEvent)e);
180 break;
181 case FocusEvent.FOCUS_LOST:
182 canvasFocusLost((FocusEvent)e);
183 break;
184 case KeyEvent.KEY_PRESSED:
185 case KeyEvent.KEY_RELEASED:
186 if (!((InputEvent)e).isConsumed()) {
187 forwardKeyEvent((KeyEvent)e);
188 }
189 break;
371 }
372 }));
373 } else {
374 xembedLog.fine("XEmbed is not active - denying request focus");
375 }
376 }
377
378 void notifyChildEmbedded() {
379 xembed.sendMessage(xembed.handle, XEMBED_EMBEDDED_NOTIFY, getWindow(), Math.min(xembed.version, XEMBED_VERSION), 0);
380 if (isApplicationActive()) {
381 xembedLog.fine("Sending WINDOW_ACTIVATE during initialization");
382 xembed.sendMessage(xembed.handle, XEMBED_WINDOW_ACTIVATE);
383 if (hasFocus()) {
384 xembedLog.fine("Sending FOCUS_GAINED during initialization");
385 xembed.sendMessage(xembed.handle, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0);
386 }
387 }
388 }
389
390 void detachChild() {
391 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
392 xembedLog.fine("Detaching child " + Long.toHexString(xembed.handle));
393 }
394 /**
395 * XEmbed specification:
396 * "The embedder can unmap the client and reparent the client window to the root window. If the
397 * client receives an ReparentNotify event, it should check the parent field of the XReparentEvent
398 * structure. If this is the root window of the window's screen, then the protocol is finished and
399 * there is no further interaction. If it is a window other than the root window, then the protocol
400 * continues with the new parent acting as the embedder window."
401 */
402 XToolkit.awtLock();
403 try {
404 XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), xembed.handle);
405 XlibWrapper.XReparentWindow(XToolkit.getDisplay(), xembed.handle, XToolkit.getDefaultRootWindow(), 0, 0);
406 } finally {
407 XToolkit.awtUnlock();
408 }
409 endDispatching();
410 xembed.handle = 0;
411 }
412
413 public void windowGainedFocus(WindowEvent e) {
454 }
455 }
456 xembed.sendMessage(xembed.handle, XEMBED_FOCUS_OUT, num, 0, 0);
457 }
458 }
459
460 static byte[] getBData(KeyEvent e) {
461 return AWTAccessor.getAWTEventAccessor().getBData(e);
462 }
463
464 void forwardKeyEvent(KeyEvent e) {
465 xembedLog.fine("Try to forward key event");
466 byte[] bdata = getBData(e);
467 long data = Native.toData(bdata);
468 if (data == 0) {
469 return;
470 }
471 try {
472 XKeyEvent ke = new XKeyEvent(data);
473 ke.set_window(xembed.handle);
474 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
475 xembedLog.fine("Forwarding native key event: " + ke);
476 }
477 XToolkit.awtLock();
478 try {
479 XlibWrapper.XSendEvent(XToolkit.getDisplay(), xembed.handle, false, XConstants.NoEventMask, data);
480 } finally {
481 XToolkit.awtUnlock();
482 }
483 } finally {
484 XlibWrapper.unsafe.freeMemory(data);
485 }
486 }
487
488
489 /**
490 * Grab/ungrab key functionality is an unofficial API supported by
491 * GTK. Unfortunately, it doesn't support accelerator API, so,
492 * since this is the ONLY shortcut-processing API available, we
493 * must support it. See XEmbed.NON_STANDARD_XEMBED_GTK_*
494 * messages. The format of these messages is as follows:
495 * - request from client:
496 * data[1] = NON_STANDARD_XEMBED_GTK_GRAB_KEY or NON_STANDARD_XEMBED_GTK_UNGRAB_KEY
497 * data[3] = X keysym
498 * data[4] = X modifiers
499 *
500 * - response from server (in case the grabbed key has been pressed):
501 * forwarded XKeyEvent that matches keysym/modifiers pair
502 */
503 void grabKey(final long keysym, final long modifiers) {
504 postEvent(new InvocationEvent(target, new Runnable() {
505 public void run() {
506 GrabbedKey grab = new GrabbedKey(keysym, modifiers);
507 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
508 xembedLog.fine("Grabbing key: " + grab);
509 }
510 synchronized(GRAB_LOCK) {
511 grabbed_keys.add(grab);
512 }
513 }
514 }));
515 }
516
517 void ungrabKey(final long keysym, final long modifiers) {
518 postEvent(new InvocationEvent(target, new Runnable() {
519 public void run() {
520 GrabbedKey grab = new GrabbedKey(keysym, modifiers);
521 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
522 xembedLog.fine("UnGrabbing key: " + grab);
523 }
524 synchronized(GRAB_LOCK) {
525 grabbed_keys.remove(grab);
526 }
527 }
528 }));
529 }
530
531 void registerAccelerator(final long accel_id, final long keysym, final long modifiers) {
532 postEvent(new InvocationEvent(target, new Runnable() {
533 public void run() {
534 AWTKeyStroke stroke = xembed.getKeyStrokeForKeySym(keysym, modifiers);
535 if (stroke != null) {
536 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
537 xembedLog.fine("Registering accelerator " + accel_id + " for " + stroke);
538 }
539 synchronized(ACCEL_LOCK) {
540 accelerators.put(accel_id, stroke);
541 accel_lookup.put(stroke, accel_id);
542 }
543 }
544 propogateRegisterAccelerator(stroke);
545 }
546 }));
547 }
548
549 void unregisterAccelerator(final long accel_id) {
550 postEvent(new InvocationEvent(target, new Runnable() {
551 public void run() {
552 AWTKeyStroke stroke = null;
553 synchronized(ACCEL_LOCK) {
554 stroke = accelerators.get(accel_id);
555 if (stroke != null) {
556 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
557 xembedLog.fine("Unregistering accelerator: " + accel_id);
558 }
559 accelerators.remove(accel_id);
560 accel_lookup.remove(stroke); // FIXME: How about several accelerators with the same stroke?
561 }
562 }
563 propogateUnRegisterAccelerator(stroke);
564 }
565 }));
566 }
567
568 void propogateRegisterAccelerator(AWTKeyStroke stroke) {
569 // Find the top-level and see if it is XEmbed client. If so, ask him to
570 // register the accelerator
571 XWindowPeer parent = getToplevelXWindow();
572 if (parent != null && parent instanceof XEmbeddedFramePeer) {
573 XEmbeddedFramePeer embedded = (XEmbeddedFramePeer)parent;
574 embedded.registerAccelerator(stroke);
575 }
576 }
577
578 void propogateUnRegisterAccelerator(AWTKeyStroke stroke) {
584 embedded.unregisterAccelerator(stroke);
585 }
586 }
587
588 public boolean postProcessKeyEvent(KeyEvent e) {
589 // Processing events only if we are in the focused window but
590 // we are not focus owner since otherwise we will get
591 // duplicate shortcut events in the client - one is from
592 // activate_accelerator, another from forwarded event
593 // FIXME: This is probably an incompatibility, protocol
594 // doesn't say anything about disable accelerators when client
595 // is focused.
596
597 XWindowPeer parent = getToplevelXWindow();
598 if (parent == null || !((Window)parent.getTarget()).isFocused() || target.isFocusOwner()) {
599 return false;
600 }
601
602 boolean result = false;
603
604 if (xembedLog.isLoggable(PlatformLogger.FINER)) {
605 xembedLog.finer("Post-processing event " + e);
606 }
607
608 // Process ACCELERATORS
609 AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e);
610 long accel_id = 0;
611 boolean exists = false;
612 synchronized(ACCEL_LOCK) {
613 exists = accel_lookup.containsKey(stroke);
614 if (exists) {
615 accel_id = accel_lookup.get(stroke).longValue();
616 }
617 }
618 if (exists) {
619 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
620 xembedLog.fine("Activating accelerator " + accel_id);
621 }
622 xembed.sendMessage(xembed.handle, XEMBED_ACTIVATE_ACCELERATOR, accel_id, 0, 0); // FIXME: How about overloaded?
623 result = true;
624 }
625
626 // Process Grabs, unofficial GTK feature
627 exists = false;
628 GrabbedKey key = new GrabbedKey(e);
629 synchronized(GRAB_LOCK) {
630 exists = grabbed_keys.contains(key);
631 }
632 if (exists) {
633 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
634 xembedLog.fine("Forwarding grabbed key " + e);
635 }
636 forwardKeyEvent(e);
637 result = true;
638 }
639
640 return result;
641 }
642
643 public void modalityPushed(ModalityEvent ev) {
644 xembed.sendMessage(xembed.handle, XEMBED_MODALITY_ON);
645 }
646
647 public void modalityPopped(ModalityEvent ev) {
648 xembed.sendMessage(xembed.handle, XEMBED_MODALITY_OFF);
649 }
650
651 public void handleClientMessage(XEvent xev) {
652 super.handleClientMessage(xev);
653 XClientMessageEvent msg = xev.get_xclient();
654 if (xembedLog.isLoggable(PlatformLogger.FINER)) {
655 xembedLog.finer("Client message to embedder: " + msg);
656 }
657 if (msg.get_message_type() == xembed.XEmbed.getAtom()) {
658 if (xembedLog.isLoggable(PlatformLogger.FINE)) {
659 xembedLog.fine(xembed.XEmbedMessageToString(msg));
660 }
661 }
662 if (isXEmbedActive()) {
663 switch ((int)msg.get_data(1)) {
664 case XEMBED_REQUEST_FOCUS:
665 requestXEmbedFocus();
666 break;
667 case XEMBED_FOCUS_NEXT:
668 focusNext();
669 break;
670 case XEMBED_FOCUS_PREV:
671 focusPrev();
672 break;
673 case XEMBED_REGISTER_ACCELERATOR:
674 registerAccelerator(msg.get_data(2), msg.get_data(3), msg.get_data(4));
675 break;
676 case XEMBED_UNREGISTER_ACCELERATOR:
677 unregisterAccelerator(msg.get_data(2));
678 break;
679 case NON_STANDARD_XEMBED_GTK_GRAB_KEY:
680 grabKey(msg.get_data(3), msg.get_data(4));
741 long handle; // Handle to XEmbed client
742 long version;
743 long flags;
744
745 boolean processXEmbedInfo() {
746 long xembed_info_data = Native.allocateLongArray(2);
747 try {
748 if (!XEmbedInfo.getAtomData(handle, xembed_info_data, 2)) {
749 // No more XEMBED_INFO? This is not XEmbed client!
750 // Unfortunately this is the initial state of the most clients
751 // FIXME: add 5-state processing
752 //childDestroyed();
753 xembedLog.finer("Unable to get XEMBED_INFO atom data");
754 return false;
755 }
756 version = Native.getCard32(xembed_info_data, 0);
757 flags = Native.getCard32(xembed_info_data, 1);
758 boolean new_mapped = (flags & XEMBED_MAPPED) != 0;
759 boolean currently_mapped = XlibUtil.getWindowMapState(handle) != XConstants.IsUnmapped;
760 if (new_mapped != currently_mapped) {
761 if (xembedLog.isLoggable(PlatformLogger.FINER)) {
762 xembedLog.finer("Mapping state of the client has changed, old state: " + currently_mapped + ", new state: " + new_mapped);
763 }
764 if (new_mapped) {
765 XToolkit.awtLock();
766 try {
767 XlibWrapper.XMapWindow(XToolkit.getDisplay(), handle);
768 } finally {
769 XToolkit.awtUnlock();
770 }
771 } else {
772 XToolkit.awtLock();
773 try {
774 XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), handle);
775 } finally {
776 XToolkit.awtUnlock();
777 }
778 }
779 } else {
780 if (xembedLog.isLoggable(PlatformLogger.FINER)) {
781 xembedLog.finer("Mapping state didn't change, mapped: " + currently_mapped);
782 }
783 }
784 return true;
785 } finally {
786 XlibWrapper.unsafe.freeMemory(xembed_info_data);
787 }
788 }
789
790 public void handlePropertyNotify(XEvent xev) {
791 if (isXEmbedActive()) {
792 XPropertyEvent ev = xev.get_xproperty();
793 if (xembedLog.isLoggable(PlatformLogger.FINER)) {
794 xembedLog.finer("Property change on client: " + ev);
795 }
796 if (ev.get_atom() == XAtom.XA_WM_NORMAL_HINTS) {
797 childResized();
798 } else if (ev.get_atom() == XEmbedInfo.getAtom()) {
799 processXEmbedInfo();
800 } else if (ev.get_atom() ==
801 XDnDConstants.XA_XdndAware.getAtom()) {
802 XDropTargetRegistry.getRegistry().unregisterXEmbedClient(getWindow(),
803 xembed.handle);
804 if (ev.get_state() == XConstants.PropertyNewValue) {
805 XDropTargetRegistry.getRegistry().registerXEmbedClient(getWindow(),
806 xembed.handle);
807 }
808 }
809 } else {
810 xembedLog.finer("XEmbed is not active");
811 }
812 }
813 void handleConfigureNotify(XEvent xev) {
814 if (isXEmbedActive()) {
815 XConfigureEvent ev = xev.get_xconfigure();
816 if (xembedLog.isLoggable(PlatformLogger.FINER)) {
817 xembedLog.finer("Bounds change on client: " + ev);
818 }
819 if (xev.get_xany().get_window() == handle) {
820 childResized();
821 }
822 }
823 }
824 public void dispatchEvent(XEvent xev) {
825 int type = xev.get_type();
826 switch (type) {
827 case XConstants.PropertyNotify:
828 handlePropertyNotify(xev);
829 break;
830 case XConstants.ConfigureNotify:
831 handleConfigureNotify(xev);
832 break;
833 case XConstants.ClientMessage:
834 handleClientMessage(xev);
835 break;
836 }
837 }
838 }
849 init(ev);
850 }
851
852 private void init(KeyEvent e) {
853 byte[] bdata = getBData(e);
854 long data = Native.toData(bdata);
855 if (data == 0) {
856 return;
857 }
858 try {
859 XToolkit.awtLock();
860 try {
861 keysym = XWindow.getKeySymForAWTKeyCode(e.getKeyCode());
862 } finally {
863 XToolkit.awtUnlock();
864 }
865 XKeyEvent ke = new XKeyEvent(data);
866
867 // We recognize only these masks
868 modifiers = ke.get_state() & (XConstants.ShiftMask | XConstants.ControlMask | XConstants.LockMask);
869 if (xembedLog.isLoggable(PlatformLogger.FINEST)) {
870 xembedLog.finest("Mapped " + e + " to " + this);
871 }
872 } finally {
873 XlibWrapper.unsafe.freeMemory(data);
874 }
875 }
876
877 public int hashCode() {
878 return (int)keysym & 0xFFFFFFFF;
879 }
880
881 public boolean equals(Object o) {
882 if (!(o instanceof GrabbedKey)) {
883 return false;
884 }
885 GrabbedKey key = (GrabbedKey)o;
886 return (keysym == key.keysym && modifiers == key.modifiers);
887 }
888
889 public String toString() {
890 return "Key combination[keysym=" + keysym + ", mods=" + modifiers + "]";
891 }
|