Created
September 22, 2018 07:15
-
-
Save ahwayakchih/f9b42cac1a8afed28c8e732ab61e3fdf to your computer and use it in GitHub Desktop.
Proof-of-concept of quick pause/resume active application on Haiku
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2018, Marcin Konicki | |
* All rights reserved. Distributed under the terms of the MIT license. | |
*/ | |
// This was written after reading: | |
// https://vermaden.wordpress.com/2018/09/19/freebsd-desktop-part-16-configuration-pause-any-application/ | |
// and then: | |
// https://dev.haiku-os.org/ticket/14507 | |
// Build with: | |
// g++ -Wall -o pause_app pause_active_app.cpp -lbe | |
// After it's ready, add keyboard shortcut through: | |
// /boot/system/preferences/Shortcuts | |
// TODO: | |
// - notification after pausing/resuming | |
// - option to change priority instead or in addition to pasuing/resuming | |
// - working option to minimize all app windows | |
// for: be_roster->GetActiveAppInfo | |
#include <Roster.h> | |
// for: get_thread_info | |
#include <OS.h> | |
// kill | |
#include <signal.h> | |
// for: printf | |
#include <stdio.h> | |
// for: errno | |
#include <errno.h> | |
// for: strerror | |
#include <string.h> | |
// Check if current thread is part of the specified team | |
bool IsTryingSuspendItself(team_id team) | |
{ | |
thread_info thread; | |
if (get_thread_info(find_thread(NULL), &thread) != B_OK) | |
// Just in case something went wrong but we are in the same team | |
return true; | |
return thread.team == team; | |
} | |
// Get second argument from command line and try to parse it as integer | |
team_id GetTeamIdFromArgv(int argc, char** argv) | |
{ | |
if (argc < 2 || argv[1][0] == '\0') | |
return 0; | |
errno = 0; | |
team_id team = B_BAD_VALUE; | |
char *end = argv[1]; | |
team = strtol(argv[1], &end, 0); | |
if (errno != 0) { | |
return errno; | |
} | |
if (end == argv[1]) | |
return B_BAD_VALUE; | |
if (team < 1) | |
return B_BAD_VALUE; | |
return team; | |
} | |
// Load app_info for specified team or currently active application | |
status_t GetAppInfo(app_info* app, team_id team = 0) | |
{ | |
if (team > 0) | |
return be_roster->GetRunningAppInfo(team, app); | |
return be_roster->GetActiveAppInfo(app); | |
} | |
port_id GetAppServerPort() | |
{ | |
status_t status; | |
app_info info; | |
status = be_roster->GetAppInfo("application/x-vnd.Haiku-app_server", &info); | |
if (status != B_OK) | |
return status; | |
port_info port; | |
status = get_port_info(info.port, &port); | |
if (status != B_OK) | |
return status; | |
// printf("App server port name: %s\n", port.name); | |
// printf("App server port_id: %d\n", port.port); | |
return info.port; | |
} | |
// Minimize all windows of application | |
// TODO: this currently does not work, and is horribly hacky anyway | |
// (it uses private protocols and data from app server). | |
status_t MinimizeTeam(team_id team) | |
{ | |
port_id port = GetAppServerPort(); | |
if (port < 0) | |
return port; | |
// headers/private/app/ServerProtocol.h | |
const uint32 AS_MINIMIZE_TEAM = 5; | |
// src/kits/app/link_message.h | |
const int32 kLinkCode = '_PTL'; | |
uint32 message[4]; | |
message[0] = sizeof(message); | |
message[1] = AS_MINIMIZE_TEAM; | |
message[2] = 0; | |
message[3] = team; | |
return write_port(port, kLinkCode, &message, sizeof(message)); | |
} | |
// Suspend running team or resume suspended team | |
int main(int argc, char** argv) | |
{ | |
// Make our thread more important, just in case something is taking a lot of CPU time | |
set_thread_priority(find_thread(NULL), B_URGENT_DISPLAY_PRIORITY); | |
bool isTTY = isatty(fileno(stdin)); | |
status_t status; | |
team_id team = GetTeamIdFromArgv(argc, argv); | |
if (team < 0) { | |
fprintf(stderr, "ERROR: Incorrect team_id: %s\n", strerror(team)); | |
return team; | |
} | |
app_info app; | |
if ((status = GetAppInfo(&app, team)) != B_OK) { | |
fprintf(stderr, "ERROR: Could not get information about active application\n"); | |
return status; | |
} | |
if (IsTryingSuspendItself(app.team) || (isTTY && team < 1)) { | |
if (isTTY && team < 1) { | |
printf("\ | |
USAGE: pause [team_id]\n\ | |
\n\ | |
If started from Terminal, pause needs to get team_id of application to suspend.\n\ | |
You can find it by running `ps` command.\n\ | |
Otherwise it will automatically suspend currently active application (if team_id is not provided).\n\ | |
"); | |
return B_OK; | |
} | |
fprintf(stderr, "ERROR: Suspending prevented for safety\n"); | |
return B_PERMISSION_DENIED; | |
} | |
// app.team = app.thread = 32; | |
if (isTTY) printf("team_id: %d and thread_id: %d is... ", app.team, app.thread); | |
thread_info thread; | |
if ((status = get_thread_info(app.team, &thread)) != B_OK) { | |
if (isTTY) printf("not giving up the info\n"); | |
fprintf(stderr, "ERROR: Could not get info about active application (team_id: %d)\n", app.team); | |
return status; | |
} | |
int result = 0; | |
int sig; | |
if (thread.state == B_THREAD_SUSPENDED) { | |
sig = SIGCONT; | |
if (isTTY) printf("suspended.\nTrying to resume it now... "); | |
} else { | |
sig = SIGSTOP; | |
// if ((status = MinimizeTeam(app.team)) != B_OK) | |
// fprintf(stderr, "WARNING: could not minimize windows: %s", strerror(status)); | |
if (isTTY) printf("ok.\nTrying to suspend it now... "); | |
} | |
result = kill((pid_t)app.team, sig); | |
int err = errno; | |
if (result != 0) { | |
if (isTTY) printf("fail\n"); | |
fprintf(stderr, "ERROR: sending signal failed: %s\n", strerror(err)); | |
return err; | |
} | |
if (isTTY) printf("done\n"); | |
return B_OK; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment