Merge 0ffae9069e into 82771dd761
				
					
				
			This commit is contained in:
		
						commit
						75c226b10e
					
				
							
								
								
									
										14
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								README.md
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -45,6 +45,20 @@ ___
 | 
			
		|||
 | 
			
		||||
Visit the [official documentation](https://espanso.org/docs/).
 | 
			
		||||
 | 
			
		||||
## Provisional Wayland support
 | 
			
		||||
 | 
			
		||||
This branch has provisional support for Wayland, albeit **only under Fedora 36 using Gnome**.
 | 
			
		||||
 | 
			
		||||
Please look at the documentation for details. Application specific filters
 | 
			
		||||
(filter_title, filter_class, filter_exec) currently only work und Wayland with Gnome
 | 
			
		||||
version 41. In addition, a Gnome shell extension
 | 
			
		||||
(https://extensions.gnome.org/extension/4974/window-calls-extended/)
 | 
			
		||||
is required! Without this extension, espanso has no access to active window information.
 | 
			
		||||
 | 
			
		||||
* Compile espanso with `cargo make --profile release --env NO_X11=true build-binary`
 | 
			
		||||
* User must be member of group `input`
 | 
			
		||||
* Espanso must be given capability (SELinux) to access /dev/input. So install with `sudo cp ~/src/espanso/target/release/espanso /usr/local/bin ; sudo setcap "cap_dac_override+p" $(which espanso)`
 | 
			
		||||
 | 
			
		||||
## Support
 | 
			
		||||
 | 
			
		||||
If you need some help to setup espanso, want to ask a question or simply get involved
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,20 @@ fn cc_config() {
 | 
			
		|||
    println!("cargo:rustc-link-lib=dylib=stdc++");
 | 
			
		||||
    println!("cargo:rustc-link-lib=dylib=X11");
 | 
			
		||||
  } else {
 | 
			
		||||
    // Nothing to compile on wayland
 | 
			
		||||
    println!("cargo:rerun-if-changed=src/wayland/native.h");
 | 
			
		||||
    println!("cargo:rerun-if-changed=src/wayland/native.c");
 | 
			
		||||
    cc::Build::new()
 | 
			
		||||
      .cpp(true)
 | 
			
		||||
      .include("src/wayland")
 | 
			
		||||
      .include("/usr/include/dbus-1.0")
 | 
			
		||||
      .include("/usr/lib64/dbus-1.0/include")
 | 
			
		||||
      .file("src/wayland/native.cpp")
 | 
			
		||||
      .compile("espansoinfo");
 | 
			
		||||
 | 
			
		||||
    println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/");
 | 
			
		||||
    println!("cargo:rustc-link-lib=static=espansoinfo");
 | 
			
		||||
    println!("cargo:rustc-link-lib=dylib=stdc++");
 | 
			
		||||
    println!("cargo:rustc-link-lib=dylib=dbus-1");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										27
									
								
								espanso-info/src/wayland/ffi.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								espanso-info/src/wayland/ffi.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
use std::os::raw::c_char;
 | 
			
		||||
 | 
			
		||||
#[link(name = "espansoinfo", kind = "static")]
 | 
			
		||||
extern "C" {
 | 
			
		||||
  pub fn info_get_title(buffer: *mut c_char, buffer_size: i32) -> i32;
 | 
			
		||||
  pub fn info_get_exec(buffer: *mut c_char, buffer_size: i32) -> i32;
 | 
			
		||||
  pub fn info_get_class(buffer: *mut c_char, buffer_size: i32) -> i32;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -17,23 +17,78 @@
 | 
			
		|||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// This file:
 | 
			
		||||
// Last changes: 2022-04-05T17:55:36+02:00 by Hendrik G. Seliger (github@hseliger.eu)
 | 
			
		||||
 | 
			
		||||
use std::{ffi::CStr, os::raw::c_char};
 | 
			
		||||
 | 
			
		||||
use crate::{AppInfo, AppInfoProvider};
 | 
			
		||||
 | 
			
		||||
use self::ffi::{info_get_class, info_get_exec, info_get_title};
 | 
			
		||||
 | 
			
		||||
mod ffi;
 | 
			
		||||
 | 
			
		||||
pub(crate) struct WaylandAppInfoProvider {}
 | 
			
		||||
 | 
			
		||||
impl WaylandAppInfoProvider {
 | 
			
		||||
  pub fn new() -> Self {
 | 
			
		||||
    Self {}
 | 
			
		||||
  }
 | 
			
		||||
 pub fn new() -> Self {
 | 
			
		||||
   Self {}
 | 
			
		||||
 }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl AppInfoProvider for WaylandAppInfoProvider {
 | 
			
		||||
  // TODO: can we read these info on Wayland?
 | 
			
		||||
  fn get_info(&self) -> AppInfo {
 | 
			
		||||
    AppInfo {
 | 
			
		||||
      title: None,
 | 
			
		||||
      exec: None,
 | 
			
		||||
      class: None,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 fn get_info(&self) -> AppInfo {
 | 
			
		||||
   AppInfo {
 | 
			
		||||
     title: self.get_title(),
 | 
			
		||||
     class: self.get_class(),
 | 
			
		||||
     exec: self.get_exec(),
 | 
			
		||||
   }
 | 
			
		||||
 }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl WaylandAppInfoProvider {
 | 
			
		||||
 fn get_exec(&self) -> Option<String> {
 | 
			
		||||
   let mut buffer: [c_char; 2048] = [0; 2048];
 | 
			
		||||
   if unsafe { info_get_exec(buffer.as_mut_ptr(), (buffer.len() - 1) as i32) } > 0 {
 | 
			
		||||
     let string = unsafe { CStr::from_ptr(buffer.as_ptr()) };
 | 
			
		||||
     let string = string.to_string_lossy();
 | 
			
		||||
     if !string.is_empty() {
 | 
			
		||||
       Some(string.to_string())
 | 
			
		||||
     } else {
 | 
			
		||||
       None
 | 
			
		||||
     }
 | 
			
		||||
   } else {
 | 
			
		||||
     None
 | 
			
		||||
   }
 | 
			
		||||
 }
 | 
			
		||||
 | 
			
		||||
 fn get_class(&self) -> Option<String> {
 | 
			
		||||
   let mut buffer: [c_char; 2048] = [0; 2048];
 | 
			
		||||
   if unsafe { info_get_class(buffer.as_mut_ptr(), (buffer.len() - 1) as i32) } > 0 {
 | 
			
		||||
     let string = unsafe { CStr::from_ptr(buffer.as_ptr()) };
 | 
			
		||||
     let string = string.to_string_lossy();
 | 
			
		||||
     if !string.is_empty() {
 | 
			
		||||
       Some(string.to_string())
 | 
			
		||||
     } else {
 | 
			
		||||
       None
 | 
			
		||||
     }
 | 
			
		||||
   } else {
 | 
			
		||||
     None
 | 
			
		||||
   }
 | 
			
		||||
 }
 | 
			
		||||
 | 
			
		||||
 fn get_title(&self) -> Option<String> {
 | 
			
		||||
   let mut buffer: [c_char; 2048] = [0; 2048];
 | 
			
		||||
   if unsafe { info_get_title(buffer.as_mut_ptr(), (buffer.len() - 1) as i32) } > 0 {
 | 
			
		||||
     let string = unsafe { CStr::from_ptr(buffer.as_ptr()) };
 | 
			
		||||
     let string = string.to_string_lossy();
 | 
			
		||||
     if !string.is_empty() {
 | 
			
		||||
       Some(string.to_string())
 | 
			
		||||
     } else {
 | 
			
		||||
       None
 | 
			
		||||
     }
 | 
			
		||||
   } else {
 | 
			
		||||
     None
 | 
			
		||||
   }
 | 
			
		||||
 }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										233
									
								
								espanso-info/src/wayland/native.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								espanso-info/src/wayland/native.cpp
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,233 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// This file:
 | 
			
		||||
// Created: 2022-04-04T08:37:16+02:00 by Hendrik G. Seliger (github@hseliger.eu)
 | 
			
		||||
// Last changes: 2022-04-06T08:10:44+02:00 by Hendrik G. Seliger (github@hseliger.eu)
 | 
			
		||||
 | 
			
		||||
// Based on an example given by Ranjit Katuri on https://stackoverflow.com/a/17645247
 | 
			
		||||
// Uses RapidJSON header-only parser (http://rapidjson.org/)
 | 
			
		||||
 | 
			
		||||
// Error handling is quite rudimentary: whenever something goes wrong, the functions simply
 | 
			
		||||
// return a somewhat generic message instead of the active window's title, class, or command.
 | 
			
		||||
 | 
			
		||||
#define DEBUG 0
 | 
			
		||||
 | 
			
		||||
#include "native.h"
 | 
			
		||||
#include <unistd.h> // for readlink
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
DBusConnection* conn = NULL;
 | 
			
		||||
 | 
			
		||||
#define DB_INTERFACE    "org.gnome.Shell.Extensions.WindowsExt"
 | 
			
		||||
#define DB_DESTINATION  "org.gnome.Shell"
 | 
			
		||||
#define DB_PATH         "/org/gnome/Shell/Extensions/WindowsExt"
 | 
			
		||||
 | 
			
		||||
// Careful!! Code relies on methods aligning with INFO-numbers below!!
 | 
			
		||||
#define INFO_TITLE      1
 | 
			
		||||
#define INFO_EXEC       2
 | 
			
		||||
#define INFO_WINCLASS   3
 | 
			
		||||
static const char* methods[] = { "FocusTitle", "FocusPID", "FocusClass" };
 | 
			
		||||
 | 
			
		||||
#define MAX_CMD_LINE    120
 | 
			
		||||
 | 
			
		||||
static const char* gnomeReminder = "Are you on Gnome and do you have the Window Calls Extended extension installed and active?\n";
 | 
			
		||||
 | 
			
		||||
// Helper function to setup connection
 | 
			
		||||
int _vsetupconnection()
 | 
			
		||||
{
 | 
			
		||||
    DBusError err;
 | 
			
		||||
    // initialise the errors
 | 
			
		||||
    dbus_error_init(&err);
 | 
			
		||||
    // connect to session bus
 | 
			
		||||
    conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
 | 
			
		||||
    if (dbus_error_is_set(&err)) {
 | 
			
		||||
        if (DEBUG > 0) {
 | 
			
		||||
            fprintf(stderr, "Connection Error. (%s: %s)", err.name, err.message);
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(stderr, gnomeReminder);
 | 
			
		||||
        dbus_error_free(&err);
 | 
			
		||||
    }
 | 
			
		||||
    if (NULL == conn) {
 | 
			
		||||
        return(-1);
 | 
			
		||||
    }
 | 
			
		||||
    else   {
 | 
			
		||||
        if (DEBUG > 0) {
 | 
			
		||||
            fprintf(stderr, "Connected to session bus\n");
 | 
			
		||||
        }
 | 
			
		||||
        return(1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Send method call, Returns NULL on failure, else pointer to reply
 | 
			
		||||
// DBusMessage* _sendMethodCall(const char* objectpath,
 | 
			
		||||
//         const char* busname,
 | 
			
		||||
//         const char* interfacename,
 | 
			
		||||
//         const char* methodname);
 | 
			
		||||
DBusMessage* _sendMethodCall(const char* objectpath, const char* busname, const char* interfacename, const char* methodname)
 | 
			
		||||
{
 | 
			
		||||
    assert(objectpath != NULL); assert(busname != NULL);    assert(interfacename != NULL);
 | 
			
		||||
    assert(methodname != NULL); assert(conn != NULL);
 | 
			
		||||
 | 
			
		||||
    DBusMessage* methodcall = dbus_message_new_method_call(busname,objectpath, interfacename, methodname);
 | 
			
		||||
 | 
			
		||||
    if (methodcall == NULL)    {
 | 
			
		||||
        if (DEBUG > 0) {
 | 
			
		||||
            fprintf(stderr, "Cannot allocate DBus message!\n");
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(stderr, gnomeReminder);
 | 
			
		||||
        return(NULL);
 | 
			
		||||
    }
 | 
			
		||||
    //Now do a sync call
 | 
			
		||||
    DBusPendingCall* pending;
 | 
			
		||||
    DBusMessage* reply;
 | 
			
		||||
 | 
			
		||||
    //Send and expect reply using pending call object
 | 
			
		||||
    if (!dbus_connection_send_with_reply(conn, methodcall, &pending, -1))
 | 
			
		||||
    {
 | 
			
		||||
        if (DEBUG == 1) {
 | 
			
		||||
            fprintf(stderr, "failed to send message!\n");
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(stderr, gnomeReminder);
 | 
			
		||||
        return(NULL);
 | 
			
		||||
    }
 | 
			
		||||
    dbus_connection_flush(conn);
 | 
			
		||||
    dbus_message_unref(methodcall);
 | 
			
		||||
    methodcall = NULL;
 | 
			
		||||
 | 
			
		||||
    //Now block on the pending call
 | 
			
		||||
    dbus_pending_call_block(pending);
 | 
			
		||||
    //Get the reply message from the queue
 | 
			
		||||
    reply = dbus_pending_call_steal_reply(pending);
 | 
			
		||||
    //Free pending call handle
 | 
			
		||||
    dbus_pending_call_unref(pending);
 | 
			
		||||
    assert(reply != NULL);
 | 
			
		||||
 | 
			
		||||
    if(dbus_message_get_type(reply) ==  DBUS_MESSAGE_TYPE_ERROR)    {
 | 
			
		||||
        if (DEBUG >0 ) {
 | 
			
		||||
            fprintf(stderr, "Error! %s.\n", dbus_message_get_error_name(reply));
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(stderr, gnomeReminder);
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
        reply = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return reply;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _getInformation(int infoType, char *buffer, int32_t buffer_size) {
 | 
			
		||||
    // If anything goes wrong, return an empty string
 | 
			
		||||
    // Using strncpy just in case buffer size would be 0
 | 
			
		||||
    strncpy(buffer, "", buffer_size);
 | 
			
		||||
    // First, ensure we get a connection. Then, which should never happen,
 | 
			
		||||
    // but just in case ensure we have a method for the infoType
 | 
			
		||||
    if ( (_vsetupconnection() == 1) && (infoType <= (int)sizeof(methods)) ) {
 | 
			
		||||
        if (DEBUG >0 ) {
 | 
			
		||||
            fprintf(stderr, "Using method %s\n", methods[infoType - 1] );
 | 
			
		||||
        }
 | 
			
		||||
        DBusMessage* reply = _sendMethodCall(DB_PATH, DB_DESTINATION, DB_INTERFACE, methods[infoType - 1]);
 | 
			
		||||
        if(reply != NULL)    {
 | 
			
		||||
            DBusMessageIter MsgIter;
 | 
			
		||||
            dbus_message_iter_init(reply, &MsgIter);//msg is pointer to dbus message received
 | 
			
		||||
 | 
			
		||||
            if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&MsgIter)){
 | 
			
		||||
                char* dbusMsg = NULL;
 | 
			
		||||
                dbus_message_iter_get_basic(&MsgIter, &dbusMsg);
 | 
			
		||||
 | 
			
		||||
                if (DEBUG > 1) {
 | 
			
		||||
                    fprintf(stderr, "Received string: %s.\n", dbusMsg);
 | 
			
		||||
                }
 | 
			
		||||
                switch (infoType) {
 | 
			
		||||
                    case INFO_TITLE:
 | 
			
		||||
                        strncpy(buffer, dbusMsg, buffer_size);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case INFO_EXEC:
 | 
			
		||||
                        {
 | 
			
		||||
                            size_t pathLen  = snprintf(NULL, 0, "/proc/%s/cmdline", dbusMsg);
 | 
			
		||||
                            char* pathBuffer = (char*) malloc(pathLen);
 | 
			
		||||
                            sprintf(pathBuffer,"/proc/%s/exe", dbusMsg);
 | 
			
		||||
                            readlink(pathBuffer, buffer, buffer_size);
 | 
			
		||||
                            free(pathBuffer);
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    case INFO_WINCLASS:
 | 
			
		||||
                        strncpy(buffer, dbusMsg, buffer_size);
 | 
			
		||||
                        break;
 | 
			
		||||
                    default:
 | 
			
		||||
                        fprintf(stderr, gnomeReminder);
 | 
			
		||||
                }
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            dbus_message_unref(reply); //unref reply
 | 
			
		||||
        } else {
 | 
			
		||||
            if (DEBUG == 1) {
 | 
			
		||||
                fprintf(stderr, "Error! Send Message Call failed!");
 | 
			
		||||
            }
 | 
			
		||||
            fprintf(stderr, gnomeReminder);
 | 
			
		||||
        }
 | 
			
		||||
        // Closing gives error: Applications must not close shared connections - see dbus_connection_close() docs.
 | 
			
		||||
        // dbus_connection_close(conn);
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        if (DEBUG > 0) {
 | 
			
		||||
            fprintf(stderr, "Error! Could not get connection to session bus!");
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(stderr, gnomeReminder);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int32_t info_get_title(char *buffer, int32_t buffer_size)
 | 
			
		||||
{
 | 
			
		||||
    _getInformation(INFO_TITLE, buffer, buffer_size);
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t info_get_exec(char *buffer, int32_t buffer_size)
 | 
			
		||||
{
 | 
			
		||||
    _getInformation(INFO_EXEC, buffer, buffer_size);
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t info_get_class(char *buffer, int32_t buffer_size)
 | 
			
		||||
{
 | 
			
		||||
    _getInformation(INFO_WINCLASS, buffer, buffer_size);
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if DEBUG > 1
 | 
			
		||||
int main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    (void)argc;
 | 
			
		||||
    (void)argv;
 | 
			
		||||
 | 
			
		||||
    char outString[MAX_CMD_LINE];
 | 
			
		||||
 | 
			
		||||
    info_get_title(outString, MAX_CMD_LINE);
 | 
			
		||||
    std::cout << outString << "\n";
 | 
			
		||||
    info_get_exec(outString, MAX_CMD_LINE);
 | 
			
		||||
    std::cout << outString << "\n";
 | 
			
		||||
    info_get_class(outString, MAX_CMD_LINE);
 | 
			
		||||
    std::cout << outString << "\n";
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										29
									
								
								espanso-info/src/wayland/native.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								espanso-info/src/wayland/native.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
/*
 | 
			
		||||
 * This file is part of espanso.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2019-2021 Federico Terzi
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * espanso is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with espanso.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef ESPANSO_INFO_H
 | 
			
		||||
#define ESPANSO_INFO_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
extern "C" int32_t info_get_title(char * buffer, int32_t buffer_size);
 | 
			
		||||
extern "C" int32_t info_get_exec(char * buffer, int32_t buffer_size);
 | 
			
		||||
extern "C" int32_t info_get_class(char * buffer, int32_t buffer_size);
 | 
			
		||||
 | 
			
		||||
#endif //ESPANSO_INFO_H
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user