Merge pull request #67 from chaosddp/screen_related
Query supported resolutions and other display info. Fix a number of bugs Clean up docsmaster
commit
6c4c406211
192
README.md
192
README.md
|
@ -1,27 +1,31 @@
|
|||
# DefOS
|
||||
|
||||
Extra native OS functions for games written using the Defold game engine
|
||||
|
||||
Currently uses Native Extension for macOS, Windows and HTML5. Contribute!
|
||||
Currently supports macOS, Windows, Linux and HTML5. Contribute!
|
||||
|
||||
## Installation
|
||||
You can use DefOS in your own project by adding this project as a [Defold library dependency](http://www.defold.com/manuals/libraries/). Open your game.project file and in the dependencies field under project add:
|
||||
|
||||
You can use DefOS in your own project by adding this project as a
|
||||
[Defold library dependency](http://www.defold.com/manuals/libraries/).
|
||||
Open your `game.project` file and in the dependencies field under project add:
|
||||
|
||||
https://github.com/subsoap/defos/archive/master.zip
|
||||
|
||||
## Methods
|
||||
|
||||
Customize title bar accessories and title.
|
||||
**Customize title bar** accessories and title.
|
||||
|
||||
```lua
|
||||
defos.disable_maximize_button()
|
||||
defos.disable_minimize_button()
|
||||
defos.disable_window_resize()
|
||||
defos.disable_maximize_button() -- Not supported on HTML5
|
||||
defos.disable_minimize_button() -- Not supported on HTML5
|
||||
defos.disable_window_resize() -- Not supported on HTML5
|
||||
defos.set_window_title("I set this title using Defos")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Toggle window maximize status.
|
||||
**Toggle window maximize** status.
|
||||
|
||||
```lua
|
||||
defos.set_maximized(bool_value)
|
||||
|
@ -31,7 +35,7 @@ bool_value = defos.is_maximized()
|
|||
|
||||
---
|
||||
|
||||
Toggle full screen. On HTML5, this only works from `defos.on_click()`.
|
||||
**Toggle full screen**. On HTML5, this only works from `defos.on_click()`.
|
||||
|
||||
```lua
|
||||
defos.set_fullscreen(bool_value)
|
||||
|
@ -41,7 +45,25 @@ bool_value = defos.is_fullscreen()
|
|||
|
||||
---
|
||||
|
||||
Get/set the window's size and position in screen coordinates. The window area
|
||||
**Keep window on top**. Not supported on HTML5.
|
||||
|
||||
```lua
|
||||
defos.set_always_on_top(bool_value)
|
||||
defos.toggle_always_on_top()
|
||||
bool_value = defos.is_always_on_top()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Minimize window**. Not supported on HTML5.
|
||||
|
||||
```lua
|
||||
defos.minimize()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Get/set the window's size and position** in screen coordinates. The window area
|
||||
includes the title bar, so the actual contained game view area might be smaller
|
||||
than the given metrics.
|
||||
|
||||
|
@ -57,7 +79,7 @@ defos.set_window_size(x, y, w, h)
|
|||
|
||||
---
|
||||
|
||||
Get/set the game view size and position in screen coordinates. This adjusts
|
||||
**Get/set the game view size and position** in screen coordinates. This adjusts
|
||||
the window so that its containing game view is at the desired size and position.
|
||||
The window will be larger than the given metrics because it includes the title
|
||||
bar.
|
||||
|
@ -71,7 +93,75 @@ defos.set_view_size(x, y, w, h)
|
|||
|
||||
---
|
||||
|
||||
Show/hide the mouse cursor.
|
||||
**Query displays**.
|
||||
|
||||
`defos.get_displays()` returns a table which can be indexed with either number
|
||||
indices (like an array), either with display `id`s.
|
||||
|
||||
Not supported on HTML5.
|
||||
|
||||
```lua
|
||||
displays = defos.get_displays()
|
||||
pprint(displays[1]) -- Print info about the main display
|
||||
current_display_id = defos.get_current_display_id() -- Get the ID of the game's current display
|
||||
pprint(displays[current_display_id]) -- Print info about the game's current display
|
||||
```
|
||||
|
||||
A display info table has the following format:
|
||||
```lua
|
||||
{
|
||||
id = <userdata>,
|
||||
bounds = { -- This is the position and size in screen coordinates of the
|
||||
x = 0, -- display (relative to the top-left corner of the main display)
|
||||
y = 0,
|
||||
width = 1440,
|
||||
height = 900,
|
||||
}
|
||||
mode = { -- The current resolution mode of the display
|
||||
width = 2880,
|
||||
height = 1800,
|
||||
scaling_factor = 2,
|
||||
refresh_rate = 60,
|
||||
bits_per_pixel = 32,
|
||||
orientation = 0,
|
||||
reflect_x = false,
|
||||
reflect_y = false,
|
||||
},
|
||||
name = "Built-in Retina Display",
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Query resolution modes** for a display.
|
||||
|
||||
Returns a table with all the resolution modes a display supports.
|
||||
|
||||
Not supported on HTML5.
|
||||
|
||||
```lua
|
||||
display_id = defos.get_current_display_id()
|
||||
modes = defos.get_display_modes(display_id)
|
||||
pprint(modes[1]) -- Print information about the first available resolution mode
|
||||
```
|
||||
|
||||
A resolution mode has the following format:
|
||||
```lua
|
||||
{
|
||||
width = 2880, -- Full width/height in pixels (not points)
|
||||
height = 1800,
|
||||
scaling_factor = 2, -- Hi-DPI scaling factor
|
||||
refresh_rate = 60,
|
||||
bits_per_pixel = 32,
|
||||
orientation = 0, -- One of 0, 90, 180, 270 (degrees measured clockwise)
|
||||
reflect_x = false, -- Linux supports reflecting either of the axes,
|
||||
reflect_y = false, -- effectively flipping the image like a mirror
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Show/hide the mouse cursor.**
|
||||
|
||||
```lua
|
||||
defos.set_cursor_visible(bool_value)
|
||||
|
@ -80,7 +170,9 @@ bool_value = defos.is_cursor_visible()
|
|||
|
||||
---
|
||||
|
||||
Respond to the mouse entering and leaving the game view area.
|
||||
**Respond to the mouse entering and leaving** the game view area.
|
||||
|
||||
`on_mouse_enter()` / `on_mouse_leave()` not supported on Linux yet.
|
||||
|
||||
```lua
|
||||
bool_value = defos.is_mouse_in_view()
|
||||
|
@ -94,16 +186,28 @@ end)
|
|||
|
||||
---
|
||||
|
||||
Move the cursor programatically.
|
||||
**Get the cursor position**.
|
||||
|
||||
```lua
|
||||
defos.set_cursor_pos(x, y) -- In screen coordinates
|
||||
defos.move_cursor_to(x, y) -- In game view coordinates
|
||||
x, y = defos.get_cursor_pos() -- In screen coordinates
|
||||
x, y = defos.get_cursor_pos_view() -- In game view coordinates
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Clip cursor to current game view area. Windows only.
|
||||
**Move the cursor** programatically.
|
||||
|
||||
Not supported on HTML5.
|
||||
|
||||
```lua
|
||||
defos.set_cursor_pos(x, y) -- In screen coordinates
|
||||
defos.set_cursor_pos_view(x, y) -- In game view coordinates
|
||||
```
|
||||
---
|
||||
|
||||
**Clip cursor** to current game view area.
|
||||
|
||||
Not supported on Linux and HTML5.
|
||||
|
||||
```lua
|
||||
defos.set_cursor_clipped(bool_value)
|
||||
|
@ -112,7 +216,10 @@ bool_value = defos.is_cursor_clipped()
|
|||
|
||||
---
|
||||
|
||||
Lock cursor movement. On HTML5 this only works from `defos.on_click()`.
|
||||
**Lock cursor movement**.
|
||||
|
||||
On HTML5 this only works from `defos.on_click()`.
|
||||
Not supported on Linux yet.
|
||||
|
||||
```lua
|
||||
defos.set_cursor_locked(bool_value)
|
||||
|
@ -124,7 +231,7 @@ end)
|
|||
|
||||
---
|
||||
|
||||
Set custom hardware cursors. `cursor` can be one of the following:
|
||||
**Set custom hardware cursors**. `cursor` can be one of the following:
|
||||
* `nil`: Resets the cursor to default. Equivalent to `defos.reset_cursor()`.
|
||||
* `defos.CURSOR_ARROW`
|
||||
* `defos.CURSOR_HAND`
|
||||
|
@ -141,11 +248,14 @@ Set custom hardware cursors. `cursor` can be one of the following:
|
|||
}
|
||||
```
|
||||
|
||||
On macOS, custom cursors can be any image file supported by `NSImage`, but it's highly recommended to
|
||||
[create a TIFF](https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW27)
|
||||
with two images, one at 72DPI (for low density displays) and another at 144DPI (for Retina displays).
|
||||
On macOS, custom cursors can be any image file supported by `NSImage`, but it's
|
||||
highly recommended to [create a TIFF][cursor-tiff] with two images, one at
|
||||
72DPI (for low density displays) and another at 144DPI (for Retina displays).
|
||||
|
||||
The hotspot is an anchor point within the image that will overlap with the functional position of the mouse pointer (eg. the tip of the arrow).
|
||||
The hotspot is an anchor point within the image that will overlap with the
|
||||
functional position of the mouse pointer (eg. the tip of the arrow).
|
||||
|
||||
[cursor-tiff]: https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW27
|
||||
|
||||
```lua
|
||||
defos.set_cursor(cursor)
|
||||
|
@ -154,7 +264,7 @@ defos.reset_cursor()
|
|||
|
||||
---
|
||||
|
||||
On Windows only, show/hide the console window. Only works when not running
|
||||
**Show/hide the console window** on Windows. Only works when not running
|
||||
from the Editor.
|
||||
|
||||
```lua
|
||||
|
@ -164,7 +274,7 @@ bool_value = defos.is_console_visible()
|
|||
|
||||
---
|
||||
|
||||
On HTML5 only, get a synchronous event when the user clicks in the canvas.
|
||||
On HTML5 only, **get a synchronous event when the user clicks** in the canvas.
|
||||
This is necessary because some HTML5 functions only work when called
|
||||
synchronously from an event handler.
|
||||
|
||||
|
@ -180,7 +290,9 @@ end)
|
|||
|
||||
---
|
||||
|
||||
Get the absolute path to the game's containing directory. On macOS this will be the path to the .app bundle
|
||||
**Get the absolute path to the game's containing directory**. On macOS this
|
||||
will be the path to the .app bundle. On HTML5 this will be the page URL up until
|
||||
the last `/`.
|
||||
|
||||
```lua
|
||||
path = defos.get_bundle_root()
|
||||
|
@ -188,32 +300,38 @@ path = defos.get_bundle_root()
|
|||
|
||||
---
|
||||
|
||||
The system path separator. `"\\"` on Windows, `"/"` everywhere else.
|
||||
**The system path separator.** `"\\"` on Windows, `"/"` everywhere else.
|
||||
|
||||
```lua
|
||||
defos.PATH_SEP
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Change the game's icon at runtime.
|
||||
|
||||
```lua
|
||||
defos.set_window_icon(path_to_icon)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Returns a table of command line arguments used to run the app. On HTML5, returns a table with a single string: the query string part of the URL (eg. `{ "?param1=foo¶m2=bar" }`).
|
||||
**Change the game window's icon** at runtime. On Windows, this function accepts
|
||||
`.ico` files. On macOS this accepts any image file supported by `NSImage`.
|
||||
On Linux this function is not supported yet.
|
||||
|
||||
```lua
|
||||
arguments = defos.get_parameters()
|
||||
defos.set_window_icon(path_to_icon_file)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
If you'd like to see any other feature, open an issue.
|
||||
**Returns a table of command line arguments** used to run the app. On HTML5,
|
||||
returns a table with a single string: the query string part of the URL
|
||||
(eg. `{ "?param1=foo¶m2=bar" }`).
|
||||
|
||||
```lua
|
||||
arguments = defos.get_arguments()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
If you'd like to see any other features, open an issue.
|
||||
|
||||
## Example
|
||||
|
||||
An example is made using [DirtyLarry](https://github.com/andsve/dirtylarry)
|
||||
|
||||
![Defos example screenshot](https://user-images.githubusercontent.com/2209596/37050119-158e6b34-2184-11e8-95fd-b2e293fba456.jpg)
|
||||
|
|
|
@ -0,0 +1,590 @@
|
|||
/*
|
||||
* Copyright © 2000 Compaq Computer Corporation, Inc.
|
||||
* Copyright © 2002 Hewlett-Packard Company, Inc.
|
||||
* Copyright © 2006 Intel Corporation
|
||||
* Copyright © 2008 Red Hat, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Jim Gettys, HP Labs, Hewlett-Packard, Inc.
|
||||
* Keith Packard, Intel Corporation
|
||||
*/
|
||||
#if defined(DM_PLATFORM_LINUX)
|
||||
|
||||
#ifndef _XRANDR_H_
|
||||
#define _XRANDR_H_
|
||||
|
||||
#include <randr.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
|
||||
#include <X11/Xfuncproto.h>
|
||||
|
||||
_XFUNCPROTOBEGIN
|
||||
|
||||
typedef XID RROutput;
|
||||
typedef XID RRCrtc;
|
||||
typedef XID RRMode;
|
||||
typedef XID RRProvider;
|
||||
|
||||
typedef struct {
|
||||
int width, height;
|
||||
int mwidth, mheight;
|
||||
} XRRScreenSize;
|
||||
|
||||
/*
|
||||
* Events.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int type; /* event base */
|
||||
unsigned long serial; /* # of last request processed by server */
|
||||
Bool send_event; /* true if this came from a SendEvent request */
|
||||
Display *display; /* Display the event was read from */
|
||||
Window window; /* window which selected for this event */
|
||||
Window root; /* Root window for changed screen */
|
||||
Time timestamp; /* when the screen change occurred */
|
||||
Time config_timestamp; /* when the last configuration change */
|
||||
SizeID size_index;
|
||||
SubpixelOrder subpixel_order;
|
||||
Rotation rotation;
|
||||
int width;
|
||||
int height;
|
||||
int mwidth;
|
||||
int mheight;
|
||||
} XRRScreenChangeNotifyEvent;
|
||||
|
||||
typedef struct {
|
||||
int type; /* event base */
|
||||
unsigned long serial; /* # of last request processed by server */
|
||||
Bool send_event; /* true if this came from a SendEvent request */
|
||||
Display *display; /* Display the event was read from */
|
||||
Window window; /* window which selected for this event */
|
||||
int subtype; /* RRNotify_ subtype */
|
||||
} XRRNotifyEvent;
|
||||
|
||||
typedef struct {
|
||||
int type; /* event base */
|
||||
unsigned long serial; /* # of last request processed by server */
|
||||
Bool send_event; /* true if this came from a SendEvent request */
|
||||
Display *display; /* Display the event was read from */
|
||||
Window window; /* window which selected for this event */
|
||||
int subtype; /* RRNotify_OutputChange */
|
||||
RROutput output; /* affected output */
|
||||
RRCrtc crtc; /* current crtc (or None) */
|
||||
RRMode mode; /* current mode (or None) */
|
||||
Rotation rotation; /* current rotation of associated crtc */
|
||||
Connection connection; /* current connection status */
|
||||
SubpixelOrder subpixel_order;
|
||||
} XRROutputChangeNotifyEvent;
|
||||
|
||||
typedef struct {
|
||||
int type; /* event base */
|
||||
unsigned long serial; /* # of last request processed by server */
|
||||
Bool send_event; /* true if this came from a SendEvent request */
|
||||
Display *display; /* Display the event was read from */
|
||||
Window window; /* window which selected for this event */
|
||||
int subtype; /* RRNotify_CrtcChange */
|
||||
RRCrtc crtc; /* current crtc (or None) */
|
||||
RRMode mode; /* current mode (or None) */
|
||||
Rotation rotation; /* current rotation of associated crtc */
|
||||
int x, y; /* position */
|
||||
unsigned int width, height; /* size */
|
||||
} XRRCrtcChangeNotifyEvent;
|
||||
|
||||
typedef struct {
|
||||
int type; /* event base */
|
||||
unsigned long serial; /* # of last request processed by server */
|
||||
Bool send_event; /* true if this came from a SendEvent request */
|
||||
Display *display; /* Display the event was read from */
|
||||
Window window; /* window which selected for this event */
|
||||
int subtype; /* RRNotify_OutputProperty */
|
||||
RROutput output; /* related output */
|
||||
Atom property; /* changed property */
|
||||
Time timestamp; /* time of change */
|
||||
int state; /* NewValue, Deleted */
|
||||
} XRROutputPropertyNotifyEvent;
|
||||
|
||||
typedef struct {
|
||||
int type; /* event base */
|
||||
unsigned long serial; /* # of last request processed by server */
|
||||
Bool send_event; /* true if this came from a SendEvent request */
|
||||
Display *display; /* Display the event was read from */
|
||||
Window window; /* window which selected for this event */
|
||||
int subtype; /* RRNotify_ProviderChange */
|
||||
RRProvider provider; /* current provider (or None) */
|
||||
Time timestamp; /* time of change */
|
||||
unsigned int current_role;
|
||||
} XRRProviderChangeNotifyEvent;
|
||||
|
||||
typedef struct {
|
||||
int type; /* event base */
|
||||
unsigned long serial; /* # of last request processed by server */
|
||||
Bool send_event; /* true if this came from a SendEvent request */
|
||||
Display *display; /* Display the event was read from */
|
||||
Window window; /* window which selected for this event */
|
||||
int subtype; /* RRNotify_ProviderProperty */
|
||||
RRProvider provider; /* related provider */
|
||||
Atom property; /* changed property */
|
||||
Time timestamp; /* time of change */
|
||||
int state; /* NewValue, Deleted */
|
||||
} XRRProviderPropertyNotifyEvent;
|
||||
|
||||
typedef struct {
|
||||
int type; /* event base */
|
||||
unsigned long serial; /* # of last request processed by server */
|
||||
Bool send_event; /* true if this came from a SendEvent request */
|
||||
Display *display; /* Display the event was read from */
|
||||
Window window; /* window which selected for this event */
|
||||
int subtype; /* RRNotify_ResourceChange */
|
||||
Time timestamp; /* time of change */
|
||||
} XRRResourceChangeNotifyEvent;
|
||||
|
||||
/* internal representation is private to the library */
|
||||
typedef struct _XRRScreenConfiguration XRRScreenConfiguration;
|
||||
|
||||
Bool XRRQueryExtension (Display *dpy,
|
||||
int *event_base_return,
|
||||
int *error_base_return);
|
||||
Status XRRQueryVersion (Display *dpy,
|
||||
int *major_version_return,
|
||||
int *minor_version_return);
|
||||
|
||||
XRRScreenConfiguration *XRRGetScreenInfo (Display *dpy,
|
||||
Window window);
|
||||
|
||||
void XRRFreeScreenConfigInfo (XRRScreenConfiguration *config);
|
||||
|
||||
/*
|
||||
* Note that screen configuration changes are only permitted if the client can
|
||||
* prove it has up to date configuration information. We are trying to
|
||||
* insist that it become possible for screens to change dynamically, so
|
||||
* we want to ensure the client knows what it is talking about when requesting
|
||||
* changes.
|
||||
*/
|
||||
Status XRRSetScreenConfig (Display *dpy,
|
||||
XRRScreenConfiguration *config,
|
||||
Drawable draw,
|
||||
int size_index,
|
||||
Rotation rotation,
|
||||
Time timestamp);
|
||||
|
||||
/* added in v1.1, sorry for the lame name */
|
||||
Status XRRSetScreenConfigAndRate (Display *dpy,
|
||||
XRRScreenConfiguration *config,
|
||||
Drawable draw,
|
||||
int size_index,
|
||||
Rotation rotation,
|
||||
short rate,
|
||||
Time timestamp);
|
||||
|
||||
|
||||
Rotation XRRConfigRotations(XRRScreenConfiguration *config, Rotation *current_rotation);
|
||||
|
||||
Time XRRConfigTimes (XRRScreenConfiguration *config, Time *config_timestamp);
|
||||
|
||||
XRRScreenSize *XRRConfigSizes(XRRScreenConfiguration *config, int *nsizes);
|
||||
|
||||
short *XRRConfigRates (XRRScreenConfiguration *config, int sizeID, int *nrates);
|
||||
|
||||
SizeID XRRConfigCurrentConfiguration (XRRScreenConfiguration *config,
|
||||
Rotation *rotation);
|
||||
|
||||
short XRRConfigCurrentRate (XRRScreenConfiguration *config);
|
||||
|
||||
int XRRRootToScreen(Display *dpy, Window root);
|
||||
|
||||
/*
|
||||
* returns the screen configuration for the specified screen; does a lazy
|
||||
* evalution to delay getting the information, and caches the result.
|
||||
* These routines should be used in preference to XRRGetScreenInfo
|
||||
* to avoid unneeded round trips to the X server. These are new
|
||||
* in protocol version 0.1.
|
||||
*/
|
||||
|
||||
|
||||
void XRRSelectInput(Display *dpy, Window window, int mask);
|
||||
|
||||
/*
|
||||
* the following are always safe to call, even if RandR is not implemented
|
||||
* on a screen
|
||||
*/
|
||||
|
||||
|
||||
Rotation XRRRotations(Display *dpy, int screen, Rotation *current_rotation);
|
||||
XRRScreenSize *XRRSizes(Display *dpy, int screen, int *nsizes);
|
||||
short *XRRRates (Display *dpy, int screen, int sizeID, int *nrates);
|
||||
Time XRRTimes (Display *dpy, int screen, Time *config_timestamp);
|
||||
|
||||
|
||||
/* Version 1.2 additions */
|
||||
|
||||
/* despite returning a Status, this returns 1 for success */
|
||||
Status
|
||||
XRRGetScreenSizeRange (Display *dpy, Window window,
|
||||
int *minWidth, int *minHeight,
|
||||
int *maxWidth, int *maxHeight);
|
||||
|
||||
void
|
||||
XRRSetScreenSize (Display *dpy, Window window,
|
||||
int width, int height,
|
||||
int mmWidth, int mmHeight);
|
||||
|
||||
typedef unsigned long XRRModeFlags;
|
||||
|
||||
typedef struct _XRRModeInfo {
|
||||
RRMode id;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned long dotClock;
|
||||
unsigned int hSyncStart;
|
||||
unsigned int hSyncEnd;
|
||||
unsigned int hTotal;
|
||||
unsigned int hSkew;
|
||||
unsigned int vSyncStart;
|
||||
unsigned int vSyncEnd;
|
||||
unsigned int vTotal;
|
||||
char *name;
|
||||
unsigned int nameLength;
|
||||
XRRModeFlags modeFlags;
|
||||
} XRRModeInfo;
|
||||
|
||||
typedef struct _XRRScreenResources {
|
||||
Time timestamp;
|
||||
Time configTimestamp;
|
||||
int ncrtc;
|
||||
RRCrtc *crtcs;
|
||||
int noutput;
|
||||
RROutput *outputs;
|
||||
int nmode;
|
||||
XRRModeInfo *modes;
|
||||
} XRRScreenResources;
|
||||
|
||||
XRRScreenResources *
|
||||
XRRGetScreenResources (Display *dpy, Window window);
|
||||
|
||||
void
|
||||
XRRFreeScreenResources (XRRScreenResources *resources);
|
||||
|
||||
typedef struct _XRROutputInfo {
|
||||
Time timestamp;
|
||||
RRCrtc crtc;
|
||||
char *name;
|
||||
int nameLen;
|
||||
unsigned long mm_width;
|
||||
unsigned long mm_height;
|
||||
Connection connection;
|
||||
SubpixelOrder subpixel_order;
|
||||
int ncrtc;
|
||||
RRCrtc *crtcs;
|
||||
int nclone;
|
||||
RROutput *clones;
|
||||
int nmode;
|
||||
int npreferred;
|
||||
RRMode *modes;
|
||||
} XRROutputInfo;
|
||||
|
||||
XRROutputInfo *
|
||||
XRRGetOutputInfo (Display *dpy, XRRScreenResources *resources, RROutput output);
|
||||
|
||||
void
|
||||
XRRFreeOutputInfo (XRROutputInfo *outputInfo);
|
||||
|
||||
Atom *
|
||||
XRRListOutputProperties (Display *dpy, RROutput output, int *nprop);
|
||||
|
||||
typedef struct {
|
||||
Bool pending;
|
||||
Bool range;
|
||||
Bool immutable;
|
||||
int num_values;
|
||||
long *values;
|
||||
} XRRPropertyInfo;
|
||||
|
||||
XRRPropertyInfo *
|
||||
XRRQueryOutputProperty (Display *dpy, RROutput output, Atom property);
|
||||
|
||||
void
|
||||
XRRConfigureOutputProperty (Display *dpy, RROutput output, Atom property,
|
||||
Bool pending, Bool range, int num_values,
|
||||
long *values);
|
||||
|
||||
void
|
||||
XRRChangeOutputProperty (Display *dpy, RROutput output,
|
||||
Atom property, Atom type,
|
||||
int format, int mode,
|
||||
_Xconst unsigned char *data, int nelements);
|
||||
|
||||
void
|
||||
XRRDeleteOutputProperty (Display *dpy, RROutput output, Atom property);
|
||||
|
||||
int
|
||||
XRRGetOutputProperty (Display *dpy, RROutput output,
|
||||
Atom property, long offset, long length,
|
||||
Bool _delete, Bool pending, Atom req_type,
|
||||
Atom *actual_type, int *actual_format,
|
||||
unsigned long *nitems, unsigned long *bytes_after,
|
||||
unsigned char **prop);
|
||||
|
||||
XRRModeInfo *
|
||||
XRRAllocModeInfo (_Xconst char *name, int nameLength);
|
||||
|
||||
RRMode
|
||||
XRRCreateMode (Display *dpy, Window window, XRRModeInfo *modeInfo);
|
||||
|
||||
void
|
||||
XRRDestroyMode (Display *dpy, RRMode mode);
|
||||
|
||||
void
|
||||
XRRAddOutputMode (Display *dpy, RROutput output, RRMode mode);
|
||||
|
||||
void
|
||||
XRRDeleteOutputMode (Display *dpy, RROutput output, RRMode mode);
|
||||
|
||||
void
|
||||
XRRFreeModeInfo (XRRModeInfo *modeInfo);
|
||||
|
||||
typedef struct _XRRCrtcInfo {
|
||||
Time timestamp;
|
||||
int x, y;
|
||||
unsigned int width, height;
|
||||
RRMode mode;
|
||||
Rotation rotation;
|
||||
int noutput;
|
||||
RROutput *outputs;
|
||||
Rotation rotations;
|
||||
int npossible;
|
||||
RROutput *possible;
|
||||
} XRRCrtcInfo;
|
||||
|
||||
XRRCrtcInfo *
|
||||
XRRGetCrtcInfo (Display *dpy, XRRScreenResources *resources, RRCrtc crtc);
|
||||
|
||||
void
|
||||
XRRFreeCrtcInfo (XRRCrtcInfo *crtcInfo);
|
||||
|
||||
Status
|
||||
XRRSetCrtcConfig (Display *dpy,
|
||||
XRRScreenResources *resources,
|
||||
RRCrtc crtc,
|
||||
Time timestamp,
|
||||
int x, int y,
|
||||
RRMode mode,
|
||||
Rotation rotation,
|
||||
RROutput *outputs,
|
||||
int noutputs);
|
||||
|
||||
int
|
||||
XRRGetCrtcGammaSize (Display *dpy, RRCrtc crtc);
|
||||
|
||||
typedef struct _XRRCrtcGamma {
|
||||
int size;
|
||||
unsigned short *red;
|
||||
unsigned short *green;
|
||||
unsigned short *blue;
|
||||
} XRRCrtcGamma;
|
||||
|
||||
XRRCrtcGamma *
|
||||
XRRGetCrtcGamma (Display *dpy, RRCrtc crtc);
|
||||
|
||||
XRRCrtcGamma *
|
||||
XRRAllocGamma (int size);
|
||||
|
||||
void
|
||||
XRRSetCrtcGamma (Display *dpy, RRCrtc crtc, XRRCrtcGamma *gamma);
|
||||
|
||||
void
|
||||
XRRFreeGamma (XRRCrtcGamma *gamma);
|
||||
|
||||
/* Version 1.3 additions */
|
||||
|
||||
XRRScreenResources *
|
||||
XRRGetScreenResourcesCurrent (Display *dpy, Window window);
|
||||
|
||||
void
|
||||
XRRSetCrtcTransform (Display *dpy,
|
||||
RRCrtc crtc,
|
||||
XTransform *transform,
|
||||
_Xconst char *filter,
|
||||
XFixed *params,
|
||||
int nparams);
|
||||
|
||||
typedef struct _XRRCrtcTransformAttributes {
|
||||
XTransform pendingTransform;
|
||||
char *pendingFilter;
|
||||
int pendingNparams;
|
||||
XFixed *pendingParams;
|
||||
XTransform currentTransform;
|
||||
char *currentFilter;
|
||||
int currentNparams;
|
||||
XFixed *currentParams;
|
||||
} XRRCrtcTransformAttributes;
|
||||
|
||||
/*
|
||||
* Get current crtc transforms and filters.
|
||||
* Pass *attributes to XFree to free
|
||||
*/
|
||||
Status
|
||||
XRRGetCrtcTransform (Display *dpy,
|
||||
RRCrtc crtc,
|
||||
XRRCrtcTransformAttributes **attributes);
|
||||
|
||||
/*
|
||||
* intended to take RRScreenChangeNotify, or
|
||||
* ConfigureNotify (on the root window)
|
||||
* returns 1 if it is an event type it understands, 0 if not
|
||||
*/
|
||||
int XRRUpdateConfiguration(XEvent *event);
|
||||
|
||||
typedef struct _XRRPanning {
|
||||
Time timestamp;
|
||||
unsigned int left;
|
||||
unsigned int top;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int track_left;
|
||||
unsigned int track_top;
|
||||
unsigned int track_width;
|
||||
unsigned int track_height;
|
||||
int border_left;
|
||||
int border_top;
|
||||
int border_right;
|
||||
int border_bottom;
|
||||
} XRRPanning;
|
||||
|
||||
XRRPanning *
|
||||
XRRGetPanning (Display *dpy, XRRScreenResources *resources, RRCrtc crtc);
|
||||
|
||||
void
|
||||
XRRFreePanning (XRRPanning *panning);
|
||||
|
||||
Status
|
||||
XRRSetPanning (Display *dpy,
|
||||
XRRScreenResources *resources,
|
||||
RRCrtc crtc,
|
||||
XRRPanning *panning);
|
||||
|
||||
void
|
||||
XRRSetOutputPrimary(Display *dpy,
|
||||
Window window,
|
||||
RROutput output);
|
||||
|
||||
RROutput
|
||||
XRRGetOutputPrimary(Display *dpy,
|
||||
Window window);
|
||||
|
||||
typedef struct _XRRProviderResources {
|
||||
Time timestamp;
|
||||
int nproviders;
|
||||
RRProvider *providers;
|
||||
} XRRProviderResources;
|
||||
|
||||
XRRProviderResources *
|
||||
XRRGetProviderResources(Display *dpy, Window window);
|
||||
|
||||
void
|
||||
XRRFreeProviderResources(XRRProviderResources *resources);
|
||||
|
||||
typedef struct _XRRProviderInfo {
|
||||
unsigned int capabilities;
|
||||
int ncrtcs;
|
||||
RRCrtc *crtcs;
|
||||
int noutputs;
|
||||
RROutput *outputs;
|
||||
char *name;
|
||||
int nassociatedproviders;
|
||||
RRProvider *associated_providers;
|
||||
unsigned int *associated_capability;
|
||||
int nameLen;
|
||||
} XRRProviderInfo;
|
||||
|
||||
XRRProviderInfo *
|
||||
XRRGetProviderInfo(Display *dpy, XRRScreenResources *resources, RRProvider provider);
|
||||
|
||||
void
|
||||
XRRFreeProviderInfo(XRRProviderInfo *provider);
|
||||
|
||||
int
|
||||
XRRSetProviderOutputSource(Display *dpy, XID provider, XID source_provider);
|
||||
|
||||
int
|
||||
XRRSetProviderOffloadSink(Display *dpy, XID provider, XID sink_provider);
|
||||
|
||||
Atom *
|
||||
XRRListProviderProperties (Display *dpy, RRProvider provider, int *nprop);
|
||||
|
||||
XRRPropertyInfo *
|
||||
XRRQueryProviderProperty (Display *dpy, RRProvider provider, Atom property);
|
||||
|
||||
void
|
||||
XRRConfigureProviderProperty (Display *dpy, RRProvider provider, Atom property,
|
||||
Bool pending, Bool range, int num_values,
|
||||
long *values);
|
||||
|
||||
void
|
||||
XRRChangeProviderProperty (Display *dpy, RRProvider provider,
|
||||
Atom property, Atom type,
|
||||
int format, int mode,
|
||||
_Xconst unsigned char *data, int nelements);
|
||||
|
||||
void
|
||||
XRRDeleteProviderProperty (Display *dpy, RRProvider provider, Atom property);
|
||||
|
||||
int
|
||||
XRRGetProviderProperty (Display *dpy, RRProvider provider,
|
||||
Atom property, long offset, long length,
|
||||
Bool _delete, Bool pending, Atom req_type,
|
||||
Atom *actual_type, int *actual_format,
|
||||
unsigned long *nitems, unsigned long *bytes_after,
|
||||
unsigned char **prop);
|
||||
|
||||
|
||||
typedef struct _XRRMonitorInfo {
|
||||
Atom name;
|
||||
Bool primary;
|
||||
Bool automatic;
|
||||
int noutput;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
int mwidth;
|
||||
int mheight;
|
||||
RROutput *outputs;
|
||||
} XRRMonitorInfo;
|
||||
|
||||
XRRMonitorInfo *
|
||||
XRRAllocateMonitor(Display *dpy, int noutput);
|
||||
|
||||
XRRMonitorInfo *
|
||||
XRRGetMonitors(Display *dpy, Window window, Bool get_active, int *nmonitors);
|
||||
|
||||
void
|
||||
XRRSetMonitor(Display *dpy, Window window, XRRMonitorInfo *monitor);
|
||||
|
||||
void
|
||||
XRRDeleteMonitor(Display *dpy, Window window, Atom name);
|
||||
|
||||
void
|
||||
XRRFreeMonitors(XRRMonitorInfo *monitors);
|
||||
|
||||
_XFUNCPROTOEND
|
||||
|
||||
#endif /* _XRANDR_H_ */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright © 2000 Compaq Computer Corporation
|
||||
* Copyright © 2002 Hewlett Packard Company
|
||||
* Copyright © 2006 Intel Corporation
|
||||
* Copyright © 2008 Red Hat, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Jim Gettys, HP Labs, Hewlett-Packard, Inc.
|
||||
* Keith Packard, Intel Corporation
|
||||
*/
|
||||
#if defined(DM_PLATFORM_LINUX)
|
||||
|
||||
#ifndef _RANDR_H_
|
||||
#define _RANDR_H_
|
||||
|
||||
typedef unsigned short Rotation;
|
||||
typedef unsigned short SizeID;
|
||||
typedef unsigned short SubpixelOrder;
|
||||
typedef unsigned short Connection;
|
||||
typedef unsigned short XRandrRotation;
|
||||
typedef unsigned short XRandrSizeID;
|
||||
typedef unsigned short XRandrSubpixelOrder;
|
||||
typedef unsigned long XRandrModeFlags;
|
||||
|
||||
#define RANDR_NAME "RANDR"
|
||||
#define RANDR_MAJOR 1
|
||||
#define RANDR_MINOR 5
|
||||
|
||||
#define RRNumberErrors 4
|
||||
#define RRNumberEvents 2
|
||||
#define RRNumberRequests 45
|
||||
|
||||
#define X_RRQueryVersion 0
|
||||
/* we skip 1 to make old clients fail pretty immediately */
|
||||
#define X_RROldGetScreenInfo 1
|
||||
#define X_RR1_0SetScreenConfig 2
|
||||
/* V1.0 apps share the same set screen config request id */
|
||||
#define X_RRSetScreenConfig 2
|
||||
#define X_RROldScreenChangeSelectInput 3
|
||||
/* 3 used to be ScreenChangeSelectInput; deprecated */
|
||||
#define X_RRSelectInput 4
|
||||
#define X_RRGetScreenInfo 5
|
||||
|
||||
/* V1.2 additions */
|
||||
#define X_RRGetScreenSizeRange 6
|
||||
#define X_RRSetScreenSize 7
|
||||
#define X_RRGetScreenResources 8
|
||||
#define X_RRGetOutputInfo 9
|
||||
#define X_RRListOutputProperties 10
|
||||
#define X_RRQueryOutputProperty 11
|
||||
#define X_RRConfigureOutputProperty 12
|
||||
#define X_RRChangeOutputProperty 13
|
||||
#define X_RRDeleteOutputProperty 14
|
||||
#define X_RRGetOutputProperty 15
|
||||
#define X_RRCreateMode 16
|
||||
#define X_RRDestroyMode 17
|
||||
#define X_RRAddOutputMode 18
|
||||
#define X_RRDeleteOutputMode 19
|
||||
#define X_RRGetCrtcInfo 20
|
||||
#define X_RRSetCrtcConfig 21
|
||||
#define X_RRGetCrtcGammaSize 22
|
||||
#define X_RRGetCrtcGamma 23
|
||||
#define X_RRSetCrtcGamma 24
|
||||
|
||||
/* V1.3 additions */
|
||||
#define X_RRGetScreenResourcesCurrent 25
|
||||
#define X_RRSetCrtcTransform 26
|
||||
#define X_RRGetCrtcTransform 27
|
||||
#define X_RRGetPanning 28
|
||||
#define X_RRSetPanning 29
|
||||
#define X_RRSetOutputPrimary 30
|
||||
#define X_RRGetOutputPrimary 31
|
||||
|
||||
#define RRTransformUnit (1L << 0)
|
||||
#define RRTransformScaleUp (1L << 1)
|
||||
#define RRTransformScaleDown (1L << 2)
|
||||
#define RRTransformProjective (1L << 3)
|
||||
|
||||
/* v1.4 */
|
||||
#define X_RRGetProviders 32
|
||||
#define X_RRGetProviderInfo 33
|
||||
#define X_RRSetProviderOffloadSink 34
|
||||
#define X_RRSetProviderOutputSource 35
|
||||
#define X_RRListProviderProperties 36
|
||||
#define X_RRQueryProviderProperty 37
|
||||
#define X_RRConfigureProviderProperty 38
|
||||
#define X_RRChangeProviderProperty 39
|
||||
#define X_RRDeleteProviderProperty 40
|
||||
#define X_RRGetProviderProperty 41
|
||||
|
||||
/* v1.5 */
|
||||
#define X_RRGetMonitors 42
|
||||
#define X_RRSetMonitor 43
|
||||
#define X_RRDeleteMonitor 44
|
||||
|
||||
/* Event selection bits */
|
||||
#define RRScreenChangeNotifyMask (1L << 0)
|
||||
/* V1.2 additions */
|
||||
#define RRCrtcChangeNotifyMask (1L << 1)
|
||||
#define RROutputChangeNotifyMask (1L << 2)
|
||||
#define RROutputPropertyNotifyMask (1L << 3)
|
||||
/* V1.4 additions */
|
||||
#define RRProviderChangeNotifyMask (1L << 4)
|
||||
#define RRProviderPropertyNotifyMask (1L << 5)
|
||||
#define RRResourceChangeNotifyMask (1L << 6)
|
||||
|
||||
/* Event codes */
|
||||
#define RRScreenChangeNotify 0
|
||||
/* V1.2 additions */
|
||||
#define RRNotify 1
|
||||
/* RRNotify Subcodes */
|
||||
#define RRNotify_CrtcChange 0
|
||||
#define RRNotify_OutputChange 1
|
||||
#define RRNotify_OutputProperty 2
|
||||
#define RRNotify_ProviderChange 3
|
||||
#define RRNotify_ProviderProperty 4
|
||||
#define RRNotify_ResourceChange 5
|
||||
/* used in the rotation field; rotation and reflection in 0.1 proto. */
|
||||
#define RR_Rotate_0 1
|
||||
#define RR_Rotate_90 2
|
||||
#define RR_Rotate_180 4
|
||||
#define RR_Rotate_270 8
|
||||
|
||||
/* new in 1.0 protocol, to allow reflection of screen */
|
||||
|
||||
#define RR_Reflect_X 16
|
||||
#define RR_Reflect_Y 32
|
||||
|
||||
#define RRSetConfigSuccess 0
|
||||
#define RRSetConfigInvalidConfigTime 1
|
||||
#define RRSetConfigInvalidTime 2
|
||||
#define RRSetConfigFailed 3
|
||||
|
||||
/* new in 1.2 protocol */
|
||||
|
||||
#define RR_HSyncPositive 0x00000001
|
||||
#define RR_HSyncNegative 0x00000002
|
||||
#define RR_VSyncPositive 0x00000004
|
||||
#define RR_VSyncNegative 0x00000008
|
||||
#define RR_Interlace 0x00000010
|
||||
#define RR_DoubleScan 0x00000020
|
||||
#define RR_CSync 0x00000040
|
||||
#define RR_CSyncPositive 0x00000080
|
||||
#define RR_CSyncNegative 0x00000100
|
||||
#define RR_HSkewPresent 0x00000200
|
||||
#define RR_BCast 0x00000400
|
||||
#define RR_PixelMultiplex 0x00000800
|
||||
#define RR_DoubleClock 0x00001000
|
||||
#define RR_ClockDivideBy2 0x00002000
|
||||
|
||||
#define RR_Connected 0
|
||||
#define RR_Disconnected 1
|
||||
#define RR_UnknownConnection 2
|
||||
|
||||
#define BadRROutput 0
|
||||
#define BadRRCrtc 1
|
||||
#define BadRRMode 2
|
||||
#define BadRRProvider 3
|
||||
|
||||
/* Conventional RandR output properties */
|
||||
|
||||
#define RR_PROPERTY_BACKLIGHT "Backlight"
|
||||
#define RR_PROPERTY_RANDR_EDID "EDID"
|
||||
#define RR_PROPERTY_SIGNAL_FORMAT "SignalFormat"
|
||||
#define RR_PROPERTY_SIGNAL_PROPERTIES "SignalProperties"
|
||||
#define RR_PROPERTY_CONNECTOR_TYPE "ConnectorType"
|
||||
#define RR_PROPERTY_CONNECTOR_NUMBER "ConnectorNumber"
|
||||
#define RR_PROPERTY_COMPATIBILITY_LIST "CompatibilityList"
|
||||
#define RR_PROPERTY_CLONE_LIST "CloneList"
|
||||
#define RR_PROPERTY_BORDER "Border"
|
||||
#define RR_PROPERTY_BORDER_DIMENSIONS "BorderDimensions"
|
||||
#define RR_PROPERTY_GUID "GUID"
|
||||
#define RR_PROPERTY_RANDR_TILE "TILE"
|
||||
|
||||
/* roles this device can carry out */
|
||||
#define RR_Capability_None 0
|
||||
#define RR_Capability_SourceOutput 1
|
||||
#define RR_Capability_SinkOutput 2
|
||||
#define RR_Capability_SourceOffload 4
|
||||
#define RR_Capability_SinkOffload 8
|
||||
|
||||
#endif /* _RANDR_H_ */
|
||||
#endif
|
Binary file not shown.
|
@ -144,6 +144,32 @@ static int is_maximized(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int toggle_always_on_top(lua_State *L)
|
||||
{
|
||||
defos_toggle_always_on_top();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_always_on_top(lua_State *L)
|
||||
{
|
||||
if (checkboolean(L, 1) != defos_is_always_on_top()) {
|
||||
defos_toggle_always_on_top();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_always_on_top(lua_State *L)
|
||||
{
|
||||
lua_pushboolean(L, defos_is_always_on_top());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int minimize(lua_State *L)
|
||||
{
|
||||
defos_minimize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_window_icon(lua_State *L)
|
||||
{
|
||||
const char *icon_path = luaL_checkstring(L, 1);
|
||||
|
@ -159,19 +185,18 @@ static int get_bundle_root(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int get_parameters(lua_State *L)
|
||||
static int get_arguments(lua_State *L)
|
||||
{
|
||||
dmArray<char*>* parameters = new dmArray<char*>();
|
||||
defos_get_parameters(parameters);
|
||||
dmArray<char*> arguments;
|
||||
defos_get_arguments(arguments);
|
||||
lua_newtable(L);
|
||||
for(int i = 0; i < parameters->Size(); i++)
|
||||
for (unsigned int i = 0; i < arguments.Size(); i++)
|
||||
{
|
||||
char* param = (*parameters)[i];
|
||||
lua_pushstring(L, param);
|
||||
char* arg = arguments[i];
|
||||
lua_pushstring(L, arg);
|
||||
lua_rawseti(L, 1, i+1);
|
||||
free(param);
|
||||
free(arg);
|
||||
}
|
||||
delete parameters;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -209,6 +234,24 @@ static int is_cursor_visible(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int get_cursor_pos(lua_State *L)
|
||||
{
|
||||
WinPoint point;
|
||||
point = defos_get_cursor_pos();
|
||||
lua_pushnumber(L, point.x);
|
||||
lua_pushnumber(L, point.y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int get_cursor_pos_view(lua_State *L)
|
||||
{
|
||||
WinPoint point;
|
||||
point = defos_get_cursor_pos_view();
|
||||
lua_pushnumber(L, point.x);
|
||||
lua_pushnumber(L, point.y);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int set_cursor_pos(lua_State *L)
|
||||
{
|
||||
float x = luaL_checknumber(L, 1);
|
||||
|
@ -216,11 +259,11 @@ static int set_cursor_pos(lua_State *L)
|
|||
defos_set_cursor_pos(x, y);
|
||||
return 0;
|
||||
}
|
||||
static int move_cursor_to(lua_State *L)
|
||||
static int set_cursor_pos_view(lua_State *L)
|
||||
{
|
||||
float x = luaL_checknumber(L, 1);
|
||||
float y = luaL_checknumber(L, 2);
|
||||
defos_move_cursor_to(x, y);
|
||||
defos_set_cursor_pos_view(x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -319,6 +362,118 @@ static int reset_cursor(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Displays
|
||||
|
||||
static void push_display_mode(lua_State *L, const DisplayModeInfo &mode)
|
||||
{
|
||||
lua_newtable(L);
|
||||
lua_pushnumber(L, mode.width);
|
||||
lua_setfield(L, -2, "width");
|
||||
lua_pushnumber(L, mode.height);
|
||||
lua_setfield(L, -2, "height");
|
||||
lua_pushnumber(L, mode.refresh_rate);
|
||||
lua_setfield(L, -2, "refresh_rate");
|
||||
lua_pushnumber(L, mode.scaling_factor);
|
||||
lua_setfield(L, -2, "scaling_factor");
|
||||
lua_pushnumber(L, mode.bits_per_pixel);
|
||||
lua_setfield(L, -2, "bits_per_pixel");
|
||||
lua_pushnumber(L, mode.orientation);
|
||||
lua_setfield(L, -2, "orientation");
|
||||
lua_pushboolean(L, mode.reflect_x);
|
||||
lua_setfield(L, -2, "reflect_x");
|
||||
lua_pushboolean(L, mode.reflect_y);
|
||||
lua_setfield(L, -2, "reflect_y");
|
||||
}
|
||||
|
||||
static int get_displays(lua_State *L)
|
||||
{
|
||||
dmArray<DisplayInfo> displayList;
|
||||
defos_get_displays(displayList);
|
||||
|
||||
lua_newtable(L); // Final result
|
||||
for (int i = 0; i < displayList.Size(); i++)
|
||||
{
|
||||
DisplayInfo &display = displayList[i];
|
||||
lua_newtable(L); // The display info table
|
||||
|
||||
#ifdef DM_PLATFORM_WINDOWS
|
||||
lua_pushstring(L, display.id);
|
||||
free(const_cast<char*>(display.id));
|
||||
#else
|
||||
lua_pushlightuserdata(L, display.id);
|
||||
#endif
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -3, "id");
|
||||
|
||||
// screen positioning bounds
|
||||
lua_newtable(L);
|
||||
lua_pushnumber(L, display.bounds.x);
|
||||
lua_setfield(L, -2, "x");
|
||||
lua_pushnumber(L, display.bounds.y);
|
||||
lua_setfield(L, -2, "y");
|
||||
lua_pushnumber(L, display.bounds.w);
|
||||
lua_setfield(L, -2, "width");
|
||||
lua_pushnumber(L, display.bounds.h);
|
||||
lua_setfield(L, -2, "height");
|
||||
lua_setfield(L, -3, "bounds");
|
||||
|
||||
push_display_mode(L, display.mode);
|
||||
lua_setfield(L, -3, "mode");
|
||||
|
||||
if (display.name)
|
||||
{
|
||||
lua_pushstring(L, display.name);
|
||||
lua_setfield(L, -3, "name");
|
||||
free(display.name);
|
||||
}
|
||||
|
||||
// result[id] = display
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, -4);
|
||||
|
||||
// result[i + 1] = display
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_display_modes(lua_State *L)
|
||||
{
|
||||
#ifdef DM_PLATFORM_WINDOWS
|
||||
DisplayID displayID = luaL_checkstring(L, 1);
|
||||
#else
|
||||
luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
|
||||
DisplayID displayID = lua_touserdata(L, 1);
|
||||
#endif
|
||||
|
||||
dmArray<DisplayModeInfo> modeList;
|
||||
defos_get_display_modes(displayID, modeList);
|
||||
|
||||
lua_newtable(L);
|
||||
for (int i = 0; i < modeList.Size(); i++)
|
||||
{
|
||||
push_display_mode(L, modeList[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_current_display_id(lua_State *L)
|
||||
{
|
||||
DisplayID displayID = defos_get_current_display();
|
||||
|
||||
#ifdef DM_PLATFORM_WINDOWS
|
||||
lua_pushstring(L, displayID);
|
||||
free(const_cast<char*>(displayID));
|
||||
#else
|
||||
lua_pushlightuserdata(L, displayID);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Events
|
||||
|
||||
static void set_event_handler(lua_State *L, int index, DefosEvent event)
|
||||
|
@ -366,7 +521,7 @@ static int on_mouse_enter(lua_State *L)
|
|||
static int on_click(lua_State *L)
|
||||
{
|
||||
#ifndef DM_PLATFORM_HTML5
|
||||
dmLogInfo("Event 'on_click' exists only on HTML5");
|
||||
dmLogWarning("Event 'on_click' exists only in HTML5");
|
||||
#endif
|
||||
set_event_handler(L, 1, DEFOS_EVENT_CLICK);
|
||||
return 0;
|
||||
|
@ -419,10 +574,14 @@ static const luaL_reg Module_methods[] =
|
|||
{"toggle_fullscreen", toggle_fullscreen},
|
||||
{"set_fullscreen", set_fullscreen},
|
||||
{"is_fullscreen", is_fullscreen},
|
||||
{"toggle_always_on_top", toggle_always_on_top},
|
||||
{"set_always_on_top", set_always_on_top},
|
||||
{"is_always_on_top", is_always_on_top},
|
||||
{"toggle_maximize", toggle_maximized}, // For backwards compatibility
|
||||
{"toggle_maximized", toggle_maximized},
|
||||
{"set_maximized", set_maximized},
|
||||
{"is_maximized", is_maximized},
|
||||
{"minimize", minimize},
|
||||
{"set_console_visible", set_console_visible},
|
||||
{"is_console_visible", is_console_visible},
|
||||
{"set_cursor_visible", set_cursor_visible},
|
||||
|
@ -431,8 +590,11 @@ static const luaL_reg Module_methods[] =
|
|||
{"on_mouse_leave", on_mouse_leave},
|
||||
{"on_click", on_click},
|
||||
{"is_mouse_in_view", is_mouse_in_view},
|
||||
{"get_cursor_pos", get_cursor_pos},
|
||||
{"get_cursor_pos_view", get_cursor_pos_view},
|
||||
{"set_cursor_pos", set_cursor_pos},
|
||||
{"move_cursor_to", move_cursor_to},
|
||||
{"set_cursor_pos_view", set_cursor_pos_view},
|
||||
{"move_cursor_to", set_cursor_pos_view}, // For backwards compatibility
|
||||
{"set_cursor_clipped", set_cursor_clipped},
|
||||
{"is_cursor_clipped", is_cursor_clipped},
|
||||
{"set_cursor_locked", set_cursor_locked},
|
||||
|
@ -442,16 +604,20 @@ static const luaL_reg Module_methods[] =
|
|||
{"get_view_size", get_view_size},
|
||||
{"set_cursor", set_cursor},
|
||||
{"reset_cursor", reset_cursor},
|
||||
{"get_displays", get_displays},
|
||||
{"get_display_modes", get_display_modes},
|
||||
{"get_current_display_id", get_current_display_id},
|
||||
{"set_window_icon", set_window_icon},
|
||||
{"get_bundle_root", get_bundle_root},
|
||||
{"get_parameters", get_parameters},
|
||||
{"get_arguments", get_arguments},
|
||||
{"get_parameters", get_arguments}, // For backwards compatibility
|
||||
{0, 0}};
|
||||
|
||||
static void LuaInit(lua_State *L)
|
||||
{
|
||||
int top = lua_gettop(L);
|
||||
luaL_register(L, MODULE_NAME, Module_methods);
|
||||
|
||||
|
||||
lua_pushnumber(L, DEFOS_CURSOR_ARROW);
|
||||
lua_setfield(L, -2, "CURSOR_ARROW");
|
||||
lua_pushnumber(L, DEFOS_CURSOR_CROSSHAIR);
|
||||
|
@ -460,15 +626,15 @@ static void LuaInit(lua_State *L)
|
|||
lua_setfield(L, -2, "CURSOR_HAND");
|
||||
lua_pushnumber(L, DEFOS_CURSOR_IBEAM);
|
||||
lua_setfield(L, -2, "CURSOR_IBEAM");
|
||||
|
||||
|
||||
#if defined(DM_PLATFORM_WINDOWS)
|
||||
lua_pushstring(L, "\\");
|
||||
lua_setfield(L, -2, "PATH_SEP");
|
||||
#else
|
||||
lua_pushstring(L, "/");
|
||||
lua_setfield(L, -2, "PATH_SEP");
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
lua_pop(L, 1);
|
||||
assert(top == lua_gettop(L));
|
||||
}
|
||||
|
@ -510,4 +676,4 @@ dmExtension::Result FinalizeDefos(dmExtension::Params *params)
|
|||
}
|
||||
|
||||
DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, 0, 0, InitializeDefos, 0, 0, FinalizeDefos)
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -49,9 +49,17 @@ void defos_init() {
|
|||
Module.__defosjs_click_listener = function () {
|
||||
_defos_emit_event_from_js($2);
|
||||
};
|
||||
Module.__defosjs_mousemove_listener = function (evt) {
|
||||
var rect = Module.canvas.getBoundingClientRect();
|
||||
Module.__defosjs_mouse_x = evt.clientX - rect.left;
|
||||
Module.__defosjs_mouse_y = evt.clientY - rect.top;
|
||||
};
|
||||
Module.__defosjs_mouse_x = -1;
|
||||
Module.__defosjs_mouse_y = -1;
|
||||
Module.canvas.addEventListener('mouseenter', Module.__defosjs_mouseenter_listener);
|
||||
Module.canvas.addEventListener('mouseleave', Module.__defosjs_mouseleave_listener);
|
||||
Module.canvas.addEventListener('click', Module.__defosjs_click_listener);
|
||||
document.addEventListener('mousemove', Module.__defosjs_mousemove_listener);
|
||||
}, DEFOS_EVENT_MOUSE_ENTER, DEFOS_EVENT_MOUSE_LEAVE, DEFOS_EVENT_CLICK);
|
||||
|
||||
EM_ASM_({
|
||||
|
@ -86,6 +94,7 @@ void defos_final() {
|
|||
Module.canvas.removeEventListener('mouseenter', Module.__defosjs_mouseenter_listener);
|
||||
Module.canvas.removeEventListener('mouseleave', Module.__defosjs_mouseleave_listener);
|
||||
Module.canvas.removeEventListener('click', Module.__defosjs_click_listener);
|
||||
document.removeEventListener('mousemove', Module.__defosjs_mousemove_listener);
|
||||
document.removeEventListener('pointerlockchange', Module.__defosjs_pointerlockchange_listener);
|
||||
document.removeEventListener('mozpointerlockchange', Module.__defosjs_pointerlockchange_listener);
|
||||
document.removeEventListener('webkitpointerlockchange', Module.__defosjs_pointerlockchange_listener);
|
||||
|
@ -100,15 +109,19 @@ void defos_event_handler_was_set(DefosEvent event) {
|
|||
}
|
||||
|
||||
void defos_disable_maximize_button() {
|
||||
dmLogInfo("Method 'disable_maximize_button' is not supported in html5");
|
||||
dmLogWarning("Method 'disable_maximize_button' is not supported in HTML5");
|
||||
}
|
||||
|
||||
void defos_disable_minimize_button() {
|
||||
dmLogInfo("Method 'disable_minimize_button' is not supported in html5");
|
||||
dmLogWarning("Method 'disable_minimize_button' is not supported in HTML5");
|
||||
}
|
||||
|
||||
void defos_disable_window_resize() {
|
||||
dmLogInfo("Method 'disable_window_resize' is not supported in html5");
|
||||
dmLogWarning("Method 'disable_window_resize' is not supported in HTML5");
|
||||
}
|
||||
|
||||
void defos_minimize() {
|
||||
dmLogWarning("Method 'minimize' is not supported in HTML5");
|
||||
}
|
||||
|
||||
void defos_toggle_fullscreen() {
|
||||
|
@ -140,6 +153,14 @@ bool defos_is_maximized() {
|
|||
return is_maximized;
|
||||
}
|
||||
|
||||
void defos_toggle_always_on_top() {
|
||||
dmLogWarning("Method 'toggle_always_on_top' is not supported in HTML5");
|
||||
}
|
||||
|
||||
bool defos_is_always_on_top() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void defos_set_window_title(const char* title_lua) {
|
||||
EM_ASM_({document.title = UTF8ToString($0)}, title_lua);
|
||||
}
|
||||
|
@ -152,7 +173,7 @@ void defos_set_window_icon(const char *icon_path)
|
|||
if (oldLink) { document.head.removeChild(oldLink); }
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'shortcut icon';
|
||||
link.href = src;
|
||||
link.href = src;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
changeFavicon(UTF8ToString($0));
|
||||
|
@ -170,16 +191,16 @@ char* defos_get_bundle_root() {
|
|||
return bundlePath;
|
||||
}
|
||||
|
||||
void defos_get_parameters(dmArray<char*>* parameters) {
|
||||
char*param = (char*)EM_ASM_INT({
|
||||
void defos_get_arguments(dmArray<char*> &arguments) {
|
||||
char *param = (char*)EM_ASM_INT({
|
||||
var jsString = window.location.search;
|
||||
var lengthBytes = lengthBytesUTF8(jsString) + 1;
|
||||
var stringOnWasmHeap = _malloc(lengthBytes);
|
||||
stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1);
|
||||
return stringOnWasmHeap;
|
||||
},0);
|
||||
parameters->OffsetCapacity(1);
|
||||
parameters->Push(param);
|
||||
arguments.OffsetCapacity(1);
|
||||
arguments.Push(param);
|
||||
}
|
||||
|
||||
void defos_set_window_size(float x, float y, float w, float h) {
|
||||
|
@ -215,7 +236,7 @@ bool defos_is_console_visible() {
|
|||
}
|
||||
|
||||
void defos_set_console_visible(bool visible) {
|
||||
dmLogInfo("Method 'defos_set_console_visible' is not supported in html5, it is meant for Windows builds only");
|
||||
dmLogWarning("Method 'set_console_visible' is only supported on Windows");
|
||||
}
|
||||
|
||||
void defos_set_cursor_visible(bool visible) {
|
||||
|
@ -236,16 +257,27 @@ bool defos_is_mouse_in_view() {
|
|||
return is_mouse_inside;
|
||||
}
|
||||
|
||||
void defos_set_cursor_pos(float x, float y) {
|
||||
dmLogInfo("Method 'defos_set_cursor_pos' is not supported in html5");
|
||||
WinPoint defos_get_cursor_pos() {
|
||||
return defos_get_cursor_pos_view();
|
||||
}
|
||||
|
||||
void defos_move_cursor_to(float x, float y) {
|
||||
dmLogInfo("Method 'defos_move_cursor_to' is not supported in html5");
|
||||
WinPoint defos_get_cursor_pos_view() {
|
||||
WinPoint point;
|
||||
point.x = (float)EM_ASM_DOUBLE({ return Module.__defosjs_mouse_x }, 0.0);
|
||||
point.y = (float)EM_ASM_DOUBLE({ return Module.__defosjs_mouse_y }, 0.0);
|
||||
return point;
|
||||
}
|
||||
|
||||
void defos_set_cursor_pos(float x, float y) {
|
||||
dmLogWarning("Method 'defos_set_cursor_pos' is not supported in HTML5");
|
||||
}
|
||||
|
||||
void defos_set_cursor_pos_view(float x, float y) {
|
||||
dmLogWarning("Method 'defos_set_cursor_pos_view' is not supported in HTML5");
|
||||
}
|
||||
|
||||
void defos_set_cursor_clipped(bool clipped) {
|
||||
dmLogInfo("Method 'defos_set_cursor_clipped' is not supported in html5");
|
||||
dmLogWarning("Method 'defos_set_cursor_clipped' is not supported in HTML5");
|
||||
}
|
||||
|
||||
bool defos_is_cursor_clipped() {
|
||||
|
@ -334,4 +366,14 @@ void defos_reset_cursor() {
|
|||
}
|
||||
}
|
||||
|
||||
void defos_get_displays(dmArray<DisplayInfo> &displayList) {
|
||||
}
|
||||
|
||||
void defos_get_display_modes(DisplayID displayID, dmArray<DisplayModeInfo> &modeList) {
|
||||
}
|
||||
|
||||
DisplayID defos_get_current_display() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,13 @@
|
|||
3. https://github.com/yetanothergeek/xctrl/blob/master/src/xctrl.c
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
ON_MOUSE_ENTER / ON_MOUSE_LEAVE
|
||||
cursor locking
|
||||
cursor clipping
|
||||
setting the window icon
|
||||
*/
|
||||
|
||||
#include "defos_private.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
@ -17,10 +24,17 @@
|
|||
#include <X11/Xos.h>
|
||||
#include <X11/cursorfont.h>
|
||||
#include <Xcursor.h>
|
||||
#include <Xrandr.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <limits.h>
|
||||
|
||||
//static GC gc;
|
||||
#define _NET_WM_STATE_REMOVE 0
|
||||
#define _NET_WM_STATE_ADD 1
|
||||
#define _NET_WM_STATE_REMOVE 0
|
||||
#define _NET_WM_STATE_ADD 1
|
||||
#define _NET_WM_STATE_TOGGLE 2
|
||||
#define XATOM(name) XInternAtom(disp, name, False)
|
||||
|
||||
|
@ -36,18 +50,21 @@ static Atom NET_WM_STATE;
|
|||
static Atom NET_WM_STATE_FULLSCREEN;
|
||||
static Atom NET_WM_STATE_MAXIMIZED_VERT;
|
||||
static Atom NET_WM_STATE_MAXIMIZED_HORZ;
|
||||
static Atom NET_WM_STATE_ABOVE;
|
||||
static Atom NET_WM_ALLOWED_ACTIONS;
|
||||
static Atom NET_WM_ACTION_MAXIMIZE_HORZ;
|
||||
static Atom NET_WM_ACTION_MAXIMIZE_VERT;
|
||||
static Atom NET_WM_ACTION_MINIMIZE;
|
||||
static Atom NET_FRAME_EXTENTS;
|
||||
|
||||
// TODO: should query state from system
|
||||
static bool is_maximized = false;
|
||||
static bool is_fullscreen = false;
|
||||
|
||||
static Cursor custom_cursor;// image cursor
|
||||
|
||||
static Cursor custom_cursor; // image cursor
|
||||
static bool has_custom_cursor = false;
|
||||
static Cursor invisible_cursor;
|
||||
static bool is_cursor_visible = true;
|
||||
static bool resize_locked = false;
|
||||
|
||||
static bool is_window_visible(Window window);
|
||||
static void send_message(Window& window, Atom type, long a, long b, long c, long d,long e);
|
||||
|
||||
static void send_message(Window &window, Atom type, long a, long b, long c, long d, long e);
|
||||
|
||||
void defos_init()
|
||||
{
|
||||
|
@ -63,120 +80,242 @@ void defos_init()
|
|||
NET_WM_STATE_FULLSCREEN = XATOM("_NET_WM_STATE_FULLSCREEN");
|
||||
NET_WM_STATE_MAXIMIZED_VERT = XATOM("_NET_WM_STATE_MAXIMIZED_VERT");
|
||||
NET_WM_STATE_MAXIMIZED_HORZ = XATOM("_NET_WM_STATE_MAXIMIZED_HORZ");
|
||||
NET_WM_STATE_ABOVE = XATOM("_NET_WM_STATE_ABOVE");
|
||||
NET_WM_ALLOWED_ACTIONS = XATOM("_NET_WM_ALLOWED_ACTIONS");
|
||||
NET_WM_ACTION_MINIMIZE = XATOM("_NET_WM_ACTION_MINIMIZE");
|
||||
NET_WM_ACTION_MAXIMIZE_HORZ = XATOM("_NET_WM_ACTION_MAXIMIZE_HORZ");
|
||||
NET_WM_ACTION_MAXIMIZE_VERT = XATOM("_NET_WM_ACTION_MAXIMIZE_VERT");
|
||||
NET_FRAME_EXTENTS = XATOM("_NET_FRAME_EXTENTS");
|
||||
|
||||
resize_locked = false;
|
||||
|
||||
// Create invisible cursor
|
||||
Pixmap bitmapNoData;
|
||||
XColor black;
|
||||
static char noData[] = { 0,0,0,0,0,0,0,0 };
|
||||
black.red = black.green = black.blue = 0;
|
||||
|
||||
bitmapNoData = XCreateBitmapFromData(disp, win, noData, 8, 8);
|
||||
invisible_cursor = XCreatePixmapCursor(disp, bitmapNoData, bitmapNoData, &black, &black, 0, 0);
|
||||
XFreePixmap(disp, bitmapNoData);
|
||||
|
||||
is_cursor_visible = true;
|
||||
}
|
||||
|
||||
void defos_final()
|
||||
{
|
||||
if(custom_cursor==NULL)
|
||||
if (has_custom_cursor)
|
||||
{
|
||||
XFreeCursor(disp, custom_cursor);
|
||||
has_custom_cursor = false;
|
||||
}
|
||||
|
||||
XFreeCursor(disp, invisible_cursor);
|
||||
}
|
||||
|
||||
void defos_event_handler_was_set(DefosEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
static Atom* get_atom_list(Atom property, unsigned long &nItems)
|
||||
{
|
||||
Atom actualType;
|
||||
int actualFormat;
|
||||
unsigned long bytesAfter;
|
||||
Atom* data = NULL;
|
||||
XEvent event;
|
||||
while (XGetWindowProperty(disp, win, property,
|
||||
0, (~0L), False, AnyPropertyType,
|
||||
&actualType, &actualFormat,
|
||||
&nItems, &bytesAfter, (unsigned char**)&data) == Success && bytesAfter != 0
|
||||
) {
|
||||
XNextEvent(disp, &event);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static bool hint_state_contains_atom(Atom atom)
|
||||
{
|
||||
unsigned long nItems;
|
||||
Atom* data = get_atom_list(NET_WM_STATE, nItems);
|
||||
|
||||
if (data) {
|
||||
for (unsigned int i = 0; i < nItems; i++) {
|
||||
if (data[i] == atom) {
|
||||
XFree(data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool defos_is_fullscreen()
|
||||
{
|
||||
return is_fullscreen;
|
||||
return hint_state_contains_atom(NET_WM_STATE_FULLSCREEN);
|
||||
}
|
||||
|
||||
bool defos_is_maximized()
|
||||
{
|
||||
return is_maximized;
|
||||
return hint_state_contains_atom(NET_WM_STATE_MAXIMIZED_VERT);
|
||||
}
|
||||
|
||||
bool defos_is_always_on_top()
|
||||
{
|
||||
return hint_state_contains_atom(NET_WM_STATE_ABOVE);
|
||||
}
|
||||
|
||||
bool defos_is_mouse_in_view()
|
||||
{
|
||||
return false;
|
||||
Window d1, d2;
|
||||
int x, y, d3, d4;
|
||||
unsigned int d5;
|
||||
if (!XQueryPointer(disp, win, &d1, &d2, &d3, &d4, &x, &y, &d5)) { return false; }
|
||||
|
||||
if (x < 0 || y < 0) { return false; }
|
||||
|
||||
unsigned int w, h, d6;
|
||||
XGetGeometry(disp, win, &d1, &d3, &d4, &w, &h, &d5, &d6);
|
||||
|
||||
if ((unsigned)x >= w || (unsigned)y >= h) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
void defos_disable_maximize_button()
|
||||
{
|
||||
dmLogInfo("Method 'defos_disable_maximize_button' is not supported in Linux");
|
||||
unsigned long nItems;
|
||||
Atom* data = get_atom_list(NET_WM_ALLOWED_ACTIONS, nItems);
|
||||
|
||||
if (!data) { return; }
|
||||
|
||||
// Filter the allowed actions list
|
||||
Atom* newList = (Atom*)malloc(sizeof(Atom) * nItems);
|
||||
unsigned long newNItems = 0;
|
||||
for (unsigned long i = 0; i < nItems; i++) {
|
||||
if (data[i] == NET_WM_ACTION_MAXIMIZE_HORZ || data[i] == NET_WM_ACTION_MAXIMIZE_VERT) { continue; }
|
||||
newList[newNItems++] = data[i];
|
||||
}
|
||||
XFree(data);
|
||||
|
||||
XChangeProperty(disp, win, NET_WM_ALLOWED_ACTIONS, XA_ATOM, 32, PropModeReplace, (unsigned char*)newList, newNItems);
|
||||
XFlush(disp);
|
||||
free(newList);
|
||||
}
|
||||
|
||||
void defos_disable_minimize_button()
|
||||
{
|
||||
dmLogInfo("Method 'defos_disable_minimize_button' is not supported in Linux");
|
||||
unsigned long nItems;
|
||||
Atom* data = get_atom_list(NET_WM_ALLOWED_ACTIONS, nItems);
|
||||
|
||||
if (!data) { return; }
|
||||
|
||||
// Filter the allowed actions list
|
||||
Atom* newList = (Atom*)malloc(sizeof(Atom) * nItems);
|
||||
unsigned long newNItems = 0;
|
||||
for (unsigned long i = 0; i < nItems; i++) {
|
||||
if (data[i] == NET_WM_ACTION_MINIMIZE) { return; }
|
||||
newList[newNItems++] = data[i];
|
||||
}
|
||||
XFree(data);
|
||||
|
||||
XChangeProperty(disp, win, NET_WM_ALLOWED_ACTIONS, XA_ATOM, 32, PropModeReplace, (unsigned char*)newList, newNItems);
|
||||
XFlush(disp);
|
||||
free(newList);
|
||||
}
|
||||
|
||||
static void lock_resize(int width, int height)
|
||||
{
|
||||
XSizeHints *sizeHints = XAllocSizeHints();
|
||||
sizeHints->flags = PMinSize | PMaxSize;
|
||||
sizeHints->min_width = width;
|
||||
sizeHints->min_height = height;
|
||||
sizeHints->max_width = width;
|
||||
sizeHints->max_height = height;
|
||||
|
||||
XSetWMNormalHints(disp, win, sizeHints);
|
||||
XFlush(disp);
|
||||
XFree(sizeHints);
|
||||
|
||||
resize_locked = true;
|
||||
}
|
||||
|
||||
void defos_disable_window_resize()
|
||||
{
|
||||
dmLogInfo("Method 'defos_disable_window_resize' is not supported in Linux");
|
||||
int x, y;
|
||||
unsigned int w, h, bw, depth;
|
||||
|
||||
Window dummy;
|
||||
XGetGeometry(disp, win, &dummy, &x, &y, &w, &h, &bw, &depth);
|
||||
|
||||
lock_resize(w, h);
|
||||
}
|
||||
|
||||
void defos_set_cursor_visible(bool visible)
|
||||
{
|
||||
dmLogInfo("Method 'defos_set_cursor_visible' is not supported in Linux");
|
||||
if (visible == is_cursor_visible) { return; }
|
||||
is_cursor_visible = visible;
|
||||
if (visible)
|
||||
{
|
||||
XDefineCursor(disp, win, has_custom_cursor ? custom_cursor : None);
|
||||
} else {
|
||||
XDefineCursor(disp, win, invisible_cursor);
|
||||
}
|
||||
}
|
||||
|
||||
bool defos_is_cursor_visible()
|
||||
{
|
||||
return false;
|
||||
return is_cursor_visible;
|
||||
}
|
||||
|
||||
void defos_toggle_fullscreen()
|
||||
{
|
||||
if(!is_fullscreen)
|
||||
{
|
||||
send_message(win,
|
||||
NET_WM_STATE,
|
||||
_NET_WM_STATE_ADD,
|
||||
NET_WM_STATE_FULLSCREEN,
|
||||
0,
|
||||
1,
|
||||
0);
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
send_message(win,
|
||||
NET_WM_STATE,
|
||||
_NET_WM_STATE_REMOVE,
|
||||
NET_WM_STATE_FULLSCREEN,
|
||||
0,
|
||||
1,
|
||||
0);
|
||||
}
|
||||
|
||||
is_fullscreen = !is_fullscreen;
|
||||
send_message(win,
|
||||
NET_WM_STATE,
|
||||
_NET_WM_STATE_TOGGLE,
|
||||
NET_WM_STATE_FULLSCREEN,
|
||||
0,
|
||||
1,
|
||||
0
|
||||
);
|
||||
XFlush(disp);
|
||||
}
|
||||
|
||||
void defos_toggle_maximized()
|
||||
{
|
||||
if(!is_maximized)
|
||||
{
|
||||
send_message(win,
|
||||
NET_WM_STATE,
|
||||
_NET_WM_STATE_ADD,
|
||||
NET_WM_STATE_MAXIMIZED_VERT,
|
||||
NET_WM_STATE_MAXIMIZED_HORZ,
|
||||
1,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
send_message(win,
|
||||
NET_WM_STATE,
|
||||
_NET_WM_STATE_REMOVE,
|
||||
NET_WM_STATE_MAXIMIZED_VERT,
|
||||
NET_WM_STATE_MAXIMIZED_HORZ,
|
||||
1,
|
||||
0);
|
||||
}
|
||||
|
||||
is_maximized = !is_maximized;
|
||||
send_message(win,
|
||||
NET_WM_STATE,
|
||||
_NET_WM_STATE_TOGGLE,
|
||||
NET_WM_STATE_MAXIMIZED_VERT,
|
||||
NET_WM_STATE_MAXIMIZED_HORZ,
|
||||
1,
|
||||
0
|
||||
);
|
||||
XFlush(disp);
|
||||
}
|
||||
|
||||
void defos_toggle_always_on_top()
|
||||
{
|
||||
send_message(win,
|
||||
NET_WM_STATE,
|
||||
defos_is_always_on_top() ? _NET_WM_STATE_REMOVE : _NET_WM_STATE_ADD,
|
||||
NET_WM_STATE_ABOVE,
|
||||
0,
|
||||
1,
|
||||
0
|
||||
);
|
||||
XFlush(disp);
|
||||
}
|
||||
|
||||
void defos_minimize()
|
||||
{
|
||||
XIconifyWindow(disp, win, screen);
|
||||
}
|
||||
|
||||
void defos_set_console_visible(bool visible)
|
||||
{
|
||||
dmLogInfo("Method 'defos_set_console_visible' is not supported in Linux");
|
||||
dmLogWarning("Method 'set_console_visible' is only supported on Windows");
|
||||
}
|
||||
|
||||
bool defos_is_console_visible()
|
||||
|
@ -184,19 +323,58 @@ bool defos_is_console_visible()
|
|||
return false;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
long left, right, top, bottom;
|
||||
} WindowExtents;
|
||||
|
||||
static WindowExtents get_window_extents()
|
||||
{
|
||||
Atom actualType;
|
||||
int actualFormat;
|
||||
unsigned long nitems, bytesAfter;
|
||||
long* extents = NULL;
|
||||
XEvent event;
|
||||
while (XGetWindowProperty(disp, win, NET_FRAME_EXTENTS,
|
||||
0, 4, False, AnyPropertyType,
|
||||
&actualType, &actualFormat,
|
||||
&nitems, &bytesAfter, (unsigned char**)&extents) == Success && bytesAfter != 0
|
||||
) {
|
||||
XNextEvent(disp, &event);
|
||||
}
|
||||
|
||||
if (!extents || nitems != 4) {
|
||||
WindowExtents result = { 0, 0, 0, 0 };
|
||||
if (extents) { XFree(extents); }
|
||||
return result;
|
||||
}
|
||||
|
||||
WindowExtents result = { extents[0], extents[1], extents[2], extents[3] };
|
||||
if (extents) { XFree(extents); }
|
||||
return result;
|
||||
}
|
||||
|
||||
static RRCrtc get_current_crtc(WinRect &bounds);
|
||||
|
||||
void defos_set_window_size(float x, float y, float w, float h)
|
||||
{
|
||||
// change size only if it is visible
|
||||
if(is_window_visible(win))
|
||||
if (is_window_visible(win))
|
||||
{
|
||||
if(isnan(x) || isnan(y)){
|
||||
XWindowAttributes attributes;
|
||||
XGetWindowAttributes(disp, root, &attributes);
|
||||
|
||||
x = ((float)attributes.width - w)/2;
|
||||
y = ((float)attributes.height - h)/2;
|
||||
if (isnan(x) || isnan(y))
|
||||
{
|
||||
WinRect screenBounds;
|
||||
get_current_crtc(screenBounds);
|
||||
if (isnan(x)) { x = screenBounds.x + ((float)screenBounds.w - w) / 2; }
|
||||
if (isnan(y)) { y = screenBounds.y + ((float)screenBounds.h - h) / 2; }
|
||||
}
|
||||
|
||||
|
||||
WindowExtents extents = get_window_extents();
|
||||
w -= extents.left + extents.right;
|
||||
h -= extents.top + extents.bottom;
|
||||
x += extents.left;
|
||||
y += extents.top;
|
||||
|
||||
if (resize_locked) { lock_resize(w, h); }
|
||||
XMoveResizeWindow(disp, win, (int)x, (int)y, (unsigned int)w, (unsigned int)h);
|
||||
XFlush(disp);
|
||||
}
|
||||
|
@ -204,68 +382,96 @@ void defos_set_window_size(float x, float y, float w, float h)
|
|||
|
||||
void defos_set_view_size(float x, float y, float w, float h)
|
||||
{
|
||||
XWindowChanges changes;
|
||||
changes.x = (int)x;
|
||||
changes.y = (int)y;
|
||||
changes.width = (int)w;
|
||||
changes.height = (int)h;
|
||||
|
||||
XConfigureWindow(disp, win, CWX | CWY | CWWidth | CWHeight, &changes);
|
||||
XFlush(disp);
|
||||
// change size only if it is visible
|
||||
if (is_window_visible(win))
|
||||
{
|
||||
if (isnan(x) || isnan(y))
|
||||
{
|
||||
WinRect screenBounds;
|
||||
get_current_crtc(screenBounds);
|
||||
if (isnan(x)) { x = screenBounds.x + ((float)screenBounds.w - w) / 2; }
|
||||
if (isnan(y)) { y = screenBounds.y + ((float)screenBounds.h - h) / 2; }
|
||||
}
|
||||
|
||||
if (resize_locked) { lock_resize(w, h); }
|
||||
XMoveResizeWindow(disp, win, (int)x, (int)y, (unsigned int)w, (unsigned int)h);
|
||||
XFlush(disp);
|
||||
}
|
||||
}
|
||||
|
||||
void defos_set_window_title(const char *title_lua)
|
||||
{
|
||||
XChangeProperty(disp, win, NET_WM_NAME, UTF8_STRING, 8, PropModeReplace, (unsigned char*)title_lua, strlen(title_lua));
|
||||
XChangeProperty(disp, win, NET_WM_NAME, UTF8_STRING, 8, PropModeReplace, (unsigned char *)title_lua, strlen(title_lua));
|
||||
XFlush(disp); // IMPORTANT: we have to flush, or nothing will be changed
|
||||
}
|
||||
|
||||
WinRect defos_get_window_size()
|
||||
{
|
||||
WinRect r = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
return r;
|
||||
WindowExtents extents = get_window_extents();
|
||||
WinRect size = defos_get_view_size();
|
||||
|
||||
size.w += extents.left + extents.right;
|
||||
size.h += extents.top + extents.bottom;
|
||||
size.x -= extents.left;
|
||||
size.y -= extents.top;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
WinRect defos_get_view_size()
|
||||
{
|
||||
int x,y;
|
||||
int x, y;
|
||||
unsigned int w, h, bw, depth;
|
||||
|
||||
Window dummy;
|
||||
XGetGeometry(disp, win, &dummy, &x, &y, &w, &h, &bw, &depth);
|
||||
XTranslateCoordinates(disp, win, root, x, y, &x, &y, &dummy);
|
||||
XTranslateCoordinates(disp, win, root, 0, 0, &x, &y, &dummy);
|
||||
|
||||
WinRect r = {(float)x, (float)y, (float)w, (float)h};
|
||||
return r;
|
||||
}
|
||||
|
||||
WinPoint defos_get_cursor_pos()
|
||||
{
|
||||
WinPoint point = { .x = -INFINITY, .y = -INFINITY };
|
||||
Window d1, d2;
|
||||
int x, y, d3, d4;
|
||||
unsigned int d5;
|
||||
if (XQueryPointer(disp, root, &d1, &d2, &d3, &d4, &x, &y, &d5)) {
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
WinPoint defos_get_cursor_pos_view()
|
||||
{
|
||||
WinPoint point = { .x = -INFINITY, .y = -INFINITY };
|
||||
Window d1, d2;
|
||||
int x, y, d3, d4;
|
||||
unsigned int d5;
|
||||
if (XQueryPointer(disp, win, &d1, &d2, &d3, &d4, &x, &y, &d5)) {
|
||||
point.x = x;
|
||||
point.y = y;
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
void defos_set_cursor_pos(float x, float y)
|
||||
{
|
||||
XWarpPointer(disp, None, root, 0, 0, 0, 0, (int)x, (int)y);
|
||||
XFlush(disp);
|
||||
}
|
||||
|
||||
void defos_move_cursor_to(float x, float y)
|
||||
void defos_set_cursor_pos_view(float x, float y)
|
||||
{
|
||||
WinRect rect = defos_get_window_size();
|
||||
|
||||
int ix = (int)x;
|
||||
int iy = (int)y;
|
||||
|
||||
// TODO: need this?
|
||||
if(ix > rect.w) ix = rect.w;
|
||||
if(ix < 0) ix = 0;
|
||||
if(iy > rect.h) iy=rect.h;
|
||||
if(iy < 0) iy = 0;
|
||||
|
||||
|
||||
XWarpPointer(disp, None, win, 0, 0, 0, 0, ix, iy);
|
||||
XFlush(disp);
|
||||
XWarpPointer(disp, None, win, 0, 0, 0, 0, (int)x, (int)y);
|
||||
XFlush(disp);
|
||||
}
|
||||
|
||||
void defos_set_cursor_clipped(bool clipped)
|
||||
{
|
||||
dmLogInfo("Method 'defos_set_cursor_clipped' is not supported in Linux");
|
||||
dmLogWarning("Method 'set_cursor_clipped' is not supported on Linux");
|
||||
}
|
||||
|
||||
bool defos_is_cursor_clipped()
|
||||
|
@ -275,7 +481,7 @@ bool defos_is_cursor_clipped()
|
|||
|
||||
void defos_set_cursor_locked(bool locked)
|
||||
{
|
||||
dmLogInfo("Method 'defos_set_cursor_locked' is not supported in Linux");
|
||||
dmLogWarning("Method 'set_cursor_locked' is not supported on Linux");
|
||||
}
|
||||
|
||||
bool defos_is_cursor_locked()
|
||||
|
@ -283,51 +489,54 @@ bool defos_is_cursor_locked()
|
|||
return false;
|
||||
}
|
||||
|
||||
void defos_update() {
|
||||
|
||||
void defos_update()
|
||||
{
|
||||
}
|
||||
|
||||
void defos_set_custom_cursor_linux(const char *filename)
|
||||
{
|
||||
custom_cursor = XcursorFilenameLoadCursor(disp, filename);
|
||||
XDefineCursor(disp, win, custom_cursor);
|
||||
Cursor cursor = XcursorFilenameLoadCursor(disp, filename);
|
||||
if (is_cursor_visible) { XDefineCursor(disp, win, cursor); }
|
||||
if (has_custom_cursor) { XFreeCursor(disp, custom_cursor); }
|
||||
custom_cursor = cursor;
|
||||
has_custom_cursor = true;
|
||||
}
|
||||
|
||||
static unsigned int get_cursor(DefosCursor cursor);
|
||||
|
||||
void defos_set_cursor(DefosCursor cursor)
|
||||
void defos_set_cursor(DefosCursor cursor_type)
|
||||
{
|
||||
// TODO: X11 support change the cursor color, add it later
|
||||
defos_reset_cursor();
|
||||
custom_cursor = XCreateFontCursor(disp, get_cursor(cursor));
|
||||
XDefineCursor(disp, win, custom_cursor);
|
||||
Cursor cursor = XCreateFontCursor(disp, get_cursor(cursor_type));
|
||||
if (is_cursor_visible) { XDefineCursor(disp, win, cursor); }
|
||||
if (has_custom_cursor) { XFreeCursor(disp, custom_cursor); }
|
||||
custom_cursor = cursor;
|
||||
has_custom_cursor = true;
|
||||
}
|
||||
|
||||
void defos_reset_cursor()
|
||||
{
|
||||
XUndefineCursor(disp, win);
|
||||
|
||||
if(custom_cursor!=NULL)
|
||||
if (has_custom_cursor)
|
||||
{
|
||||
if (is_cursor_visible) { XUndefineCursor(disp, win); }
|
||||
XFreeCursor(disp, custom_cursor);
|
||||
custom_cursor = NULL;
|
||||
has_custom_cursor = false;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int get_cursor(DefosCursor cursor)
|
||||
{
|
||||
switch(cursor)
|
||||
switch (cursor)
|
||||
{
|
||||
case DEFOS_CURSOR_ARROW:
|
||||
return XC_left_ptr;
|
||||
case DEFOS_CURSOR_CROSSHAIR:
|
||||
return XC_tcross;
|
||||
case DEFOS_CURSOR_HAND:
|
||||
return XC_hand2;
|
||||
case DEFOS_CURSOR_IBEAM:
|
||||
return XC_xterm;
|
||||
default:
|
||||
return XC_left_ptr;
|
||||
case DEFOS_CURSOR_ARROW:
|
||||
return XC_left_ptr;
|
||||
case DEFOS_CURSOR_CROSSHAIR:
|
||||
return XC_tcross;
|
||||
case DEFOS_CURSOR_HAND:
|
||||
return XC_hand2;
|
||||
case DEFOS_CURSOR_IBEAM:
|
||||
return XC_xterm;
|
||||
default:
|
||||
return XC_left_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,8 +547,281 @@ static bool is_window_visible(Window window)
|
|||
return attributes.map_state == IsViewable;
|
||||
}
|
||||
|
||||
static const XRRModeInfo* get_mode_info(const XRRScreenResources* screenResources, RRMode id){
|
||||
for (int i = 0; i < screenResources->nmode; i++)
|
||||
{
|
||||
if (screenResources->modes[i].id == id)
|
||||
{
|
||||
return screenResources->modes + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static double compute_refresh_rate(const XRRModeInfo* modeInfo)
|
||||
{
|
||||
if (!modeInfo->hTotal || !modeInfo->vTotal)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return ((double)modeInfo->dotClock / ((double)modeInfo->hTotal * (double)modeInfo->vTotal));
|
||||
}
|
||||
|
||||
static bool axis_flipped(Rotation rotation)
|
||||
{
|
||||
return !!(rotation & (RR_Rotate_90 | RR_Rotate_270));
|
||||
}
|
||||
|
||||
static unsigned long orientation_from_rotation(Rotation rotation)
|
||||
{
|
||||
if (rotation & RR_Rotate_0) { return 0; }
|
||||
if (rotation & RR_Rotate_90) { return 90; }
|
||||
if (rotation & RR_Rotate_180) { return 180; }
|
||||
if (rotation & RR_Rotate_270) { return 270; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void parse_display_mode(const XRRModeInfo* modeInfo, DisplayModeInfo &mode, Rotation rotation)
|
||||
{
|
||||
if (axis_flipped(rotation))
|
||||
{
|
||||
mode.width = modeInfo->height;
|
||||
mode.height = modeInfo->width;
|
||||
} else {
|
||||
mode.width = modeInfo->width;
|
||||
mode.height = modeInfo->height;
|
||||
}
|
||||
mode.refresh_rate = compute_refresh_rate(modeInfo);
|
||||
mode.bits_per_pixel = 32;
|
||||
mode.scaling_factor = 1.0;
|
||||
mode.orientation = orientation_from_rotation(rotation);
|
||||
mode.reflect_x = !!(rotation & RR_Reflect_X);
|
||||
mode.reflect_y = !!(rotation & RR_Reflect_Y);
|
||||
}
|
||||
|
||||
void defos_get_displays(dmArray<DisplayInfo> &displayList)
|
||||
{
|
||||
XRRScreenResources *screenResources = XRRGetScreenResourcesCurrent(disp, win);
|
||||
unsigned long bpp = (long)DefaultDepth(disp, screen);
|
||||
|
||||
displayList.OffsetCapacity(screenResources->ncrtc);
|
||||
for (int i = 0; i < screenResources->ncrtc; i++)
|
||||
{
|
||||
RRCrtc crtc = screenResources->crtcs[i];
|
||||
DisplayInfo display;
|
||||
|
||||
XRRCrtcInfo *crtcInfo = XRRGetCrtcInfo(disp, screenResources, crtc);
|
||||
const XRRModeInfo * modeInfo = get_mode_info(screenResources, crtcInfo->mode);
|
||||
|
||||
if (!modeInfo)
|
||||
{
|
||||
XRRFreeCrtcInfo(crtcInfo);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isMirror = false;
|
||||
for (unsigned int j = 0; j < displayList.Size(); j++)
|
||||
{
|
||||
DisplayInfo &otherDisplay = displayList[j];
|
||||
if (otherDisplay.bounds.x == crtcInfo->x
|
||||
&& otherDisplay.bounds.y == crtcInfo->y
|
||||
&& otherDisplay.bounds.w == crtcInfo->width
|
||||
&& otherDisplay.bounds.h == crtcInfo->height)
|
||||
{
|
||||
isMirror = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isMirror)
|
||||
{
|
||||
XRRFreeCrtcInfo(crtcInfo);
|
||||
continue;
|
||||
}
|
||||
|
||||
display.id = (DisplayID)crtc;
|
||||
display.bounds.x = crtcInfo->x;
|
||||
display.bounds.y = crtcInfo->y;
|
||||
display.bounds.w = crtcInfo->width;
|
||||
display.bounds.h = crtcInfo->height;
|
||||
parse_display_mode(modeInfo, display.mode, crtcInfo->rotation);
|
||||
display.mode.bits_per_pixel = bpp;
|
||||
display.mode.scaling_factor = (double)display.mode.width / (double)crtcInfo->width;
|
||||
display.name = NULL;
|
||||
|
||||
if (crtcInfo->noutput > 0)
|
||||
{
|
||||
XRROutputInfo *outputInfo = XRRGetOutputInfo(disp, screenResources, crtcInfo->outputs[0]);
|
||||
if (outputInfo->name)
|
||||
{
|
||||
display.name = (char*)malloc(outputInfo->nameLen + 1);
|
||||
strcpy(display.name, outputInfo->name);
|
||||
}
|
||||
XRRFreeOutputInfo(outputInfo);
|
||||
}
|
||||
|
||||
displayList.Push(display);
|
||||
|
||||
XRRFreeCrtcInfo(crtcInfo);
|
||||
}
|
||||
|
||||
XRRFreeScreenResources(screenResources);
|
||||
}
|
||||
|
||||
void defos_get_display_modes(DisplayID displayID, dmArray<DisplayModeInfo> &modeList)
|
||||
{
|
||||
RRCrtc crtc = (RRCrtc)displayID;
|
||||
|
||||
XRRScreenResources *screenResources = XRRGetScreenResourcesCurrent(disp, win);
|
||||
XRRCrtcInfo *crtcInfo = XRRGetCrtcInfo(disp, screenResources, crtc);
|
||||
|
||||
if (crtcInfo->noutput <= 0)
|
||||
{
|
||||
XRRFreeCrtcInfo(crtcInfo);
|
||||
XRRFreeScreenResources(screenResources);
|
||||
return;
|
||||
}
|
||||
|
||||
RROutput output = crtcInfo->outputs[0];
|
||||
XRROutputInfo *outputInfo = XRRGetOutputInfo(disp, screenResources, output);
|
||||
|
||||
unsigned long bpp = (long)DefaultDepth(disp, screen);
|
||||
|
||||
const XRRModeInfo *currentModeInfo = get_mode_info(screenResources, crtcInfo->mode);
|
||||
double scaling_factor = (double)currentModeInfo->width / (double)(
|
||||
axis_flipped(crtcInfo->rotation) ? crtcInfo->height : crtcInfo->width
|
||||
);
|
||||
|
||||
modeList.OffsetCapacity(outputInfo->nmode);
|
||||
for (int i = 0; i < outputInfo->nmode; i++)
|
||||
{
|
||||
const XRRModeInfo *modeInfo = get_mode_info(screenResources, outputInfo->modes[i]);
|
||||
|
||||
DisplayModeInfo mode;
|
||||
parse_display_mode(modeInfo, mode, crtcInfo->rotation);
|
||||
mode.bits_per_pixel = bpp;
|
||||
mode.scaling_factor = scaling_factor;
|
||||
|
||||
modeList.Push(mode);
|
||||
}
|
||||
|
||||
XRRFreeOutputInfo(outputInfo);
|
||||
XRRFreeScreenResources(screenResources);
|
||||
}
|
||||
|
||||
static RRCrtc get_current_crtc(WinRect &bounds)
|
||||
{
|
||||
WinRect viewBounds = defos_get_view_size();
|
||||
WinRect bestBounds = { 0, 0, 0, 0 };
|
||||
RRCrtc bestCrtc = 0;
|
||||
float bestArea = -1.0f;
|
||||
|
||||
XRRScreenResources *screenResources = XRRGetScreenResourcesCurrent(disp, win);
|
||||
for (int i = 0; i < screenResources->ncrtc; i++)
|
||||
{
|
||||
RRCrtc crtc = screenResources->crtcs[i];
|
||||
XRRCrtcInfo *crtcInfo = XRRGetCrtcInfo(disp, screenResources, crtc);
|
||||
WinRect crtcBounds = { (float)crtcInfo->x, (float)crtcInfo->y, (float)crtcInfo->width, (float)crtcInfo->height };
|
||||
XRRFreeCrtcInfo(crtcInfo);
|
||||
|
||||
if (!crtcBounds.w || !crtcBounds.h) { continue; }
|
||||
|
||||
WinRect clip = viewBounds;
|
||||
if (crtcBounds.x > clip.x)
|
||||
{
|
||||
clip.w -= crtcBounds.x - clip.x;
|
||||
clip.x = crtcBounds.x;
|
||||
}
|
||||
if (crtcBounds.y > clip.y)
|
||||
{
|
||||
clip.h -= crtcBounds.y - clip.y;
|
||||
clip.y = crtcBounds.y;
|
||||
}
|
||||
if (crtcBounds.x + crtcBounds.w < clip.x + clip.w)
|
||||
{
|
||||
clip.w = crtcBounds.x + crtcBounds.w - clip.x;
|
||||
}
|
||||
if (crtcBounds.y + crtcBounds.h < clip.y + clip.h)
|
||||
{
|
||||
clip.h = crtcBounds.y + crtcBounds.h - clip.y;
|
||||
}
|
||||
|
||||
float area = (clip.w > 0 && clip.h > 0) ? clip.w * clip.h : 0.0f;
|
||||
if (area > bestArea)
|
||||
{
|
||||
bestCrtc = crtc;
|
||||
bestBounds = crtcBounds;
|
||||
bestArea = area;
|
||||
}
|
||||
}
|
||||
XRRFreeScreenResources(screenResources);
|
||||
|
||||
bounds = bestBounds;
|
||||
return bestCrtc;
|
||||
}
|
||||
|
||||
DisplayID defos_get_current_display()
|
||||
{
|
||||
WinRect bounds;
|
||||
return (DisplayID)get_current_crtc(bounds);
|
||||
}
|
||||
|
||||
void defos_set_window_icon(const char *icon_path)
|
||||
{
|
||||
dmLogWarning("Method 'set_window_icon' is not supported on Linux");
|
||||
}
|
||||
|
||||
static char* copy_string(const char * s)
|
||||
{
|
||||
char *newString = (char*)malloc(strlen(s) + 1);
|
||||
strcpy(newString, s);
|
||||
return newString;
|
||||
}
|
||||
|
||||
char* defos_get_bundle_root()
|
||||
{
|
||||
char* result;
|
||||
char* path = (char*)malloc(PATH_MAX + 2);
|
||||
ssize_t ret = readlink("/proc/self/exe", path, PATH_MAX + 2);
|
||||
if (ret >= 0 && ret <= PATH_MAX + 1) {
|
||||
result = copy_string(dirname(path));
|
||||
} else {
|
||||
const char* path2 = (const char*)getauxval(AT_EXECFN);
|
||||
if (!path2) {
|
||||
result = copy_string(".");
|
||||
} else if (!realpath(path2, path)) {
|
||||
result = copy_string(".");
|
||||
} else {
|
||||
result = copy_string(dirname(path));
|
||||
}
|
||||
}
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int shared_argc = 0;
|
||||
static char** shared_argv = NULL;
|
||||
static void arguments_main_hook(int argc, char* argv[], char* envp[])
|
||||
{
|
||||
shared_argc = argc;
|
||||
shared_argv = argv;
|
||||
}
|
||||
|
||||
__attribute__((section(".init_array"), used))
|
||||
void (* defos_arguments_main_hook)(int,char*[],char*[]) = &arguments_main_hook;
|
||||
|
||||
|
||||
void defos_get_arguments(dmArray<char*> &arguments)
|
||||
{
|
||||
arguments.OffsetCapacity(shared_argc);
|
||||
for (int i = 0; i < shared_argc; i++)
|
||||
{
|
||||
arguments.Push(copy_string(shared_argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
//from glfw/x11_window.c
|
||||
static void send_message(Window& window, Atom type, long a, long b, long c, long d,long e)
|
||||
static void send_message(Window &window, Atom type, long a, long b, long c, long d, long e)
|
||||
{
|
||||
XEvent event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
|
@ -348,13 +830,13 @@ static void send_message(Window& window, Atom type, long a, long b, long c, long
|
|||
event.xclient.window = window;
|
||||
event.xclient.format = 32;
|
||||
event.xclient.message_type = type;
|
||||
event.xclient.data.l[0]=a;
|
||||
event.xclient.data.l[1]=b;
|
||||
event.xclient.data.l[2]=c;
|
||||
event.xclient.data.l[3]=d;
|
||||
event.xclient.data.l[4]=e;
|
||||
|
||||
XSendEvent(disp, root, False, SubstructureNotifyMask|SubstructureRedirectMask, &event);
|
||||
event.xclient.data.l[0] = a;
|
||||
event.xclient.data.l[1] = b;
|
||||
event.xclient.data.l[2] = c;
|
||||
event.xclient.data.l[3] = d;
|
||||
event.xclient.data.l[4] = e;
|
||||
|
||||
XSendEvent(disp, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &event);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -5,12 +5,16 @@
|
|||
|
||||
#include "defos_private.h"
|
||||
#include <AppKit/AppKit.h>
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <CoreVideo/CVDisplayLink.h>
|
||||
|
||||
static NSWindow* window = nil;
|
||||
static NSCursor* current_cursor = nil;
|
||||
static NSCursor* default_cursor = nil;
|
||||
|
||||
#define MAX_DISPLAYS 32
|
||||
|
||||
static bool is_maximized = false;
|
||||
static bool is_mouse_in_view = false;
|
||||
static bool is_cursor_visible = true;
|
||||
|
@ -21,6 +25,29 @@ static NSRect previous_state;
|
|||
static void enable_mouse_tracking();
|
||||
static void disable_mouse_tracking();
|
||||
|
||||
/*
|
||||
* Convert the mode string to the more convinient bits per pixel value
|
||||
*/
|
||||
static int getBPPFromModeString(CFStringRef mode)
|
||||
{
|
||||
if ((CFStringCompare(mode, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)) {
|
||||
// This is a strange mode, where we using 10 bits per RGB component and pack it into 32 bits
|
||||
// Java is not ready to work with this mode but we have to specify it as supported
|
||||
return 30;
|
||||
}
|
||||
else if (CFStringCompare(mode, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
|
||||
return 32;
|
||||
}
|
||||
else if (CFStringCompare(mode, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
|
||||
return 16;
|
||||
}
|
||||
else if (CFStringCompare(mode, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void defos_init() {
|
||||
window = dmGraphics::GetNativeOSXNSWindow();
|
||||
// [window disableCursorRects];
|
||||
|
@ -79,6 +106,10 @@ void defos_toggle_maximized() {
|
|||
}
|
||||
}
|
||||
|
||||
void defos_toggle_always_on_top() {
|
||||
window.level = defos_is_always_on_top() ? NSNormalWindowLevel : NSFloatingWindowLevel;
|
||||
}
|
||||
|
||||
bool defos_is_fullscreen() {
|
||||
BOOL fullscreen = (([window styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask);
|
||||
return fullscreen == YES;
|
||||
|
@ -88,6 +119,14 @@ bool defos_is_maximized() {
|
|||
return is_maximized;
|
||||
}
|
||||
|
||||
bool defos_is_always_on_top() {
|
||||
return window.level == NSFloatingWindowLevel;
|
||||
}
|
||||
|
||||
void defos_minimize() {
|
||||
[window performMiniaturize: nil];
|
||||
}
|
||||
|
||||
void defos_set_window_title(const char* title_lua) {
|
||||
NSString* title = [NSString stringWithUTF8String:title_lua];
|
||||
[window setTitle:title];
|
||||
|
@ -110,14 +149,15 @@ char* defos_get_bundle_root() {
|
|||
return bundlePath_lua;
|
||||
}
|
||||
|
||||
void defos_get_parameters(dmArray<char*>* parameters) {
|
||||
void defos_get_arguments(dmArray<char*> &arguments) {
|
||||
NSArray *args = [[NSProcessInfo processInfo] arguments];
|
||||
for (int i = 0; i < [args count]; i++){
|
||||
int argCount = [args count];
|
||||
arguments.OffsetCapacity(argCount);
|
||||
for (int i = 0; i < argCount; i++){
|
||||
const char *param = [args[i] UTF8String];
|
||||
char* lua_param = (char*)malloc(strlen(param) + 1);
|
||||
strcpy(lua_param, param);
|
||||
parameters->OffsetCapacity(1);
|
||||
parameters->Push(lua_param);
|
||||
arguments.Push(lua_param);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,7 +228,7 @@ WinRect defos_get_view_size() {
|
|||
}
|
||||
|
||||
void defos_set_console_visible(bool visible) {
|
||||
dmLogInfo("Method 'defos_set_console_visible' is not supported in macOS");
|
||||
dmLogWarning("Method 'set_console_visible' is only supported on Windows");
|
||||
}
|
||||
|
||||
bool defos_is_console_visible() {
|
||||
|
@ -199,28 +239,51 @@ void defos_set_cursor_visible(bool visible) {
|
|||
if (is_cursor_visible == visible) { return; }
|
||||
is_cursor_visible = visible;
|
||||
if (visible) {
|
||||
[NSCursor unhide];
|
||||
[NSCursor unhide];
|
||||
} else {
|
||||
[NSCursor hide];
|
||||
[NSCursor hide];
|
||||
}
|
||||
}
|
||||
|
||||
bool defos_is_cursor_visible() {
|
||||
return is_cursor_visible;
|
||||
return is_cursor_visible;
|
||||
}
|
||||
|
||||
bool defos_is_mouse_in_view() {
|
||||
return is_mouse_in_view;
|
||||
}
|
||||
|
||||
WinPoint defos_get_cursor_pos() {
|
||||
NSPoint point = NSEvent.mouseLocation;
|
||||
WinPoint result;
|
||||
result.x = (float)point.x;
|
||||
result.y = (float)NSMaxY(NSScreen.screens[0].frame) - point.y;
|
||||
return result;
|
||||
}
|
||||
|
||||
WinPoint defos_get_cursor_pos_view() {
|
||||
NSView* view = dmGraphics::GetNativeOSXNSView();
|
||||
NSPoint pointInScreen = NSEvent.mouseLocation;
|
||||
NSPoint windowOrigin = window.frame.origin;
|
||||
NSPoint pointInWindow = NSMakePoint(
|
||||
pointInScreen.x - windowOrigin.x,
|
||||
pointInScreen.y - windowOrigin.y
|
||||
);
|
||||
NSPoint point = [view convertPoint: pointInWindow fromView: nil];
|
||||
WinPoint result;
|
||||
result.x = (float)point.x;
|
||||
result.y = (float)(view.bounds.size.height - point.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
void defos_set_cursor_pos(float x, float y) {
|
||||
CGWarpMouseCursorPosition(CGPointMake(x, y));
|
||||
if (!is_cursor_locked) {
|
||||
CGAssociateMouseAndMouseCursorPosition(true); // Prevents a delay after the Wrap call
|
||||
CGAssociateMouseAndMouseCursorPosition(true); // Prevents a delay after the Wrap call
|
||||
}
|
||||
}
|
||||
|
||||
void defos_move_cursor_to(float x, float y) {
|
||||
void defos_set_cursor_pos_view(float x, float y) {
|
||||
NSView* view = dmGraphics::GetNativeOSXNSView();
|
||||
NSPoint pointInWindow = [view convertPoint: NSMakePoint(x, view.bounds.size.height - y) toView: nil];
|
||||
NSPoint windowOrigin = window.frame.origin;
|
||||
|
@ -262,7 +325,7 @@ static void clip_cursor(NSEvent * event) {
|
|||
}
|
||||
|
||||
if (willClip) {
|
||||
defos_move_cursor_to(mousePos.x, bounds.size.height - mousePos.y);
|
||||
defos_set_cursor_pos_view(mousePos.x, bounds.size.height - mousePos.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,6 +389,224 @@ void defos_reset_cursor() {
|
|||
current_cursor = default_cursor;
|
||||
}
|
||||
|
||||
static DisplayModeInfo parse_mode(CGDisplayModeRef mode, CVDisplayLinkRef displayLink, double rotation) {
|
||||
DisplayModeInfo mode_info;
|
||||
mode_info.width = CGDisplayModeGetPixelWidth(mode);
|
||||
mode_info.height = CGDisplayModeGetPixelHeight(mode);
|
||||
mode_info.scaling_factor = (double)mode_info.width / (double)CGDisplayModeGetWidth(mode);
|
||||
mode_info.refresh_rate = CGDisplayModeGetRefreshRate(mode);
|
||||
|
||||
CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding(mode);
|
||||
mode_info.bits_per_pixel = getBPPFromModeString(pixelEncoding);
|
||||
CFRelease(pixelEncoding);
|
||||
mode_info.orientation = (unsigned long)rotation;
|
||||
mode_info.reflect_x = false;
|
||||
mode_info.reflect_y = false;
|
||||
|
||||
if (mode_info.refresh_rate == 0) {
|
||||
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(displayLink);
|
||||
if (!(time.flags & kCVTimeIsIndefinite)) {
|
||||
mode_info.refresh_rate = (double)time.timeScale / (double)time.timeValue;
|
||||
}
|
||||
}
|
||||
|
||||
return mode_info;
|
||||
}
|
||||
|
||||
static io_service_t IOServicePortFromCGDisplayID(CGDirectDisplayID displayID) {
|
||||
io_iterator_t iter;
|
||||
io_service_t serv, servicePort = 0;
|
||||
|
||||
CFMutableDictionaryRef matching = IOServiceMatching("IODisplayConnect");
|
||||
|
||||
// releases matching for us
|
||||
kern_return_t err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iter);
|
||||
if (err) { return 0; }
|
||||
|
||||
while ((serv = IOIteratorNext(iter)) != 0) {
|
||||
CFDictionaryRef displayInfo;
|
||||
CFNumberRef vendorIDRef;
|
||||
CFNumberRef productIDRef;
|
||||
CFNumberRef serialNumberRef;
|
||||
|
||||
displayInfo = IODisplayCreateInfoDictionary(serv, kIODisplayOnlyPreferredName);
|
||||
|
||||
Boolean success;
|
||||
success = CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplayVendorID), (const void**)&vendorIDRef);
|
||||
success &= CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplayProductID), (const void**)&productIDRef);
|
||||
|
||||
if (!success) {
|
||||
CFRelease(displayInfo);
|
||||
continue;
|
||||
}
|
||||
|
||||
SInt32 vendorID;
|
||||
CFNumberGetValue(vendorIDRef, kCFNumberSInt32Type, &vendorID);
|
||||
SInt32 productID;
|
||||
CFNumberGetValue(productIDRef, kCFNumberSInt32Type, &productID);
|
||||
|
||||
// If a serial number is found, use it.
|
||||
// Otherwise serial number will be nil (= 0) which will match with the output of 'CGDisplaySerialNumber'
|
||||
SInt32 serialNumber = 0;
|
||||
if (CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplaySerialNumber), (const void**)&serialNumberRef)) {
|
||||
CFNumberGetValue(serialNumberRef, kCFNumberSInt32Type, &serialNumber);
|
||||
}
|
||||
|
||||
// If the vendor and product id along with the serial don't match
|
||||
// then we are not looking at the correct monitor.
|
||||
// NOTE: The serial number is important in cases where two monitors
|
||||
// are the exact same.
|
||||
if (CGDisplayVendorNumber(displayID) != vendorID ||
|
||||
CGDisplayModelNumber(displayID) != productID ||
|
||||
CGDisplaySerialNumber(displayID) != serialNumber ) {
|
||||
CFRelease(displayInfo);
|
||||
continue;
|
||||
}
|
||||
|
||||
servicePort = serv;
|
||||
CFRelease(displayInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
IOObjectRelease(iter);
|
||||
return servicePort;
|
||||
}
|
||||
|
||||
static char* get_display_name(CGDirectDisplayID displayID) {
|
||||
NSString *screenName = nil;
|
||||
|
||||
NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(IOServicePortFromCGDisplayID(displayID), kIODisplayOnlyPreferredName);
|
||||
NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
|
||||
|
||||
if ([localizedNames count] > 0) {
|
||||
NSString *screenName = [localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]];
|
||||
size_t nameLength = [screenName lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1;
|
||||
char *name = (char*)malloc(nameLength);
|
||||
[screenName getCString:name maxLength:nameLength encoding:NSUTF8StringEncoding];
|
||||
[deviceInfo release];
|
||||
return name;
|
||||
}
|
||||
|
||||
[deviceInfo release];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void defos_get_displays(dmArray<DisplayInfo> &displayList){
|
||||
uint32_t numDisplays;
|
||||
CGDirectDisplayID displays[MAX_DISPLAYS];
|
||||
CGGetActiveDisplayList(MAX_DISPLAYS, displays, &numDisplays);
|
||||
|
||||
displayList.OffsetCapacity(numDisplays);
|
||||
for (int i = 0; i < numDisplays; i++) {
|
||||
CGDirectDisplayID displayID = displays[i];
|
||||
|
||||
// We don't report mirrored displays
|
||||
if (CGDisplayIsInMirrorSet(displayID) && CGDisplayPrimaryDisplay(displayID) != displayID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DisplayInfo display;
|
||||
display.id = (void*)(size_t)displayID;
|
||||
|
||||
CGRect bounds = CGDisplayBounds(displayID);
|
||||
display.bounds.x = bounds.origin.x;
|
||||
display.bounds.y = bounds.origin.y;
|
||||
display.bounds.w = bounds.size.width;
|
||||
display.bounds.h = bounds.size.height;
|
||||
|
||||
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayID);
|
||||
CVDisplayLinkRef displayLink;
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &displayLink);
|
||||
double rotation = CGDisplayRotation(displayID);
|
||||
display.mode = parse_mode(mode, displayLink, rotation);
|
||||
CVDisplayLinkRelease(displayLink);
|
||||
CGDisplayModeRelease(mode);
|
||||
|
||||
display.name = get_display_name(displayID);
|
||||
|
||||
displayList.Push(display);
|
||||
}
|
||||
}
|
||||
|
||||
void defos_get_display_modes(DisplayID displayID_, dmArray<DisplayModeInfo> &modeList) {
|
||||
CGDirectDisplayID displayID = (CGDirectDisplayID)(size_t)displayID_;
|
||||
|
||||
NSDictionary *optDict = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
[NSNumber numberWithBool: YES], kCGDisplayShowDuplicateLowResolutionModes, nil
|
||||
];
|
||||
CFArrayRef modes = CGDisplayCopyAllDisplayModes(displayID, (__bridge CFDictionaryRef)optDict);
|
||||
[optDict release];
|
||||
|
||||
// Prepend the current display mode
|
||||
int modeCount = CFArrayGetCount(modes) + 1;
|
||||
CGDisplayModeRef* allModes = new CGDisplayModeRef[modeCount];
|
||||
allModes[0] = CGDisplayCopyDisplayMode(displayID);
|
||||
for (int i = 1; i < modeCount; i++) {
|
||||
allModes[i] = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i - 1);
|
||||
}
|
||||
|
||||
// Make a display link for refresh rate detection fallback
|
||||
CVDisplayLinkRef displayLink;
|
||||
CVDisplayLinkCreateWithCGDisplay(displayID, &displayLink);
|
||||
|
||||
double rotation = CGDisplayRotation(displayID);
|
||||
|
||||
modeList.OffsetCapacity(modeCount);
|
||||
for (int i = 0; i < modeCount; i++) {
|
||||
CGDisplayModeRef mode = allModes[i];
|
||||
DisplayModeInfo modeInfo = parse_mode(mode, displayLink, rotation);
|
||||
|
||||
// Remove duplicates
|
||||
size_t width = CGDisplayModeGetWidth(mode);
|
||||
size_t height = CGDisplayModeGetHeight(mode);
|
||||
size_t pixelWidth = modeInfo.width;
|
||||
size_t pixelHeight = modeInfo.height;
|
||||
double refreshRate = CGDisplayModeGetRefreshRate(mode);
|
||||
CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding(mode);
|
||||
|
||||
bool shouldAdd = true;
|
||||
for (int j = 0; j < i; j++) {
|
||||
CGDisplayModeRef otherMode = allModes[j];
|
||||
if (CFEqual(mode, otherMode)) {
|
||||
shouldAdd = false;
|
||||
break;
|
||||
}
|
||||
|
||||
size_t otherWidth = CGDisplayModeGetWidth(otherMode);
|
||||
size_t otherHeight = CGDisplayModeGetHeight(otherMode);
|
||||
size_t otherPixelWidth = CGDisplayModeGetPixelWidth(otherMode);
|
||||
size_t otherPixelHeight = CGDisplayModeGetPixelHeight(otherMode);
|
||||
double otherRefreshRate = CGDisplayModeGetRefreshRate(otherMode);
|
||||
CFStringRef otherPixelEncoding = CGDisplayModeCopyPixelEncoding(otherMode);
|
||||
|
||||
bool samePixelEncoding = (CFStringCompare(pixelEncoding, otherPixelEncoding, 0) == kCFCompareEqualTo);
|
||||
CFRelease(pixelEncoding);
|
||||
CFRelease(otherPixelEncoding);
|
||||
|
||||
if (samePixelEncoding
|
||||
&& pixelWidth == otherPixelWidth
|
||||
&& pixelHeight == otherPixelHeight
|
||||
&& width == otherWidth
|
||||
&& height == otherHeight
|
||||
&& refreshRate == otherRefreshRate
|
||||
) {
|
||||
shouldAdd = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldAdd) { modeList.Push(modeInfo); }
|
||||
}
|
||||
|
||||
CVDisplayLinkRelease(displayLink);
|
||||
CGDisplayModeRelease(allModes[0]);
|
||||
CFRelease(modes);
|
||||
}
|
||||
|
||||
DisplayID defos_get_current_display() {
|
||||
return (void*)(size_t)[[[[window screen] deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
|
||||
}
|
||||
|
||||
@interface DefOSMouseTracker : NSResponder
|
||||
@end
|
||||
@implementation DefOSMouseTracker
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
#include <math.h>
|
||||
|
||||
struct WinRect {
|
||||
float x,y,w,h;
|
||||
float x, y, w, h;
|
||||
};
|
||||
|
||||
struct WinPoint {
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct LuaCallbackInfo {
|
||||
|
@ -29,6 +33,30 @@ typedef enum {
|
|||
DEFOS_CURSOR_IBEAM,
|
||||
} DefosCursor;
|
||||
|
||||
#ifdef DM_PLATFORM_WINDOWS
|
||||
typedef const char* DisplayID;
|
||||
#else
|
||||
typedef void* DisplayID;
|
||||
#endif
|
||||
|
||||
struct DisplayModeInfo {
|
||||
unsigned long width;
|
||||
unsigned long height;
|
||||
unsigned long bits_per_pixel;
|
||||
double refresh_rate;
|
||||
double scaling_factor;
|
||||
unsigned long orientation;
|
||||
bool reflect_x;
|
||||
bool reflect_y;
|
||||
};
|
||||
|
||||
struct DisplayInfo {
|
||||
DisplayID id;
|
||||
struct WinRect bounds;
|
||||
struct DisplayModeInfo mode;
|
||||
char * name;
|
||||
};
|
||||
|
||||
extern LuaCallbackInfo defos_event_handlers[];
|
||||
extern void defos_emit_event(DefosEvent event);
|
||||
extern void defos_event_handler_was_set(DefosEvent event);
|
||||
|
@ -46,13 +74,16 @@ extern void defos_disable_window_resize();
|
|||
|
||||
extern void defos_toggle_fullscreen();
|
||||
extern void defos_toggle_maximized();
|
||||
extern void defos_toggle_always_on_top();
|
||||
extern bool defos_is_fullscreen();
|
||||
extern bool defos_is_maximized();
|
||||
extern bool defos_is_always_on_top();
|
||||
extern void defos_minimize();
|
||||
|
||||
extern void defos_set_window_title(const char* title_lua);
|
||||
extern void defos_set_window_icon(const char *icon_path);
|
||||
extern char* defos_get_bundle_root();
|
||||
extern void defos_get_parameters(dmArray<char*>* parameters);
|
||||
extern void defos_get_arguments(dmArray<char*> &arguments);
|
||||
|
||||
extern void defos_set_window_size(float x, float y, float w, float h);
|
||||
extern WinRect defos_get_window_size();
|
||||
|
@ -67,7 +98,9 @@ extern bool defos_is_cursor_visible();
|
|||
|
||||
extern bool defos_is_mouse_in_view();
|
||||
extern void defos_set_cursor_pos(float x, float y);
|
||||
extern void defos_move_cursor_to(float x, float y);
|
||||
extern void defos_set_cursor_pos_view(float x, float y);
|
||||
extern WinPoint defos_get_cursor_pos();
|
||||
extern WinPoint defos_get_cursor_pos_view();
|
||||
|
||||
extern void defos_set_cursor_clipped(bool clipped);
|
||||
extern bool defos_is_cursor_clipped();
|
||||
|
@ -79,4 +112,8 @@ extern void defos_set_custom_cursor_win(const char *filename);
|
|||
extern void defos_set_custom_cursor_mac(dmBuffer::HBuffer buffer, float hotSpotX, float hotSpotY);
|
||||
extern void defos_set_custom_cursor_linux(const char *filename);
|
||||
extern void defos_set_cursor(DefosCursor cursor);
|
||||
extern void defos_reset_cursor();
|
||||
extern void defos_reset_cursor();
|
||||
|
||||
extern void defos_get_displays(dmArray<DisplayInfo> &displayList);
|
||||
extern void defos_get_display_modes(DisplayID displayID, dmArray<DisplayModeInfo> &modeList);
|
||||
extern DisplayID defos_get_current_display();
|
||||
|
|
|
@ -23,6 +23,8 @@ static bool is_cursor_clipped = false;
|
|||
static POINT lock_point;
|
||||
static bool is_cursor_locked = false;
|
||||
|
||||
static bool is_window_on_top = false;
|
||||
static bool is_window_active = true;
|
||||
static bool is_cursor_visible = true;
|
||||
static bool is_custom_cursor_loaded;
|
||||
static HCURSOR custom_cursor;
|
||||
|
@ -41,6 +43,8 @@ void subclass_window();
|
|||
|
||||
void defos_init()
|
||||
{
|
||||
is_window_active = true;
|
||||
is_window_on_top = false;
|
||||
is_mouse_inside = false;
|
||||
is_cursor_clipped = false;
|
||||
GetClipCursor(&originalRect); // keep the original clip for restore
|
||||
|
@ -153,6 +157,26 @@ void defos_toggle_maximized()
|
|||
}
|
||||
}
|
||||
|
||||
void defos_toggle_always_on_top()
|
||||
{
|
||||
is_window_on_top = !is_window_on_top;
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
SetWindowPos(window,
|
||||
is_window_on_top ? HWND_TOPMOST : HWND_NOTOPMOST,
|
||||
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE
|
||||
);
|
||||
}
|
||||
|
||||
bool defos_is_always_on_top() {
|
||||
return is_window_on_top;
|
||||
}
|
||||
|
||||
void defos_minimize()
|
||||
{
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
ShowWindow(window, SW_MINIMIZE);
|
||||
}
|
||||
|
||||
void defos_set_console_visible(bool visible)
|
||||
{
|
||||
::ShowWindow(::GetConsoleWindow(), visible ? SW_SHOW : SW_HIDE);
|
||||
|
@ -165,28 +189,33 @@ bool defos_is_console_visible()
|
|||
|
||||
void defos_set_window_size(float x, float y, float w, float h)
|
||||
{
|
||||
if (isnan(x))
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
|
||||
if (isnan(x) || isnan(y))
|
||||
{
|
||||
x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
|
||||
}
|
||||
if (isnan(y))
|
||||
{
|
||||
y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
|
||||
HMONITOR hMonitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
GetMonitorInfo(hMonitor, &monitorInfo);
|
||||
if (isnan(x)) { x = (monitorInfo.rcMonitor.left + monitorInfo.rcMonitor.right - w) / 2; }
|
||||
if (isnan(y)) { y = (monitorInfo.rcMonitor.top + monitorInfo.rcMonitor.bottom - h) / 2; }
|
||||
}
|
||||
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
SetWindowPos(window, window, (int)x, (int)y, (int)w, (int)h, SWP_NOZORDER);
|
||||
}
|
||||
|
||||
void defos_set_view_size(float x, float y, float w, float h)
|
||||
{
|
||||
if (isnan(x))
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
|
||||
if (isnan(x) || isnan(y))
|
||||
{
|
||||
x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
|
||||
}
|
||||
if (isnan(y))
|
||||
{
|
||||
y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
|
||||
HMONITOR hMonitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
GetMonitorInfo(hMonitor, &monitorInfo);
|
||||
if (isnan(x)) { x = (monitorInfo.rcMonitor.left + monitorInfo.rcMonitor.right - w) / 2; }
|
||||
if (isnan(y)) { y = (monitorInfo.rcMonitor.top + monitorInfo.rcMonitor.bottom - h) / 2; }
|
||||
}
|
||||
|
||||
RECT rect = {0, 0, (int)w, (int)h};
|
||||
|
@ -196,8 +225,6 @@ void defos_set_view_size(float x, float y, float w, float h)
|
|||
// TODO: we are assuming the window have no menu, maybe it is better to expose it as parameter later
|
||||
AdjustWindowRect(&rect, style, false);
|
||||
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
|
||||
SetWindowPos(window, window, (int)x, (int)y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
|
||||
}
|
||||
|
||||
|
@ -235,19 +262,19 @@ char* defos_get_bundle_root() {
|
|||
return bundlePath;
|
||||
}
|
||||
|
||||
void defos_get_parameters(dmArray<char*>* parameters) {
|
||||
void defos_get_arguments(dmArray<char*> &arguments) {
|
||||
LPWSTR *szArglist;
|
||||
int nArgs;
|
||||
int i;
|
||||
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
|
||||
if( NULL != szArglist ){
|
||||
arguments.OffsetCapacity(nArgs);
|
||||
for( i=0; i<nArgs; i++) {
|
||||
const wchar_t *param = szArglist[i];
|
||||
int len = wcslen(param) + 1;
|
||||
char* lua_param = (char*)malloc(len);
|
||||
wcstombs(lua_param, param, len);
|
||||
parameters->OffsetCapacity(1);
|
||||
parameters->Push(lua_param);
|
||||
arguments.Push(lua_param);
|
||||
}
|
||||
}
|
||||
LocalFree(szArglist);
|
||||
|
@ -256,14 +283,15 @@ void defos_get_parameters(dmArray<char*>* parameters) {
|
|||
WinRect defos_get_window_size()
|
||||
{
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
WINDOWPLACEMENT frame = {sizeof(placement)};
|
||||
GetWindowPlacement(window, &frame);
|
||||
WinRect rect;
|
||||
rect.x = (float)frame.rcNormalPosition.left;
|
||||
rect.y = (float)frame.rcNormalPosition.top;
|
||||
rect.w = (float)(frame.rcNormalPosition.right - frame.rcNormalPosition.left);
|
||||
rect.h = (float)(frame.rcNormalPosition.bottom - frame.rcNormalPosition.top);
|
||||
return rect;
|
||||
RECT rect;
|
||||
GetWindowRect(window, &rect);
|
||||
WinRect result = {
|
||||
.x = rect.left,
|
||||
.y = rect.top,
|
||||
.w = rect.right - rect.left,
|
||||
.h = rect.bottom - rect.top,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
WinRect defos_get_view_size()
|
||||
|
@ -276,16 +304,36 @@ WinRect defos_get_view_size()
|
|||
POINT pos = {wrect.left, wrect.top};
|
||||
ClientToScreen(window, &pos);
|
||||
|
||||
WINDOWPLACEMENT frame = {sizeof(placement)};
|
||||
GetWindowPlacement(window, &frame);
|
||||
WinRect rect;
|
||||
rect.x = (float)pos.x;
|
||||
rect.y = (float)pos.y;
|
||||
rect.w = (float)(wrect.right - wrect.left);
|
||||
rect.h = (float)(wrect.bottom - wrect.top);
|
||||
WinRect rect = {
|
||||
.x = pos.x,
|
||||
.y = pos.y,
|
||||
.w = wrect.right - wrect.left,
|
||||
.h = wrect.bottom - wrect.top,
|
||||
};
|
||||
return rect;
|
||||
}
|
||||
|
||||
WinPoint defos_get_cursor_pos()
|
||||
{
|
||||
POINT point;
|
||||
GetCursorPos(&point);
|
||||
|
||||
WinPoint result = { .x = point.x, .y = point.y };
|
||||
return result;
|
||||
}
|
||||
|
||||
WinPoint defos_get_cursor_pos_view()
|
||||
{
|
||||
POINT point;
|
||||
GetCursorPos(&point);
|
||||
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
ScreenToClient(window, &point);
|
||||
|
||||
WinPoint result = { .x = point.x, .y = point.y };
|
||||
return result;
|
||||
}
|
||||
|
||||
void defos_set_cursor_pos(float x, float y)
|
||||
{
|
||||
SetCursorPos((int)x, (int)y);
|
||||
|
@ -293,7 +341,7 @@ void defos_set_cursor_pos(float x, float y)
|
|||
|
||||
// move cursor to pos relative to current window
|
||||
// top-left is (0, 0)
|
||||
void defos_move_cursor_to(float x, float y)
|
||||
void defos_set_cursor_pos_view(float x, float y)
|
||||
{
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
|
||||
|
@ -357,7 +405,7 @@ bool defos_is_cursor_locked()
|
|||
}
|
||||
|
||||
void defos_update() {
|
||||
if (is_cursor_locked) {
|
||||
if (is_cursor_locked && is_window_active) {
|
||||
SetCursorPos(lock_point.x, lock_point.y);
|
||||
}
|
||||
}
|
||||
|
@ -387,6 +435,151 @@ void defos_reset_cursor()
|
|||
is_custom_cursor_loaded = false;
|
||||
}
|
||||
|
||||
static char* copy_string(const char *s)
|
||||
{
|
||||
char *buffer = (char*)malloc(strlen(s) + 1);
|
||||
strcpy(buffer, s);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static unsigned long translate_orientation(DWORD orientation)
|
||||
{
|
||||
switch (orientation)
|
||||
{
|
||||
case DMDO_DEFAULT: return 0;
|
||||
case DMDO_90: return 90;
|
||||
case DMDO_180: return 180;
|
||||
case DMDO_270: return 270;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_display_mode(const DEVMODE &devMode, DisplayModeInfo &mode)
|
||||
{
|
||||
mode.width = devMode.dmPelsWidth;
|
||||
mode.height = devMode.dmPelsHeight;
|
||||
mode.bits_per_pixel = devMode.dmBitsPerPel;
|
||||
mode.refresh_rate = devMode.dmDisplayFrequency;
|
||||
mode.scaling_factor = 1.0;
|
||||
mode.orientation = (devMode.dmFields & DM_DISPLAYORIENTATION)
|
||||
? translate_orientation(devMode.dmDisplayOrientation)
|
||||
: 0;
|
||||
mode.reflect_x = false;
|
||||
mode.reflect_y = false;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK monitor_enum_callback(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
|
||||
{
|
||||
MONITORINFOEX monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (!GetMonitorInfo(hMonitor, &monitorInfo)) { return TRUE; }
|
||||
|
||||
DisplayInfo display;
|
||||
display.id = copy_string(monitorInfo.szDevice);
|
||||
display.bounds.x = monitorInfo.rcMonitor.left;
|
||||
display.bounds.y = monitorInfo.rcMonitor.top;
|
||||
display.bounds.w = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
|
||||
display.bounds.h = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
|
||||
|
||||
DEVMODE devMode;
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
EnumDisplaySettingsEx(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &devMode, 0);
|
||||
parse_display_mode(devMode, display.mode);
|
||||
display.mode.scaling_factor = (double)devMode.dmPelsWidth / (double)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
|
||||
|
||||
DISPLAY_DEVICE displayDevice;
|
||||
displayDevice.cb = sizeof(displayDevice);
|
||||
EnumDisplayDevices(monitorInfo.szDevice, 0, &displayDevice, 0);
|
||||
display.name = copy_string(displayDevice.DeviceString);
|
||||
|
||||
dmArray<DisplayInfo> *displayList = reinterpret_cast<dmArray<DisplayInfo>*>(dwData);
|
||||
displayList->OffsetCapacity(1);
|
||||
displayList->Push(display);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void defos_get_displays(dmArray<DisplayInfo> &displayList)
|
||||
{
|
||||
EnumDisplayMonitors(NULL, NULL, monitor_enum_callback, reinterpret_cast<LPARAM>(&displayList));
|
||||
}
|
||||
|
||||
struct MonitorScaleData {
|
||||
const char *display_device_name;
|
||||
double scaling_factor;
|
||||
};
|
||||
|
||||
static BOOL CALLBACK monitor_scale_enum_callback(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
|
||||
{
|
||||
MonitorScaleData *data = reinterpret_cast<MonitorScaleData*>(dwData);
|
||||
|
||||
MONITORINFOEX monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (!GetMonitorInfo(hMonitor, &monitorInfo)) { return TRUE; }
|
||||
|
||||
if (strcmp(monitorInfo.szDevice, data->display_device_name) != 0) { return TRUE; }
|
||||
|
||||
DEVMODE devMode;
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &devMode);
|
||||
data->scaling_factor = (double)devMode.dmPelsWidth / (double)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static double scale_of_monitor(DisplayID displayID)
|
||||
{
|
||||
MonitorScaleData data = {
|
||||
.display_device_name = displayID,
|
||||
.scaling_factor = 1.0,
|
||||
};
|
||||
EnumDisplayMonitors(NULL, NULL, monitor_scale_enum_callback, reinterpret_cast<LPARAM>(&data));
|
||||
return data.scaling_factor;
|
||||
}
|
||||
|
||||
void defos_get_display_modes(DisplayID displayID, dmArray<DisplayModeInfo> &modeList)
|
||||
{
|
||||
DEVMODE devMode = {};
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
|
||||
double scaling_factor = scale_of_monitor(displayID);
|
||||
|
||||
for (int i = 0; EnumDisplaySettingsEx(displayID, i, &devMode, 0) != 0; i++)
|
||||
{
|
||||
DisplayModeInfo mode;
|
||||
parse_display_mode(devMode, mode);
|
||||
mode.scaling_factor = scaling_factor;
|
||||
|
||||
bool isDuplicate = false;
|
||||
for (int j = (int)modeList.Size() - 1; j >= 0; j--)
|
||||
{
|
||||
DisplayModeInfo &otherMode = modeList[j];
|
||||
if (mode.width == otherMode.width
|
||||
&& mode.height == otherMode.height
|
||||
&& mode.bits_per_pixel == otherMode.bits_per_pixel
|
||||
&& mode.refresh_rate == otherMode.refresh_rate
|
||||
) {
|
||||
isDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDuplicate) { continue; }
|
||||
modeList.OffsetCapacity(1);
|
||||
modeList.Push(mode);
|
||||
}
|
||||
}
|
||||
|
||||
DisplayID defos_get_current_display()
|
||||
{
|
||||
HWND window = dmGraphics::GetNativeWindowsHWND();
|
||||
HMONITOR hMonitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFOEX monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
GetMonitorInfo(hMonitor, &monitorInfo);
|
||||
return copy_string(monitorInfo.szDevice);
|
||||
}
|
||||
|
||||
/********************
|
||||
* internal functions
|
||||
********************/
|
||||
|
@ -478,12 +671,14 @@ static LRESULT __stdcall custom_wndproc(HWND hwnd, UINT umsg, WPARAM wp, LPARAM
|
|||
}
|
||||
break;
|
||||
|
||||
case WM_SIZE:
|
||||
if (is_cursor_locked)
|
||||
case WM_ACTIVATE:
|
||||
if (wp != WA_INACTIVE)
|
||||
{
|
||||
defos_set_cursor_locked(true);
|
||||
is_window_active = true;
|
||||
if (is_cursor_clipped) { defos_set_cursor_clipped(true); }
|
||||
} else {
|
||||
is_window_active = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (originalProc != NULL)
|
||||
|
|
|
@ -2892,6 +2892,68 @@ nodes {
|
|||
text_leading: 1.0
|
||||
text_tracking: 0.0
|
||||
}
|
||||
nodes {
|
||||
position {
|
||||
x: 367.0
|
||||
y: 270.066
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
rotation {
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
scale {
|
||||
x: 1.0
|
||||
y: 1.0
|
||||
z: 1.0
|
||||
w: 1.0
|
||||
}
|
||||
size {
|
||||
x: 700.0
|
||||
y: 100.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
color {
|
||||
x: 1.0
|
||||
y: 1.0
|
||||
z: 1.0
|
||||
w: 1.0
|
||||
}
|
||||
type: TYPE_TEXT
|
||||
blend_mode: BLEND_MODE_ALPHA
|
||||
text: "cursor position"
|
||||
font: "larryfont"
|
||||
id: "cursor_pos"
|
||||
xanchor: XANCHOR_NONE
|
||||
yanchor: YANCHOR_NONE
|
||||
pivot: PIVOT_NW
|
||||
outline {
|
||||
x: 0.0
|
||||
y: 0.0
|
||||
z: 0.0
|
||||
w: 1.0
|
||||
}
|
||||
shadow {
|
||||
x: 1.0
|
||||
y: 1.0
|
||||
z: 1.0
|
||||
w: 1.0
|
||||
}
|
||||
adjust_mode: ADJUST_MODE_FIT
|
||||
line_break: false
|
||||
layer: ""
|
||||
inherit_alpha: true
|
||||
alpha: 1.0
|
||||
outline_alpha: 1.0
|
||||
shadow_alpha: 1.0
|
||||
template_node_child: false
|
||||
text_leading: 1.0
|
||||
text_tracking: 0.0
|
||||
}
|
||||
material: "/builtins/materials/gui.material"
|
||||
adjust_reference: ADJUST_REFERENCE_LEGACY
|
||||
max_nodes: 512
|
||||
|
|
|
@ -11,25 +11,6 @@ local ICON_NAMES = {
|
|||
["Darwin"] = "mac.png"
|
||||
}
|
||||
|
||||
function window_callback(self, event, data)
|
||||
if event == window.WINDOW_EVENT_FOCUS_LOST then
|
||||
-- though after lost focus cursor clipping will restore, we should restore it
|
||||
if self.cursor_clipped then
|
||||
defos.set_cursor_clipped(false)
|
||||
end
|
||||
if self.cursor_locked then
|
||||
defos.set_cursor_locked(false)
|
||||
end
|
||||
elseif event == window.WINDOW_EVENT_FOCUS_GAINED then
|
||||
if self.cursor_clipped then
|
||||
defos.set_cursor_clipped(true)
|
||||
end
|
||||
if self.cursor_locked then
|
||||
defos.set_cursor_locked(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function toggle_cursor_lock(self)
|
||||
self.cursor_locked = not self.cursor_locked
|
||||
defos.set_cursor_locked(self.cursor_locked)
|
||||
|
@ -68,7 +49,7 @@ function init(self)
|
|||
-- NOTE: cursor should be normal x11 cursor file that type is: image/x-xcursor
|
||||
table.insert(self.cursors, extract_to_savefolder("cursor.xcur"))
|
||||
end
|
||||
|
||||
|
||||
if system_name == "Windows" then
|
||||
for i, v in ipairs({"cursor_01.ani", "cursor_02.ani" }) do
|
||||
-- load source file and write them to save folder, so that we can access them with fullpath, or you can use bundle_resource
|
||||
|
@ -129,8 +110,27 @@ function init(self)
|
|||
defos.set_console_visible(not defos.is_console_visible())
|
||||
end
|
||||
|
||||
window.set_listener(window_callback)
|
||||
pprint(defos.get_parameters())
|
||||
local displays = defos.get_displays()
|
||||
print("Found " .. #displays .. " displays:")
|
||||
for i, display in ipairs(displays) do
|
||||
pprint(display)
|
||||
end
|
||||
|
||||
local current_display_id = defos.get_current_display_id()
|
||||
print("Current display id: ", current_display_id)
|
||||
|
||||
local modes = defos.get_display_modes(current_display_id)
|
||||
print("Found " .. #modes .. " modes for current display:")
|
||||
for i, mode in ipairs(modes) do
|
||||
print(
|
||||
mode.width .. "x" .. mode.height .. " " ..
|
||||
mode.bits_per_pixel .. "bit @" .. mode.refresh_rate .. "Hz x" ..
|
||||
mode.scaling_factor .. " " .. mode.orientation .. "deg"
|
||||
)
|
||||
end
|
||||
|
||||
print("App command line arguments:")
|
||||
pprint(defos.get_arguments())
|
||||
end
|
||||
|
||||
local function change_mouse_label(text)
|
||||
|
@ -143,6 +143,9 @@ function update(self, dt)
|
|||
gui.set_text(gui.get_node("window_pos"),"window position "..x.." "..y.." "..w.." "..h)
|
||||
x,y,w,h = defos.get_view_size()
|
||||
gui.set_text(gui.get_node("view_pos"),"view position "..x.." "..y.." "..w.." "..h)
|
||||
x, y = defos.get_cursor_pos()
|
||||
w, h = defos.get_cursor_pos_view()
|
||||
gui.set_text(gui.get_node("cursor_pos"),"cursor: "..math.floor(x).." "..math.floor(y).." view: "..math.floor(w).." "..math.floor(h))
|
||||
gui.set_text(gui.get_node("is_fullscreen"),"is_fullscreen "..tostring(defos.is_fullscreen()))
|
||||
gui.set_text(gui.get_node("is_maximized"),"is_maximized "..tostring(defos.is_maximized()))
|
||||
gui.set_text(gui.get_node("is_mouse_in_view"),"is_mouse_in_view "..tostring(defos.is_mouse_in_view()))
|
||||
|
@ -182,8 +185,7 @@ function on_input(self, action_id, action)
|
|||
end)
|
||||
|
||||
dirtylarry:button("set_window_size", action_id, action, function ()
|
||||
defos.set_window_size(nil, nil, 1024, 768)
|
||||
--defos.set_view_size(0, 0, 800, 600)
|
||||
defos.set_view_size(nil, nil, 1024, 768)
|
||||
end)
|
||||
|
||||
dirtylarry:button("toggle_fullscreen", action_id, action, function ()
|
||||
|
@ -208,7 +210,7 @@ function on_input(self, action_id, action)
|
|||
dirtylarry:button("random_cursor_pos", action_id, action, function()
|
||||
local x = math.random(1,2000)
|
||||
local y = math.random(1,2000)
|
||||
defos.move_cursor_to(x, y)
|
||||
defos.set_cursor_pos_view(x, y)
|
||||
end)
|
||||
|
||||
dirtylarry:button("clip_cursor", action_id, action, function()
|
||||
|
@ -236,8 +238,4 @@ function on_input(self, action_id, action)
|
|||
|
||||
defos.set_cursor(self.cursors[self.current_cursor])
|
||||
end)
|
||||
|
||||
if self.cursor_locked and not action_id then
|
||||
print("FPS mouse dx, dy: ", action.dx, action.dy)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,6 +15,7 @@ game_binding = /input/game.input_bindingc
|
|||
[display]
|
||||
width = 1024
|
||||
height = 768
|
||||
high_dpi = 1
|
||||
|
||||
[physics]
|
||||
scale = 0.02
|
||||
|
|
Loading…
Reference in New Issue