diff options
author | graydon <graydon@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-09-02 05:10:34 +0000 |
---|---|---|
committer | graydon <graydon@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-09-02 05:10:34 +0000 |
commit | 998d01227e4b1c1980db971f01db98195a7d4eaa (patch) | |
tree | a420c1005dbef38d790847b62b0d57eb9bc758cb /libjava/jni | |
parent | 9bc2282c56748dd872dfc03f953c8539f7cbab81 (diff) | |
download | gcc-998d01227e4b1c1980db971f01db98195a7d4eaa.tar.gz |
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicTextAreaUI.java
(create): New method.
* javax/swing/text/DefaultHighlighter.java
(DefaultHighlightPainter.debugRect): Removed.
* javax/swing/text/StyleContext.java
(DEFAULT_STYLE): New field.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicLookAndFeel.java
(initComponentDefaults): Add keybindings for selection.backward and
selection-forward for text components.
* javax/swing/plaf/basic/BasicTextUI.java
(paintSafely): Paint highlight only when something is actually
selected.
* javax/swing/text/DefaultCaret.java
(handleHighlight): New method.
(setSelectionVisible): Don't do anything when nothing changes.
Handle highlight.
(moveDot): Reimplemented. Handle highlight.
(setDot): Set mark too. Handle highlight.
(getSelectionPainter): New method.
* javax/swing/text/DefaultEditorKit.java
(defaultActions): Added new actions for text selection.
* javax/swing/text/DefaultHighlighter.java
(DefaultHighlightPainter): New inner class.
(DefaultPainter): New field.
(paint): Implemented.
* javax/swing/text/PlainView.java
(paint): Don't draw background here again.
* javax/swing/text/Utilities.java
(getTabbedTextWidth): Use width of ' ' instead of 'm' for tabsize.
(drawTabbedText): Likewise.
2004-08-31 Graydon Hoare <graydon@redhat.com>
* javax/swing/JComponent.java
(resetKeyboardActions): Add null checks.
2004-08-31 Graydon Hoare <graydon@redhat.com>
* javax/swing/DefaultButtonModel.java:
Skip group notification when no group is set.
2004-08-31 Graydon Hoare <graydon@redhat.com>
* javax/swing/JColorChooser.java:
Make a couple inner classes static, for jikes.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicTextUI.java
(RottView.modelToView): New method.
(UpdateHandler): Renamed from EventHandler.
(updateHandler): Renamed from eventHandler.
(modelToView): Implemented.
* javax/swing/text/AbstractDocument.java
(BranchElement.getElement): Return null for non-existing indeces.
(BranchElement.getElementIndex): Return 0 in some corner cases.
* javax/swing/text/FieldView.java
(modelToView): New method.
* javax/swing/text/PlainView.java
(modelToView): Made public.
2004-08-31 Kim Ho <kho@redhat.com>
* Makefile.am: New files.
* Makefile.in: Regenerate.
* gcj/Makefile.in: Regenerate.
* include/Makefile.in: Regenerate.
* java/awt/Color.java: Fix documentation.
(RGBtoHSB): Use floats for conversions.
* javax/swing/ButtonGroup.java: Run Jalopy.
(setSelected): Reimplement.
* javax/swing/DefaultButtonModel.java: Run Jalopy.
(changeState): Let ButtonGroup know that the button
is changing state.
* javax/swing/JColorChooser.java: Implement.
* javax/swing/JLabel.java: Run Jalopy.
* javax/swing/JSpinner.java: Run Jalopy.
(setValue): New method.
* javax/swing/JTabbedPane.java: Run Jalopy.
(removeTabAt): Call correct remove method.
* javax/swing/SpinnerNumberModel.java: Run Jalopy.
(getPreviousValue): Compare minimum value.
* javax/swing/Timer.java: Run Jalopy.
(run): Comment out println.
* javax/swing/ToolTipManager.java:
(mouseMoved): Get new tooltip text for location.
* javax/swing/colorchooser/AbstractColorChooserPanel.java:
Jalopy and Javadoc.
* javax/swing/colorchooser/ColorChooserComponentFactory.java:
Implement.
* javax/swing/colorchooser/DefaultColorSelectionModel.java:
Run Jalopy.
(setSelectedColor): Fire ChangeEvent.
* javax/swing/colorchooser/DefaultHSBChooserPanel.java:
New file. Implement.
* javax/swing/colorchooser/DefaultPreviewPanel.java:
Ditto.
* javax/swing/colorchooser/DefaultRGBChooserPanel.java:
Ditto.
* javax/swing/colorchooser/DefaultSwatchChooserPanel.java:
Ditto.
* javax/swing/plaf/basic/BasicArrowButton.java:
(getArrow): Fix size of upward pointing button.
* javax/swing/plaf/basic/BasicColorChooserUI.java:
Implement.
* javax/swing/plaf/basic/BasicSliderUI.java:
(getWidthOfWidestLabel): Use preferred dimensions.
(getHeightOfTallestLabel): Ditto.
* javax/swing/plaf/basic/BasicSpinnerUI.java:
Run Jalopy.
(mousePressed): Disable changes to spinner if it is not enabled.
* testsuite/Makefile.in: Regenerate.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicTableHeaderUI.java,
javax/swing/plaf/basic/BasicTableUI.java:
Added copyright notice.
2004-08-31 Olga Rodimina <rodimina@redhat.com>
* Makefile.am: Added new files.
* Makefile.in: Regenerate.
* javax/swing/ComboBoxEditor.java: Added javadocs.
* javax/swing/ComboBoxModel.java: Likewise.
* javax/swing/DefaultComboBoxModel.java: Implemented.
* javax/swing/DefaultListCellRenderer.java: Added javadocs
and ran through jalopy to fix formatting style.
(getListCellRendererComponent): Use appropriate border
if renderer has focus and use noFocusBorder when it doesn't.
* javax/swing/JComboBox.java: Implemented.
* javax/swing/JList.java:
(locationToIndex): New Method. Implemented.
(indexToLocation): New Method.
* javax/swing/JPopupMenu.java:
(visible): New field.
(isVisible): Changed to use new field above.
(setVisible): Likewise.
* javax/swing/MutableComboBoxModel.java: Added javadocs.
* javax/swing/plaf/basic/BasicArrowButton.java:
(shadow): Changed default color to Color.gray.
* javax/swing/plaf/basic/BasicComboBoxUI.java: New File.
UI delegate for JComboBox.
* javax/swing/plaf/basic/BasicComboPopup.java: New File.
Popup menu containing list of JComboBox's items.
* javax/swing/plaf/basic/BasicComboBoxEditor.java: New File.
* javax/swing/plaf/basic/BasicComboBoxRenderer.java: New File.
* javax/swing/plaf/basic/BasicComboBoxUI.java: New File.
* javax/swing/plaf/basic/BasicComboPopup.java: New File.
* javax/swing/plaf/basic/BasicPopupMenuUI.java:
(popupMenuWillBecomeVisible): Set selected path to the first
element only if it is of type MenuElement. Also fix formatting
style.
* javax/swing/plaf/basic/ComboPopup.java: Added javadocs and missing
methods signatures.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/text/AbstractDocument.java
(createBranchElement): Use new constructor of BranchElement.
(createLeafElement): Renamed arguments.
(getRootElements): Implemented.
(BranchElement.start): Removed.
(BranchElement.end): Likewise.
(BranchElement.BranchElement): Fixed arguments.
(BranchElement.getEndOffset): Reimplemented.
(BranchElement.getStartOffset): Likewis.
* javax/swing/text/DefaultCaret.java
(paint): Draw simple vertical line as caret instead of a rectangle.
* javax/swing/text/JTextComponent.java
(setText): Use doc directly.
* javax/swing/text/PlainView.java
(nextTabStop): Implemented.
* javax/swing/text/Utilities.java
(drawTabbedText): nextTabStop() returns an absolute x position.
(getTabbedTextWidth): Likewise.
2004-08-31 Graydon Hoare <graydon@redhat.com>
* java/awt/Component.java
(isFocusTraversable): Predicate on isLightweight()
(setFocusable): Set isFocusTraversableOverridden.
(requestFocus): Predicate peer dispatch on !isLightweight()
(requestFocusInWindow): Likewise.
(dispatchEventImpl): Coordinate with KeyboardFocusManager.
* java/awt/Container.java
(dispatchEventImpl): Predicate on event mask.
(LightweightDispatcher): Remove focus machinery.
* java/awt/DefaultFocusTraversalPolicy.java
(accept): Expand predicate to include isFocusable().
* java/awt/DefaultKeyboardFocusManager.java:
Globally change c.dispatchEvent(e) to redispatchEvent(c,e)
* java/awt/KeyboardFocusManager.java
(redispatchEvent): Synchronize on event to prevent feedback.
* javax/swing/AbstractButton.java
(ButtonFocusListener): Remove class.
(init): Set focusPainted, focusable.
* javax/swing/ActionMap.java (get): Check parent for null.
* javax/swing/InputMap.java (get): Likewise.
* javax/swing/JComponent.java
(inputMap_whenFocused): New InputMap.
(inputMap_whenAncestorOfFocused): Likewise.
(inputMap_whenInFocusedWindow): Likewise.
(getActionForKeyStroke): Rewrite.
(getConditionForKeystroke): Likewise.
(ActionListenerProxy): New private class.
(setInputMap): Implement.
(getInputMap): Likewise.
(setActionMap): Likewise.
(getActionMap): Likewise.
(processComponentKeyEvent): New empty method.
(processKeyEvent): Implement.
(processKeyBinding): Likewise.
(resetKeyboardActions): Rewrite.
* javax/swing/KeyStroke.java: Rewrite.
* javax/swing/SwingUtilities.java
(notifyAction): Implement.
(replaceUIActionMap): Likewise.
(replaceUIInputMap): Likewise.
* javax/swing/plaf/basic/BasicButtonListener.java
(focusGained): Implement.
(focusLost): Repaint if focusPainted().
(installKeyboardActions): Install pressed / released actions.
(uninstallKeyboardActions): Implement.
* javax/swing/plaf/basic/BasicButtonUI.java
(focusColor): New field.
(installDefaults): Load focus color, install input map.
(installKeyboardActions): Implement.
(uninstallKeyboardActions): Likewise.
(paintFocus): Rewrite.
* javax/swing/plaf/basic/BasicLookAndFeel.java
(Button.focus): New default, midPurple.
* javax/swing/plaf/basic/BasicTextUI.java
(kit): Make static.
(installUI): Get doc from kit, load defaults.
(getKeymapName): Implement.
(createKeymap): Likewise.
(installKeyboardActions): Likewise.
(getInputMap): Likewise.
(getActionMap): Likewise.
(createActionMap): Likewise.
* javax/swing/text/AbstractDocument.java
(getStartPosition): Implement.
(getEndPosition): Likewise.
* javax/swing/text/DefaultEditorKit.java
(CopyAction): New class.
(CutAction): Likewise.
(DefaultKeyTypedAction): Likewise.
(InsertBreakAction): Likewise.
(InsertContentAction): Likewise.
(InsertTabAction): Likewise.
(PasteAction): Likewise.
(defaultActions): New static table.
(createCaret): Implement.
(getActions): Likewise.
* javax/swing/text/JTextComponent.java
(KeymapWrapper): New private class.
(KeymapActionMap): Likewise.
(DefaultKeymap): New class.
(keymaps): New static table.
(keymap): New field.
(getKeymap): Implement.
(removeKeymap): Likewise.
(addKeymap): Likewise.
(setKeymap): Likewise.
(loadKeymap): Likewise.
(getActions): Likewise.
(margin): New field.
(JTextComponent): Build and install default keymap.
* javax/swing/text/TextAction.java
(textAction): Call super properly.
(getTextComponent): Implement.
* javax/swing/text/Utilities.java
(drawTabbedText): Adjust position by ascent.
2004-08-31 David Jee <djee@redhat.com>
PR AWT/17156
* gnu/java/awt/peer/gtk/GtkMenuItemPeer.java
(setEnabled): Make it a native method.
* java/awt/DefaultKeyboardFocusManager.java
(postProcessKeyEvent): Only post event if the menu item
is active.
* java/awt/MenuItem.java:
Private field 'enabled' should be true by default.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuItemPeer.c
(setEnabled): New function.
2004-08-31 David Jee <djee@redhat.com>
PR AWT/17059
* gnu/java/awt/peer/gtk/GtkMenuBarPeer.java
(nativeSetHelpMenu): New native method declaration.
(addHelpMenu): Call nativeSetHelpMenu().
(addMenu): Remove.
* java/awt/MenuBar.java
(setHelpMenu): Call addNotify() on the new help menu.
(add): Call addNotify() on the new menu.
(addNotify): Set the help menu if one exists.
* java/awt/peer/MenuBarPeer.java
(addMenu): Remove.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuBarPeer.c
(nativeSetHelpMenu): New method.
2004-08-31 Graydon Hoare <graydon@redhat.com>
* Makefile.am: Add new files.
* Makefile.in: Regenerate.
* javax/swing/Box.java: Fix setting of layout in ctor.
* javax/swing/JScrollPane.java: Scroll headers as well.
* javax/swing/JTable.java: Reimplement.
* javax/swing/JViewPort.java: Only add non-null children.
* javax/swing/ScrollPaneLayout.java: Correct header calculations.
* javax/swing/Timer.java: Fix stopping null waker.
* javax/swing/plaf/basic/BasicTableHeaderUI.java: New file.
* javax/swing/plaf/basic/BasicTableUI.java: New file.
* javax/swing/table/DefaultTableCellRenderer.java: Configure.
* javax/swing/table/DefaultTableColumnModel.java: Flesh out.
* javax/swing/table/DefaultTableModel.java: Clean up.
* javax/swing/table/JTableHeader.java: Implement.
2004-08-31 Mark Wielaard <mark@klomp.org>
* javax/swing/JSpinner.java (getChangeListeners): Remove double
semi-colon.
2004-08-31 Mark Wielaard <mark@klomp.org>
* jni/gtk-peer/gnu_java_awt_peer_gtk_GdkClasspathFontPeerMetrics.c:
Declare variables at top of functions/block.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c: Likewise.
2004-08-31 Mark Wielaard <mark@klomp.org>
* java/lang/Rectangle.java (intersects): Check r.width and r.height
first.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/text/PlainView.java
(selectedColor): New field.
(unselectedColor): Likewise.
(font): Likewise.
(updateMetrics): New method.
(lineToRect): Likewise.
(modelToView): Likewise.
(drawSelectedText): Use color from JTextComponent ad draw with
Utilities class.
(drawUnselectedText): Likewise.
(paint): Initialize helper fields.
* javax/swing/text/View.java
(getChildAllocation): New method.
(getViewIndex): Likewise.
(getToolTipText): Likewise.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/text/Utilities.java
(drawTabbedText): Reimplemented.
(getTabbedTextWidth): Likewise.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicTextUI.java
(installDefaults): Install caret and highlighter.
(modelToView): Use Bias.Forward when calling sibling.
* javax/swing/text/AbstractDocument.java
(ElementEdit): Implements DocumentEvent.ElementChange.
(ElementEdit.ElementEdit): New method.
(ElementEdit.getChildrenAdded): Likewise.
(ElementEdit.getChildrenRemoved): Likewise.
(ElementEdit.getElement): Likewise.
(ElementEdit.getIndex): Likewise.
* javax/swing/text/DefaultCaret.java
(color): Removed.
(textComponent): Renamed from parent, made private.
(selectionVisible): Renamed from vis_sel, made private.
(blinkRate): Renamed from blink, made private.
(magicCaretPosition): Renamed from magic, made private.
(visible): Renamed from vis, made private.
(dot): Made private.
(mark): Likewise.
(deinstall): Remove as MouseMotionListener.
(install): Initialize textComponent first. Add as MouseMotionListener.
(paint): Reimplemented.
* javax/swing/text/JTextComponent.java
(setCaret): Deinstall old caret, install new one and fire property
change after setting property.
(setHighlighter): Deinstall old highlighter, install new one and fire
property change after setting property.
(setCaretColor): Fire property change after setting property.
(setDisabledTextColor): Likewise.
(setSelectedTextColor): Likewise.
(setSelectionColor): Likewise.
(modelToView): New method.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/text/AbstractDocument.java
(getText): Simplified.
* javax/swing/text/Segment.java
(current): New field.
(current): Reimplemented.
(first): Likewise.
(getIndex): Likewise.
(last): Likewise.
(next): Likewise.
(previous): Likewise.
(setIndex): Likewise.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicButtonUI.java
(defaultTextIconGap): Made protected.
(defaultTextShiftOffset): Likewise.
(textShiftOffset): New field.
(clearTextShiftOffset): New method.
(getTextShiftOffset): Likewise.
(setTextShiftOffset): Likewise.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicTextUI.java
(installUI): Add eventHandler as property listener.
(uninstallUI): remove eventHandler as propert listener.
(installDefaults): Added comment.
(installListeners): Likewise.
(installKeyboardActions): Likewise.
(uninstallDefaults): Likewise.
(uninstallListeners): Likewise.
(uninstallKeyboardActions): Likewise.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/text/AbstractDocument.java:
Fixed some typos in comments.
(insertString): Reimplemented.
(remove): Likewise.
(replace): New method.
(children): Dont use fully qualified class name.
(DefaultDocumentEvent.offset): Renamed from off.
(DefaultDocumentEvent.length): Renamed from len.
(DefaultDocumentEvent.type): New field.
(DefaultDocumentEvent.DefaultDocumentEvent): New constructor.
(DefaultDocumentEvent.getType): Implemented.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicTextUI.java
(RootView.textComponent): Removed.
(RootView.RootView): Don't initialize textComponent.
(RootView.getViewFactory): New method.
(EventHandler): New inner class.
(rootView): Initialize at instance creation.
(eventHandler): New field.
(installUI): Don't create view hierarchy directly,
call modelChanged() instead.
(modelChanged): New method.
* javax/swing/text/JTextComponent.java
(setDocument): Fire property change event.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicTextUI.java
(RootView.paint): Removed debug output.
(paintSafely): Draw highlighter before text.
(paintBackground): Use background color of text component.
* javax/swing/plaf/basic/BasicToggleButtonUI.java:
Reformatted.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicToolBarUI.java
(BasicToolBarUI): Fixed arguments for constructor.
(createUI): Fixed creation of object.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/DefaultListSelectionModel.java
(fireValueChanged): Renamed from fireSelectionValueChanged,
made protected.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/text/TabSet.java
(TabSet): Implements java.io.Serializable.
* javax/swing/text/TabStop.java
(TabStop): Implements java.io.Serializable.
(TabStop): Made public.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/JComponent.java
(setUI): Fire PropertyChange.
* javax/swing/JLabel.java
(text): Renamed from labelText.
(horizontalAlignment): New default vlaue.
(icon): Renamed from activeIcon.
(displayedMnemonic): Renamed from mnemonicKey, added default value.
(displayedMnemonicIndex): Renamed from underlineChar.
(setDisplayedMnemonic): Reimplemented.
* javax/swing/JRadioButton.java
(JRadioButton): New constructors.
* javax/swing/JTextField.java
(JTextField): Throw exception if colums < 0, initialitialz
this.columns directly and initialize document with text conditionally.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicFormattedTextFieldUI.java,
javax/swing/plaf/basic/BasicPasswordFieldUI.java,
javax/swing/plaf/basic/BasicTextAreaUI.java: New files.
* javax/swing/text/FieldView.java
(paint): Just call super method for now.
* Makefile.am: Added new files.
* Makefile.in: Regenerated.
2004-08-31 Ka-Hing Cheung <kahing@javabsp.org>
* javax/swing/AbstractSpinnerModel.java,
javax/swing/JSpinner.java,
javax/swing/SpinnerNumberModel.java,
javax/swing/plaf/basic/BasicSpinnerUI.java:
New files.
* javax/swing/plaf/basic/BasicLookAndFeel.java
(initClassDefaults): Added defaults for BasicSpinnerUI.
2004-08-31 Michael Koch <konqueror@gmx.de>
* Makefile.am: Added new files.
* Makefile.in: Regenerated.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/TransferHandler.java,
javax/swing/plaf/basic/ComboPopup.java: New files
* Makefile.am: Added javax/swing/TransferHandler.java and
javax/swing/plaf/basic/ComboPopup.java
* Makefile.in: Regenerated.
2004-08-31 Roman Kennke <roman@ontographics.com>
* javax/swing/text/Utilities.java: New file.
2004-08-31 Michael Koch <konqueror@gmx.de>
* Makefile.am: Added javax/swing/text/Utilities.java.
* Makefile.in: Regenerated.
2004-08-31 Graydon Hoare <graydon@redhat.com>
* javax/swing/text/SimpleAttributeSet.java: New file.
* javax/swing/text/StyleConstants.java: New file.
* javax/swing/text/StyleContext.java: New file.
* javax/swing/text/TabSet.java: New file.
* javax/swing/text/TabStop.java: New file.
* javax/swing/text/AbstactDocument.java:
(AbstractElement): Implement attribute support.
* javax/swing/text/AttributeSet.java
(NameAttribute): New static field.
(ResolveAttribute): New static field.
* Makefile.am: Update for new files.
* Makefile.in: Regenerate.
2004-08-31 Craig Black <craig.black@aonix.com>
* gnu/java/awt/peer/gtk/GdkGraphics.java
(drawImage): Add support for scaling pixmaps.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics.c
(copyAndScalePixmap): New native method.
2004-08-31 Thomas Fitzsimmons <fitzsim@redhat.com>
PR AWT/16121
* jni/gtk-peer/gthread-jni.c: Include stdio.h. Eliminate
type-punning compiler warnings using unions.
(throw): Replace bzero with memset.
2004-08-31 Andreas Tobler <a.tobler@schweiz.ch>
Thomas Fitzsimmons <fitzsim@redhat.com>
* jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c: Move
NSA_PB macros to gtkpeer.h. Include gtkpeer.h.
* jni/gtk-peer/gtkpeer.h: Move NSA_PB macros here.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
(nativeSetIconImageFromDecoder): Use NSA_GET_PB_PTR macro.
2004-08-31 Mark Wielaard <mark@klomp.org>
* native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c:
#include gdk.h, not gtk.h. #include jni.h, native_state.h, string.h
and stdlib.h, not gtkpeer.h.
(*vm): New static variable.
(areaPreparedID): Make static.
(areaUpdatedID): Likewise.
(area_prepared): Get and use JNIEnv through stored JavaVM *vm.
(area_prepared): Likewise.
(area_updated): Likewise.
(closed): Likewise.
(initStaticState): Initialize *vm javaVM.
(pumpBytes): Use given env, not global gdk_env.
2004-08-31 Mark Wielaard <mark@klomp.org>
* java/awt/geom/CubicCurve2D.java (solveCubic): Removed duplicate
comments.
2004-08-31 Sven de Marothy <sven@physto.se>
* java/awt/geom/CubicCurve2D.java: Reindent.
(contains): Implemented.
(intersects): Implemented.
* java/awt/geom/QuadCurve2D.java: Likewise.
* java/awt/geom/GeneralPath.java: Reindent and document.
Fully (re)implemented using separate xpoints and ypoints
float[] coords.
* java/awt/geom/RoundRectangle2D.java: Several bugfixes (Bug #6007).
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/JMenuItem.java
(getMenuDragMouseListeners): New method.
(getMenuKeyListeners): Likewise.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/AbstractButton.java
(model): Made protected.
(actionListener): Likewise.
(changeListener): Likewise.
(itemListener): Likewise.
(multiClickThreshhold): New field.
(getActionListeners): New method.
(getChangeListeners): Likewise.
(getItemListeners): Likewise.
(fireItemStateChanged): Simplified implementation.
(fireActionPerformed): Likewise.
(fireStateChanged): Likewise.
(getMultiClickThreshhold): New method.
(setMultiClickThreshhold): Likewise.
2004-08-31 Tom Tromey <tromey@redhat.com>
* java/awt/image/Kernel.java (clone): Use super.clone().
2004-08-31 David Jee <djee@redhat.com>
PR AWT/16682
* gnu/java/awt/peer/gtk/GtkFramePeer.java
(nativeSetIconImage): Rename to nativeSetIconImageFromDecoder.
(nativeSetIconImageFromData): New native method declaration.
(setIconImage): Handle images not produced from GdkPixbufDecoder.
* gnu/java/awt/peer/gtk/GtkImage.java
(getPixelCache): New method.
(getColorModel): New method.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
(nativeSetIconImage): Rename to nativeSetIconImageFromDecoder.
(free_pixbuf_data): New helper function.
(nativeSetIconImageFromData): New function.
2004-08-31 Graydon Hoare <graydon@redhat.com>
PR SWING/16576
* javax/swing/JLayeredPane.java
(setLayer): Permit changing layer after addition.
(setPosition): Permit over-length positions.
(layerToRange): Compare intValue()s.
* javax/swing/Box.java (createHorizontalBox): Implement.
(createRigidArea): Likewise.
(createVerticalBox): Likewise.
2004-08-31 Kim Ho <kho@redhat.com>
* java/awt/Component.java:
(processMouseEvent): Consume event after
listeners process it.
(processMouseMotionEvent): ditto.
(processMouseWheelEvent): ditto.
* java/awt/Container.java:
(acquireComponentForMouseEvent):
Do not dispatch to events that have been
removed from the Container.
(handleEvent): Consume the MouseEvents.
* javax/swing/RepaintManager.java:
(paintDirtyRegions): Do not add to list of
damaged areas if the component has no root.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/plaf/basic/BasicMenuItemUI.java: Clean ip imports.
2004-08-31 Mark Wielaard <mark@klomp.org>
* gnu/java/awt/peer/gtk/GtkToolkit.java (getFontPeer): Don't return
null when a MissingResourceException is thrown. Should never happen.
2004-08-31 Mark Wielaard <mark@klomp.org>
* java/awt/EventQueue.java (postEvent): Throw NullPointerException
when argument is null.
2004-08-31 Mark Wielaard <mark@klomp.org>
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
(Java_gnu_java_awt_peer_gtk_GtkComponentPeer_addExposeFilter):
Define hid at start of function.
(Java_gnu_java_awt_peer_gtk_GtkComponentPeer_removeExposeFilter):
Likewise.
2004-08-31 Mark Wielaard <mark@klomp.org>
* gnu/java/awt/EmbeddedWindow.java: Reindent.
* javax/swing/JButton.java: Reindent.
* javax/swing/JCheckBox.java: Reindent.
2004-08-31 Mark Wielaard <mark@klomp.org>
* Makefile.am (gtk_c_source_files): Added
jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c.
(gtk_awt_peer_sources): Added
gnu/java/awt/peer/gtk/GThreadMutex.java and
gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java.
* Makefile.in: Regenerated.
2004-08-31 Archie Cobbs <archie@dellroad.org>
* jni/gtk-peer/gthread-jni.c: don't #include nonexistent files
2004-08-31 Steven Augart <augart@watson.ibm.com>
* jni/gtk-peer/gthread-jni.c (c-font-lock-extra-types):
Added jfieldID, jmethodID.
2004-08-31 Mark Wielaard <mark@klomp.org>
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c
(Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit): Initialize
gdk_env before calling any gdk or gtk function.
* gnu/java/awt/peer/gtk/GtkMainThread.java (gtkInitCalled): New field.
(GtkMainThread): Call wait() in while loop waiting for gtkInitCalled.
(run): Set gtkInitCalled.
2004-08-31 Steven Augart <augart@watson.ibm.com>
* gnu/java/awt/peer/gtk/GtkMainThread.java (run): Pass the value of
the gnu.classpath.awt.gtk.portable.native.sync system property to C.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c
(Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit): New argument,
portableNativeSync. Delegate PORTABLE_NATIVE_SYNC work to
init_glib_threads.
(init_glib_threads): New function.
2004-08-31 Mark Wielaard <mark@klomp.org>
* jni/gtk-peer/gthread-jni.c: Define MIN_, MAX_ and NORM_
PRIORITY when not already defined in header file.
2004-08-31 Mark Wielaard <mark@klomp.org>
* jni/gtk-peer/gthread-jni.c (setup_cache): Call
ExceptionOccurred, not ExceptionCheck, when we don't have JNI 1.2.
2004-08-31 Steven Augart <augart@watson.ibm.com>
* gnu/native/jni/gtk-peer/gthread-jni.c: Indentation fixes.
Implemented missing functions for GTK2.
Added error handling.
Renamed static functions out of the g_ namespace.
Added TRACE_API_CALLS, EXPLAIN_TROUBLE, EXPLAIN_BROKEN,
EXPLAIN_BADLY_BROKEN, and DELETE_LOCAL_REFS options.
Rewrote global-reference code.
Eliminated cascading errors.
(mutex_trylock_jni_impl) Fully implemented.
(cond_timed_wait_jni_impl) Went from millisecond to microsecond
resolution.
(setup_cache) New function.
(mutex_cond_wait_jni_impl, mutex_cond_timed_wait_jni_impl) Fixed
bug where they were not unlocking the GMutex associated with the
condition variable during the wait on that condition variable.
* native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c,
native/jni/gtk-peer/gthread-jni.c,
native/jni/gtk-peer/gthread-jni.h
(g_thread_jni_functions): Renamed to ...
(portable_native_sync_jni_functions): this name.
(gdk_vm): Renamed to...
(the_vm): this name.
* native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c
(gdk_vm): Removed duplicate definition.
(gtkInit): Removed stray message to stdout.
(gtkInit): Use g_malloc and g_free instead of malloc and free.
(gtkInit): Fix a const assignment bug.
(gtkInit): Simplified code.
* gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java,
native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.c,
native/jni/gtk-peer/gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h,
gnu/java/awt/peer/gtk/GThreadMutex.java:
New files.
2004-08-31 Mark Wielaard <mark@klomp.org>
* javax/swing/Box.java: Put FIXME comment above class declaration.
* javax/swing/JButton.java: Remove illegal L&F HTML from comments.
* javax/swing/JCheckBox.java: Likewise.
* javax/swing/JDialog.java: Likewise.
* javax/swing/JRadioButton.java: Likewise.
* javax/swing/JToggleButton.java: Likewise.
* javax/swing/UIManager.java: Likewise.
* javax/swing/border/TitledBorder.java: Likewise.
* javax/swing/plaf/basic/BasicLabelUI.java: Likewise.
* javax/swing/plaf/basic/BasicLookAndFeel.java: Likewise.
* javax/swing/plaf/basic/BasicPopupMenuSeparatorUI.java: Likewise.
* javax/swing/plaf/basic/BasicProgressBarUI.java: Likewise.
* javax/swing/plaf/basic/BasicScrollBarUI.java: Likewise.
* javax/swing/plaf/basic/BasicSeparatorUI.java: Likewise.
* javax/swing/text/JTextComponent.java: Likewise.
2004-08-31 David Jee <djee@redhat.com>
PR AWT/16682
* gnu/java/awt/peer/gtk/GtkFramePeer.java
(setIconImage): Add a FIXME for unhandled cases.
2004-08-31 Thomas Fitzsimmons <fitzsim@redhat.com>
PR AWT/16040
* gnu/awt/LightweightRedirector.java: Call getModifiersEx, not
getModifiers. Replace old button masks with new ones.
* gnu/awt/xlib/XEventLoop.java: Likewise.
* gnu/java/awt/peer/gtk/GtkButtonPeer.java: Likewise.
* gnu/java/awt/peer/gtk/GtkComponentPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c: Likewise.
* gnu/java/awt/peer/gtk/GtkListPeer.java: Likewise.
* gnu/java/awt/peer/gtk/GtkTextFieldPeer.java: Likewise.
* java/awt/AWTKeyStroke.java: Remove old modifier masks.
* java/awt/Component.java: Replace old modifier masks with new
ones.
* java/awt/Container.java: Call getModifiersEx, not
getModifiers.
* java/awt/DefaultKeyboardFocusManager.java: Likewise. Remove
old modifier masks.
* javax/swing/JMenuItem.java: Replace old button masks with new
ones.
* javax/swing/KeyStroke.java: Call getModifiersEx, not
getModifiers.
* javax/swing/SwingUtilities.java: Likewise.
* javax/swing/plaf/basic/BasicButtonListener.java: Likewise.
* javax/swing/plaf/basic/BasicInternalFrameUI.java: Likewise.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c: Replace old
mask macros with new ones.
* jni/gtk-peer/gtkpeer.h: Replace old button and modifier mask
macros with new ones representing new masks.
2004-08-31 Craig Black <craig.black@aonix.com>
* gnu/java/awt/peer/gtk/GdkGraphics.java
(drawRoundRect): Implemented.
(fillRoundRect): Implemented.
* gnu/java/awt/peer/gtk/GdkGraphics2D.java
(drawRoundRect): Reimplemented to match GdkGraphics.
(fillRoundRect): Reimplemented to match GdkGraphics.
2004-08-31 Mark Wielaard <mark@klomp.org>
* Makefile.in: Regenerated.
2004-08-31 Michael Koch <konqueror@gmx.de>
* gnu/java/awt/EmbeddedWindow.java
(addNotify): Use AccessController to allow execution of privileged
code.
2004-08-31 Michael Koch <konqueror@gmx.de>
* gnu/java/awt/EmbeddedWindow.java
(static): Removed.
(addNotify): Set peer via reflection.
(setWindowPeer): Removed.
* gnu/java/awt/natEmbeddedWindow.cc: Removed.
* Makefile.am (nat_source_files):
Removed gnu/java/awt/natEmbeddedWindow.cc.
2004-08-31 Bryce McKinlay <mckinlay@redhat.com>
* Makefile.am: Add gnu/java/security/action/GetPropertyAction.java
and gnu/java/security/action/SetAccessibleAction.java.
2004-08-31 Bryce McKinlay <mckinlay@redhat.com>
* gnu/java/security/action/GetPropertyAction.java (setParameters):
Renamed from 'setName'. New 2-argument form with default value.
(run): Pass default 'value' parameter to System.getProperty().
* gnu/java/security/action/SetAccessibleAction.java: Fix javadoc
typos.
2004-08-31 Bryce McKinlay <mckinlay@redhat.com>
* gnu/java/security/action/GetPropertyAction.java: New class.
* gnu/java/security/action/SetAccessibleAction.java: New class.
2004-08-31 David Jee <djee@redhat.com>
* gnu/java/awt/peer/gtk/GtkFramePeer.java
(setIconImage): Check if image is null.
2004-08-31 David Jee <djee@redhat.com>
* gnu/java/awt/peer/gtk/GtkFramePeer.java
(create): Set the icon image.
(nativeSetIconImage): New native method declaration.
(setIconImage): Implement.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
(nativeSetIconImage): New function.
2004-08-31 Dalibor Topic <robilad@kaffe.org>
* native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c
(filenameFilterCallback): Declare local variable accepted before use.
2004-08-31 Dalibor Topic <robilad@kaffe.org>
* gnu/java/awt/ComponentDataBlitOp.java:
Cleaned up imports.
2004-08-31 Tom Tromey <tromey@redhat.com>
* gnu/java/awt/peer/GLightweightPeer.java,
gnu/java/awt/peer/gtk/GdkGraphics2D.java,
gnu/java/awt/peer/gtk/GtkComponentPeer.java,
javax/swing/JScrollPane.java: Removed
redundant imports.
2004-08-31 David Jee <djee@redhat.com>
* java/awt/DefaultKeyboardFocusManager.java
(postProcessKeyEvent): Only activate MenuShortcuts on KEY_PRESSED
event. Fix shift modifier checking.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c
(accel_attach): Remove.
(setupAccelGroup): Remove calls to accel_attach.
2004-08-31 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GtkArg.java: Remove file.
* gnu/java/awt/peer/gtk/GtkArgList.java: Remove file.
* Makefile.am (gtk_awt_peer_sources): Remove GtkArg.java and
GtkArgList.java.
(gtk_c_files): Use CAIRO_CFLAGS and PANGOFT2_CFLAGS, not _LIBS.
* Makefile.in: Regenerate.
* gnu/java/awt/peer/gtk/GtkButtonPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c
(create(String)): New method.
(create): Call new create method.
(getArgs): Remove method.
* gnu/java/awt/peer/gtk/GtkCheckboxPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c
(nativeCreate): Rename to create.
(gtkSetLabel): Rename to gtkButtonSetLabel.
(gtkToggleButtonSetActive): New method.
(create): Call gtkToggleButtonSetActive and gtkButtonSetLabel.
(setState): Replace set call with gtkToggleButtonSetActive.
(setLabel): Replace gtkSetLabel call with gtkButtonSetLabel.
(getArgs): Remove method.
* gnu/java/awt/peer/gtk/GtkComponentPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
(gtkWidgetSetSensitive): New method.
(gtkWidgetSetParent): Likewise.
(GtkComponentPeer): Call setParent, setComponentBounds and
setVisibleAndEnabled.
(setParent): New method.
(setComponentBounds): New method.
(setVisibleAndEnabled): New method.
(setEnabled): Call gtkWidgetSetSensitive.
(getArgs): Remove method.
Remove all set methods.
* gnu/java/awt/peer/gtk/GtkDialogPeer.java (create): Call
gtkWindowSetModal, setTitle and setResizable.
(getArgs): Remove method.
* gnu/java/awt/peer/gtk/GtkFileDialogPeer.java
(setComponentBounds): New method.
* gnu/java/awt/peer/gtk/GtkFramePeer.java (setResizable):
Replace set call with gtkWindowSetResizable.
(getArgs): Remove method.
(create): Call setTitle and setResizable.
* gnu/java/awt/peer/gtk/GtkWindowPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
(gtkWindowSetTitle): New method.
(gtkWindowSetResizable): New method.
(gtkWindowSetModal): New method.
(setParent): New method.
(setVisibleAndEnabled): New method.
(getArgs): Remove method.
(setTitle): Call gtkWindowSetTitle.
(setResizable): Call gtkWindowSetResizable.
* jni/gtk-peer/gtkpeer.h [DEBUG_LOCKING]: New define to turn on
and off locking instrumentation.
2004-08-31 Kim Ho <kho@redhat.com>
* Makefile.am: Add new file.
* Makefile.in: Regenerate.
* gcj/Makefile.in: Regenerate
* include/Makefile.in:
* java/awt/Container.java:
(acquireComponentForMouseEvent): Respect
the event mask when looking for candidate.
* javax/swing/JComponent.java:
Remove toolTip field.
(createToolTip): Create a tooltip on demand.
(setToolTipText): Register with the ToolTipManager.
(getToolTipText(MouseEvent)): Return getToolTipText().
* javax/swing/JToolTip.java: Implement.
* javax/swing/Timer.java: Jalopy.
(restart): Call stop, then start.
(stop): Interrupt the timer rather than wait for
the timer to come to a stop naturally.
* javax/swing/ToolTipManager.java: Implement.
* javax/swing/plaf/basic/BasicLookAndFeel.java:
Change ToolTip.background color.
* javax/swing/plaf/basic/BasicToolTipUI.java:
Implement.
* testsuite/Makefile.in: Regenerate
2004-08-31 Jerry Quinn <jlquinn@optonline.net>
* java/awt/image/DirectColorModel.java (DirectColorModel): Fix
constructor param comments.
2004-08-31 Thomas Fitzsimmons <fitzsim@redhat.com>
* java/awt/Component.java: Document AWT 1.0 event handler
methods.
2004-08-31 Roman Kennke <roman@ontographics.com>
* javax/swing/Box.java:
(createGlue): Implemented
(createHorizontalGlue): Implemented
(createHorizontalStrut): Implemented
(createVerticalGlue): Implemented
(createVerticalStrut): Implemented
2004-08-31 David Jee <djee@redhat.com>
* gnu/java/awt/peer/gtk/GtkChoicePeer.java
(GtkChoicePeer): Do not automatically select first item.
(getHistory): Remove.
(nativeGetSelected): New method.
(nativeRemoveAll): New method.
(add): Use nativeGetSelected() instead of getHistory().
(remove): Likewise.
(removeAll): Call nativeRemoveAll().
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c
(create): Migrate to GtkComboBox.
(append): Likewise.
(nativeAdd): Likewise.
(nativeRemove): Likewise.
(select): Likewise.
(nativeRemoveAll): New method.
(nativeGetSelected): New method.
(selection_changed): New method.
(getHistory): Remove.
(item_activate): Remove.
(item_removed): Remove.
(connect_choice_item_selectable_hook): Remove.
2004-08-31 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GtkTextFieldPeer.java (create): Use tf
variable in setEditable call.
* gnu/java/awt/peer/gtk/GtkTextFieldPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextFieldPeer.c
(gtkWidgetSetBackground): New method.
(gtkWidgetSetForeground): Likewise.
(create): Set peer's editable state based on awtComponent's.
* java/awt/Button.java (Button()): Use empty string rather than
null in no-label constructor.
2004-08-31 Roman Kennke <roman@ontographics.com>
* javax/swing/BoxLayout.java: Reimplement.
2004-08-31 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GdkGraphics.java,
gnu_java_awt_peer_gtk_GdkGraphics.c
(initState(GtkComponentPeer)): Don't return array of colour
values.
(GdkGraphics(int,int)): Set default font to size 12.
(GdkGraphics(GtkComponentPeer)): Set graphics colour to
component's foreground colour.
* gnu/java/awt/peer/gtk/GdkGraphics2D.java,
gnu_java_awt_peer_gtk_GdkGraphics2D.c
(initState(GtkComponentPeer)): Don't return array of colour
values.
(GdkGraphics2D(GtkComponentPeer)): Set foreground and background
colours to component's colours.
(current_colors_of_widget): Remove function.
* gnu/java/awt/peer/gtk/GtkOffScreenImage.java (getGraphics):
Return a new graphics object.
* java/awt/Font.java (toString): Fix format.
* java/awt/Graphics.java (toString): Likewise.
2004-08-31 Craig Black <craig.black@aonix.com>
* native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c
(addTearOff): New function.
* gnu/java/awt/peer/gtk/GtkMenuPeer.java (addTearOff):
New native method.
(init): Call addTearOff() when menu.isTearOff().
2004-08-31 Bryce McKinlay <mckinlay@redhat.com>
* gnu/java/awt/ClasspathToolkit.java (createImageProducer): New.
Default implementation.
* gnu/java/awt/peer/gtk/GtkToolkit.java (createImageProducer): New.
Implement using GdkPixbufDecoder.
2004-08-31 David Jee <djee@redhat.com>
* gnu/java/awt/peer/gtk/GtkComponentPeer.java
(GtkComponentPeer): Use gtkWidgetGetPreferredDimensions() for
setting the size of GtkFileDialogPeers.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
(gtkWidgetGetPreferredDimensions): For widgets extending GtkWindow,
use their default sizes rather than their natural requisitions.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/JFormattedTextField.java
(JFormattedTextField): Implemented.
* javax/swing/text/DefaultEditorKit.java
(BeepAction): New inner class.
* javax/swing/text/Segment.java
(partialReturn): New field.
(setPartialReturn): New method.
(isPartialReturn): Likewise.
* javax/swing/text/View.java
(createFragment): Fixed typo.
(getStartOffset): New method.
(getEndOffset): Likewise.
2004-08-31 Michael Koch <konqueror@gmx.de>
* javax/swing/table/DefaultTableColumnModel.java
(serialVersionUID): Made private.
(listenerList): Initialize.
(changeEvent): Initialize.
* javax/swing/table/JTableHeader.java
(JTableHeader): New constructors.
(createDefaultColumnModel): New method.
* javax/swing/table/TableColumn.java
(setHeaderRenderer): Simplified code.
(setCellRenderer): Likewise.
(setWidth): Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@86956 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/jni')
20 files changed, 3054 insertions, 786 deletions
diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkClasspathFontPeerMetrics.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkClasspathFontPeerMetrics.c index cc09102debd..c10b945ab6b 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkClasspathFontPeerMetrics.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkClasspathFontPeerMetrics.c @@ -54,6 +54,8 @@ JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkClasspathFontPeerMetri jint *metrics; struct peerfont *pf = NULL; FT_Matrix mat; + double pointsize; + FT_Face face; pf = NSA_GET_FONT_PTR(env, font); g_assert (pf != NULL); @@ -68,7 +70,7 @@ JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkClasspathFontPeerMetri #define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) #define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) - double pointsize = pango_font_description_get_size (pf->desc); + pointsize = pango_font_description_get_size (pf->desc); pointsize /= (double) PANGO_SCALE; mat.xx = DOUBLE_TO_16_16(1); @@ -76,7 +78,7 @@ JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkClasspathFontPeerMetri mat.yx = DOUBLE_TO_16_16(0); mat.yy = DOUBLE_TO_16_16(1); - FT_Face face = pango_ft2_font_get_face (pf->font); + face = pango_ft2_font_get_face (pf->font); FT_Set_Transform(face, &mat, NULL); FT_Set_Char_Size( face, DOUBLE_TO_26_6 (pointsize), diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics.c index 864e465871b..a79ed5eb093 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics.c @@ -94,15 +94,13 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics_initState__II /* copy the native state of the peer (GtkWidget *) to the native state of the graphics object */ -JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics_initState__Lgnu_java_awt_peer_gtk_GtkComponentPeer_2 +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics_initState__Lgnu_java_awt_peer_gtk_GtkComponentPeer_2 (JNIEnv *env, jobject obj, jobject peer) { struct graphics *g = (struct graphics *) malloc (sizeof (struct graphics)); void *ptr; GtkWidget *widget; GdkColor color; - jintArray array; - jint *rgb; ptr = NSA_GET_PTR (env, peer); g->x_offset = g->y_offset = 0; @@ -133,16 +131,7 @@ JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics_initState__Lg gdk_threads_leave (); - array = (*env)->NewIntArray (env, 3); - rgb = (*env)->GetIntArrayElements (env, array, NULL); - rgb[0] = color.red >> 8; - rgb[1] = color.green >> 8; - rgb[2] = color.blue >> 8; - (*env)->ReleaseIntArrayElements (env, array, rgb, 0); - NSA_SET_PTR (env, obj, g); - - return array; } JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics_dispose @@ -323,7 +312,111 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics_copyPixmap gdk_flush (); gdk_threads_leave (); } + +static void flip_pixbuf (GdkPixbuf *pixbuf, + jboolean flip_x, + jboolean flip_y, + jint width, + jint height) +{ + gint src_rs; + guchar *src_pix; + + src_rs = gdk_pixbuf_get_rowstride (pixbuf); + src_pix = gdk_pixbuf_get_pixels (pixbuf); + + if (flip_x) + { + gint i, channels; + guchar buf[4]; + + channels = gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3; + + for (i = 0; i < height; i++) + { + guchar *left = src_pix + i * src_rs; + guchar *right = left + channels * (width - 1); + while (left < right) + { + g_memmove (buf, left, channels); + g_memmove (left, right, channels); + g_memmove (right, buf, channels); + left += channels; + right -= channels; + } + } + } + + if (flip_y) + { + guchar *top = src_pix; + guchar *bottom = top + (height - 1) * src_rs; + gpointer buf = g_malloc (src_rs); + + while (top < bottom) + { + g_memmove (buf, top, src_rs); + g_memmove (top, bottom, src_rs); + g_memmove (bottom, buf, src_rs); + top += src_rs; + bottom -= src_rs; + } + + g_free (buf); + } +} +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics_copyAndScalePixmap + (JNIEnv *env, jobject obj, jobject offscreen, jboolean flip_x, jboolean flip_y, + jint src_x, jint src_y, jint src_width, jint src_height, + jint dest_x, jint dest_y, jint dest_width, jint dest_height) +{ + struct graphics *g1, *g2; + GdkPixbuf *buf_src, *buf_dest; + + g1 = (struct graphics *) NSA_GET_PTR (env, obj); + g2 = (struct graphics *) NSA_GET_PTR (env, offscreen); + + gdk_threads_enter (); + + buf_src = gdk_pixbuf_get_from_drawable (NULL, + g2->drawable, + g2->cm, + src_x, + src_y, + 0, + 0, + src_width, + src_height); + + buf_dest = gdk_pixbuf_scale_simple (buf_src, + dest_width, + dest_height, + GDK_INTERP_BILINEAR); + + if (flip_x || flip_y) + { + flip_pixbuf (buf_dest, flip_x, flip_y, dest_width, dest_height); + } + + gdk_pixbuf_render_to_drawable (buf_dest, + g1->drawable, + g1->gc, + 0, + 0, + dest_x, + dest_y, + dest_width, + dest_height, + GDK_RGB_DITHER_NORMAL, + 0, + 0); + + g_object_unref (G_OBJECT (buf_src)); + g_object_unref (G_OBJECT (buf_dest)); + + gdk_threads_leave (); +} diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c index 733461dcfc1..e4d223c543d 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c @@ -400,7 +400,6 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_gdkDrawDrawable struct graphics2d *src = NULL, *dst = NULL; gint s_height, s_width, d_height, d_width, height, width; cairo_matrix_t *matrix; - GdkGC *gc; cairo_operator_t tmp_op; gdk_threads_enter(); @@ -443,41 +442,12 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_gdkDrawDrawable gdk_threads_leave(); } -static jintArray -current_colors_of_widget (GtkWidget *widget, JNIEnv *env) -{ - GdkColor color; - jintArray array; - jint *rgb; - - g_assert (widget != NULL); - g_assert (env != NULL); - - color = widget->style->fg[GTK_STATE_NORMAL]; - array = (*env)->NewIntArray (env, 6); - - rgb = (*env)->GetIntArrayElements (env, array, NULL); - rgb[0] = color.red >> 8; - rgb[1] = color.green >> 8; - rgb[2] = color.blue >> 8; - - color = widget->style->bg[GTK_STATE_NORMAL]; - rgb[3] = color.red >> 8; - rgb[4] = color.green >> 8; - rgb[5] = color.blue >> 8; - - (*env)->ReleaseIntArrayElements (env, array, rgb, 0); - - return array; -} - -JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__Lgnu_java_awt_peer_gtk_GtkComponentPeer_2 +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__Lgnu_java_awt_peer_gtk_GtkComponentPeer_2 (JNIEnv *env, jobject obj, jobject peer) { struct graphics2d *gr = NULL; GtkWidget *widget = NULL; void *ptr = NULL; - jintArray color; gdk_threads_enter(); if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; } @@ -504,11 +474,8 @@ JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__ else init_graphics2d_as_pixbuf (gr); - color = current_colors_of_widget (widget, env); - NSA_SET_G2D_PTR (env, obj, gr); gdk_threads_leave(); - return color; } JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_dispose @@ -637,20 +604,21 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setGradient negate offsets. oh well. */ - - double a = (x2 - x1 == 0.) ? 0. : ((cyclic ? 3.0 : 2.0) / (x2 - x1)); - double c = (y2 - y1 == 0.) ? 0. : (1. / (y2 - y1)); - double dx = (x1 == 0.) ? 0. : 1. / x1; - double dy = (y1 == 0.) ? 0. : 1. / y1; - - cairo_matrix_set_affine (mat, - a, 0., - c, 0., - dx, dy); - - cairo_surface_set_matrix (surf, mat); - cairo_matrix_destroy (mat); - cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR); + { + double a = (x2 - x1 == 0.) ? 0. : ((cyclic ? 3.0 : 2.0) / (x2 - x1)); + double c = (y2 - y1 == 0.) ? 0. : (1. / (y2 - y1)); + double dx = (x1 == 0.) ? 0. : 1. / x1; + double dy = (y1 == 0.) ? 0. : 1. / y1; + + cairo_matrix_set_affine (mat, + a, 0., + c, 0., + dx, dy); + + cairo_surface_set_matrix (surf, mat); + cairo_matrix_destroy (mat); + cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR); + } /* FIXME: repeating gradients (not to mention hold gradients) don't seem to work. */ /* cairo_surface_set_repeat (surf, cyclic ? 1 : 0); */ @@ -783,7 +751,7 @@ JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_getImagePix jint i, px; gdk_threads_enter(); - if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; } + if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return NULL; } gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); g_assert (gr != NULL); diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c index 97e49625cb7..f58c289aa40 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c @@ -1,5 +1,5 @@ /* gdkpixbufdecoder.c - Copyright (C) 1999, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2003, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,36 +35,38 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - -#include <gtk/gtk.h> +#include <gtkpeer.h> +#include <gdk/gdk.h> #include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk-pixbuf/gdk-pixbuf-loader.h> -#include "gtkpeer.h" +#include <jni.h> +#include "native_state.h" #include "gnu_java_awt_peer_gtk_GdkPixbufDecoder.h" -struct state_table *native_pixbufdecoder_state_table; - -#define NSA_PB_INIT(env, clazz) \ - native_pixbufdecoder_state_table = init_state_table (env, clazz) +#include <string.h> +#include <stdlib.h> -#define NSA_GET_PB_PTR(env, obj) \ - get_state (env, obj, native_pixbufdecoder_state_table) - -#define NSA_SET_PB_PTR(env, obj, ptr) \ - set_state (env, obj, native_pixbufdecoder_state_table, (void *)ptr) +struct state_table *native_pixbufdecoder_state_table; -#define NSA_DEL_PB_PTR(env, obj) \ - remove_state_slot (env, obj, native_pixbufdecoder_state_table) +/* Union used for type punning. */ +union env_union +{ + void **void_env; + JNIEnv **jni_env; +}; +static JavaVM *vm; -jmethodID areaPreparedID; -jmethodID areaUpdatedID; +static jmethodID areaPreparedID; +static jmethodID areaUpdatedID; static void area_prepared (GdkPixbufLoader *loader, jobject *decoder) { + JNIEnv *env; + union env_union e; jint width, height; GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); @@ -78,11 +80,13 @@ area_prepared (GdkPixbufLoader *loader, g_assert (decoder != NULL); - (*gdk_env)->CallVoidMethod (gdk_env, - *decoder, - areaPreparedID, - width, height); - + e.jni_env = &env; + (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1); + (*env)->CallVoidMethod (env, + *decoder, + areaPreparedID, + width, height); + gdk_threads_enter (); } @@ -92,6 +96,8 @@ area_updated (GdkPixbufLoader *loader, gint width, gint height, jobject *decoder) { + JNIEnv *env; + union env_union e; jint stride_bytes, stride_pixels, n_channels, n_pixels; int i, px; jintArray jpixels; @@ -114,8 +120,10 @@ area_updated (GdkPixbufLoader *loader, n_pixels = height * stride_pixels; gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); - jpixels = (*gdk_env)->NewIntArray (gdk_env, n_pixels); - java_pixels = (*gdk_env)->GetIntArrayElements (gdk_env, jpixels, NULL); + e.jni_env = &env; + (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1); + jpixels = (*env)->NewIntArray (env, n_pixels); + java_pixels = (*env)->GetIntArrayElements (env, jpixels, NULL); memcpy (java_pixels, gdk_pixels + (y * stride_bytes), @@ -141,22 +149,27 @@ area_updated (GdkPixbufLoader *loader, gdk_threads_leave (); - (*gdk_env)->ReleaseIntArrayElements (gdk_env, jpixels, java_pixels, 0); - (*gdk_env)->CallVoidMethod (gdk_env, - *decoder, - areaUpdatedID, - (jint) x, (jint) y, - (jint) width, (jint) height, - jpixels, - stride_pixels); + (*env)->ReleaseIntArrayElements (env, jpixels, java_pixels, 0); + (*env)->CallVoidMethod (env, + *decoder, + areaUpdatedID, + (jint) x, (jint) y, + (jint) width, (jint) height, + jpixels, + stride_pixels); gdk_threads_enter (); } static void closed (GdkPixbufLoader *loader __attribute__((unused)), jobject *decoder) { + JNIEnv *env; + union env_union e; + e.jni_env = &env; + (*vm)->GetEnv (vm, e.void_env, JNI_VERSION_1_1); + gdk_threads_leave (); - (*gdk_env)->DeleteGlobalRef (gdk_env, *decoder); + (*env)->DeleteGlobalRef (env, *decoder); free (decoder); gdk_threads_enter (); } @@ -187,6 +200,8 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initState JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState (JNIEnv *env, jclass clazz) { + (*env)->GetJavaVM(env, &vm); + areaPreparedID = (*env)->GetMethodID (env, clazz, "areaPrepared", "(II)V"); @@ -223,14 +238,14 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpBytes if (len < 1) return; - bytes = (*gdk_env)->GetByteArrayElements (gdk_env, jarr, NULL); + bytes = (*env)->GetByteArrayElements (env, jarr, NULL); g_assert (bytes != NULL); loader = (GdkPixbufLoader *)NSA_GET_PB_PTR (env, obj); g_assert (loader != NULL); gdk_threads_enter (); - gdk_pixbuf_loader_write (loader, bytes, len, NULL); + gdk_pixbuf_loader_write (loader, (const guchar *) bytes, len, NULL); gdk_threads_leave (); - (*gdk_env)->ReleaseByteArrayElements (gdk_env, jarr, bytes, 0); + (*env)->ReleaseByteArrayElements (env, jarr, bytes, 0); } diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c index d9647e9ba10..08d38b5871d 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c @@ -42,20 +42,23 @@ exception statement from your version. */ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkButtonPeer_create - (JNIEnv *env, jobject obj) + (JNIEnv *env, jobject obj, jstring label) { + const char *c_label; GtkWidget *button; - /* Create global reference and save it for future use */ NSA_SET_GLOBAL_REF (env, obj); + c_label = (*env)->GetStringUTFChars (env, label, NULL); + gdk_threads_enter (); - - button = gtk_button_new(); + + button = gtk_button_new_with_label (c_label); gtk_widget_show (button); gdk_threads_leave (); + (*env)->ReleaseStringUTFChars (env, label, c_label); NSA_SET_PTR (env, obj, button); } @@ -102,7 +105,7 @@ Java_gnu_java_awt_peer_gtk_GtkButtonPeer_gtkSetLabel gdk_threads_enter (); label = gtk_bin_get_child (GTK_BIN (ptr)); - gtk_label_set_text (GTK_LABEL(label), text); + gtk_label_set_text (GTK_LABEL (label), text); gdk_threads_leave (); @@ -126,9 +129,6 @@ Java_gnu_java_awt_peer_gtk_GtkButtonPeer_gtkSetFont label = gtk_bin_get_child (GTK_BIN (ptr)); - if (!label) - return; - font_desc = pango_font_description_from_string (font_name); pango_font_description_set_size (font_desc, size * dpi_conversion_factor); @@ -165,9 +165,6 @@ Java_gnu_java_awt_peer_gtk_GtkButtonPeer_gtkWidgetSetForeground label = gtk_bin_get_child (GTK_BIN(ptr)); - if (!label) - return; - gtk_widget_modify_fg (label, GTK_STATE_NORMAL, &color); gtk_widget_modify_fg (label, GTK_STATE_ACTIVE, &color); gtk_widget_modify_fg (label, GTK_STATE_PRELIGHT, &color); diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c index f5d7cfb89aa..4d5c8114cd7 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c @@ -43,12 +43,11 @@ exception statement from your version. */ static void item_toggled (GtkToggleButton *item, jobject peer); JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_nativeCreate - (JNIEnv *env, jobject obj, jobject group, jboolean state) +Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_create + (JNIEnv *env, jobject obj, jobject group) { GtkWidget *button; - /* Create global reference and save it for future use */ NSA_SET_GLOBAL_REF (env, obj); gdk_threads_enter (); @@ -66,7 +65,6 @@ Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_nativeCreate NSA_SET_PTR (env, group, button); } } - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), state); gdk_threads_leave (); @@ -131,6 +129,21 @@ Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_nativeSetCheckboxGroup } JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkToggleButtonSetActive + (JNIEnv *env, jobject obj, jboolean is_active) +{ + void *ptr; + + ptr = NSA_GET_PTR (env, obj); + + gdk_threads_enter (); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ptr), is_active); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkSetFont (JNIEnv *env, jobject obj, jstring name, jint style, jint size) { @@ -171,26 +184,25 @@ Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkSetFont } JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkSetLabel +Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkButtonSetLabel (JNIEnv *env, jobject obj, jstring label) { - const char *str; - void *ptr; + const char *c_label; GtkWidget *label_widget; + void *ptr; ptr = NSA_GET_PTR (env, obj); - label_widget = gtk_bin_get_child (GTK_BIN(ptr)); - - str = (*env)->GetStringUTFChars (env, label, 0); + c_label = (*env)->GetStringUTFChars (env, label, NULL); gdk_threads_enter (); - gtk_label_set_label (GTK_LABEL (label_widget), str); + label_widget = gtk_bin_get_child (GTK_BIN (ptr)); + gtk_label_set_text (GTK_LABEL (label_widget), c_label); gdk_threads_leave (); - (*env)->ReleaseStringUTFChars (env, label, str); + (*env)->ReleaseStringUTFChars (env, label, c_label); } static void diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c index 9b262d33d7d..128443121b2 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c @@ -39,38 +39,27 @@ exception statement from your version. */ #include "gtkpeer.h" #include "gnu_java_awt_peer_gtk_GtkChoicePeer.h" -static void connect_choice_item_selectable_hook (JNIEnv *env, - jobject peer_obj, - GtkItem *menuitem, - const char *label); +static void selection_changed (GtkComboBox *combobox, gpointer data); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkChoicePeer_create (JNIEnv *env, jobject obj) { GtkWidget *menu; - GtkOptionMenu *option_menu; - GtkRequisition child_requisition; + GtkComboBox *combobox; - /* Create global reference and save it for future use */ NSA_SET_GLOBAL_REF (env, obj); gdk_threads_enter (); - option_menu = GTK_OPTION_MENU (gtk_option_menu_new ()); - menu = gtk_menu_new (); - gtk_widget_show (menu); + combobox = gtk_combo_box_new_text (); - gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); - - gtk_widget_size_request (gtk_menu_item_new_with_label (""), - &child_requisition); - option_menu->width = child_requisition.width; - option_menu->height = child_requisition.height; + g_signal_connect (combobox, "changed", + G_CALLBACK (selection_changed), obj); gdk_threads_leave (); - NSA_SET_PTR (env, obj, option_menu); + NSA_SET_PTR (env, obj, combobox); } JNIEXPORT void JNICALL @@ -78,45 +67,27 @@ Java_gnu_java_awt_peer_gtk_GtkChoicePeer_append (JNIEnv *env, jobject obj, jobjectArray items) { gpointer ptr; - GtkMenu *menu; jsize count, i; - int need_set_history = 0; ptr = NSA_GET_PTR (env, obj); gdk_threads_enter (); - menu = GTK_MENU (gtk_option_menu_get_menu (GTK_OPTION_MENU (ptr))); - - /* Are we adding the first element? */ - if (gtk_option_menu_get_history (GTK_OPTION_MENU (ptr)) < 0) - need_set_history = 1; - count = (*env)->GetArrayLength (env, items); for (i = 0; i < count; i++) { jobject item; const char *label; - GtkWidget *menuitem; item = (*env)->GetObjectArrayElement (env, items, i); label = (*env)->GetStringUTFChars (env, item, NULL); - menuitem = gtk_menu_item_new_with_label (label); - gtk_menu_append (menu, menuitem); - gtk_widget_show (menuitem); - - connect_choice_item_selectable_hook (env, obj, - GTK_ITEM (menuitem), label); + gtk_combo_box_append_text (GTK_COMBO_BOX (ptr), label); (*env)->ReleaseStringUTFChars (env, item, label); } - /* If we just added the first element select it. */ - if (need_set_history) - gtk_option_menu_set_history (GTK_OPTION_MENU (ptr), 0); - gdk_threads_leave (); } @@ -126,36 +97,13 @@ Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeAdd { void *ptr; const char *label; - GtkWidget *menu, *menuitem; - int current; - int need_set_history = 0; ptr = NSA_GET_PTR (env, obj); label = (*env)->GetStringUTFChars (env, item, 0); gdk_threads_enter (); - - current = gtk_option_menu_get_history (GTK_OPTION_MENU (ptr)); - - /* Are we adding the first element or below or at the currently - selected one? */ - if ((current < 0) || (current >= index)) - need_set_history = 1; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (ptr)); - menuitem = gtk_menu_item_new_with_label (label); - gtk_menu_insert (GTK_MENU (menu), menuitem, index); - gtk_widget_show (menuitem); - - connect_choice_item_selectable_hook (env, obj, GTK_ITEM (menuitem), label); - - /* If we just added the first element select it. - If we added at of below the currently selected position make - the first item the selected one. */ - if (need_set_history) - gtk_option_menu_set_history (GTK_OPTION_MENU (ptr), 0); - + gtk_combo_box_insert_text (GTK_COMBO_BOX (ptr), index, label); gdk_threads_leave (); (*env)->ReleaseStringUTFChars (env, item, label); @@ -166,50 +114,35 @@ Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeRemove (JNIEnv *env, jobject obj, jint index) { void *ptr; - GtkContainer *menu; - GtkWidget *menuitem; - GList *children; - int need_set_history = 0; - int i, from, to; ptr = NSA_GET_PTR (env, obj); gdk_threads_enter (); + gtk_combo_box_remove_text (GTK_COMBO_BOX (ptr), index); + gdk_threads_leave (); +} - menu = GTK_CONTAINER (gtk_option_menu_get_menu (GTK_OPTION_MENU (ptr))); - children = gtk_container_children (menu); +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeRemoveAll + (JNIEnv *env, jobject obj) +{ + void *ptr; + GtkTreeModel *model; + gint count, i; - if (index == -1) - { - /* Remove all elements (removeAll) */ - from = g_list_length (children) - 1; - to = 0; + ptr = NSA_GET_PTR (env, obj); - /* Select the first item to prevent spurious activate signals */ - gtk_option_menu_set_history (GTK_OPTION_MENU (ptr), 0); - } - else - { - /* Remove the specific index element */ - from = index; - to = index; + gdk_threads_enter (); - /* Are we removing the currently selected element? */ - if (gtk_option_menu_get_history (GTK_OPTION_MENU (ptr)) == index) - need_set_history = 1; - } + model = gtk_combo_box_get_model (GTK_COMBO_BOX (ptr)); + count = gtk_tree_model_iter_n_children (model, NULL); - for (i = from; i >= to; i--) - { - menuitem = GTK_WIDGET (g_list_nth (children, i)->data); - gtk_container_remove (menu, menuitem); - gtk_widget_destroy (menuitem); - } + /* First, unselect everything, to avoid problems when removing items. */ + gtk_combo_box_set_active (GTK_COMBO_BOX (ptr), -1); - /* If we just removed the currently selected element and there are - still elements left in the list, make the first item the selected one. */ - if (need_set_history && gtk_container_children (menu)) - gtk_option_menu_set_history (GTK_OPTION_MENU (ptr), 0); + for (i = count - 1; i >= 0; i--) { + gtk_combo_box_remove_text (GTK_COMBO_BOX (ptr), i); + } gdk_threads_leave (); } @@ -223,12 +156,12 @@ Java_gnu_java_awt_peer_gtk_GtkChoicePeer_select ptr = NSA_GET_PTR (env, obj); gdk_threads_enter (); - gtk_option_menu_set_history (GTK_OPTION_MENU (ptr), index); + gtk_combo_box_set_active (GTK_COMBO_BOX (ptr), index); gdk_threads_leave (); } JNIEXPORT jint JNICALL -Java_gnu_java_awt_peer_gtk_GtkChoicePeer_getHistory +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeGetSelected (JNIEnv *env, jobject obj) { void *ptr; @@ -237,58 +170,38 @@ Java_gnu_java_awt_peer_gtk_GtkChoicePeer_getHistory ptr = NSA_GET_PTR (env, obj); gdk_threads_enter (); - - index = gtk_option_menu_get_history (GTK_OPTION_MENU (ptr)); - + index = gtk_combo_box_get_active (GTK_COMBO_BOX (ptr)); gdk_threads_leave (); return index; } -static void -item_activate (GtkItem *item __attribute__((unused)), - struct item_event_hook_info *ie) +void selection_changed (GtkComboBox *combobox, jobject peer) { jstring label; - gdk_threads_leave (); + GtkTreeModel *model; + GtkTreeIter iter; + GValue value; + gchar *selected; + gint index; - label = (*gdk_env)->NewStringUTF (gdk_env, ie->label); - (*gdk_env)->CallVoidMethod (gdk_env, ie->peer_obj, - choicePostItemEventID, - label, - (jint) AWT_ITEM_SELECTED); - gdk_threads_enter (); -} + index = gtk_combo_box_get_active(combobox); -static void -item_removed (gpointer data, - GClosure gc __attribute__((unused))) -{ - struct item_event_hook_info *ie = data; - - free ((void *) ie->label); - free (ie); -} - -static void -connect_choice_item_selectable_hook (JNIEnv *env, - jobject peer_obj, - GtkItem *menuitem, - const char *label) -{ - struct item_event_hook_info *ie; - jobject *peer_objGlobPtr; + if (index >= 0) + { + model = gtk_combo_box_get_model (combobox); - ie = (struct item_event_hook_info *) - malloc (sizeof (struct item_event_hook_info)); + gtk_combo_box_get_active_iter (combobox, &iter); - peer_objGlobPtr = NSA_GET_GLOBAL_REF (env, peer_obj); - g_assert (peer_objGlobPtr); + gtk_tree_model_get (model, &iter, 0, &selected, -1); - ie->peer_obj = *peer_objGlobPtr; - ie->label = strdup (label); + gdk_threads_leave (); - g_signal_connect_data (G_OBJECT (menuitem), "activate", - GTK_SIGNAL_FUNC (item_activate), ie, - (GClosureNotify) item_removed, 0); + label = (*gdk_env)->NewStringUTF (gdk_env, selected); + (*gdk_env)->CallVoidMethod (gdk_env, peer, + choicePostItemEventID, + label, + (jint) AWT_ITEM_SELECTED); + gdk_threads_enter (); + } } diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c index 6bc24872dfa..8aaf0d26282 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c @@ -473,6 +473,63 @@ Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetCursor } JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetParent + (JNIEnv *env, jobject obj, jobject parent) +{ + void *ptr; + void *parent_ptr; + GtkWidget *widget; + GtkWidget *parent_widget; + + ptr = NSA_GET_PTR (env, obj); + parent_ptr = NSA_GET_PTR (env, parent); + + gdk_threads_enter (); + + widget = GTK_WIDGET (ptr); + parent_widget = GTK_WIDGET (parent_ptr); + + if (GTK_IS_WINDOW (parent_widget)) + { + GList *children = gtk_container_children + (GTK_CONTAINER (GTK_BIN (parent_widget)->child)); + + if (GTK_IS_MENU_BAR (children->data)) + gtk_layout_put (GTK_LAYOUT (children->next->data), widget, 0, 0); + else + gtk_layout_put (GTK_LAYOUT (children->data), widget, 0, 0); + } + else + if (GTK_IS_SCROLLED_WINDOW (parent_widget)) + { + gtk_scrolled_window_add_with_viewport + (GTK_SCROLLED_WINDOW (parent_widget), widget); + gtk_viewport_set_shadow_type (GTK_VIEWPORT (widget->parent), + GTK_SHADOW_NONE); + + } + else + gtk_layout_put (GTK_LAYOUT (parent_widget), widget, 0, 0); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetSensitive + (JNIEnv *env, jobject obj, jboolean sensitive) +{ + void *ptr; + + ptr = NSA_GET_PTR (env, obj); + + gdk_threads_enter (); + + gtk_widget_set_sensitive (GTK_WIDGET (ptr), sensitive); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetRequestFocus (JNIEnv *env, jobject obj) { @@ -525,11 +582,11 @@ Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetDispatchKeyEvent event->key.send_event = 0; event->key.time = (guint32) when; - if (mods & AWT_SHIFT_MASK) + if (mods & AWT_SHIFT_DOWN_MASK) event->key.state |= GDK_SHIFT_MASK; - if (mods & AWT_CTRL_MASK) + if (mods & AWT_CTRL_DOWN_MASK) event->key.state |= GDK_CONTROL_MASK; - if (mods & AWT_ALT_MASK) + if (mods & AWT_ALT_DOWN_MASK) event->key.state |= GDK_MOD1_MASK; /* This hack is needed because the AWT has no notion of num lock. @@ -680,19 +737,33 @@ Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetPreferredDimensions gdk_threads_enter (); - /* Save the widget's current size request. */ - gtk_widget_size_request (GTK_WIDGET (ptr), ¤t_req); + /* Widgets that extend GtkWindow such as GtkFileChooserDialog may have + a default size. These values seem more useful then the natural + requisition values, particularly for GtkFileChooserDialog. */ + if (GTK_IS_WINDOW (ptr)) + { + gint width, height; + gtk_window_get_default_size (GTK_WINDOW (ptr), &width, &height); - /* Get the widget's "natural" size request. */ - gtk_widget_set_size_request (GTK_WIDGET (ptr), -1, -1); - gtk_widget_size_request (GTK_WIDGET (ptr), &natural_req); + dims[0] = width; + dims[1] = height; + } + else + { + /* Save the widget's current size request. */ + gtk_widget_size_request (GTK_WIDGET (ptr), ¤t_req); + + /* Get the widget's "natural" size request. */ + gtk_widget_set_size_request (GTK_WIDGET (ptr), -1, -1); + gtk_widget_size_request (GTK_WIDGET (ptr), &natural_req); - /* Reset the widget's size request. */ - gtk_widget_set_size_request (GTK_WIDGET (ptr), - current_req.width, current_req.height); + /* Reset the widget's size request. */ + gtk_widget_set_size_request (GTK_WIDGET (ptr), + current_req.width, current_req.height); - dims[0] = natural_req.width; - dims[1] = natural_req.height; + dims[0] = natural_req.width; + dims[1] = natural_req.height; + } gdk_threads_leave (); @@ -911,45 +982,6 @@ find_gtk_layout (GtkWidget *parent) return NULL; } -#define WIDGET_CLASS(w) GTK_WIDGET_CLASS (GTK_OBJECT (w)->klass) - -void -set_parent (GtkWidget *widget, GtkContainer *parent) -{ - if (GTK_IS_WINDOW (parent)) - { - GList *children = gtk_container_children - (GTK_CONTAINER (GTK_BIN (parent)->child)); - - if (GTK_IS_MENU_BAR (children->data)) - gtk_layout_put (GTK_LAYOUT (children->next->data), widget, 0, 0); - else /* GTK_IS_LAYOUT (children->data) */ - gtk_layout_put (GTK_LAYOUT (children->data), widget, 0, 0); - } - else - if (GTK_IS_SCROLLED_WINDOW (parent)) - { -/* if (WIDGET_CLASS (widget)->set_scroll_adjustments_signal) */ -/* gtk_container_add (GTK_CONTAINER (parent), widget); */ -/* else */ -/* { */ - gtk_scrolled_window_add_with_viewport - (GTK_SCROLLED_WINDOW (parent), widget); - gtk_viewport_set_shadow_type (GTK_VIEWPORT (widget->parent), - GTK_SHADOW_NONE); -/* } */ - - } -/* gtk_layout_put */ -/* (GTK_LAYOUT (GTK_BIN (parent)->child), widget, 0, 0); */ - -/* if (GTK_IS_SCROLLED_WINDOW (parent)) */ -/* gtk_layout_put */ -/* (GTK_LAYOUT (GTK_BIN (GTK_BIN (parent)->child)->child), widget, 0, 0); */ - else - gtk_layout_put (GTK_LAYOUT (parent), widget, 0, 0); -} - JNIEXPORT jboolean JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_isEnabled (JNIEnv *env, jobject obj) @@ -981,105 +1013,6 @@ Java_gnu_java_awt_peer_gtk_GtkComponentPeer_modalHasGrab return retval; } -JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GtkComponentPeer_set__Ljava_lang_String_2Ljava_lang_String_2 - (JNIEnv *env, jobject obj, jstring jname, jstring jvalue) -{ - const char *name; - const char *value; - void *ptr; - - ptr = NSA_GET_PTR (env, obj); - name = (*env)->GetStringUTFChars (env, jname, NULL); - value = (*env)->GetStringUTFChars (env, jvalue, NULL); - - gdk_threads_enter(); - g_object_set(ptr, name, value, NULL); - gdk_threads_leave(); - - (*env)->ReleaseStringUTFChars (env, jname, name); - (*env)->ReleaseStringUTFChars (env, jvalue, value); -} - -JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_set__Ljava_lang_String_2Z - (JNIEnv *env, jobject obj, jstring jname, jboolean value) -{ - const char *name; - void *ptr; - - ptr = NSA_GET_PTR (env, obj); - - name = (*env)->GetStringUTFChars (env, jname, NULL); - - gdk_threads_enter(); - g_object_set(ptr, name, value, NULL); - gdk_threads_leave(); - - (*env)->ReleaseStringUTFChars (env, jname, name); -} - -JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_set__Ljava_lang_String_2I - (JNIEnv *env, jobject obj, jstring jname, jint value) -{ - const char *name; - void *ptr; - - ptr = NSA_GET_PTR (env, obj); - name = (*env)->GetStringUTFChars (env, jname, NULL); - - gdk_threads_enter(); - g_object_set(ptr, name, value, NULL); - gdk_threads_leave(); - - (*env)->ReleaseStringUTFChars (env, jname, name); -} - -JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_set__Ljava_lang_String_2F - (JNIEnv *env, jobject obj, jstring jname, jfloat value) -{ - const char *name; - void *ptr; - - ptr = NSA_GET_PTR (env, obj); - name = (*env)->GetStringUTFChars (env, jname, NULL); - - gdk_threads_enter(); - g_object_set(ptr, name, value, NULL); - gdk_threads_leave(); - - (*env)->ReleaseStringUTFChars (env, jname, name); -} - -JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GtkComponentPeer_set__Ljava_lang_String_2Ljava_lang_Object_2 - (JNIEnv *env, jobject obj1, jstring jname, jobject obj2) -{ - const char *name; - void *ptr1, *ptr2; - - ptr1 = NSA_GET_PTR (env, obj1); - ptr2 = NSA_GET_PTR (env, obj2); - - name = (*env)->GetStringUTFChars (env, jname, NULL); - - /* special case to catch where we need to set the parent */ - if (!strcmp (name, "parent")) - { - gdk_threads_enter (); - set_parent (GTK_WIDGET (ptr1), GTK_CONTAINER (ptr2)); - gdk_threads_leave (); - - (*env)->ReleaseStringUTFChars (env, jname, name); - return; - } - - gdk_threads_enter(); - g_object_set(ptr1, name, ptr2, NULL); - gdk_threads_leave(); - - (*env)->ReleaseStringUTFChars (env, jname, name); -} - static gboolean filter_expose_event_handler (GtkWidget *widget, GdkEvent *event, jobject peer) { @@ -1111,6 +1044,7 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_addExposeFilt GList *children; void *ptr = NSA_GET_PTR (env, obj); jobject *gref = NSA_GET_GLOBAL_REF (env, obj); + gulong hid; g_assert (gref); @@ -1144,10 +1078,9 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_addExposeFilt { filterobj = GTK_OBJECT(ptr); } - - gulong hid = g_signal_handler_find(filterobj, - G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, *pre_event_handler, NULL); + hid = g_signal_handler_find(filterobj, + G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, *pre_event_handler, NULL); if (hid > 0) { g_signal_handler_block(filterobj, hid); @@ -1166,6 +1099,7 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_removeExposeF GList *children; void *ptr = NSA_GET_PTR (env, obj); jobject *gref = NSA_GET_GLOBAL_REF (env, obj); + gulong hid; g_assert (gref); @@ -1202,9 +1136,9 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkComponentPeer_removeExposeF g_signal_handlers_disconnect_by_func (filterobj, *filter_expose_event_handler, *gref); - gulong hid = g_signal_handler_find(filterobj, - G_SIGNAL_MATCH_FUNC, - 0, 0, NULL, *pre_event_handler, NULL); + hid = g_signal_handler_find(filterobj, + G_SIGNAL_MATCH_FUNC, + 0, 0, NULL, *pre_event_handler, NULL); if (hid > 0) { g_signal_handler_unblock(filterobj, hid); diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c index 8fb619e2563..7cf405df902 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c @@ -58,11 +58,11 @@ button_to_awt_mods (int button) switch (button) { case 1: - return AWT_BUTTON1_MASK; + return AWT_BUTTON1_DOWN_MASK; case 2: - return AWT_BUTTON2_MASK; + return AWT_BUTTON2_DOWN_MASK; case 3: - return AWT_BUTTON3_MASK; + return AWT_BUTTON3_DOWN_MASK; } return 0; @@ -74,11 +74,11 @@ state_to_awt_mods (guint state) jint result = 0; if (state & GDK_SHIFT_MASK) - result |= AWT_SHIFT_MASK; + result |= AWT_SHIFT_DOWN_MASK; if (state & GDK_CONTROL_MASK) - result |= AWT_CTRL_MASK; + result |= AWT_CTRL_DOWN_MASK; if (state & GDK_MOD1_MASK) - result |= AWT_ALT_MASK; + result |= AWT_ALT_DOWN_MASK; return result; } @@ -89,17 +89,17 @@ state_to_awt_mods_with_button_states (guint state) jint result = 0; if (state & GDK_SHIFT_MASK) - result |= AWT_SHIFT_MASK; + result |= AWT_SHIFT_DOWN_MASK; if (state & GDK_CONTROL_MASK) - result |= AWT_CTRL_MASK; + result |= AWT_CTRL_DOWN_MASK; if (state & GDK_MOD1_MASK) - result |= AWT_ALT_MASK; + result |= AWT_ALT_DOWN_MASK; if (state & GDK_BUTTON1_MASK) - result |= AWT_BUTTON1_MASK; + result |= AWT_BUTTON1_DOWN_MASK; if (state & GDK_BUTTON2_MASK) - result |= AWT_BUTTON2_MASK; + result |= AWT_BUTTON2_DOWN_MASK; if (state & GDK_BUTTON3_MASK) - result |= AWT_BUTTON3_MASK; + result |= AWT_BUTTON3_DOWN_MASK; return result; } @@ -124,29 +124,29 @@ keyevent_state_to_awt_mods (GdkEvent *event) if (event->key.keyval == GDK_Shift_L || event->key.keyval == GDK_Shift_R) - result |= AWT_SHIFT_MASK; + result |= AWT_SHIFT_DOWN_MASK; else { if (state & GDK_SHIFT_MASK) - result |= AWT_SHIFT_MASK; + result |= AWT_SHIFT_DOWN_MASK; } if (event->key.keyval == GDK_Control_L || event->key.keyval == GDK_Control_R) - result |= AWT_CTRL_MASK; + result |= AWT_CTRL_DOWN_MASK; else { if (state & GDK_CONTROL_MASK) - result |= AWT_CTRL_MASK; + result |= AWT_CTRL_DOWN_MASK; } if (event->key.keyval == GDK_Alt_L || event->key.keyval == GDK_Alt_R) - result |= AWT_ALT_MASK; + result |= AWT_ALT_DOWN_MASK; else { if (state & GDK_MOD1_MASK) - result |= AWT_ALT_MASK; + result |= AWT_ALT_DOWN_MASK; } } else if (event->type == GDK_KEY_RELEASE) @@ -157,20 +157,20 @@ keyevent_state_to_awt_mods (GdkEvent *event) && event->key.keyval != GDK_Shift_R) { if (state & GDK_SHIFT_MASK) - result |= AWT_SHIFT_MASK; + result |= AWT_SHIFT_DOWN_MASK; } if (event->key.keyval != GDK_Control_L && event->key.keyval != GDK_Control_R) { if (state & GDK_CONTROL_MASK) - result |= AWT_CTRL_MASK; + result |= AWT_CTRL_DOWN_MASK; } if (event->key.keyval != GDK_Alt_L && event->key.keyval != GDK_Alt_R) { if (state & GDK_MOD1_MASK) - result |= AWT_ALT_MASK; + result |= AWT_ALT_DOWN_MASK; } } @@ -885,8 +885,8 @@ pre_event_handler (GtkWidget *widget, GdkEvent *event, jobject peer) postMouseEventID, AWT_MOUSE_PRESSED, (jlong)event->button.time, - state_to_awt_mods (event->button.state) | - button_to_awt_mods (event->button.button), + state_to_awt_mods (event->button.state) + | button_to_awt_mods (event->button.button), (jint)event->button.x, (jint)event->button.y, click_count, @@ -902,8 +902,8 @@ pre_event_handler (GtkWidget *widget, GdkEvent *event, jobject peer) postMouseEventID, AWT_MOUSE_RELEASED, (jlong)event->button.time, - state_to_awt_mods (event->button.state) | - button_to_awt_mods (event->button.button), + state_to_awt_mods (event->button.state) + | button_to_awt_mods (event->button.button), (jint)event->button.x, (jint)event->button.y, click_count, @@ -923,8 +923,8 @@ pre_event_handler (GtkWidget *widget, GdkEvent *event, jobject peer) postMouseEventID, AWT_MOUSE_CLICKED, (jlong)event->button.time, - state_to_awt_mods (event->button.state) | - button_to_awt_mods (event->button.button), + state_to_awt_mods (event->button.state) + | button_to_awt_mods (event->button.button), (jint)event->button.x, (jint)event->button.y, click_count, diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c index 95bec4a10be..594fcce4165 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c @@ -151,6 +151,7 @@ gboolean filenameFilterCallback (const GtkFileFilterInfo *filter_info, jclass cx; jmethodID id; jstring *filename; + gboolean accepted; cx = (*gdk_env)->GetObjectClass (gdk_env, (jobject) obj); id = (*gdk_env)->GetMethodID (gdk_env, cx, "filenameFilterCallback", @@ -159,7 +160,7 @@ gboolean filenameFilterCallback (const GtkFileFilterInfo *filter_info, filename = (*gdk_env)->NewStringUTF(gdk_env, filter_info->filename); gdk_threads_leave(); - gboolean accepted = (*gdk_env)->CallBooleanMethod(gdk_env, obj, id, filename); + accepted = (*gdk_env)->CallBooleanMethod(gdk_env, obj, id, filename); gdk_threads_enter(); return accepted; diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c index a9da539f223..99107a1282c 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMainThread.c @@ -63,12 +63,10 @@ jmethodID postWindowEventID; JNIEnv *gdk_env; -#ifdef PORTABLE_NATIVE_SYNC -JavaVM *gdk_vm; -#endif - GtkWindowGroup *global_gtk_window_group; +static void init_glib_threads(JNIEnv *, jint); + double dpi_conversion_factor; static void init_dpi_conversion_factor (); @@ -78,10 +76,17 @@ static void dpi_changed_cb (GtkSettings *settings, /* * Call gtk_init. It is very important that this happen before any other * gtk calls. + * + * The portableNativeSync argument may have the values: + * 1 if the Java property gnu.classpath.awt.gtk.portable.native.sync + * is set to "true". + * 0 if it is set to "false" + * -1 if unset. */ JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit (JNIEnv *env, jclass clazz) +Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit (JNIEnv *env, jclass clazz, + jint portableNativeSync) { int argc = 1; char **argv; @@ -91,23 +96,22 @@ Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit (JNIEnv *env, jclass clazz) gtkmenuitempeer, gtktextcomponentpeer, window; NSA_INIT (env, clazz); + gdk_env = env; /* GTK requires a program's argc and argv variables, and requires that they - be valid. */ - - argv = (char **) malloc (sizeof (char *) * 2); - argv[0] = ""; + be valid. Set it up. */ + argv = (char **) g_malloc (sizeof (char *) * 2); + argv[0] = (char *) g_malloc(1); +#if 1 + strcpy(argv[0], ""); +#else /* The following is a more efficient alternative, but less intuitively + * expresses what we are trying to do. This code is only run once, so + * I'm going for intuitive. */ + argv[0][0] = '\0'; +#endif argv[1] = NULL; - /* until we have JDK 1.2 JNI, assume we have a VM with threads that - match what GLIB was compiled for */ -#ifdef PORTABLE_NATIVE_SYNC - (*env)->GetJavaVM( env, &gdk_vm ); - g_thread_init ( &g_thread_jni_functions ); - printf("called gthread init\n"); -#else - g_thread_init ( NULL ); -#endif + init_glib_threads(env, portableNativeSync); /* From GDK 2.0 onwards we have to explicitly call gdk_threads_init */ gdk_threads_init(); @@ -122,21 +126,19 @@ Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit (JNIEnv *env, jclass clazz) we're shutting down. */ atexit (gdk_threads_enter); - gdk_env = env; gdk_event_handler_set ((GdkEventFunc)awt_event_handler, NULL, NULL); if ((homedir = getenv ("HOME"))) { - rcpath = (char *) malloc (strlen (homedir) + strlen (RC_FILE) + 2); + rcpath = (char *) g_malloc (strlen (homedir) + strlen (RC_FILE) + 2); sprintf (rcpath, "%s/%s", homedir, RC_FILE); } gtk_rc_parse ((rcpath) ? rcpath : RC_FILE); - if (rcpath) - free (rcpath); - - free (argv); + g_free (rcpath); + g_free (argv[0]); + g_free (argv); /* setup cached IDs for posting GTK events to Java */ /* gtkgenericpeer = (*env)->FindClass (env, */ @@ -204,6 +206,37 @@ Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit (JNIEnv *env, jclass clazz) init_dpi_conversion_factor (); } + +/** Initialize GLIB's threads properly, based on the value of the + gnu.classpath.awt.gtk.portable.native.sync Java system property. If + that's unset, use the PORTABLE_NATIVE_SYNC config.h macro. (TODO: + In some release following 0.10, that config.h macro will go away.) + */ +static void +init_glib_threads(JNIEnv *env, jint portableNativeSync) +{ + if (portableNativeSync < 0) + { +#ifdef PORTABLE_NATIVE_SYNC /* Default value, if not set by the Java system + property */ + portableNativeSync = 1; +#else + portableNativeSync = 0; +#endif + } + + (*env)->GetJavaVM( env, &the_vm ); + if (portableNativeSync) + g_thread_init ( &portable_native_sync_jni_functions ); + else + g_thread_init ( NULL ); + + /* Debugging progress message; uncomment if needed: */ + /* printf("called gthread init\n"); */ +} + + + /* * Run gtk_main and block. */ diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuBarPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuBarPeer.c index 8034f647300..53c7351e6ec 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuBarPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuBarPeer.c @@ -70,6 +70,29 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_addMenu gdk_threads_leave (); } +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_nativeSetHelpMenu + (JNIEnv *env, jobject obj, jobject menupeer) +{ + static void *helpmenu; + void *mbar, *menu; + GList *list; + + mbar = NSA_GET_PTR (env, obj); + menu = NSA_GET_PTR (env, menupeer); + + gdk_threads_enter (); + if (helpmenu != NULL) + { + list = gtk_container_children (GTK_CONTAINER (mbar)); + while (list != NULL && list->data != helpmenu) + list = list->next; + if (list != NULL && list->data == helpmenu) + gtk_container_remove (GTK_CONTAINER (mbar), GTK_WIDGET (list->data)); + } + helpmenu = menu; + gdk_threads_leave (); +} + JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuBarPeer_delMenu (JNIEnv *env, jobject obj, jint index) { diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuItemPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuItemPeer.c index 70fc8095519..5d5de6780a0 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuItemPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuItemPeer.c @@ -86,6 +86,18 @@ Java_gnu_java_awt_peer_gtk_GtkMenuItemPeer_connectSignals gdk_threads_leave (); } +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuItemPeer_setEnabled + (JNIEnv *env, jobject obj, jboolean enabled) +{ + void *ptr; + + ptr = NSA_GET_PTR (env, obj); + + gdk_threads_enter (); + gtk_widget_set_sensitive (GTK_WIDGET (ptr), enabled); + gdk_threads_leave (); +} + JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuItemPeer_setLabel (JNIEnv *env, jobject obj, jstring label) { diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c index 0bb0ec52567..1ffe61b0c52 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c @@ -39,20 +39,6 @@ exception statement from your version. */ #include "gtkpeer.h" #include "gnu_java_awt_peer_gtk_GtkMenuPeer.h" -static void -accel_attach (GtkMenuItem *menu_item, - gpointer *user_data __attribute__((unused))) -{ - GtkAccelGroup *accel; - - accel = gtk_menu_get_accel_group (GTK_MENU (menu_item->submenu)); - /* FIXME: update this to use GTK-2.4 GtkActions. */ -#if 0 - _gtk_accel_group_attach (accel, - G_OBJECT (gtk_widget_get_toplevel (GTK_WIDGET(menu_item)))); -#endif -} - JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuPeer_setupAccelGroup (JNIEnv *env, jobject obj, jobject parent) { @@ -65,14 +51,6 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuPeer_setupAccelGroup { gtk_menu_set_accel_group (GTK_MENU (GTK_MENU_ITEM (ptr1)->submenu), gtk_accel_group_new ()); - - if (GTK_WIDGET_REALIZED (GTK_WIDGET (ptr1))) - accel_attach (GTK_MENU_ITEM (ptr1), NULL); - else - g_signal_connect (G_OBJECT (ptr1), - "realize", - GTK_SIGNAL_FUNC (accel_attach), - NULL); } else { @@ -128,6 +106,24 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuPeer_create (*env)->ReleaseStringUTFChars (env, label, str); } +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuPeer_addTearOff + (JNIEnv *env, jobject obj) +{ + void *ptr1; + GtkWidget *menu, *item; + + ptr1 = NSA_GET_PTR (env, obj); + + gdk_threads_enter (); + + menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (ptr1)); + item = gtk_tearoff_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + gdk_threads_leave (); +} + JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkMenuPeer_addItem (JNIEnv *env, jobject obj, jobject menuitempeer, jint key, jboolean shift) { diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextComponentPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextComponentPeer.c index 2d62c33a4d7..771f2b81d75 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextComponentPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextComponentPeer.c @@ -151,7 +151,6 @@ Java_gnu_java_awt_peer_gtk_GtkTextComponentPeer_setCaretPosition GtkWidget *text = NULL; GtkTextBuffer *buf; GtkTextIter iter; - GtkTextMark *mark; GtkTextMark *oldmark; GtkTextIter olditer; int oldpos; diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextFieldPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextFieldPeer.c index 5bea49a3f3c..2a6666a0d83 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextFieldPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextFieldPeer.c @@ -62,6 +62,47 @@ Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_create NSA_SET_PTR (env, obj, entry); } +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkWidgetSetBackground + (JNIEnv *env, jobject obj, jint red, jint green, jint blue) +{ + GdkColor color; + void *ptr; + + ptr = NSA_GET_PTR (env, obj); + + color.red = (red / 255.0) * 65535; + color.green = (green / 255.0) * 65535; + color.blue = (blue / 255.0) * 65535; + + gdk_threads_enter (); + + gtk_widget_modify_base (GTK_WIDGET (ptr), GTK_STATE_NORMAL, &color); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkWidgetSetForeground + (JNIEnv *env, jobject obj, jint red, jint green, jint blue) +{ + GdkColor color; + void *ptr; + + ptr = NSA_GET_PTR (env, obj); + + color.red = (red / 255.0) * 65535; + color.green = (green / 255.0) * 65535; + color.blue = (blue / 255.0) * 65535; + + gdk_threads_enter (); + + gtk_widget_modify_text (GTK_WIDGET (ptr), GTK_STATE_NORMAL, &color); + gtk_widget_modify_base (GTK_WIDGET (ptr), GTK_STATE_SELECTED, &color); + + gdk_threads_leave (); +} + JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_gtk_GtkTextFieldPeer_gtkEntryGetBorderWidth (JNIEnv *env, jobject obj) diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c index 4d11e6201bc..508893168b1 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c @@ -104,7 +104,6 @@ Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create insets = (*env)->GetIntArrayElements (env, jinsets, 0); insets[0] = insets[1] = insets[2] = insets[3] = 0; - /* Create global reference and save it for future use */ NSA_SET_GLOBAL_REF (env, obj); gdk_threads_enter (); @@ -163,6 +162,56 @@ Java_gnu_java_awt_peer_gtk_GtkWindowPeer_create } JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetTitle + (JNIEnv *env, jobject obj, jstring title) +{ + const char *c_title; + void *ptr; + + ptr = NSA_GET_PTR (env, obj); + + c_title = (*env)->GetStringUTFChars (env, title, NULL); + + gdk_threads_enter (); + + gtk_window_set_title (GTK_WINDOW (ptr), c_title); + + gdk_threads_leave (); + + (*env)->ReleaseStringUTFChars (env, title, c_title); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetResizable + (JNIEnv *env, jobject obj, jboolean resizable) +{ + void *ptr; + + ptr = NSA_GET_PTR (env, obj); + + gdk_threads_enter (); + + gtk_window_set_policy (GTK_WINDOW (ptr), resizable, resizable, FALSE); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkWindowPeer_gtkWindowSetModal + (JNIEnv *env, jobject obj, jboolean modal) +{ + void *ptr; + + ptr = NSA_GET_PTR (env, obj); + + gdk_threads_enter (); + + gtk_window_set_modal (GTK_WINDOW (ptr), modal); + + gdk_threads_leave (); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkWindowPeer_nativeSetVisible (JNIEnv *env, jobject obj, jboolean visible) { @@ -486,6 +535,72 @@ Java_gnu_java_awt_peer_gtk_GtkFramePeer_gtkLayoutSetVisible gdk_threads_leave (); } +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFramePeer_nativeSetIconImageFromDecoder + (JNIEnv *env, jobject obj, jobject decoder) +{ + void *ptr; + GdkPixbufLoader *loader = NULL; + GdkPixbuf *pixbuf = NULL; + + ptr = NSA_GET_PTR (env, obj); + + loader = NSA_GET_PB_PTR (env, decoder); + g_assert (loader != NULL); + + gdk_threads_enter (); + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + g_assert (pixbuf != NULL); + + gtk_window_set_icon (GTK_WINDOW (ptr), pixbuf); + + gdk_threads_leave (); +} + +void free_pixbuf_data (guchar *pixels, gpointer data __attribute__((unused))) +{ + free(pixels); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFramePeer_nativeSetIconImageFromData + (JNIEnv *env, jobject obj, jintArray pixelArray, jint width, jint height) +{ + void *ptr; + GdkPixbuf *pixbuf; + jint *pixels; + int pixels_length, i; + guchar *data; + + ptr = NSA_GET_PTR (env, obj); + + pixels = (*env)->GetIntArrayElements (env, pixelArray, 0); + pixels_length = (*env)->GetArrayLength (env, pixelArray); + + data = malloc (sizeof (guchar) * pixels_length); + for (i = 0; i < pixels_length; i++) + data[i] = (guchar) pixels[i]; + + gdk_threads_enter (); + + pixbuf = gdk_pixbuf_new_from_data (data, + GDK_COLORSPACE_RGB, + TRUE, + 8, + width, + height, + width*4, + free_pixbuf_data, + NULL); + + gtk_window_set_icon (GTK_WINDOW (ptr), pixbuf); + + gdk_threads_leave (); + + (*env)->ReleaseIntArrayElements(env, pixelArray, pixels, 0); +} + static void window_get_frame_extents (GtkWidget *window, int *top, int *left, int *bottom, int *right) diff --git a/libjava/jni/gtk-peer/gthread-jni.c b/libjava/jni/gtk-peer/gthread-jni.c index 3dd5596b4bc..ee79424475c 100644 --- a/libjava/jni/gtk-peer/gthread-jni.c +++ b/libjava/jni/gtk-peer/gthread-jni.c @@ -40,142 +40,1166 @@ exception statement from your version. */ /************************************************************************/ /* - * Julian Dolby (dolby@us.ibm.com) - * February 7, 2003 + * @author Julian Dolby (dolby@us.ibm.com) + * @date February 7, 2003 implemented for GLIB v.1 + * + * + * @author Steven Augart + * <steve+classpath at augart dot com>, <augart at watson dot ibm dot com> + * @date April 30, 2004 -- May 10 2004: Support new functions for Glib v.2, + * fix cond_wait to free and re-acquire the mutex, + * replaced trylock stub implementation with a full one. * * This code implements the GThreadFunctions interface for GLIB using * Java threading primitives. All of the locking and conditional variable * functionality required by GThreadFunctions is implemented using the * monitor and wait/notify functionality of Java objects. The thread- - * local fucntionality uses the java.lang.ThreadLocal class. + * local functionality uses the java.lang.ThreadLocal class. + * + * Classpath's AWT support uses GTK+ peers. GTK+ uses GLIB. GLIB by default + * uses the platform's native threading model -- pthreads in most cases. If + * the Java runtime doesn't use the native threading model, then it needs this + * code in order to use Classpath's (GTK+-based) AWT routines. * - * This code is designed to be portable in that it makes no assumptions + * This code should be portable; I believe it makes no assumptions * about the underlying VM beyond that it implements the JNI functionality * that this code uses. * - * The one piece that does not really work is trylock for mutexes. The - * Java locking model does not include such functionality, and I do not - * see how to implement it without knowing something about how the VM - * implements locking. + * Currently, use of this code is governed by the configuration option + * --enable-portable-native-sync. We will soon add a VM hook so the VM can + * select which threading model it wants to use at run time; at that point, + * the configuration option will go away. + * + * The code in this file uses only JNI 1.1, except for one JNI 1.2 function: + * GetEnv, in the JNI Invocation API. (There seems to be no way around using + * GetEnv). + * + * ACKNOWLEDGEMENT: + * + * I would like to thank Mark Wielaard for his kindness in spending at least + * six hours of his own time in reviewing this code and correcting my GNU + * coding and commenting style. --Steve Augart + * * * NOTES: * - * I have tested it only on JikesRVM---the CVS head as of early February - * 2003. + * This code has been tested with Jikes RVM and with Kaffe. * - * Currently, use of this code is governed by the configuration option - * --enable-portable-native-sync + * This code should have proper automated unit tests. I manually tested it + * by running an application that uses AWT. --Steven Augart + * + * MINOR NIT: * + * - Using a jboolean in the arglist to "throw()" and "rethrow()" + * triggers many warnings from GCC's -Wconversion operation, because that + * is not the same as the conversion (upcast to an int) that would occur in + * the absence of a prototype. + * + * It would be very slightly more efficient to just pass the jboolean, but + * is not worth the clutter of messages. The right solution would be to + * turn off the -Wconversion warning for just this file, *except* that + * -Wconversion also warns you against constructs such as: + * unsigned u = -1; + * and that is a useful warning. So I went from a "jboolean" to a + * "gboolean" (-Wconversion is not enabled by default for GNU Classpath, + * but it is in my own CFLAGS, which, for gcc 3.3.3, read: -pipe -ggdb3 -W + * -Wall -Wbad-function-cast -Wcast-align -Wpointer-arith -Wcast-qual + * -Wshadow -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations + * -fkeep-static-consts -fkeep-inline-functions -Wundef -Wwrite-strings + * -Wno-aggregate-return -Wmissing-noreturn -Wnested-externs -Wtrigraphs + * -Wconversion -Wsign-compare -Wno-float-equal -Wmissing-format-attribute + * -Wno-unreachable-code -Wdisabled-optimization ) */ +#include <config.h> + +/************************************************************************/ +/* Configuration */ +/************************************************************************/ + +/** Tracing and Reporting **/ +#define TRACE_API_CALLS 0 /* announce entry and exit into each method, + by printing to stderr. */ + +#define TRACE_MONITORS 0 /* Every enterMonitor() and exitMonitor() goes + to stderr. */ + +/** Trouble handling. There is a discussion below of this. **/ +#define EXPLAIN_TROUBLE 1 /* Describe any unexpected trouble that + happens. This is a superset + of EXPLAIN_BROKEN, and if set trumps an + unset EXPLAIN_BROKEN. It is not a strict + superset, since at the moment there is no + TROUBLE that is not also BROKEN. + + Use criticalMsg() to describe the problem. + */ + +#define EXPLAIN_BROKEN 1 /* Describe trouble that is serious enough to + be BROKEN. (Right now all trouble is at + least BROKEN.) */ + +/* There is no EXPLAIN_BADLY_BROKEN definition. We always explain + BADLY_BROKEN trouble, since there is no other way to report it. */ + + +/** Error Handling **/ +#define DIE_IF_BROKEN 1 /* Dies if serious trouble happens. There is + really no non-serious trouble, except + possibly problems that arise during + pthread_create, which are reported by a + GError. + + If you do not set DIE_IF_BROKEN, then + trouble will raise a Java RuntimeException. + We probably do want to die right away, + since anything that's BROKEN really + indicates a programming error or a + system-wide error, and that's what the glib + documentation says you should do in case of + that kind of error in a glib-style + function. But it does work to turn this + off. */ + +#if DIE_IF_BROKEN +#define DIE_IF_BADLY_BROKEN 1 /* DIE_IF_BROKEN implies DIE_IF_BADLY_BROKEN */ +#else +#define DIE_IF_BADLY_BROKEN 1 /* Die if the system is badly broken -- + that is, if we have further trouble while + attempting to throw an exception + upwards, or if we are unable to generate + one of the classes we'll need in order to + throw wrapped exceptions upward. + + If unset, we will print a warning message, + and limp along anyway. Not that the system + is likely to work. */ +#endif + +/** Performance tuning parameters **/ + +#define ENABLE_EXPENSIVE_ASSERTIONS 0 /* Enable expensive assertions? */ + +#define DELETE_LOCAL_REFS 1 /* Whether to delete local references. + + JNI only guarantees that there wil be 16 + available. (Jikes RVM provides an number + only limited by VM memory.) + + Jikes RVM will probably perform faster if + this is turned off, but other VMs may need + this to be turned on in order to perform at + all, or might need it if things change. + + Remember, we don't know how many of those + local refs might have already been used up + by higher layers of JNI code that end up + calling g_thread_self(), + g_thread_set_private(), and so on. + + We set this to 1 for GNU Classpath, since + one of our principles is "always go for the + most robust implementation" */ + +#define HAVE_JNI_VERSION_1_2 0 /* Assume we don't. We could + dynamically check for this. We will + assume JNI 1.2 in later versions of + Classpath. + + As it stands, the code in this file + already needs one JNI 1.2 function: + GetEnv, in the JNI Invocation API. + + TODO This code hasn't been tested yet. + And really hasn't been implemented yet. + */ /************************************************************************/ /* Global data */ /************************************************************************/ +#if defined HAVE_STDINT_H +#include <stdint.h> /* provides intptr_t */ +#elif defined HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#include <stdio.h> /* snprintf */ +#include <stdarg.h> /* va_list */ #include "gthread-jni.h" +#include <assert.h> /* assert() */ + +/* For Java thread priority constants. */ +#include <gnu_java_awt_peer_gtk_GThreadNativeMethodRunner.h> + +/* Since not all JNI header generators actually define constants we + define them here explicitly. */ +#ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY +#define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY 1 +#endif +#ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY +#define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY 5 +#endif +#ifndef gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY +#define gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY 10 +#endif + +/* The VM handle. This is set in + Java_gnu_java_awt_peer_gtk_GtkMainThread_gtkInit */ +JavaVM *the_vm; + +/* Unions used for type punning. */ +union env_union +{ + void **void_env; + JNIEnv **jni_env; +}; + +union func_union +{ + void *void_func; + GThreadFunc g_func; +}; + +/* Forward Declarations for Functions */ +static int threadObj_set_priority (JNIEnv * env, jobject threadObj, + GThreadPriority gpriority); +static void fatalMsg (const char fmt[], ...) + __attribute__ ((format (printf, 1, 2))) + __attribute__ ((noreturn)); + +static void criticalMsg (const char fmt[], ...) + __attribute__ ((format (printf, 1, 2))); -/* The VM handle. This is set in GtkToolkitMain.gtkInit */ -JavaVM *gdk_vm; +static void tracing (const char fmt[], ...) + __attribute__ ((format (printf, 1, 2))); +static jint javaPriorityLevel (GThreadPriority priority) + __attribute__ ((const)); /************************************************************************/ -/* Utilities to reflect exceptions back to the VM */ +/* Trouble-handling, including utilities to reflect exceptions */ +/* back to the VM. Also some status reporting. */ /************************************************************************/ -/* This function checks for a pending exception, and rethrows it with +/* How are we going to handle problems? + + There are several approaches: + + 1) Report them with the GError mechanism. + + (*thread_create)() is the only one of these functions that takes a + GError pointer. And the only G_THREAD error defined maps onto EAGAIN. + We don't have any errors in our (*thread_create)() implementation that + can be mapped to EAGAIN. So this idea is a non-starter. + + 2) Reflect the exception back to the VM, wrapped in a RuntimeException. + This will fail sometimes, if we're so broken (BADLY_BROKEN) that we + fail to throw the exception. + + 3) Abort execution. This is what the glib functions themselves do for + errors that they can't report via GError. + + Enable DIE_IF_BROKEN and/or DIE_IF_BADLY_BROKEN to + make this the default for BROKEN and/or BADLY_BROKEN trouble. + + 4) Display messages to stderr. We always do this for BADLY_BROKEN + trouble. The glib functions do that for errors they can't report via + GError. + + There are some complications. + + When I attempted to report a problem in g_thread_self() using g_critical (a + macro around g_log(), I found that g_log in turn looks for thread-private + data and calls g_thread_self() again. + + We got a segfault, probably due to stack overflow. So, this code doesn't + use the g_critical() and g_error() functions any more. Nor do we use + g_assert(); we use the C library's assert() instead. +*/ + + +#define WHERE __FILE__ ":" G_STRINGIFY(__LINE__) ": " + +/* This is portable to older compilers that lack variable-argument macros. + This used to be just g_critical(), but then we ran into the error reporting + problem discussed above. +*/ +static void +fatalMsg (const char fmt[], ...) +{ + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fputs ("\nAborting execution\n", stderr); + abort (); +} + + +static void +criticalMsg (const char fmt[], ...) +{ + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + putc ('\n', stderr); +} + +/* Unlike the other two, this one does not append a newline. This is only + used if one of the TRACE_ macros is defined. */ +static void +tracing (const char fmt[], ...) +{ + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); +} + +#define assert_not_reached() \ + do \ + { \ + fputs(WHERE "You should never get here. Aborting execution.\n", \ + stderr); \ + abort(); \ + } \ + while(0) + + +#if DIE_IF_BADLY_BROKEN +#define BADLY_BROKEN fatalMsg +#else +#define BADLY_BROKEN criticalMsg +/* So, the user may still attempt to recover, even though we do not advise + this. */ +#endif + +/* I find it so depressing to have to use C without varargs macros. */ +#define BADLY_BROKEN_MSG WHERE "Something fundamental" \ + " to GNU Classpath's AWT JNI broke while we were trying to pass up a Java error message" + +#define BADLY_BROKEN0() \ + BADLY_BROKEN(BADLY_BROKEN_MSG); +#define BADLY_BROKEN1(msg) \ + BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg) +#define BADLY_BROKEN2(msg, arg) \ + BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg) +#define BADLY_BROKEN3(msg, arg, arg2) \ + BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg1, arg2) +#define BADLY_BROKEN4(msg, arg, arg2, arg3) \ + BADLY_BROKEN(BADLY_BROKEN_MSG ": " msg, arg1, arg2, arg3) + +#define DELETE_LOCAL_REF(env, ref) \ + do \ + { \ + if ( DELETE_LOCAL_REFS ) \ + { \ + (*env)->DeleteLocalRef (env, ref); \ + (ref) = NULL; \ + } \ + } \ + while(0) + +/* Cached info for Exception-wrapping */ + +jclass runtimeException_class; /* java.lang.RuntimeException */ +jmethodID runtimeException_ctor; /* constructor for it */ + + +/* Throw a new RuntimeException. It may wrap around an existing exception. + 1 if we did rethrow, -1 if we had trouble while rethrowing. + isBroken is always true in this case. */ +static int +throw (JNIEnv * env, jthrowable cause, const char *message, + gboolean isBroken, const char *file, int line) +{ + jstring jmessage; + gboolean describedException = FALSE; /* Did we already describe the + exception to stderr or the + equivalent? */ + jthrowable wrapper; + + /* allocate local message in Java */ + const char fmt[] = "In AWT JNI, %s (at %s:%d)"; + size_t len = strlen (message) + strlen (file) + sizeof fmt + 25; + char *buf; + + if (EXPLAIN_TROUBLE || (isBroken && EXPLAIN_BROKEN)) + { + criticalMsg ("%s:%d: AWT JNI failure%s: %s\n", file, line, + isBroken ? " (BROKEN)" : "", message); + if (cause) + { + jthrowable currentException = (*env)->ExceptionOccurred (env); + + if (cause == currentException) + { + criticalMsg ("Description follows to System.err:"); + (*env)->ExceptionDescribe (env); + /* ExceptionDescribe has the side-effect of clearing the pending + exception; relaunch it. */ + describedException = TRUE; + + if ((*env)->Throw (env, cause)) + { + BADLY_BROKEN1 + ("Relaunching an exception with Throw failed."); + return -1; + } + } + else + { + DELETE_LOCAL_REF (env, currentException); + criticalMsg (WHERE + "currentException != cause; something else happened" + " while handling an exception."); + } + } + } /* if (EXPLAIN_TROUBLE) */ + + if (isBroken && DIE_IF_BROKEN) + fatalMsg ("%s:%d: Aborting execution; BROKEN: %s\n", file, line, message); + + if ((buf = malloc (len))) + { + memset (buf, 0, len); + snprintf (buf, len, fmt, message, file, line); + jmessage = (*env)->NewStringUTF (env, buf); + free (buf); + } + else + { + jmessage = NULL; + } + + /* Create the RuntimeException wrapper object and throw it. It is OK for + CAUSE to be NULL. */ + wrapper = (jthrowable) (*env)->NewObject + (env, runtimeException_class, runtimeException_ctor, jmessage, cause); + DELETE_LOCAL_REF (env, jmessage); + + if (!wrapper) + { + /* I think this should only happen: + - if there are bugs in my JNI code, or + - if the VM is broken, or + - if we run out of memory. + */ + if (EXPLAIN_TROUBLE) + { + criticalMsg (WHERE "GNU Classpath: JNI NewObject() could not create" + " a new java.lang.RuntimeException."); + criticalMsg ("We were trying to warn about the following" + " previous failure:"); + criticalMsg ("%s:%d: %s", file, line, message); + criticalMsg ("The latest (NewObject()) exception's description" + " follows, to System.err:"); + (*env)->ExceptionDescribe (env); + } + BADLY_BROKEN1 ("Failure of JNI NewObject()" + " to make a java.lang.RuntimeException"); + return -1; + } + + + /* throw it */ + if ((*env)->Throw (env, wrapper)) + { + /* Throw() should just never fail, unless we're in such severe trouble + that we might as well die. */ + BADLY_BROKEN1 + ("GNU Classpath: Failure of JNI Throw to report an Exception"); + return -1; + } + + DELETE_LOCAL_REF (env, wrapper); + return 1; +} + + + +/* Rethrow an exception we received, wrapping it with a RuntimeException. 1 + if we did rethrow, -1 if we had trouble while rethrowing. + CAUSE should be identical to the most recent exception that happened, so + that ExceptionDescribe will work. (Otherwise nix.) */ +static int +rethrow (JNIEnv * env, jthrowable cause, const char *message, + gboolean isBroken, const char *file, int line) +{ + assert (cause); + return throw (env, cause, message, isBroken, file, line); +} + + +/* This function checks for a pending exception, and rethrows it with * a wrapper RuntimeException to deal with possible type problems (in * case some calling piece of code does not expect the exception being * thrown) and to include the given extra message. + * + * Returns 0 if no problems found (so no exception thrown), 1 if we rethrew an + * exception. Returns -1 on failure. */ -static void maybe_rethrow(JNIEnv *gdk_env, char *message, char *file, int line) { - jthrowable cause; +static int +maybe_rethrow (JNIEnv * env, const char *message, gboolean isBroken, + const char *file, int line) +{ + jthrowable cause = (*env)->ExceptionOccurred (env); + int ret = 0; + + /* rethrow if an exception happened */ + if (cause) + { + ret = rethrow (env, cause, message, isBroken, file, line); + DELETE_LOCAL_REF (env, cause); + } + + return 0; +} + +/* MAYBE_TROUBLE() is used to include a source location in the exception + message. Once we have run maybe_rethrow, if there WAS trouble, + return TRUE, else FALSE. + + MAYBE_TROUBLE() is actually never used; all problems that throw exceptions + are BROKEN, at least. Nothing is recoverable :(. See the discussion of + possible errors at thread_create_jni_impl(). */ +#define MAYBE_TROUBLE(_env, _message) \ + maybe_rethrow(_env, _message, FALSE, __FILE__, __LINE__) + +/* MAYBE_TROUBLE(), but something would be BROKEN if it were true. */ +#define MAYBE_BROKEN(_env, _message) \ + maybe_rethrow(_env, _message, TRUE, __FILE__, __LINE__) + +/* Like MAYBE_TROUBLE(), TROUBLE() is never used. */ +#define TROUBLE(_env, _message) \ + rethrow(_env, (*env)->ExceptionOccurred (env), _message, FALSE, \ + __FILE__, __LINE__) + +#define BROKEN(_env, _message) \ + rethrow (_env, (*env)->ExceptionOccurred (env), _message, TRUE, \ + __FILE__, __LINE__) + +/* Like MAYBE_TROUBLE(), NEW_TROUBLE() is never used. */ +#define NEW_TROUBLE(_env, _message) \ + throw (_env, NULL, _message, FALSE, __FILE__, __LINE__) + +#define NEW_BROKEN(_env, _message) \ + throw (_env, NULL, _message, TRUE, __FILE__, __LINE__) + +/* Like MAYBE_TROUBLE(), RETHROW_CAUSE() is never used. */ +#define RETHROW_CAUSE(_env, _cause, _message) \ + rethrow (_env, _cause, _message, FALSE, __FILE__, __LINE__) + +#define BROKEN_CAUSE(_env, _cause, _message) \ + rethrow (_env, _cause, _message, TRUE, __FILE__, __LINE__) + +/* Macros to handle the possibility that someone might have called one of the + GThreadFunctions API functions with a Java exception pending. It is + generally discouraged to continue to use JNI after a Java exception has + been raised. Sun's JNI book advises that one trap JNI errors immediately + and not continue with an exception pending. + + These are #if'd out for these reasons: + + 1) They do not work in the C '89 subset that Classpath is currently + (2004 May 10) sticking to; HIDE_OLD_TROUBLE() includes a declaration + that should be in scope for the rest of the function, so it needs a + language version that lets you mix declarations and statements. (This + could be worked around if it were important.) + + 2) They chew up more time and resources. + + 3) There does not ever seem to be old trouble -- the assertion in + HIDE_OLD_TROUBLE never goes off. + + You will want to re-enable them if this code needs to be used in a context + where old exceptions might be pending when the GThread functions are + called. + + The implementations in this file are responsible for skipping around calls + to SHOW_OLD_TROUBLE() if they've raised exceptions during the call. So, if + we reach SHOW_OLD_TROUBLE, we are guaranteed that there are no exceptions + pending. */ +#if 1 +#define HIDE_OLD_TROUBLE(env) \ + assert ( NULL == (*env)->ExceptionOccurred (env) ) + +#define SHOW_OLD_TROUBLE() \ + assert ( NULL == (*env)->ExceptionOccurred (env) ) +#else /* 0 */ +#define HIDE_OLD_TROUBLE(env) \ + jthrowable savedTrouble = (*env)->ExceptionOccurred (env); \ + (*env)->ExceptionClear (env); + +#define SHOW_OLD_TROUBLE() do \ +{ \ + assert ( NULL == (*env)->ExceptionOccurred (env) ) \ + if (savedTrouble) \ + { \ + if ((*env)->Throw (env, savedTrouble)) \ + BADLY_BROKEN ("ReThrowing the savedTrouble failed"); \ + } \ + DELETE_LOCAL_REF (env, savedTrouble); \ +} while(0) + +#endif /* 0 */ + +/* Set up the cache of jclass and jmethodID primitives we need + in order to throw new exceptions and rethrow exceptions. We do this + independently of the other caching. We need to have this cache set up + first, so that we can then report errors properly. + + If any errors while setting up the error cache, the world is BADLY_BROKEN. + + May be called more than once. + + Returns -1 if the cache was not initialized properly, 1 if it was. +*/ +static int +setup_exception_cache (JNIEnv * env) +{ + static int exception_cache_initialized = 0; /* -1 for trouble, 1 for proper + init. */ + + jclass lcl_class; /* a class used for local refs */ + + if (exception_cache_initialized) + return exception_cache_initialized; + lcl_class = (*env)->FindClass (env, "java/lang/RuntimeException"); + if ( ! lcl_class ) + { + BADLY_BROKEN1 ("Broken Class library or VM?" + " Couldn't find java/lang/RuntimeException"); + return exception_cache_initialized = -1; + } + /* Pin it down. */ + runtimeException_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!runtimeException_class) + { + BADLY_BROKEN1 ("Serious trouble: could not turn" + " java.lang.RuntimeException into a global reference"); + return exception_cache_initialized = -1; + } + + runtimeException_ctor = + (*env)->GetMethodID (env, runtimeException_class, "<init>", + "(Ljava/lang/String;Ljava/lang/Throwable;)V"); + if ( ! runtimeException_ctor ) + { + BADLY_BROKEN1 ("Serious trouble: classpath couldn't find a" + " two-arg constructor for java/lang/RuntimeException"); + return exception_cache_initialized = -1; + } + + return exception_cache_initialized = 1; +} + + +/**********************************************************/ +/***** The main cache *************************************/ +/**********************************************************/ + +/** This is a cache of all classes, methods, and field IDs that we use during + the run. We maintain a permanent global reference to each of the classes + we cache, since otherwise the (local) jclass that refers to that class + would go out of scope and possibly be reused in further calls. + + The permanent global reference also achieves the secondary goal of + protecting the validity of the methods and field IDs in case the classes + were otherwise unloaded and then later loaded again. Obviously, this will + never happen to classes such as java.lang.Thread and java.lang.Object, but + the primary reason for maintaining permanent global refs is sitll valid. + + The code in jnilink.c has a similar objective. TODO: Consider using that + code instead. + + --Steven Augart +*/ + +/* All of these are cached classes and method IDs: */ +/* java.lang.Object */ +static jclass obj_class; /* java.lang.Object */ +static jmethodID obj_ctor; /* no-arg Constructor for java.lang.Object */ +static jmethodID obj_notify_mth; /* java.lang.Object.notify() */ +static jmethodID obj_notifyall_mth; /* java.lang.Object.notifyall() */ +static jmethodID obj_wait_mth; /* java.lang.Object.wait() */ +static jmethodID obj_wait_nanotime_mth; /* java.lang.Object.wait(JI) */ + +/* GThreadMutex and its methods */ +static jclass mutex_class; +static jmethodID mutex_ctor; +static jfieldID mutex_lockForPotentialLockers_fld; +static jfieldID mutex_potentialLockers_fld; + +/* java.lang.Thread and its methods*/ +static jclass thread_class; /* java.lang.Thread */ +static jmethodID thread_current_mth; /* Thread.currentThread() */ +static jmethodID thread_equals_mth; /* Thread.equals() */ +static jmethodID thread_join_mth; /* Thread.join() */ +static jmethodID thread_setPriority_mth; /* Thread.setPriority() */ +static jmethodID thread_stop_mth; /* Thread.stop() */ +static jmethodID thread_yield_mth; /* Thread.yield() */ + +/* java.lang.ThreadLocal and its methods */ +static jclass threadlocal_class; /* java.lang.ThreadLocal */ +static jmethodID threadlocal_ctor; /* Its constructor */ +static jmethodID threadlocal_set_mth; /* ThreadLocal.set() */ +static jmethodID threadlocal_get_mth; /* ThreadLocal.get() */ + +/* java.lang.Long and its methods */ +static jclass long_class; /* java.lang.Long */ +static jmethodID long_ctor; /* constructor for it: (J) */ +static jmethodID long_longValue_mth; /* longValue()J */ + + +/* GThreadNativeMethodRunner */ +static jclass runner_class; +static jmethodID runner_ctor; +static jmethodID runner_threadToThreadID_mth; +static jmethodID runner_threadIDToThread_mth; +static jmethodID runner_deRegisterJoinable_mth; +static jmethodID runner_start_mth; /* Inherited Thread.start() */ + + +/* java.lang.InterruptedException */ +static jclass interrupted_exception_class; + + + + +/* Returns a negative value if there was trouble during initialization. + Returns a positive value of the cache was initialized correctly. + Never returns zero. */ +static int +setup_cache (JNIEnv * env) +{ + jclass lcl_class; + static int initialized = 0; /* 1 means initialized, 0 means uninitialized, + -1 means mis-initialized */ + + if (initialized) + return initialized; + + /* make sure we can report on trouble */ + if (setup_exception_cache (env) < 0) + return initialized = -1; + +#ifdef JNI_VERSION_1_2 + if (HAVE_JNI_VERSION_1_2) + assert ( ! (*env)->ExceptionCheck (env)); + else +#endif + assert ( ! (*env)->ExceptionOccurred (env)); + + /* java.lang.Object and its methods */ + lcl_class = (*env)->FindClass (env, "java/lang/Object"); + if (!lcl_class) + { + BROKEN (env, "cannot find java.lang.Object"); + return initialized = -1; + } + + /* Pin it down. */ + obj_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!obj_class) + { + BROKEN (env, "Cannot get a global reference to java.lang.Object"); + return initialized = -1; + } + + obj_ctor = (*env)->GetMethodID (env, obj_class, "<init>", "()V"); + if (!obj_ctor) + { + BROKEN (env, "cannot find constructor for java.lang.Object"); + return initialized = -1; + } + + obj_notify_mth = (*env)->GetMethodID (env, obj_class, "notify", "()V"); + if ( ! obj_notify_mth ) + { + BROKEN (env, "cannot find java.lang.Object.notify()V"); + return initialized = -1; + } + + obj_notifyall_mth = + (*env)->GetMethodID (env, obj_class, "notifyAll", "()V"); + if ( ! obj_notifyall_mth) + { + BROKEN (env, "cannot find java.lang.Object.notifyall()V"); + return initialized = -1; + } + + obj_wait_mth = (*env)->GetMethodID (env, obj_class, "wait", "()V"); + if ( ! obj_wait_mth ) + { + BROKEN (env, "cannot find Object.<wait()V>"); + return initialized = -1; + } + + obj_wait_nanotime_mth = + (*env)->GetMethodID (env, obj_class, "wait", "(JI)V"); + if ( ! obj_wait_nanotime_mth ) + { + BROKEN (env, "cannot find Object.<wait(JI)V>"); + return initialized = -1; + } + + /* GThreadMutex and its methods */ + lcl_class = (*env)->FindClass (env, "gnu/java/awt/peer/gtk/GThreadMutex"); + if ( ! lcl_class) + { + BROKEN (env, "cannot find gnu.java.awt.peer.gtk.GThreadMutex"); + return initialized = -1; + } + /* Pin it down. */ + mutex_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if ( ! mutex_class) + { + BROKEN (env, "Cannot get a global reference to GThreadMutex"); + return initialized = -1; + } + + mutex_ctor = (*env)->GetMethodID (env, mutex_class, "<init>", "()V"); + if ( ! mutex_ctor) + { + BROKEN (env, "cannot find zero-arg constructor for GThreadMutex"); + return initialized = -1; + } + + mutex_potentialLockers_fld = (*env)->GetFieldID + (env, mutex_class, "potentialLockers", "I"); + if ( ! mutex_class ) + { + BROKEN (env, "cannot find GThreadMutex.potentialLockers"); + return initialized = -1; + } + + if (! (mutex_lockForPotentialLockers_fld = (*env)->GetFieldID + (env, mutex_class, "lockForPotentialLockers", "Ljava/lang/Object;"))) + { + BROKEN (env, "cannot find GThreadMutex.lockForPotentialLockers"); + return initialized = -1; + } + + + /* java.lang.Thread */ + if (! (lcl_class = (*env)->FindClass (env, "java/lang/Thread"))) + { + BROKEN (env, "cannot find java.lang.Thread"); + return initialized = -1; + } + + /* Pin it down. */ + thread_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!thread_class) + { + BROKEN (env, "Cannot get a global reference to java.lang.Thread"); + return initialized = -1; + } + + thread_current_mth = + (*env)->GetStaticMethodID (env, thread_class, "currentThread", + "()Ljava/lang/Thread;"); + if (!thread_current_mth) + { + BROKEN (env, "cannot find Thread.currentThread() method"); + return initialized = -1; + } + + thread_equals_mth = + (*env)->GetMethodID (env, thread_class, "equals", "(Ljava/lang/Object;)Z"); + if (!thread_equals_mth) + { + BROKEN (env, "cannot find Thread.equals() method"); + return initialized = -1; + } + + thread_join_mth = (*env)->GetMethodID (env, thread_class, "join", "()V"); + if (!thread_join_mth) + { + BROKEN (env, "cannot find Thread.join() method"); + return initialized = -1; + } + + thread_stop_mth = (*env)->GetMethodID (env, thread_class, "stop", "()V"); + if ( ! thread_stop_mth ) + { + BROKEN (env, "cannot find Thread.stop() method"); + return initialized = -1; + } + + thread_setPriority_mth = + (*env)->GetMethodID (env, thread_class, "setPriority", "(I)V"); + if ( ! thread_setPriority_mth ) + { + BROKEN (env, "cannot find Thread.setPriority() method"); + return initialized = -1; + } + + thread_yield_mth = + (*env)->GetStaticMethodID (env, thread_class, "yield", "()V"); + if ( ! thread_yield_mth ) + { + BROKEN (env, "cannot find Thread.yield() method"); + return initialized = -1; + } + + /* java.lang.ThreadLocal */ + lcl_class = (*env)->FindClass (env, "java/lang/ThreadLocal"); + if ( ! lcl_class ) + { + BROKEN (env, "cannot find class java.lang.ThreadLocal"); + return initialized = -1; + } + + /* Pin it down. */ + threadlocal_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if ( ! threadlocal_class ) + { + BROKEN (env, "Cannot get a global reference to java.lang.ThreadLocal"); + return initialized = -1; + } + + threadlocal_ctor = (*env)->GetMethodID (env, threadlocal_class, + "<init>", "()V"); + if ( ! threadlocal_ctor ) + { + BROKEN (env, "cannot find ThreadLocal.<init>()V"); + return initialized = -1; + } + + threadlocal_get_mth = (*env)->GetMethodID (env, threadlocal_class, + "get", "()Ljava/lang/Object;"); + if ( ! threadlocal_get_mth ) + { + BROKEN (env, "cannot find java.lang.ThreadLocal.get()Object"); + return initialized = -1; + } + + threadlocal_set_mth = (*env)->GetMethodID (env, threadlocal_class, + "set", "(Ljava/lang/Object;)V"); + if ( ! threadlocal_set_mth ) + { + BROKEN (env, "cannot find ThreadLocal.set(Object)V"); + return initialized = -1; + } + + /* java.lang.Long */ + lcl_class = (*env)->FindClass (env, "java/lang/Long"); + if ( ! lcl_class ) + { + BROKEN (env, "cannot find class java.lang.Long"); + return initialized = -1; + } + + /* Pin it down. */ + long_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!long_class) + { + BROKEN (env, "Cannot get a global reference to java.lang.Long"); + return initialized = -1; + } + + long_ctor = (*env)->GetMethodID (env, long_class, "<init>", "(J)V"); + if (!long_ctor) + { + BROKEN (env, "cannot find method java.lang.Long.<init>(J)V"); + return initialized = -1; + } + + long_longValue_mth = + (*env)->GetMethodID (env, long_class, "longValue", "()J"); + if (!long_longValue_mth) + { + BROKEN (env, "cannot find method java.lang.Long.longValue()J"); + return initialized = -1; + } + + + /* GThreadNativeMethodRunner */ + lcl_class = + (*env)->FindClass (env, + "gnu/java/awt/peer/gtk/GThreadNativeMethodRunner"); + if ( ! lcl_class ) + { + BROKEN (env, + "cannot find gnu.java.awt.peer.gtk.GThreadNativeMethodRunner"); + return initialized = -1; + } + + /* Pin it down. */ + runner_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!runner_class) + { + BROKEN (env, + "Cannot get a global reference to the class GThreadNativeMethodRunner"); + return initialized = -1; + } + + runner_ctor = (*env)->GetMethodID (env, runner_class, "<init>", "(JJZ)V"); + if ( ! runner_ctor ) + { + BROKEN (env, + "cannot find method GThreadNativeMethodRunner.<init>(JJZ)"); + return initialized = -1; + } + + runner_start_mth = (*env)->GetMethodID (env, runner_class, "start", "()V"); + if ( ! runner_start_mth ) + { + BROKEN (env, "cannot find method GThreadNativeMethodRunner.start()V"); + return initialized = -1; + } + + + runner_threadToThreadID_mth = + (*env)->GetStaticMethodID (env, runner_class, + "threadToThreadID", "(Ljava/lang/Thread;)I"); + if ( ! runner_threadToThreadID_mth ) + { + BROKEN (env, + "cannot find method GThreadNativeMethodRunner.threadToThreadID(java.lang.Thread)I"); + return initialized = -1; + } + + + runner_threadIDToThread_mth = + (*env)->GetStaticMethodID (env, runner_class, + "threadIDToThread", "(I)Ljava/lang/Thread;"); + if ( ! runner_threadIDToThread_mth ) + { + BROKEN (env, + "cannot find method GThreadNativeMethodRunner.threadIDToThread(I)java.lang.Thread"); + return initialized = -1; + } + + + runner_deRegisterJoinable_mth = + (*env)->GetStaticMethodID (env, runner_class, "deRegisterJoinable", + "(Ljava/lang/Thread;)V"); + if (!runner_deRegisterJoinable_mth) + { + BROKEN (env, + "cannot find method GThreadNativeMethodRunner.deRegisterJoinable(java.lang.Thread)V"); + return initialized = -1; + } + + + /* java.lang.InterruptedException */ + lcl_class = (*env)->FindClass (env, "java/lang/InterruptedException"); + if ( ! lcl_class ) + { + BROKEN (env, "cannot find class java.lang.InterruptedException"); + return initialized = -1; + } + + /* Pin it down. */ + interrupted_exception_class = (jclass) (*env)->NewGlobalRef (env, lcl_class); + DELETE_LOCAL_REF (env, lcl_class); + if (!interrupted_exception_class) + { + BROKEN (env, "Cannot make a global reference" + " to java.lang.InterruptedException"); + return initialized = -1; + } + +#ifdef JNI_VERSION_1_2 + if (HAVE_JNI_VERSION_1_2) + assert ( ! (*env)->ExceptionCheck (env)); + else +#endif + assert ( ! (*env)->ExceptionOccurred (env)); + + + return initialized = 1; +} + + - jstring jmessage; - jclass obj_class; - jobject obj; - jmethodID ctor; - int len; - char *buf; - - /* rethrow if an exception happened */ - if ((cause = (*gdk_env)->ExceptionOccurred(gdk_env)) != NULL) - { - - /* allocate local message in Java */ - len = strlen(message) + strlen(file) + 25; - buf = (char *) malloc(len); - if (buf != NULL) - { - bzero(buf, len); - sprintf(buf, "%s (at %s:%d)", message, file, line); - jmessage = (*gdk_env)->NewStringUTF(gdk_env, buf); - free(buf); - } - else - jmessage = NULL; - - /* create RuntimeException wrapper object */ - obj_class = (*gdk_env)->FindClass (gdk_env, - "java/lang/RuntimeException"); - ctor = (*gdk_env)->GetMethodID(gdk_env, obj_class, "<init>", - "(Ljava/langString;Ljava/lang/Throwable)V"); - obj = (*gdk_env)->NewObject (gdk_env, obj_class, ctor, jmessage, cause); - - /* throw it */ - (*gdk_env)->Throw(gdk_env, (jthrowable)obj); - } -} - -/* This macro is used to include a source location in the exception message */ -#define MAYBE_RETHROW(_class, _message) \ -maybe_rethrow(_class, _message, __FILE__, __LINE__) /************************************************************************/ /* Utilities to allocate and free java.lang.Objects */ /************************************************************************/ -/* Both the mutexes and the condition variables are java.lang.Object objects, +/* The condition variables are java.lang.Object objects, * which this method allocates and returns a global ref. Note that global * refs must be explicitly freed (isn't C fun?). */ -static jobject *allocatePlainObject() { - jclass obj_class; - jobject *obj; - JNIEnv *gdk_env; - jmethodID ctor; - - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); +static jobject +allocatePlainObject (JNIEnv * env) +{ + jobject lcl_obj, global_obj; - obj_class = (*gdk_env)->FindClass (gdk_env, "java/lang/Object"); - MAYBE_RETHROW(gdk_env, "cannot find Object"); + lcl_obj = (*env)->NewObject (env, obj_class, obj_ctor); + if (!lcl_obj) + { + BROKEN (env, "cannot allocate object"); + return NULL; + } - ctor = (*gdk_env)->GetMethodID(gdk_env, obj_class, "<init>", "()V"); - MAYBE_RETHROW(gdk_env, "cannot find constructor"); + global_obj = (*env)->NewGlobalRef (env, lcl_obj); + DELETE_LOCAL_REF (env, lcl_obj); + if (!global_obj) + { + NEW_BROKEN (env, "cannot make global ref for a new plain Java object"); + /* Deliberate fall-through */ + } - obj = (jobject *) g_malloc (sizeof (jobject)); - *obj = (*gdk_env)->NewObject (gdk_env, obj_class, ctor); - MAYBE_RETHROW(gdk_env, "cannot allocate object"); - - *obj = (*gdk_env)->NewGlobalRef (gdk_env, *obj); - MAYBE_RETHROW(gdk_env, "cannot make global ref"); + return global_obj; +} - return obj; +/* Frees any Java object given a global ref (isn't C fun?) */ +static void +freeObject (JNIEnv * env, jobject obj) +{ + if (obj) + { + (*env)->DeleteGlobalRef (env, obj); + /* DeleteGlobalRef can never fail */ + } } -/* Frees a Java object given a global ref (isn't C fun?) */ -static void freePlainObject(jobject *obj) { - JNIEnv *gdk_env; - if (obj) { - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); +/************************************************************************/ +/* Utilities to allocate and free Java mutexes */ +/************************************************************************/ - (*gdk_env)->DeleteGlobalRef (gdk_env, *obj); - MAYBE_RETHROW(gdk_env, "cannot delete global ref"); - - g_free (obj); - } +/* The mutexes are gnu.java.awt.peer.gtk.GThreadMutex objects, + * which this method allocates and returns a global ref. Note that global + * refs must be explicitly freed (isn't C fun?). + * + * Free this with freeObject() + */ +static jobject +allocateMutexObject (JNIEnv * env) +{ + jobject lcl_obj, global_obj; + + lcl_obj = (*env)->NewObject (env, mutex_class, mutex_ctor); + if (!lcl_obj) + { + BROKEN (env, "cannot allocate a GThreadMutex"); + return NULL; + } + + global_obj = (*env)->NewGlobalRef (env, lcl_obj); + DELETE_LOCAL_REF (env, lcl_obj); + if (!global_obj) + { + NEW_BROKEN (env, "cannot make global ref"); + /* Deliberate fallthrough */ + } + + return global_obj; } @@ -184,195 +1208,746 @@ static void freePlainObject(jobject *obj) { /************************************************************************/ /* Lock a Java object */ -static void takeLock(JNIEnv *gdk_env, void *mutex) { - (*gdk_env)->MonitorEnter (gdk_env, *((jobject *)mutex)); - MAYBE_RETHROW(gdk_env, "cannot get lock"); +#define ENTER_MONITOR(env, m) \ + enterMonitor(env, m, G_STRINGIFY(m)) + +/* Return -1 on failure, 0 on success. */ +static int +enterMonitor (JNIEnv * env, jobject monitorObj, const char monName[]) +{ + if (TRACE_MONITORS) + tracing (" <MonitorEnter(%s)>", monName); + assert (monitorObj); + if ((*env)->MonitorEnter (env, monitorObj) < 0) + { + BROKEN (env, "cannot enter monitor"); + return -1; + } + return 0; } + /* Unlock a Java object */ -static void releaseLock(JNIEnv *gdk_env, void *mutex) { - (*gdk_env)->MonitorExit (gdk_env, *((jobject *)mutex)); - MAYBE_RETHROW(gdk_env, "cannot release lock"); +#define EXIT_MONITOR(env, m) \ + exitMonitor(env, m, G_STRINGIFY(m)) + +static int +exitMonitor (JNIEnv * env, jobject mutexObj, const char monName[]) +{ + if (TRACE_MONITORS) + tracing (" <MonitorExit(%s)>", monName); + assert (mutexObj); + if ((*env)->MonitorExit (env, mutexObj) < 0) + { + BROKEN (env, "cannot exit monitor "); + return -1; + } + return 0; } -/* Create a mutex, which is a java.lang.Object for us */ -static GMutex *g_mutex_new_jni_impl (void) { - return (GMutex*) allocatePlainObject(); + +/************************************************************************/ +/* Miscellaneous utilities */ +/************************************************************************/ + +/* Get the Java Thread object that corresponds to a particular thread ID. + A negative thread Id gives us a null object. + + Returns a local reference. +*/ +static jobject +getThreadFromThreadID (JNIEnv * env, gpointer gThreadID) +{ + jint threadNum = (jint) gThreadID; + jobject thread; + + if (threadNum < 0) + { + NEW_BROKEN (env, "getThreadFromThreadID asked to look up" + " a negative thread index"); + return NULL; + } + + thread = (*env)->CallStaticObjectMethod + (env, runner_class, runner_threadIDToThread_mth, threadNum); + + if (MAYBE_BROKEN (env, "cannot get Thread for threadID ")) + return NULL; + + return thread; +} + +/** Return the unique threadID of THREAD. + + Error handling: Return (gpointer) -1 on all failures, + and propagate an exception. +*/ +static gpointer +getThreadIDFromThread (JNIEnv * env, jobject thread) +{ + jint threadNum; + + if (ENABLE_EXPENSIVE_ASSERTIONS) + assert ((*env)->IsInstanceOf (env, thread, thread_class)); + + HIDE_OLD_TROUBLE (env); + + threadNum = (*env)->CallStaticIntMethod + (env, runner_class, runner_threadToThreadID_mth, thread); + + if (MAYBE_BROKEN (env, "cannot get ThreadID for a Thread ")) + { + threadNum = -1; + goto done; + } + + + SHOW_OLD_TROUBLE (); + +done: + return (gpointer) threadNum; +} + + +/************************************************************************/ +/* The Actual JNI functions that we pass to the function vector. */ +/************************************************************************/ + + +/************************************************************************/ +/* Mutex Functions */ +/************************************************************************/ + +/*** Mutex Utilities ****/ +struct mutexObj_cache +{ + jobject lockForPotentialLockersObj; /* Lock for the potentialLockers + field. Local reference. */ + jobject lockObj; /* The real lock we use. This is a GLOBAL + reference and must not be freed. */ +}; + +/* Initialize the cache of sub-locks for a particular mutex object. + + -1 on error, 0 on success. The caller is not responsible for freeing the + partially-populated cache in case of failure (but in practice does anyway) + (This actually never fails, though, since GetObjectField allegedly never + fails.) + + Guaranteed to leave all fields of the cache initialized, even if only to + zero. +*/ +static int +populate_mutexObj_cache (JNIEnv * env, jobject mutexObj, + struct mutexObj_cache *mcache) +{ + mcache->lockObj = mutexObj; /* the mutexObj is its own lock. */ + assert (mcache->lockObj); + + mcache->lockForPotentialLockersObj = (*env)->GetObjectField + (env, mutexObj, mutex_lockForPotentialLockers_fld); + /* GetObjectField can never fail. */ + + /* Retrieving a NULL object could only happen if we somehow got a + a mutex object that was not properly intialized. */ + assert (mcache->lockForPotentialLockersObj); + + return 0; +} + + +/* Clean out the mutexObj_cache, even if it was never populated. */ +static void +clean_mutexObj_cache (JNIEnv * env, struct mutexObj_cache *mcache) +{ + /* OK to pass NULL refs to DELETE_LOCAL_REF */ + DELETE_LOCAL_REF (env, mcache->lockForPotentialLockersObj); + /* mcache->lockObj is a GLOBAL reference. */ + mcache->lockObj = NULL; +} + +/* -1 on failure, 0 on success. + The mutexObj_cache is already populated for this particular object. */ +static int +mutexObj_lock (JNIEnv * env, jobject mutexObj, struct mutexObj_cache *mcache) +{ + jint potentialLockers; + + if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj)) + return -1; + + assert(mutexObj); + potentialLockers = + (*env)->GetIntField (env, mutexObj, mutex_potentialLockers_fld); + /* GetIntField() never fails. */ + + ++potentialLockers; + + (*env)->SetIntField + (env, mutexObj, mutex_potentialLockers_fld, potentialLockers); + + if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj)) + return -1; + + if (ENTER_MONITOR (env, mcache->lockObj)) + return -1; + + SHOW_OLD_TROUBLE (); + + return 0; +} + +/* Unlock a GMutex, once we're already in JNI and have already gotten the + mutexObj for it. This skips the messages that TRACE_API_CALLS would + print. + + Returns -1 on error, 0 on success. */ +static int +mutexObj_unlock (JNIEnv * env, jobject mutexObj, + struct mutexObj_cache *mcache) +{ + jint potentialLockers; + int ret = -1; /* assume failure until we suceed. */ + + /* Free the lock first, so that someone waiting for the lock can get it + ASAP. */ + /* This is guaranteed not to block. */ + if (EXIT_MONITOR (env, mcache->lockObj) < 0) + goto done; + + /* Kick down potentialLockers by one. We do this AFTER we free the lock, so + that we hold it no longer than necessary. */ + if (ENTER_MONITOR (env, mcache->lockForPotentialLockersObj) < 0) + goto done; + + potentialLockers = (*env)->GetIntField + (env, mutexObj, mutex_potentialLockers_fld); + /* GetIntField never fails */ + + assert (potentialLockers >= 1); + --potentialLockers; + + (*env)->SetIntField + (env, mutexObj, mutex_potentialLockers_fld, potentialLockers); + /* Never fails, so the JNI book says. */ + + /* Clean up. */ + if (EXIT_MONITOR (env, mcache->lockForPotentialLockersObj) < 0) + goto done; + ret = 0; + +done: + return ret; +} + +/*** Mutex Implementations ****/ + +/* Create a mutex, which is a java.lang.Object for us. + In case of failure, we'll return NULL. Which will implicitly + cause future calls to fail. */ +static GMutex * +mutex_new_jni_impl (void) +{ + jobject mutexObj; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("mutex_new_jni_impl()"); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + + if (setup_cache (env) < 0) + { + mutexObj = NULL; + goto done; + } + + mutexObj = allocateMutexObject (env); + +done: + if (TRACE_API_CALLS) + tracing (" ==> %p \n", mutexObj); + + return (GMutex *) mutexObj; + } /* Lock a mutex. */ -static void g_mutex_lock_jni_impl (GMutex *mutex __attribute__((unused))) { - JNIEnv *gdk_env; +static void +mutex_lock_jni_impl (GMutex * mutex) +{ + struct mutexObj_cache mcache; + jobject mutexObj = (jobject) mutex; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("mutex_lock_jni_impl( mutexObj = %p )", mutexObj); + + assert (mutexObj); + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + + if (setup_cache (env) < 0) + goto done; - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); + HIDE_OLD_TROUBLE (env); - takeLock(gdk_env, mutex); + if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0) + goto done; + + mutexObj_lock (env, mutexObj, &mcache); + /* No need to error check; we've already reported it in any case. */ + +done: + clean_mutexObj_cache (env, &mcache); + if (TRACE_API_CALLS) + tracing (" ==> VOID \n"); } -/* Try to lock a mutex. Actually, do not try because Java objects - * do not provide such an interface. To be at least minimally correct, - * pretend we tried and failed. - */ -static gboolean g_mutex_trylock_jni_impl - (GMutex *mutex __attribute__((unused))) + +/* Try to lock a mutex. Return TRUE if we succeed, FALSE if we fail. + FALSE on error. */ +static gboolean +mutex_trylock_jni_impl (GMutex * gmutex) { - /* XXX Shall we implement this in a VM-specific way under a flag? */ - return FALSE; + jobject mutexObj = (jobject) gmutex; + jint potentialLockers; + gboolean ret = FALSE; + JNIEnv *env; + union env_union e; + struct mutexObj_cache mcache; + + if (TRACE_API_CALLS) + tracing ("mutex_trylock_jni_impl(mutexObj=%p)", mutexObj); + + assert (mutexObj); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + if (populate_mutexObj_cache (env, mutexObj, &mcache) < 0) + goto done; + + if (ENTER_MONITOR (env, mcache.lockForPotentialLockersObj)) + goto done; + + potentialLockers = (*env)->GetIntField + (env, mutexObj, mutex_potentialLockers_fld); + + assert (potentialLockers >= 0); + + if (potentialLockers) + { + /* Already locked. Clean up and leave. */ + EXIT_MONITOR (env, mcache.lockForPotentialLockersObj); + /* Ignore any error code from EXIT_MONITOR; there's nothing we could do + at this level, in any case. */ + goto done; + } + + /* Guaranteed not to block. */ + if (ENTER_MONITOR (env, mcache.lockObj)) + { + /* Clean up the existing lock. */ + EXIT_MONITOR (env, mcache.lockForPotentialLockersObj); + /* Ignore any error code from EXIT_MONITOR; there's nothing we could do + at this level, in any case. */ + goto done; + } + + + /* We have the monitor. Record that fact. */ + potentialLockers = 1; + (*env)->SetIntField + (env, mutexObj, mutex_potentialLockers_fld, potentialLockers); + /* Set*Field() never fails */ + + ret = TRUE; /* We have the lock. */ + + /* Clean up. */ + if (EXIT_MONITOR (env, mcache.lockForPotentialLockersObj)) + goto done; /* If we fail at this point, still keep the + main lock. */ + + SHOW_OLD_TROUBLE (); +done: + clean_mutexObj_cache (env, &mcache); + if (TRACE_API_CALLS) + tracing (" ==> %s\n", ret ? "TRUE" : "FALSE"); + return ret; } + /* Unlock a mutex. */ -static void g_mutex_unlock_jni_impl (GMutex *mutex) { - JNIEnv *gdk_env; +static void +mutex_unlock_jni_impl (GMutex * gmutex) +{ + jobject mutexObj = (jobject) gmutex; + struct mutexObj_cache mcache; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("mutex_unlock_jni_impl(mutexObj=%p)", mutexObj); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); + assert (mutexObj); - releaseLock(gdk_env, mutex); + if ( populate_mutexObj_cache (env, mutexObj, &mcache) < 0) + goto done; + + (void) mutexObj_unlock (env, mutexObj, &mcache); + + SHOW_OLD_TROUBLE (); + +done: + clean_mutexObj_cache (env, &mcache); + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); } -/* Free a mutex (isn't C fun?) */ -static void g_mutex_free_jni_impl (GMutex *mutex) + + +/* Free a mutex (isn't C fun?). OK this time for it to be NULL. + No failure conditions, for a change. */ +static void +mutex_free_jni_impl (GMutex * mutex) { - freePlainObject( (jobject*)mutex ); + jobject mutexObj = (jobject) mutex; + JNIEnv *env; + union env_union e; + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + + if (TRACE_API_CALLS) + tracing ("mutex_free_jni_impl(%p)", mutexObj); + + freeObject (env, mutexObj); + + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); } + + /************************************************************************/ /* Condition variable code */ /************************************************************************/ /* Create a new condition variable. This is a java.lang.Object for us. */ -static GCond *g_cond_new_jni_impl () { - return (GCond*)allocatePlainObject(); +static GCond * +cond_new_jni_impl (void) +{ + jobject condObj; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("mutex_free_jni_impl()"); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + + condObj = allocatePlainObject (env); + + if (TRACE_API_CALLS) + tracing (" ==> %p\n", condObj); + + return (GCond *) condObj; } /* Signal on a condition variable. This is simply calling Object.notify * for us. */ -static void g_cond_signal_jni_impl (GCond *cond) { - jclass lcl_class; - jmethodID signal_mth; - JNIEnv *gdk_env; +static void +cond_signal_jni_impl (GCond * gcond) +{ + JNIEnv *env; + union env_union e; + jobject condObj = (jobject) gcond; - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); + if (TRACE_API_CALLS) + tracing ("cond_signal_jni_impl(condObj = %p)", condObj); - lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object"); - MAYBE_RETHROW(gdk_env, "cannot find Object"); - - signal_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "notify", "()V"); - MAYBE_RETHROW(gdk_env, "cannot find Object.<notify>"); + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + assert (condObj); /* Must have locked an object to call notify */ - takeLock(gdk_env, cond); + if (ENTER_MONITOR (env, condObj)) + goto done; + + (*env)->CallVoidMethod (env, condObj, obj_notify_mth); + if (MAYBE_BROKEN (env, "cannot signal mutex with Object.notify()")) + { + if (EXIT_MONITOR (env, condObj)) + BADLY_BROKEN1 ("Failed to unlock a monitor; the VM may deadlock."); + goto done; + } - (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, signal_mth); - MAYBE_RETHROW(gdk_env, "cannot signal mutex"); + EXIT_MONITOR (env, condObj); - releaseLock(gdk_env, cond); + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); } /* Broadcast to all waiting on a condition variable. This is simply * calling Object.notifyAll for us. */ -static void g_cond_broadcast_jni_impl (GCond *cond) { - jclass lcl_class; - jmethodID bcast_mth; - JNIEnv *gdk_env; +static void +cond_broadcast_jni_impl (GCond * gcond) +{ + jobject condObj = (jobject) gcond; + JNIEnv *env; + union env_union e; - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); + if (TRACE_API_CALLS) + tracing ("cond_broadcast_jni_impl(condObj=%p)", condObj); - lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object"); - MAYBE_RETHROW(gdk_env, "cannot find Object"); - - bcast_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "notifyAll", "()V"); - MAYBE_RETHROW(gdk_env, "cannot find Object.<notifyAll>"); + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + assert (condObj); /* Must have locked an object to call notifyAll */ - takeLock(gdk_env, cond); + if (ENTER_MONITOR (env, condObj)) + goto done; + + (*env)->CallVoidMethod (env, condObj, obj_notifyall_mth); + if (MAYBE_BROKEN (env, "cannot broadcast to mutex with Object.notify()")) + { + EXIT_MONITOR (env, condObj); + goto done; + } - (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, bcast_mth); - MAYBE_RETHROW(gdk_env, "cannot broadcast to mutex"); + EXIT_MONITOR (env, condObj); - releaseLock(gdk_env, cond); + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); } -/* Wait on a condition variable. For us, this simply means call +/* Wait on a condition variable. For us, this simply means calling * Object.wait. + * + * Throws a Java exception on trouble; may leave the mutexes set arbitrarily. + * XXX TODO: Further improve error recovery. */ -static void g_cond_wait_jni_impl - (GCond *cond, GMutex *mutex __attribute__((unused))) +static void +cond_wait_jni_impl (GCond * gcond, GMutex * gmutex) { - jclass lcl_class; - jmethodID wait_mth; - JNIEnv *gdk_env; + struct mutexObj_cache cache; + jobject condObj = (jobject) gcond; + jobject mutexObj = (jobject) gmutex; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("cond_wait_jni_impl(condObj=%p, mutexObj=%p)", + condObj, mutexObj); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + assert (condObj); + assert (mutexObj); + /* Must have locked a Java object to call wait on it */ + if (ENTER_MONITOR (env, condObj) < 0) + goto done; + + /* Our atomicity is now guaranteed; we're protected by the Java monitor on + condObj. Unlock the GMutex. */ + if (mutexObj_unlock (env, mutexObj, &cache)) + goto done; + + (*env)->CallVoidMethod (env, condObj, obj_wait_mth); + if (MAYBE_BROKEN (env, "cannot wait on condObj")) + { + EXIT_MONITOR (env, condObj); /* ignore err checking */ + goto done; + } - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); + /* Re-acquire the lock on the GMutex. Do this while we're protected by the + Java monitor on condObj. */ + if (mutexObj_lock (env, mutexObj, &cache)) + goto done; - lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object"); - MAYBE_RETHROW(gdk_env, "cannot find Object"); - - wait_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "wait", "()V"); - MAYBE_RETHROW(gdk_env, "cannot find Object.<wait>"); + EXIT_MONITOR (env, condObj); - /* Must have locked an object to call wait */ - takeLock(gdk_env, cond); + SHOW_OLD_TROUBLE (); - (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, wait_mth); - MAYBE_RETHROW(gdk_env, "cannot wait on mutex"); - - releaseLock(gdk_env, cond); +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); } -/* Wait on a condition vairable until a timeout. This is a little tricky + +/** Wait on a condition variable until a timeout. This is a little tricky * for us. We first call Object.wait(J) giving it the appropriate timeout * value. On return, we check whether an InterruptedException happened. If - * so, that is Java-speak for wait timing out. + * so, that is Java-speak for wait timing out. + * + * We return FALSE if we timed out. Return TRUE if the condition was + * signalled first, before we timed out. + * + * In case of trouble we throw a Java exception. Whether we return FALSE or + * TRUE depends upon whether the condition was raised before the trouble + * happened. + * + * I believe that this function goes to the proper lengths to try to unlock + * all of the locked mutexes and monitors, as appropriate, and that it further + * tries to make sure that the thrown exception is the current one, not any + * future cascaded one from something like a failure to unlock the monitors. */ static gboolean -g_cond_timed_wait_jni_impl - (GCond *cond, GMutex *mutex __attribute__((unused)), - GTimeVal *end_time) +cond_timed_wait_jni_impl (GCond * gcond, GMutex * gmutex, GTimeVal * end_time) { - jclass lcl_class; - jmethodID wait_mth; - JNIEnv *gdk_env; - jlong time; + JNIEnv *env; + union env_union e; + jlong time_millisec; + jint time_nanosec; jthrowable cause; + jobject condObj = (jobject) gcond; + jobject mutexObj = (jobject) gmutex; + gboolean condRaised = FALSE; /* Condition has not been raised yet. */ + struct mutexObj_cache cache; + gboolean interrupted; + + if (TRACE_API_CALLS) + { + tracing ("cond_timed_wait_jni_impl(cond=%p, mutex=%p," + " end_time=< sec=%lu, usec=%lu >)", condObj, mutexObj, + (unsigned long) end_time->tv_sec, + (unsigned long) end_time->tv_usec); + } - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); - lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Object"); - MAYBE_RETHROW(gdk_env, "cannot find Object"); - - wait_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "wait", "(J)V"); - MAYBE_RETHROW(gdk_env, "cannot find Object.<wait(J)>"); - - time = end_time->tv_sec*1000; - time += end_time->tv_usec/1000; + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + time_millisec = end_time->tv_sec * 1000 + end_time->tv_usec / 1000; + time_nanosec = 1000 * (end_time->tv_usec % 1000); /* Must have locked an object to call wait */ - takeLock(gdk_env, cond); + if (ENTER_MONITOR (env, condObj) < 0) + goto done; + + if (mutexObj_unlock (env, mutexObj, &cache) < 0) + { + if (EXIT_MONITOR (env, condObj) < 0) + criticalMsg + ("Unable to unlock an existing lock on a condition; your proram may deadlock"); + goto done; + } + + + (*env)->CallVoidMethod (env, condObj, obj_wait_nanotime_mth, + time_millisec, time_nanosec); + + /* If there was trouble, save that fact, and the reason for the trouble. We + want to respond to this condition as fast as possible. */ + cause = (*env)->ExceptionOccurred (env); + + if ( ! cause ) + { + condRaised = TRUE; /* condition was signalled */ + } + else if ((*env)->IsInstanceOf (env, cause, interrupted_exception_class)) + { + condRaised = FALSE; /* Condition was not raised before timeout. + (This is redundant with the initialization + of condRaised above) */ + (*env)->ExceptionClear (env); /* Clear the InterruptedException. */ + cause = NULL; /* no pending cause now. */ + } + else + { + interrupted = FALSE; /* Trouble, but not because of + InterruptedException. Assume the condition + was not raised. */ + /* Leave condRaised set to FALSE */ + } - (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)cond, wait_mth, time); + /* Irrespective of whether there is a pending problem to report, go ahead + and try to clean up. This may end up throwing an exception that is + different from the one that was thrown by the call to Object.wait(). + So we will override it with the first exception (don't want to have + cascading problems). */ + if (mutexObj_lock (env, mutexObj, &cache) && !cause) + { + cause = (*env)->ExceptionOccurred (env); + assert (cause); + } - if ((cause = (*gdk_env)->ExceptionOccurred(gdk_env)) != NULL) { - jclass intr = (*gdk_env)->FindClass (gdk_env, "java.lang.InterruptedException"); - if ( (*gdk_env)->IsInstanceOf(gdk_env, cause, intr) ) { - releaseLock(gdk_env, cond); - return FALSE; - } else { - MAYBE_RETHROW(gdk_env, "error in timed wait"); + if (EXIT_MONITOR (env, condObj) && !cause) + { + cause = (*env)->ExceptionOccurred (env); + assert (cause); } - } - releaseLock(gdk_env, cond); + if (cause) /* Raise the first cause. */ + { + BROKEN_CAUSE (env, cause, "error in timed wait or during its cleanup"); + goto done; + } + + SHOW_OLD_TROUBLE (); - return TRUE; +done: + if (TRACE_API_CALLS) + tracing (" ==> condRaised = %s\n", condRaised ? "TRUE" : "FALSE"); + return condRaised; } -/* Free a condition variable. (isn't C fun?) */ -static void g_cond_free_jni_impl (GCond *cond) { - freePlainObject( (jobject*)cond ); + +/* Free a condition variable. (isn't C fun?). Can not fail. */ +static void +cond_free_jni_impl (GCond * cond) +{ + jobject condObj = (jobject) cond; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("cond_free_jni_impl(condObj = %p)", condObj); + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + + freeObject (env, condObj); + + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); } @@ -380,128 +1955,638 @@ static void g_cond_free_jni_impl (GCond *cond) { /* Thread-local data code */ /************************************************************************/ -/* Create a new thread-local key. We use java.lang.ThreadLocal objects - * for this. +/* Create a new thread-local key. We use java.lang.ThreadLocal objects + * for this. This returns the pointer representation of a Java global + * reference. + * + * We will throw a Java exception and return NULL in case of failure. */ -static GPrivate *g_private_new_jni_impl - (GDestroyNotify notify __attribute__((unused))) +static GPrivate * +private_new_jni_impl (GDestroyNotify notify __attribute__ ((unused))) { - jclass lcl_class; - jobject *local; - JNIEnv *gdk_env; - jmethodID ctor; + JNIEnv *env; + union env_union e; + jobject lcl_key; + jobject global_key; + GPrivate *gkey = NULL; /* Error return code */ + + if (TRACE_API_CALLS) + tracing ("private_new_jni_impl()"); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + lcl_key = (*env)->NewObject (env, threadlocal_class, threadlocal_ctor); + if ( ! lcl_key ) + { + BROKEN (env, "cannot allocate a ThreadLocal"); + goto done; + } - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); + global_key = ((*env)->NewGlobalRef (env, lcl_key)); + DELETE_LOCAL_REF (env, lcl_key); + if ( ! global_key) + { + NEW_BROKEN (env, "cannot create a GlobalRef to a new ThreadLocal"); + goto done; + } - lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.ThreadLocal"); - MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal"); + gkey = (GPrivate *) global_key; + SHOW_OLD_TROUBLE (); - ctor = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "<init>", "()V"); - MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal.<init>"); +done: + if (TRACE_API_CALLS) + tracing (" ==> %p\n", (void *) gkey); - local = (jobject *) g_malloc (sizeof (jobject)); - *local = (*gdk_env)->NewObject(gdk_env, lcl_class, ctor); - MAYBE_RETHROW(gdk_env, "cannot allocate a ThreadLocal"); - - *local = ((*gdk_env)->NewGlobalRef (gdk_env, *local)); - MAYBE_RETHROW(gdk_env, "cannot create a GlobalRef"); - - return (GPrivate*) local; + return gkey; } /* Get this thread's value for a thread-local key. This is simply - * ThreadLocal.get for us. + * ThreadLocal.get for us. Return NULL if no value. (I can't think of + * anything else to do.) */ -static gpointer g_private_get_jni_impl (GPrivate *private) { - jclass lcl_class; - jobject lcl_obj; - JNIEnv *gdk_env; - jmethodID get_mth; - jclass int_class; - jmethodID val_mth; - jint int_val; - - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); +static gpointer +private_get_jni_impl (GPrivate * gkey) +{ + JNIEnv *env; + union env_union e; + jobject val_wrapper; + jobject keyObj = (jobject) gkey; + gpointer thread_specific_data = NULL; /* Init to the error-return value */ + + jlong val; + + if (TRACE_API_CALLS) + tracing ("private_get_jni_impl(keyObj=%p)", keyObj); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + val_wrapper = (*env)->CallObjectMethod (env, keyObj, threadlocal_get_mth); + if (MAYBE_BROKEN (env, "cannot find thread-local object")) + goto done; + + if (! val_wrapper ) + { + /* It's Java's "null" object. No ref found. This is OK; we must never + have set a value in this thread. Note that this next statement is + not necessary, strictly speaking, since we're already initialized to + NULL. A good optimizing C compiler will detect that and optimize out + this statement. */ + thread_specific_data = NULL; + goto done; + } - lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.ThreadLocal"); - MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal"); + val = (*env)->CallLongMethod (env, val_wrapper, long_longValue_mth); - get_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "get", "()Ljava/lang/Object;"); - MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal.<get>"); + if (MAYBE_BROKEN (env, "cannot get thread local value")) + goto done; - lcl_obj = (*gdk_env)->CallObjectMethod(gdk_env, *(jobject*)private, get_mth); - MAYBE_RETHROW(gdk_env, "cannot find thread-local object"); + thread_specific_data = (gpointer) (intptr_t) val; - int_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Integer"); - MAYBE_RETHROW(gdk_env, "cannot find Integer"); + /* Only re-raise the old pending exception if a new one hasn't come along to + supersede it. */ + SHOW_OLD_TROUBLE (); - val_mth = (*gdk_env)->GetMethodID(gdk_env, int_class, "intValue", "()I"); - MAYBE_RETHROW(gdk_env, "cannot find Integer.<intValue>"); +done: - int_val = (*gdk_env)->CallIntMethod(gdk_env, lcl_obj, val_mth); - MAYBE_RETHROW(gdk_env, "cannot get thread local value"); + if (TRACE_API_CALLS) + tracing (" ==> %p\n", thread_specific_data); - return (gpointer) int_val; + return thread_specific_data; } -/* Set this thread's value for a thread-local key. This is simply - * ThreadLocal.set for us. +/* Set this thread's value for a thread-local key. This is simply + * ThreadLocal.set() for us. */ -static void g_private_set_jni_impl (GPrivate *private, gpointer data) { - jclass lcl_class, int_class; - jobject lcl_obj; - JNIEnv *gdk_env; - jmethodID new_int, set_mth; +static void +private_set_jni_impl (GPrivate * gkey, gpointer thread_specific_data) +{ + JNIEnv *env; + union env_union e; + jobject val_wrapper; + jobject keyObj = (jobject) gkey; + + + if (TRACE_API_CALLS) + tracing ("private_set_jni_impl(keyObj=%p, thread_specific_data=%p)", + keyObj, thread_specific_data); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + /* We are just going to always use a Java long to represent a C pointer. + Otherwise all of the code would end up being conditionalized for various + pointer sizes, and that seems like too much of a hassle, in order to save + a paltry few bytes, especially given the horrendous overhead of JNI in + any case. + */ + + val_wrapper = (*env)->NewObject (env, long_class, long_ctor, + (jlong) (intptr_t) thread_specific_data); + if ( ! val_wrapper ) + { + BROKEN (env, "cannot create a java.lang.Long"); + goto done; + } + + /* At this point, we now have set lcl_obj as a numeric class that wraps + around the thread-specific data we were given. */ + (*env)->CallVoidMethod (env, keyObj, threadlocal_set_mth, val_wrapper); + if (MAYBE_BROKEN (env, "cannot set thread local value")) + goto done; + + SHOW_OLD_TROUBLE (); +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + +/** Create an object of type gnu.java.awt.peer.gtk.GThreadNativeMethodRunner. + Run it. + + We need to create joinable threads. We handle the notion of a joinable + thread by determining whether or not we are going to maintain a permanent + hard reference to it until it croaks. + + Posix does not appear to have a Java-like concept of daemon threads, where + the JVM will exit when there are only daemon threads running. + + Error handling: + + To quote from the glib guide: + "GError should only be used to report recoverable runtime errors, never + to report programming errors." + + So how do we consider the failure to create a thread? Well, each of the + failure cases in this function are discussed, and none of them are really + recoverable. + + The glib library is really designed so that you should fail + catastrophically in case of "programming errors". The only error defined + for the GThread functions is G_THREAD_ERROR_AGAIN, and that for + thread_create. + + Most of these GThread functions could fail if we run out of memory, for + example, but the only one capable of reporting that fact is + thread_create. */ +static void +thread_create_jni_impl (GThreadFunc func, + gpointer data, + gulong stack_size __attribute__((unused)), + gboolean joinable, + gboolean bound __attribute__((unused)), + GThreadPriority gpriority, + /* This prototype is horrible. threadIDp is actually + a gpointer to the thread's thread-ID. Which is, + of course, itself a gpointer-typed value. Ouch. */ + gpointer threadIDp, + /* Do not touch the GError stuff unless you have + RECOVERABLE trouble. There is no recoverable + trouble in this implementation. */ + GError **errorp __attribute__((unused))) +{ + JNIEnv *env; + union env_union e; + union func_union f; + jboolean jjoinable = joinable; + jobject newThreadObj; + gpointer threadID; /* to be filled in */ + + if (TRACE_API_CALLS) + { + f.g_func = func; + tracing ("thread_create_jni_impl(func=%p, data=%p, joinable=%s," + " threadIDp=%p, *(int *) threadIDp = %d)", + f.void_func, data, joinable ? "TRUE" : "FALSE", + threadIDp, *(int *) threadIDp); + } + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + { + /* The failed call to setup the cache is certainly not recoverable; + not appropriate for G_THREAD_ERROR_AGAIN. */ + *(gpointer *) threadIDp = NULL; + goto done; + } + HIDE_OLD_TROUBLE (env); + + /* If a thread is joinable, then notify its constructor. The constructor + will enter a hard reference for it, and the hard ref. won't go away until + the thread has been joined. */ + newThreadObj = + (*env)->NewObject (env, runner_class, runner_ctor, + (jlong) (intptr_t) func, (jlong) (intptr_t) data, + jjoinable); + if ( ! newThreadObj ) + { + BROKEN (env, "creating a new thread failed in the constructor"); + *(gpointer *) threadIDp = NULL; + /* The failed call to the constructor does not throw any errors such + that G_THREAD_ERROR_AGAIN is appropriate. No other recoverable + errors defined. Once again, we go back to the VM. */ + goto done; + } + + if (threadObj_set_priority (env, newThreadObj, gpriority) < 0) + { + *(gpointer *) threadIDp = NULL; + /* None of these possible exceptions from Thread.setPriority() are + recoverable, so they are not appropriate for EAGAIN. So we should + fail. */ + goto done; + } + + (*env)->CallVoidMethod (env, runner_class, runner_start_mth); + + if (MAYBE_BROKEN (env, "starting a new thread failed")) + { + *(gpointer *) threadIDp = NULL; + /* The only exception Thread.start() throws is + IllegalStateException. And that would indicate a programming error. + + So there are no situations such that G_THREAD_ERROR_AGAIN would be + OK. + + So, we don't use g_set_error() here to perform any error reporting. + */ + goto done; + } + + threadID = getThreadIDFromThread (env, newThreadObj); + + *(gpointer *) threadIDp = threadID; + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> (threadID = %p) \n", threadID); +} + + +/* Wraps a call to g_thread_yield. */ +static void +thread_yield_jni_impl (void) +{ + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("thread_yield_jni_impl()"); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + (*env)->CallStaticVoidMethod (env, thread_class, thread_yield_mth); + if (MAYBE_BROKEN (env, "Thread.yield() failed")) + goto done; + + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + +static void +thread_join_jni_impl (gpointer threadID) +{ + JNIEnv *env; + union env_union e; + jobject threadObj = NULL; + + if ( TRACE_API_CALLS ) + tracing ("thread_join_jni_impl(threadID=%p) ", threadID); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + HIDE_OLD_TROUBLE (env); + + threadObj = getThreadFromThreadID (env, threadID); + if ( ! threadObj ) /* Already reported with BROKEN */ + goto done; + + (*env)->CallVoidMethod (env, threadObj, thread_join_mth); + if (MAYBE_BROKEN (env, "Thread.join() failed")) + goto done; + + + (*env)->CallStaticVoidMethod + (env, runner_class, runner_deRegisterJoinable_mth, threadObj); + if (MAYBE_BROKEN (env, "Thread.deRegisterJoinableThread() failed")) + goto done; + + SHOW_OLD_TROUBLE (); + +done: + DELETE_LOCAL_REF (env, threadObj); + if (TRACE_API_CALLS) + tracing (" ==> VOID \n"); +} + +/* Terminate the current thread. Unlike pthread_exit(), here we do not need + to bother with a return value or exit value for the thread which is about + to croak. (The gthreads abstraction doesn't use it.) However, we *do* + need to bail immediately. We handle this with Thread.stop(), which is + a deprecated method. + + It's deprecated since we might leave objects protected by monitors in + half-constructed states on the way out -- Thread.stop() throws a + ThreadDeath exception, which is usually unchecked. There is no good + solution that I can see. */ +static void +thread_exit_jni_impl (void) +{ + JNIEnv *env; + union env_union e; + jobject this_thread; + + if (TRACE_API_CALLS) + tracing ("thread_exit_jni_impl() "); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + goto done; + + HIDE_OLD_TROUBLE (env); + + this_thread = (*env)-> + CallStaticObjectMethod (env, thread_class, thread_current_mth); + + if ( ! this_thread ) + { + BROKEN (env, "cannot get current thread"); + goto done; + } + + (*env)->CallVoidMethod (env, this_thread, thread_stop_mth); + if (MAYBE_BROKEN (env, "cannot call Thread.stop() on current thread")) + goto done; + + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> VOID \n"); +} + + +/* Translate a GThreadPriority to a Java priority level. */ +static jint +javaPriorityLevel (GThreadPriority priority) +{ + /* We have these fields in java.lang.Thread to play with: + + static int MIN_PRIORITY The minimum priority that a thread can have. + static int NORM_PRIORITY The default priority that is assigned to a + thread. + static int MAX_PRIORITY The maximum priority that a thread can have. + + We get these from the header file generated by javah, even though they're + documented as being 1, 5, and 10. + */ + static const jint minJPri = + gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MIN_PRIORITY; + static const jint normJPri = + gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_NORM_PRIORITY; + static const jint maxJPri = + gnu_java_awt_peer_gtk_GThreadNativeMethodRunner_MAX_PRIORITY; + + switch (priority) + { + case G_THREAD_PRIORITY_LOW: + return minJPri; + break; + + default: + assert_not_reached (); + /* Deliberate fall-through if assertions are turned off; also shuts up + GCC warnings if they're turned on. */ + case G_THREAD_PRIORITY_NORMAL: + return normJPri; + break; + + case G_THREAD_PRIORITY_HIGH: + return (normJPri + maxJPri) / 2; + break; + + case G_THREAD_PRIORITY_URGENT: + return maxJPri; + break; + } +} + + +/** It would be safe not to implement this, according to the JNI docs, since + not all platforms do thread priorities. However, we might as well + provide the hint for those who want it. +*/ +static void +thread_set_priority_jni_impl (gpointer gThreadID, GThreadPriority gpriority) +{ + jobject threadObj = NULL; + JNIEnv *env; + union env_union e; + + if (TRACE_API_CALLS) + tracing ("thread_set_priority_jni_impl(gThreadID=%p, gpriority = %u) ", + gThreadID, gpriority); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + + if (setup_cache (env) < 0) + goto done; + + HIDE_OLD_TROUBLE (env); + + + threadObj = getThreadFromThreadID (env, gThreadID); + if ( ! threadObj) /* Reported with BROKEN already. */ + goto done; + + if (threadObj_set_priority (env, threadObj, gpriority)) + goto done; + + SHOW_OLD_TROUBLE (); + +done: + DELETE_LOCAL_REF (env, threadObj); + + if (TRACE_API_CALLS) + tracing (" ==> VOID\n"); +} + + +/** It would be safe not to implement this, according to the JNI docs, since + not all platforms do thread priorities. However, we might as well + provide the hint for those who want it. + + -1 on failure, 0 on success. */ +static int +threadObj_set_priority (JNIEnv * env, jobject threadObj, + GThreadPriority gpriority) +{ + jint javaPriority = javaPriorityLevel (gpriority); + (*env)->CallVoidMethod (env, threadObj, thread_setPriority_mth, + javaPriority); + return MAYBE_BROKEN (env, "Thread.setPriority() failed"); +} - (*gdk_vm)->GetEnv(gdk_vm, (void **)&gdk_env, JNI_VERSION_1_1); - int_class = (*gdk_env)->FindClass (gdk_env, "java.lang.Integer"); - MAYBE_RETHROW(gdk_env, "cannot find Integer"); +/** Return the result of Thread.currentThread(), a static method. */ +static void +thread_self_jni_impl (/* Another confusing glib prototype. This is + actually a gpointer to the thread's thread-ID. + Which is, of course, a gpointer. */ + gpointer my_thread_IDp) +{ + JNIEnv *env; + union env_union e; + jobject this_thread; + gpointer my_threadID; - new_int = (*gdk_env)->GetMethodID(gdk_env, int_class, "<init>", "(I)V"); - MAYBE_RETHROW(gdk_env, "cannot find Integer.<init>"); + if (TRACE_API_CALLS) + tracing ("thread_self_jni_impl(my_thread_IDp=%p)", my_thread_IDp); - lcl_obj = (*gdk_env)->NewObject(gdk_env, int_class, new_int, (jint)data); - MAYBE_RETHROW(gdk_env, "cannot create an Integer"); + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); - lcl_class = (*gdk_env)->FindClass (gdk_env, "java.lang.ThreadLocal"); - MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal"); + if (setup_cache (env) < 0) + return; - set_mth = (*gdk_env)->GetMethodID(gdk_env, lcl_class, "set", "(Ljava/lang/Object;)V"); - MAYBE_RETHROW(gdk_env, "cannot find ThreadLocal.<set>"); + HIDE_OLD_TROUBLE (env); - (*gdk_env)->CallVoidMethod(gdk_env, *(jobject*)private, set_mth, lcl_obj); - MAYBE_RETHROW(gdk_env, "cannot set thread local value"); + this_thread = (*env)-> + CallStaticObjectMethod (env, thread_class, thread_current_mth); + if (! this_thread ) + { + BROKEN (env, "cannot get current thread"); + my_threadID = NULL; + goto done; + } + + my_threadID = getThreadIDFromThread (env, this_thread); + SHOW_OLD_TROUBLE (); + +done: + if (TRACE_API_CALLS) + tracing (" ==> (my_threadID = %p) \n", my_threadID); + + *(gpointer *) my_thread_IDp = my_threadID; } +static gboolean +thread_equal_jni_impl (gpointer thread1, gpointer thread2) +{ + JNIEnv *env; + union env_union e; + + gpointer threadID1 = *(gpointer *) thread1; + gpointer threadID2 = *(gpointer *) thread2; + + jobject thread1_obj = NULL; + jobject thread2_obj = NULL; + gboolean ret; + + if (TRACE_API_CALLS) + tracing ("thread_equal_jni_impl(threadID1=%p, threadID2=%p)", + threadID1, threadID2); + + e.jni_env = &env; + (*the_vm)->GetEnv (the_vm, e.void_env, JNI_VERSION_1_1); + if (setup_cache (env) < 0) + { + ret = FALSE; /* what is safer? We really don't ever want + to return from here. */ + goto done; + } + + HIDE_OLD_TROUBLE (env); + thread1_obj = getThreadFromThreadID (env, threadID1); + thread2_obj = getThreadFromThreadID (env, threadID2); + + ret = (*env)->CallBooleanMethod (env, thread1_obj, + thread_equals_mth, thread2_obj); + + if (MAYBE_BROKEN (env, "Thread.equals() failed")) + { + ret = FALSE; + goto done; + } + + SHOW_OLD_TROUBLE (); + + +done: + DELETE_LOCAL_REF (env, thread1_obj); + DELETE_LOCAL_REF (env, thread2_obj); + + if (TRACE_API_CALLS) + tracing (" ==> %s\n", ret ? "TRUE" : "FALSE"); + + return ret; +} + + + + /************************************************************************/ /* GLIB interface */ /************************************************************************/ /* set of function pointers to give to glib. */ -GThreadFunctions g_thread_jni_functions = -{ - g_mutex_new_jni_impl, /* mutex_new */ - g_mutex_lock_jni_impl, /* mutex_lock */ - g_mutex_trylock_jni_impl, /* mutex_try_lock */ - g_mutex_unlock_jni_impl, /* mutex_unlock */ - g_mutex_free_jni_impl, /* mutex_free */ - g_cond_new_jni_impl, /* cond_new */ - g_cond_signal_jni_impl, /* cond_signal */ - g_cond_broadcast_jni_impl, /* cond_broadcast */ - g_cond_wait_jni_impl, /* cond_wait */ - g_cond_timed_wait_jni_impl, /* cond_timed_wait */ - g_cond_free_jni_impl, /* cond_free */ - g_private_new_jni_impl, /* private_new */ - g_private_get_jni_impl, /* private_get */ - g_private_set_jni_impl, /* private_set */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL +GThreadFunctions portable_native_sync_jni_functions = { + mutex_new_jni_impl, /* mutex_new */ + mutex_lock_jni_impl, /* mutex_lock */ + mutex_trylock_jni_impl, /* mutex_trylock */ + mutex_unlock_jni_impl, /* mutex_unlock */ + mutex_free_jni_impl, /* mutex_free */ + cond_new_jni_impl, /* cond_new */ + cond_signal_jni_impl, /* cond_signal */ + cond_broadcast_jni_impl, /* cond_broadcast */ + cond_wait_jni_impl, /* cond_wait */ + cond_timed_wait_jni_impl, /* cond_timed_wait */ + cond_free_jni_impl, /* cond_free */ + private_new_jni_impl, /* private_new */ + private_get_jni_impl, /* private_get */ + private_set_jni_impl, /* private_set */ + thread_create_jni_impl, /* thread_create */ + thread_yield_jni_impl, /* thread_yield */ + thread_join_jni_impl, /* thread_join */ + thread_exit_jni_impl, /* thread_exit */ + thread_set_priority_jni_impl, /* thread_set_priority */ + thread_self_jni_impl, /* thread_self */ + thread_equal_jni_impl, /* thread_equal */ }; - + + +/* Keep c-font-lock-extra-types in alphabetical order. */ +/* Local Variables: */ +/* c-file-style: "gnu" */ +/* c-font-lock-extra-types: ("\\sw+_t" "gboolean" "GError" "gpointer" + "GPrivate" "GThreadFunc" "GThreadFunctions" "GThreadPriority" + "gulong" + "JNIEnv" + "jboolean" "jclass" "jfieldID" "jint" "jlong" "jmethodID" "jobject" "jstring" "jthrowable" ) */ +/* End: */ diff --git a/libjava/jni/gtk-peer/gthread-jni.h b/libjava/jni/gtk-peer/gthread-jni.h index a0d093dccc8..90a252fa5c0 100644 --- a/libjava/jni/gtk-peer/gthread-jni.h +++ b/libjava/jni/gtk-peer/gthread-jni.h @@ -42,7 +42,7 @@ exception statement from your version. */ #include <glib.h> #include "gtkpeer.h" -extern GThreadFunctions g_thread_jni_functions; -extern JavaVM *gdk_vm; +extern GThreadFunctions portable_native_sync_jni_functions; +extern JavaVM *the_vm; #endif /* __GTHREADJNI_H__ */ diff --git a/libjava/jni/gtk-peer/gtkpeer.h b/libjava/jni/gtk-peer/gtkpeer.h index 18c95102472..59d49cedadc 100644 --- a/libjava/jni/gtk-peer/gtkpeer.h +++ b/libjava/jni/gtk-peer/gtkpeer.h @@ -91,6 +91,20 @@ extern struct state_table *native_global_ref_table; (*env)->DeleteGlobalRef (env, *globRefPtr); \ free (globRefPtr);} while (0) +extern struct state_table *native_pixbufdecoder_state_table; + +#define NSA_PB_INIT(env, clazz) \ + native_pixbufdecoder_state_table = init_state_table (env, clazz) + +#define NSA_GET_PB_PTR(env, obj) \ + get_state (env, obj, native_pixbufdecoder_state_table) + +#define NSA_SET_PB_PTR(env, obj, ptr) \ + set_state (env, obj, native_pixbufdecoder_state_table, (void *)ptr) + +#define NSA_DEL_PB_PTR(env, obj) \ + remove_state_slot (env, obj, native_pixbufdecoder_state_table) + #endif /* JVM_SUN */ struct graphics @@ -118,14 +132,14 @@ struct graphics #define SYNTHETIC_EVENT_MASK (1 << 10) -#define AWT_SHIFT_MASK (1 << 0) -#define AWT_CTRL_MASK (1 << 1) -#define AWT_META_MASK (1 << 2) -#define AWT_ALT_MASK (1 << 3) +#define AWT_SHIFT_DOWN_MASK (1 << 6) +#define AWT_CTRL_DOWN_MASK (1 << 7) +#define AWT_META_DOWN_MASK (1 << 8) +#define AWT_ALT_DOWN_MASK (1 << 9) -#define AWT_BUTTON1_MASK (1 << 4) -#define AWT_BUTTON2_MASK AWT_ALT_MASK -#define AWT_BUTTON3_MASK AWT_META_MASK +#define AWT_BUTTON1_DOWN_MASK (1 << 10) +#define AWT_BUTTON2_DOWN_MASK (1 << 11) +#define AWT_BUTTON3_DOWN_MASK (1 << 12) #define MULTI_CLICK_TIME 250 /* as opposed to a MULTI_PASS_TIME :) */ @@ -459,4 +473,19 @@ struct item_event_hook_info const char *label; }; +#define DEBUG_LOCKING 0 + +#if DEBUG_LOCKING +#define gdk_threads_enter() \ +{ \ + g_print ("lock: %s, %d\n", __FILE__, __LINE__); \ + gdk_threads_enter (); \ +} +#define gdk_threads_leave() \ +{ \ + g_print ("unlock: %s, %d\n", __FILE__, __LINE__); \ + gdk_threads_leave (); \ +} +#endif + #endif /* __GTKPEER_H */ |