[aseprite] 203/308: Open files from Windows Explorer using DDE so we re-use the running instance

Tobias Hansen thansen at moszumanska.debian.org
Tue Mar 8 02:45:11 UTC 2016


This is an automated email from the git hooks/post-receive script.

thansen pushed a commit to branch master
in repository aseprite.

commit 210ffc090e7b446d9e6e6e8bb7a83edae8ee41ef
Author: David Capello <davidcapello at gmail.com>
Date:   Thu Feb 4 13:07:36 2016 -0300

    Open files from Windows Explorer using DDE so we re-use the running instance
    
    Fix #477
---
 src/she/CMakeLists.txt           |   5 +-
 src/she/LICENSE.txt              |   2 +-
 src/she/alleg4/alleg_display.cpp |  17 +++-
 src/she/skia/skia_window_win.cpp |  10 +-
 src/she/win/window.h             |   7 +-
 src/she/win/window_dde.cpp       | 205 +++++++++++++++++++++++++++++++++++++++
 src/she/win/window_dde.h         |  19 ++++
 7 files changed, 259 insertions(+), 6 deletions(-)

diff --git a/src/she/CMakeLists.txt b/src/she/CMakeLists.txt
index 313f168..d0f7285 100644
--- a/src/she/CMakeLists.txt
+++ b/src/she/CMakeLists.txt
@@ -1,5 +1,5 @@
 # SHE
-# Copyright (C) 2012-2015  David Capello
+# Copyright (C) 2012-2016  David Capello
 
 set(SHE_SOURCES)
 
@@ -143,7 +143,8 @@ if(USE_SKIA_BACKEND)
   if(WIN32)
     list(APPEND SHE_SOURCES
       skia/skia_window_win.cpp
-      win/vk.cpp)
+      win/vk.cpp
+      win/window_dde.cpp)
   endif()
 
   if(APPLE)
diff --git a/src/she/LICENSE.txt b/src/she/LICENSE.txt
index 1021a19..65642aa 100644
--- a/src/she/LICENSE.txt
+++ b/src/she/LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright (c) 2012-2013 David Capello
+Copyright (c) 2012-2016 David Capello
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/src/she/alleg4/alleg_display.cpp b/src/she/alleg4/alleg_display.cpp
index e4f6614..61bbb53 100644
--- a/src/she/alleg4/alleg_display.cpp
+++ b/src/she/alleg4/alleg_display.cpp
@@ -1,5 +1,5 @@
 // SHE library
-// Copyright (C) 2012-2015  David Capello
+// Copyright (C) 2012-2016  David Capello
 //
 // This file is released under the terms of the MIT license.
 // Read LICENSE.txt for more information.
