diff --git a/ClipboardApi.java b/ClipboardApi.java old mode 100755 new mode 100644 diff --git a/ComposeWindow.java b/ComposeWindow.java old mode 100755 new mode 100644 index 6a8ee25..71368da --- a/ComposeWindow.java +++ b/ComposeWindow.java @@ -44,7 +44,7 @@ ComposeWindow extends JFrame { // ---%-@-%--- - public void + public synchronized void setComposition(Composition composition) { assert composition != null; @@ -52,7 +52,7 @@ ComposeWindow extends JFrame { syncDisplayToComposition(); } - public void + public synchronized void newComposition() { composition = new Composition(); @@ -63,7 +63,7 @@ ComposeWindow extends JFrame { syncDisplayToComposition(); } - public void + public synchronized void submit() { syncCompositionToDisplay(); @@ -113,7 +113,7 @@ ComposeWindow extends JFrame { // - -%- - - private void + private synchronized void syncDisplayToComposition() { display.setText(composition.text); @@ -122,7 +122,7 @@ ComposeWindow extends JFrame { display.setContentWarning(composition.contentWarning); } - private void + private synchronized void syncCompositionToDisplay() { composition.text = display.getText(); diff --git a/ImageApi.java b/ImageApi.java old mode 100755 new mode 100644 diff --git a/ImageWindow.java b/ImageWindow.java old mode 100755 new mode 100644 index 90def6b..147137f --- a/ImageWindow.java +++ b/ImageWindow.java @@ -35,7 +35,7 @@ ImageWindow extends JFrame { // ---%-@-%--- - public void + public synchronized void showAttachments(Attachment[] attachments) { this.attachments = attachments; @@ -69,7 +69,7 @@ ImageWindow extends JFrame { // - -%- - - private void + private synchronized void toImage(int offset) { int last = attachments.length - 1; diff --git a/JKomasto.java b/JKomasto.java old mode 100755 new mode 100644 diff --git a/KDE_Dialog_Appear.wav b/KDE_Dialog_Appear.wav old mode 100755 new mode 100644 diff --git a/LoginWindow.java b/LoginWindow.java old mode 100755 new mode 100644 diff --git a/MastodonApi.java b/MastodonApi.java old mode 100755 new mode 100644 index bec86ee..c3e397a --- a/MastodonApi.java +++ b/MastodonApi.java @@ -8,6 +8,7 @@ import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; +import java.net.SocketTimeoutException; import java.io.Reader; import java.io.Writer; import java.io.InputStream; @@ -443,10 +444,11 @@ MastodonApi { try { - URL endpoint = new URL(url); + URL endpoint = new URL(url); HttpURLConnection conn = cast(endpoint.openConnection()); String s = "Bearer " + token; conn.setRequestProperty("Authorization", s); + conn.setReadTimeout(500); conn.connect(); int code = conn.getResponseCode(); @@ -462,11 +464,15 @@ MastodonApi { Reader input = ireader(conn.getInputStream()); BufferedReader br = new BufferedReader(input); Thread thread = Thread.currentThread(); - while (!thread.isInterrupted()) + while (true) try { String line = br.readLine(); if (line != null) handler.lineReceived(line); } + catch (SocketTimeoutException eSt) + { + if (thread.interrupted()) break; + } } catch (IOException eIo) { handler.connectionFailed(eIo); } } diff --git a/NotificationsWindow.java b/NotificationsWindow.java old mode 100755 new mode 100644 index b4fe3a0..d0fc032 --- a/NotificationsWindow.java +++ b/NotificationsWindow.java @@ -50,7 +50,7 @@ NotificationsWindow extends JFrame { // ---%-@-%--- - public void + public synchronized void readEntity(Tree entity) { notifications = new ArrayList<>(); @@ -111,6 +111,7 @@ NotificationsWindow extends JFrame { { if (notifications.size() < ROW_COUNT) showLatestPage(); display.showNotifications(notifications); + display.repaint(); } } diff --git a/PostWindow.java b/PostWindow.java old mode 100755 new mode 100644 index 7028391..2f7aa6b --- a/PostWindow.java +++ b/PostWindow.java @@ -66,7 +66,7 @@ PostWindow extends JFrame { // ---%-@-%--- - public void + public synchronized void use(Post post) { assert post != null; @@ -122,7 +122,7 @@ PostWindow extends JFrame { use(new Post(post)); } - public void + public synchronized void openAuthorProfile() { TimelineWindow w = new TimelineWindow(primaire); @@ -132,7 +132,7 @@ PostWindow extends JFrame { w.setVisible(true); } - public void + public synchronized void favourite(boolean favourited) { display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); @@ -174,7 +174,7 @@ PostWindow extends JFrame { display.repaint(); } - public void + public synchronized void boost(boolean boosted) { display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); @@ -216,7 +216,7 @@ PostWindow extends JFrame { display.repaint(); } - public void + public synchronized void reply() { String ownId = api.getAccountDetails().get("id").value; @@ -227,7 +227,7 @@ PostWindow extends JFrame { w.setVisible(true); } - public void + public synchronized void openMedia() { display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); @@ -236,6 +236,7 @@ PostWindow extends JFrame { ImageWindow w = new ImageWindow(); w.setTitle("Media - " + this.getTitle()); + w.setIconImage(this.getIconImage()); w.showAttachments(post.attachments); w.setLocationRelativeTo(null); w.setVisible(true); @@ -243,7 +244,7 @@ PostWindow extends JFrame { display.setCursor(null); } - public void + public synchronized void deletePost(boolean redraft) { display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); @@ -296,19 +297,19 @@ PostWindow extends JFrame { if (!isVisible()) dispose(); } - public void + public synchronized void copyPostId() { ClipboardApi.serve(post.id); } - public void + public synchronized void copyPostLink() { ClipboardApi.serve(post.uri); } - public void + public synchronized void openReplies() { RepliesWindow w = new RepliesWindow(primaire, this); @@ -354,6 +355,9 @@ implements ActionListener { private RichTextPane authorName, body; + private JScrollPane + bodyScrollPane; + private JLabel authorId, time, date; @@ -486,7 +490,11 @@ implements ActionListener { setMediaPreview(Image n) { media.setImage(n); } public void - resetFocus() { media.requestFocusInWindow(); } + resetFocus() + { + bodyScrollPane.getVerticalScrollBar().setValue(0); + media.requestFocusInWindow(); + } // - -%- - @@ -576,6 +584,11 @@ implements ActionListener { if (s.y > maxY) maxY = s.y; } body.setPreferredSize(new Dimension(1, maxY + 10)); + + ((java.awt.Graphics2D)g).setRenderingHint( + java.awt.RenderingHints.KEY_ANTIALIASING, + java.awt.RenderingHints.VALUE_ANTIALIAS_ON + ); } @@ -664,22 +677,22 @@ implements ActionListener { body = new RichTextPane(); body.setFont(f3); - JScrollPane scroll = new JScrollPane( + bodyScrollPane = new JScrollPane( body, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER ); - JScrollBar vsb = scroll.getVerticalScrollBar(); + JScrollBar vsb = bodyScrollPane.getVerticalScrollBar(); vsb.setPreferredSize(new Dimension(0, 0)); vsb.setUnitIncrement(16); - scroll.setBorder(null); - scroll.setFocusable(true); + bodyScrollPane.setBorder(null); + bodyScrollPane.setFocusable(true); JPanel centre = new JPanel(); centre.setOpaque(false); centre.setLayout(new BorderLayout(0, 8)); centre.add(top, BorderLayout.NORTH); - centre.add(scroll); + centre.add(bodyScrollPane); setLayout(new BorderLayout(8, 0)); add(left, BorderLayout.WEST); diff --git a/RepliesWindow.java b/RepliesWindow.java old mode 100755 new mode 100644 index fb1d51f..b248b0f --- a/RepliesWindow.java +++ b/RepliesWindow.java @@ -38,7 +38,7 @@ RepliesWindow extends JFrame { // ---%-@-%--- - public void + public synchronized void showFor(String postId) { display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); @@ -50,7 +50,7 @@ RepliesWindow extends JFrame { // - -%- - - public void + public synchronized void postSelected(Tree post) { postWindow.readEntity(post); diff --git a/RequestListener.java b/RequestListener.java old mode 100755 new mode 100644 diff --git a/RichTextPane.java b/RichTextPane.java old mode 100755 new mode 100644 diff --git a/RudimentaryHTMLParser.java b/RudimentaryHTMLParser.java old mode 100755 new mode 100644 diff --git a/TimelineWindow.java b/TimelineWindow.java old mode 100755 new mode 100644 index 4db24d3..07e3ebb --- a/TimelineWindow.java +++ b/TimelineWindow.java @@ -91,7 +91,7 @@ implements ActionListener { // ---%-@-%--- - public void + public synchronized void use(TimelinePage page) { assert page != null; @@ -356,7 +356,7 @@ implements ActionListener { display.setCursor(null); } - public void + public synchronized void setTimelineType(TimelineType type) { assert type != TimelineType.LIST; @@ -375,10 +375,10 @@ implements ActionListener { display.repaint(); } - public TimelineType + public synchronized TimelineType getTimelineType() { return page.type; } - public void + public synchronized void showAuthorPosts(String authorNumId) { assert authorNumId != null; @@ -391,9 +391,11 @@ implements ActionListener { display.repaint(); } - public void + public synchronized void openOwnProfile() { + display.setCursor(new Cursor(Cursor.WAIT_CURSOR)); + Tree accountDetails = api.getAccountDetails(); assert accountDetails != null; String id = accountDetails.get("id").value; @@ -403,6 +405,8 @@ implements ActionListener { w.showLatestPage(); w.setLocationRelativeTo(this); w.setVisible(true); + + display.setCursor(null); } public void @@ -519,7 +523,7 @@ implements ActionListener { // - -%- - - public void + public synchronized void previewSelected(int index) { if (index > page.posts.length) return; @@ -527,7 +531,7 @@ implements ActionListener { primaire.getAutoViewWindow().use(post); } - public void + public synchronized void previewOpened(int index) { if (index > page.posts.length) return; @@ -604,6 +608,8 @@ implements ActionListener { } } +// - -%- - + private static String toString(TimelineType type) { diff --git a/TwoToggleButton.java b/TwoToggleButton.java old mode 100755 new mode 100644 diff --git a/WindowUpdater.java b/WindowUpdater.java old mode 100755 new mode 100644 index 9ff4333..f521878 --- a/WindowUpdater.java +++ b/WindowUpdater.java @@ -39,9 +39,9 @@ WindowUpdater { public void add(TimelineWindow updatee) { - if (timelineWindows.contains(updatee)) return; + if (!timelineWindows.contains(updatee)) + timelineWindows.add(updatee); - timelineWindows.add(updatee); publicConn.reevaluate(); userConn.reevaluate(); } @@ -49,9 +49,9 @@ WindowUpdater { public void add(NotificationsWindow updatee) { - if (notificationWindows.contains(updatee)) return; + if (!notificationWindows.contains(updatee)) + notificationWindows.add(updatee); - notificationWindows.add(updatee); userConn.reevaluate(); } @@ -84,27 +84,51 @@ WindowUpdater { private Thread thread; + private boolean + stopping; + private StringBuilder event, data; // -=%=- public void - restart() + start() { - if (thread != null) stop(); + stopping = false; thread = new Thread(this); - thread.start(); + try + { + synchronized (thread) + { + thread.start(); + thread.wait(); + } + } + catch (InterruptedException eIt) + { + assert false; + } } public void stop() { + stopping = true; thread.interrupt(); - thread = null; - // We should be sure that the thread will actually - // terminate eventually after our interrupt. I'm - // confident enough in that. + try + { + thread.join(); + } + catch (InterruptedException eIt) + { + assert false; + } + thread = null; + /* + * That thread should notice it is interrupted + * promptly, and close. + */ } public void @@ -119,26 +143,18 @@ WindowUpdater { if (responsibleFor(updatee)) hasUpdatee = true; if (!hasUpdatee && thread != null) stop(); - if (hasUpdatee && thread == null) restart(); + if (hasUpdatee && thread == null) start(); } // -=- - private boolean - responsibleFor(TimelineWindow updatee) - { - return type == updatee.getTimelineType(); - } - - private boolean - responsibleFor(NotificationsWindow updatee) - { - return type == TimelineType.HOME; - } - public void run() { + synchronized (thread) + { + thread.notifyAll(); + } event = new StringBuilder(); data = new StringBuilder(); api.monitorTimeline(type, this); @@ -208,6 +224,18 @@ WindowUpdater { } } + private boolean + responsibleFor(TimelineWindow updatee) + { + return type == updatee.getTimelineType(); + } + + private boolean + responsibleFor(NotificationsWindow updatee) + { + return type == TimelineType.HOME; + } + public void connectionFailed(IOException eIo) { diff --git a/graphics/Federated.xcf b/graphics/Federated.xcf old mode 100755 new mode 100644 diff --git a/graphics/Flags.xcf b/graphics/Flags.xcf old mode 100755 new mode 100644 diff --git a/graphics/Hourglass.xcf b/graphics/Hourglass.xcf old mode 100755 new mode 100644 diff --git a/graphics/boostToggled.png b/graphics/boostToggled.png old mode 100755 new mode 100644 diff --git a/graphics/boostUntoggled.png b/graphics/boostUntoggled.png old mode 100755 new mode 100644 diff --git a/graphics/button.png b/graphics/button.png old mode 100755 new mode 100644 diff --git a/graphics/disabledOverlay.png b/graphics/disabledOverlay.png old mode 100755 new mode 100644 diff --git a/graphics/favouriteToggled.png b/graphics/favouriteToggled.png old mode 100755 new mode 100644 diff --git a/graphics/favouriteUntoggled.png b/graphics/favouriteUntoggled.png old mode 100755 new mode 100644 diff --git a/graphics/federated.png b/graphics/federated.png old mode 100755 new mode 100644 diff --git a/graphics/miscToggled.png b/graphics/miscToggled.png old mode 100755 new mode 100644 diff --git a/graphics/miscUntoggled.png b/graphics/miscUntoggled.png old mode 100755 new mode 100644 diff --git a/graphics/ref1.png b/graphics/ref1.png old mode 100755 new mode 100644 diff --git a/graphics/replyToggled.png b/graphics/replyToggled.png old mode 100755 new mode 100644 diff --git a/graphics/replyUntoggled.png b/graphics/replyUntoggled.png old mode 100755 new mode 100644 diff --git a/graphics/selectedOverlay.png b/graphics/selectedOverlay.png old mode 100755 new mode 100644 diff --git a/graphics/test1.png b/graphics/test1.png old mode 100755 new mode 100644 diff --git a/graphics/test2.png b/graphics/test2.png old mode 100755 new mode 100644 diff --git a/graphics/test3.png b/graphics/test3.png old mode 100755 new mode 100644 diff --git a/graphics/test4.png b/graphics/test4.png old mode 100755 new mode 100644 diff --git a/notifOptions.txt b/notifOptions.txt old mode 100755 new mode 100644 diff --git a/notifOptions.txt~ b/notifOptions.txt~ old mode 100755 new mode 100644