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