pub.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
  2. // file at the top-level directory of this distribution and at
  3. // https://github.com/go-vgo/robotgo/blob/master/LICENSE
  4. //
  5. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  6. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  7. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  8. // option. This file may not be copied, modified, or distributed
  9. // except according to those terms.
  10. // #include "../base/os.h"
  11. #if defined(IS_MACOSX)
  12. #include <dlfcn.h>
  13. #elif defined(USE_X11)
  14. #include <X11/Xatom.h>
  15. #endif
  16. struct _MData{
  17. #if defined(IS_MACOSX)
  18. CGWindowID CgID; // Handle to a CGWindowID
  19. AXUIElementRef AxID; // Handle to a AXUIElementRef
  20. #elif defined(USE_X11)
  21. Window XWin; // Handle to an X11 window
  22. #elif defined(IS_WINDOWS)
  23. HWND HWnd; // Handle to a window HWND
  24. TCHAR Title[512];
  25. #endif
  26. };
  27. typedef struct _MData MData;
  28. MData pub_mData;
  29. struct _Bounds {
  30. int32_t X; // Top left X coordinate
  31. int32_t Y; // Top left Y coordinate
  32. int32_t W; // bounds width
  33. int32_t H; // bounds height
  34. };
  35. typedef struct _Bounds Bounds;
  36. #if defined(IS_MACOSX)
  37. static Boolean(*gAXIsProcessTrustedWithOptions) (CFDictionaryRef);
  38. static CFStringRef* gkAXTrustedCheckOptionPrompt;
  39. AXError _AXUIElementGetWindow(AXUIElementRef, CGWindowID* out);
  40. static AXUIElementRef GetUIElement(CGWindowID win){
  41. intptr pid = 0;
  42. // double_t pid = 0;
  43. // Create array storing window
  44. CGWindowID window[1] = { win };
  45. CFArrayRef wlist = CFArrayCreate(NULL, (const void**)window, 1, NULL);
  46. // Get window info
  47. CFArrayRef info = CGWindowListCreateDescriptionFromArray(wlist);
  48. CFRelease(wlist);
  49. // Check whether the resulting array is populated
  50. if (info != NULL && CFArrayGetCount(info) > 0) {
  51. // Retrieve description from info array
  52. CFDictionaryRef desc = (CFDictionaryRef)CFArrayGetValueAtIndex(info, 0);
  53. // Get window PID
  54. CFNumberRef data = (CFNumberRef) CFDictionaryGetValue(desc, kCGWindowOwnerPID);
  55. if (data != NULL) {
  56. CFNumberGetValue(data, kCFNumberIntType, &pid);
  57. }
  58. // Return result
  59. CFRelease(info);
  60. }
  61. // Check if PID was retrieved
  62. if (pid <= 0) { return NULL; }
  63. // Create an accessibility object using retrieved PID
  64. AXUIElementRef application = AXUIElementCreateApplication(pid);
  65. if (application == 0) {return NULL;}
  66. CFArrayRef windows = NULL;
  67. // Get all windows associated with the app
  68. AXUIElementCopyAttributeValues(application, kAXWindowsAttribute, 0, 1024, &windows);
  69. // Reference to resulting value
  70. AXUIElementRef result = NULL;
  71. if (windows != NULL) {
  72. int count = CFArrayGetCount(windows);
  73. // Loop all windows in the process
  74. for (CFIndex i = 0; i < count; ++i){
  75. // Get the element at the index
  76. AXUIElementRef element = (AXUIElementRef) CFArrayGetValueAtIndex(windows, i);
  77. CGWindowID temp = 0;
  78. // Use undocumented API to get WindowID
  79. _AXUIElementGetWindow(element, &temp);
  80. if (temp == win) {
  81. // Retain element
  82. CFRetain(element);
  83. result = element;
  84. break;
  85. }
  86. }
  87. CFRelease(windows);
  88. }
  89. CFRelease(application);
  90. return result;
  91. }
  92. #elif defined(USE_X11)
  93. // Error Handling
  94. typedef int (*XErrorHandler) (Display*, XErrorEvent*);
  95. static int XHandleError(Display* dp, XErrorEvent* e) { return 0; }
  96. XErrorHandler mOld;
  97. void XDismissErrors (void) {
  98. Display *rDisplay = XOpenDisplay(NULL);
  99. // Save old handler and dismiss errors
  100. mOld = XSetErrorHandler(XHandleError);
  101. // Flush output buffer
  102. XSync(rDisplay, False);
  103. // Reinstate old handler
  104. XSetErrorHandler(mOld);
  105. XCloseDisplay(rDisplay);
  106. }
  107. // Definitions
  108. struct Hints{
  109. unsigned long Flags;
  110. unsigned long Funcs;
  111. unsigned long Decorations;
  112. signed long Mode;
  113. unsigned long Stat;
  114. };
  115. static Atom WM_STATE = None;
  116. static Atom WM_ABOVE = None;
  117. static Atom WM_HIDDEN = None;
  118. static Atom WM_HMAX = None;
  119. static Atom WM_VMAX = None;
  120. static Atom WM_DESKTOP = None;
  121. static Atom WM_CURDESK = None;
  122. static Atom WM_NAME = None;
  123. static Atom WM_UTF8 = None;
  124. static Atom WM_PID = None;
  125. static Atom WM_ACTIVE = None;
  126. static Atom WM_HINTS = None;
  127. static Atom WM_EXTENTS = None;
  128. ////////////////////////////////////////////////////////////////////////////////
  129. static void LoadAtoms (void){
  130. Display *rDisplay = XOpenDisplay(NULL);
  131. WM_STATE = XInternAtom(rDisplay, "_NET_WM_STATE", True);
  132. WM_ABOVE = XInternAtom(rDisplay, "_NET_WM_STATE_ABOVE", True);
  133. WM_HIDDEN = XInternAtom(rDisplay, "_NET_WM_STATE_HIDDEN", True);
  134. WM_HMAX = XInternAtom(rDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", True);
  135. WM_VMAX = XInternAtom(rDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", True);
  136. WM_DESKTOP = XInternAtom(rDisplay, "_NET_WM_DESKTOP", True);
  137. WM_CURDESK = XInternAtom(rDisplay, "_NET_CURRENT_DESKTOP", True);
  138. WM_NAME = XInternAtom(rDisplay, "_NET_WM_NAME", True);
  139. WM_UTF8 = XInternAtom(rDisplay, "UTF8_STRING", True);
  140. WM_PID = XInternAtom(rDisplay, "_NET_WM_PID", True);
  141. WM_ACTIVE = XInternAtom(rDisplay, "_NET_ACTIVE_WINDOW", True);
  142. WM_HINTS = XInternAtom(rDisplay, "_MOTIF_WM_HINTS", True);
  143. WM_EXTENTS = XInternAtom(rDisplay, "_NET_FRAME_EXTENTS", True);
  144. XCloseDisplay(rDisplay);
  145. }
  146. // Functions
  147. static void* GetWindowProperty(MData win, Atom atom, uint32_t* items) {
  148. // Property variables
  149. Atom type; int format;
  150. unsigned long nItems;
  151. unsigned long bAfter;
  152. unsigned char* result = NULL;
  153. Display *rDisplay = XOpenDisplay(NULL);
  154. // Check the atom
  155. if (atom != None) {
  156. // Retrieve and validate the specified property
  157. if (!XGetWindowProperty(rDisplay, win.XWin, atom, 0,
  158. BUFSIZ, False, AnyPropertyType, &type, &format, &nItems, &bAfter, &result)
  159. && result && nItems) {
  160. // Copy items result
  161. if (items != NULL) {
  162. *items = (uint32_t) nItems;
  163. }
  164. XCloseDisplay(rDisplay);
  165. return result;
  166. }
  167. }
  168. // Reset the items result if valid
  169. if (items != NULL) { *items = 0; }
  170. if (result != NULL) {
  171. XFree(result);
  172. }
  173. XCloseDisplay(rDisplay);
  174. return NULL;
  175. }
  176. //////
  177. #define STATE_TOPMOST 0
  178. #define STATE_MINIMIZE 1
  179. #define STATE_MAXIMIZE 2
  180. //////
  181. static void SetDesktopForWindow(MData win){
  182. Display *rDisplay = XOpenDisplay(NULL);
  183. // Validate every atom that we want to use
  184. if (WM_DESKTOP != None && WM_CURDESK != None) {
  185. // Get desktop property
  186. long* desktop = (long*)GetWindowProperty(win, WM_DESKTOP,NULL);
  187. // Check result value
  188. if (desktop != NULL) {
  189. // Retrieve the screen number
  190. XWindowAttributes attr = { 0 };
  191. XGetWindowAttributes(rDisplay, win.XWin, &attr);
  192. int s = XScreenNumberOfScreen(attr.screen);
  193. Window root = XRootWindow(rDisplay, s);
  194. // Prepare an event
  195. XClientMessageEvent e = { 0 };
  196. e.window = root; e.format = 32;
  197. e.message_type = WM_CURDESK;
  198. e.display = rDisplay;
  199. e.type = ClientMessage;
  200. e.data.l[0] = *desktop;
  201. e.data.l[1] = CurrentTime;
  202. // Send the message
  203. XSendEvent(rDisplay, root, False, SubstructureNotifyMask | SubstructureRedirectMask,
  204. (XEvent*) &e);
  205. XFree(desktop);
  206. }
  207. }
  208. XCloseDisplay(rDisplay);
  209. }
  210. static Bounds GetFrame(MData win){
  211. Bounds frame;
  212. // Retrieve frame bounds
  213. if (WM_EXTENTS != None) {
  214. long* result; uint32_t nItems = 0;
  215. // Get the window extents property
  216. result = (long*) GetWindowProperty(win, WM_EXTENTS, &nItems);
  217. if (result != NULL) {
  218. if (nItems == 4) {
  219. frame.X = (int32_t) result[0];
  220. frame.Y = (int32_t) result[2];
  221. frame.W = (int32_t) result[0] + (int32_t) result[1];
  222. frame.H = (int32_t) result[2] + (int32_t) result[3];
  223. }
  224. XFree(result);
  225. }
  226. }
  227. return frame;
  228. }
  229. #elif defined(IS_WINDOWS)
  230. HWND getHwnd(uintptr pid, int8_t isPid);
  231. void win_min(HWND hwnd, bool state){
  232. if (state) {
  233. ShowWindow(hwnd, SW_MINIMIZE);
  234. } else {
  235. ShowWindow(hwnd, SW_RESTORE);
  236. }
  237. }
  238. void win_max(HWND hwnd, bool state){
  239. if (state) {
  240. ShowWindow(hwnd, SW_MAXIMIZE);
  241. } else {
  242. ShowWindow(hwnd, SW_RESTORE);
  243. }
  244. }
  245. #endif