@@ -82,6 +82,21 @@ bool capture_mouse = false;
 
 static LRESULT CALLBACK wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 {
+  // Don't process DDE messages here because we cannot get the first
+  // DDE message correctly. The problem is that the message pump
+  // starts before we can subclass the Allegro HWND, so we don't have
+  // enough time to inject the code to process this kind of message.
+  //
+  // For more info see "Once you go input-idle, your application is
+  // deemed ready to receive DDE messages":
+  //   https://blogs.msdn.microsoft.com/oldnewthing/20140620-00/?p=693
+  //
+  // Anyway a possible solution would be to avoid processing the
+  // message loop until we subclass the HWND. I've tested this and it
+  // doesn't work, maybe because the message pump on Allegro 4 isn't
+  // in the main thread, I really don't know. But it just crash the
+  // whole system (Windows 10).
+
   switch (msg) {
 
     case WM_DROPFILES: {
diff --git a/src/she/skia/skia_window_win.cpp b/src/she/skia/skia_window_win.cpp
index a7ea988..f5df7fa 100644
--- a/src/she/skia/skia_window_win.cpp
+++ b/src/she/skia/skia_window_win.cpp
@@ -1,5 +1,5 @@
 // SHE library
-// Copyright (C) 2012-2015  David Capello
+// Copyright (C) 2012-2016  David Capello
 //
 // This file is released under the terms of the MIT license.
 // Read LICENSE.txt for more information.
@@ -22,6 +22,14 @@
 
 #endif
 
+#ifdef _WIN32
+
+  #include <windows.h>
+  #include "she/win/window_dde.h" // Include this one time to
+
+#endif
+
+
 namespace she {
 
 SkiaWindow::SkiaWindow(EventQueue* queue, SkiaDisplay* display,
diff --git a/src/she/win/window.h b/src/she/win/window.h
index d8eaf21..dce9a01 100644
--- a/src/she/win/window.h
+++ b/src/she/win/window.h
@@ -1,5 +1,5 @@
 // SHE library
-// Copyright (C) 2012-2015  David Capello
+// Copyright (C) 2012-2016  David Capello
 //
 // This file is released under the terms of the MIT license.
 // Read LICENSE.txt for more information.
@@ -18,6 +18,7 @@
 #include "she/event.h"
 #include "she/keys.h"
 #include "she/native_cursor.h"
+#include "she/win/window_dde.h"
 
 #ifndef WM_MOUSEHWHEEL
   #define WM_MOUSEHWHEEL 0x020E
@@ -554,6 +555,10 @@ namespace she {
 
       }
 
+      LRESULT result = FALSE;
+      if (handle_dde_messages(m_hwnd, msg, wparam, lparam, result))
+        return result;
+
       return DefWindowProc(m_hwnd, msg, wparam, lparam);
     }
 
diff --git a/src/she/win/window_dde.cpp b/src/she/win/window_dde.cpp
new file mode 100644
index 0000000..12baa42
--- /dev/null
+++ b/src/she/win/window_dde.cpp
@@ -0,0 +1,205 @@
+// SHE library
+// Copyright (C) 2016  David Capello
+//
+// This file is released under the terms of the MIT license.
+// Read LICENSE.txt for more information.
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "she/win/window_dde.h"
+
+#include "base/string.h"
+#include "she/event.h"
+#include "she/event_queue.h"
+
+#include <string>
+#include <vector>
+
+namespace she {
+
+namespace {
+
+std::string get_atom_string(ATOM atom, bool isUnicode)
+{
+  std::string result;
+  if (!atom)
+    return result;
+
+  if (isUnicode) {
+    std::vector<WCHAR> buf(256, 0);
+    GlobalGetAtomNameW(atom, &buf[0], buf.size());
+    result = base::to_utf8(std::wstring(&buf[0]));
+  }
+  else {
+    std::vector<char> buf;
+    UINT chars = GlobalGetAtomNameA(atom, &buf[0], buf.size());
+    result = &buf[0];
+  }
+
+  return result;
+}
+
+// Converts a DDE command string (e.g. "[open(filename)]") into she events.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms648995.aspx
+bool parse_dde_command(const std::string& cmd)
+{
+  bool result = false;
+
+  for (size_t i=0; i<cmd.size(); ) {
+    if (cmd[i] == '[') {
+      size_t j = ++i;
+
+      for (; j<cmd.size(); ++j) {
+        if (cmd[j] == '(')
+          break;
+      }
+
+      std::string cmdName = cmd.substr(i, j-i);
+      std::vector<std::string> cmdParams;
+
+      for (i=j+1; i<cmd.size(); ) {
+        if (cmd[i] == ')') {
+          j = i+1;
+          break;
+        }
+        else if (cmd[i] == '"') {
+          std::string cmdParam;
+          for (j=++i; j<cmd.size(); ++j) {
+            if (cmd[j] == '"')
+              break;
+            else
+              cmdParam.push_back(cmd[j]);
+          }
+          cmdParams.push_back(cmdParam);
+          i = j+1;
+        }
+        else {
+          std::string cmdParam;
+          for (j=i; j<cmd.size(); ++j) {
+            if (cmd[j] == ',' || cmd[j] == ')')
+              break;
+            else
+              cmdParam.push_back(cmd[j]);
+          }
+          cmdParams.push_back(cmdParam);
+          i = j;
+        }
+      }
+
+      if (cmdName == "open" && !cmdParams.empty()) {
+        // Send a message to open the file as if it were dropped into the window.
+        Event ev;
+        ev.setType(Event::DropFiles);
+        ev.setFiles(cmdParams);
+        she::queue_event(ev);
+
+        result = true;
+      }
+
+      i = j;
+    }
+    else
+      ++i;
+  }
+
+  return result;
+}
+
+union DdeackContainer {
+  WORD value;
+  DDEACK ddeack;
+};
+
+} // anonymous namespace
+
+bool handle_dde_messages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, LRESULT& result)
+{
+  switch (msg) {
+
+    case WM_DDE_INITIATE: {
+      HWND clienthwnd = (HWND)wparam;
+      UINT appAtom = 0, topicAtom = 0;
+      if (!UnpackDDElParam(msg, lparam,
+                           &appAtom,
+                           &topicAtom))
+        return false;
+
+      bool useUnicode = (IsWindowUnicode(clienthwnd) ? true: false);
+      std::string app = get_atom_string((ATOM)appAtom, useUnicode);
+      std::string topic = get_atom_string((ATOM)topicAtom, useUnicode);
+      FreeDDElParam(msg, lparam);
+
+      if (app != PACKAGE) {
+        return false;
+      }
+
+      // We have to create new atoms for this WM_DDE_ACK, we cannot
+      // reuse them according to MSDN:
+      //
+      //   https://msdn.microsoft.com/en-us/library/windows/desktop/ms648996(v=vs.85).aspx
+      //
+      // Anyway it looks like Windows returns the same ATOM number.
+      ATOM newApp = (useUnicode ? GlobalAddAtomW(base::from_utf8(app).c_str()):
+                                  GlobalAddAtomA(app.c_str()));
+      ATOM newTopic = (useUnicode ? GlobalAddAtomW(base::from_utf8(topic).c_str()):
+                                    GlobalAddAtomA(topic.c_str()));
+
+      if (newApp && newTopic) {
+        SendMessage(clienthwnd,
+                    WM_DDE_ACK,
+                    (WPARAM)hwnd,
+                    PackDDElParam(WM_DDE_ACK, newApp, newTopic));
+      }
+
+      if (newApp) GlobalDeleteAtom(newApp);
+      if (newTopic) GlobalDeleteAtom(newTopic);
+
+      result = 0;
+      return true;
+    }
+
+    case WM_DDE_EXECUTE: {
+      HWND clienthwnd = (HWND)wparam;
+      bool useUnicode = (IsWindowUnicode(clienthwnd) ? true: false);
+      LPCVOID cmdPtr = (LPCVOID)GlobalLock((HGLOBAL)lparam);
+      std::string cmd;
+
+      if (useUnicode)
+        cmd = base::to_utf8((const WCHAR*)cmdPtr);
+      else
+        cmd = (const CHAR*)cmdPtr;
+
+      GlobalUnlock((HGLOBAL)lparam);
+
+      DdeackContainer ddeack;
+      ddeack.value = 0;
+      ddeack.ddeack.fAck = 1;
+
+      PostMessage(clienthwnd, WM_DDE_ACK,
+                  (WPARAM)hwnd,
+                  ReuseDDElParam(lparam, msg, WM_DDE_ACK,
+                                 (UINT_PTR)ddeack.value,
+                                 (UINT_PTR)lparam));
+
+      if (parse_dde_command(cmd))
+        SetForegroundWindow(hwnd);
+
+      result = 0;
+      return true;
+    }
+
+    case WM_DDE_TERMINATE: {
+      HWND clienthwnd = (HWND)wparam;
+      PostMessage(clienthwnd, WM_DDE_TERMINATE, (WPARAM)hwnd, lparam);
+      result = 0;
+      return true;
+    }
+
+  }
+
+  return false;
+}
+
+} // namespace she
diff --git a/src/she/win/window_dde.h b/src/she/win/window_dde.h
new file mode 100644
index 0000000..1551eff
--- /dev/null
+++ b/src/she/win/window_dde.h
@@ -0,0 +1,19 @@
+// SHE library
+// Copyright (C) 2016  David Capello
+//
+// This file is released under the terms of the MIT license.
+// Read LICENSE.txt for more information.
+
+#ifndef SHE_WIN_WINDOW_DDE_H_INCLUDED
+#define SHE_WIN_WINDOW_DDE_H_INCLUDED
+#pragma once
+
+#include <windows.h>
+
+namespace she {
+
+bool handle_dde_messages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, LRESULT& result);
+
+} // namespace she
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git



More information about the Pkg-games-commits mailing list