Going through some GTK troubles

This commit is contained in:
Paul 2018-02-20 00:24:44 +01:00
parent f396acadd0
commit 8860f59a7e
8 changed files with 329 additions and 81 deletions

2
.vscode/launch.json vendored
View File

@ -8,7 +8,7 @@
"name": "(gdb) Launch launcher",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/a.out",
"program": "${workspaceFolder}/bin/samrewritten",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",

View File

@ -0,0 +1,56 @@
#include "MainPickerWindow.h"
MainPickerWindow::MainPickerWindow()
:
m_main_window(nullptr),
m_game_list(nullptr),
m_loading_game_list_box(nullptr)
{
GError *error = NULL;
GtkBuilder *builder = gtk_builder_new();
const char ui_file[] = "glade/main_window.glade";
gtk_builder_add_from_file (builder, ui_file, &error);
if(error != NULL) {
std::cerr << "An error occurred opening the main window.. Make sure " << ui_file << " exists and is a valid file." << std::endl;
exit(EXIT_FAILURE);
}
gtk_builder_connect_signals(builder, NULL);
m_game_list = GTK_BOX(gtk_builder_get_object(builder, "game_list"));
m_main_window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
m_loading_game_list_box = GTK_BOX(gtk_builder_get_object(builder, "loading_game_box"));
g_object_unref(builder);
}
// See https://stackoverflow.com/questions/9192223/remove-gtk-container-children-repopulate-it-then-refresh
void MainPickerWindow::reset_game_list() {
GList *children, *iter;
children = gtk_container_get_children(GTK_CONTAINER(m_game_list));
for(iter = children; iter != NULL; iter = g_list_next(iter))
gtk_container_remove(GTK_CONTAINER(m_game_list), GTK_WIDGET(iter->data));
g_list_free(children);
//List is cleared, let's readd the spinner
if(gtk_box_get_center_widget(m_game_list) == NULL) {
gtk_box_set_center_widget(GTK_BOX(m_game_list), GTK_WIDGET(m_loading_game_list_box));
}
else {
std::cerr << "There already is a center widget. Cannot add a new one" << std::endl;
}
}
void MainPickerWindow::add_to_game_list(const char app_name[]) {
GtkWidget *entry = gtk_button_new_with_label(app_name);
gtk_box_pack_start(GTK_BOX(m_game_list), entry, FALSE, TRUE, 0);
//TODO continue here, get the list to display onr item
//TODO remove the central widget if there is one
g_object_ref(m_loading_game_list_box);
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <gtk/gtk.h>
#include <iostream>
class MainPickerWindow {
public:
MainPickerWindow();
void reset_game_list();
void add_to_game_list(const char app_name[]);
GtkWidget* get_main_window() { return m_main_window; };
private:
GtkWidget *m_main_window;
GtkBox *m_game_list;
GtkBox *m_loading_game_list_box;
};

View File

@ -7,13 +7,12 @@
#include "MySteam.h"
MySteam::MySteam() : m_child_pid(-1) {
get_all_owned_games();
//Not necessary, going to call it only when neededs
//refresh_owned_apps();
}
MySteam::~MySteam() {
#ifdef DEBUG
puts("MySteam deleted");
#endif
}
MySteam* MySteam::get_instance() {
@ -69,29 +68,35 @@ bool MySteam::quit_game() {
return true;
}
void MySteam::get_all_owned_games() {
ISteamApps* steamapps = SteamApps();
ISteamAppList* list = SteamAppList();
//ISteamUserStats* stats = SteamUserStats();
AppId_t appid;
char name[256];
Game_t app;
int name_length;
/**
* This does NOT retrieves all owned games.
* It does retrieve all owned games WITH STATS or ACHIEVEMENTS
* Stores the owned games in m_all_subscribed_apps
* We assume the user didn't put any garbage in his steam folder as well.
*/
void MySteam::refresh_owned_apps() {
const std::string path_to_cache_dir(MySteam::get_steam_install_path() + "/appcache/stats/");
DIR* dirp = opendir(path_to_cache_dir.c_str());
struct dirent * dp;
std::string filename;
const std::string prefix("UserGameStats_" + MySteam::get_user_steamId3() + "_");
const std::string input_scheme_c(prefix + "%lu.bin");
Game_t game;
unsigned long app_id;
m_all_subscribed_apps.clear();
for(unsigned long i = 10; i < 10000; i++) {
appid = i;
if(steamapps->BIsSubscribedApp(appid)) {
name_length = list->GetAppName(i, name, 256);
if(name_length > 0) {
app.app_name = std::string(name);
app.app_id = i;
app.number_achievements = 1; // TODO put a real value here
m_all_subscribed_apps.push_back(app);
while ((dp = readdir(dirp)) != NULL) {
filename = dp->d_name;
if(filename.rfind(prefix, 0) == 0) {
if(sscanf(dp->d_name, input_scheme_c.c_str(), &app_id) == 1) {
game.app_id = app_id;
game.app_name = "To retrieve";
m_all_subscribed_apps.push_back(game);
}
}
}
closedir(dirp);
}
/**
@ -101,7 +106,7 @@ void MySteam::get_all_owned_games() {
* Returns empty string on error
*/
std::string MySteam::get_user_steamId3() {
static const std::string file_path(std::string(getenv("HOME")) + "/.local/share/Steam/logs/parental_log.txt");
static const std::string file_path(MySteam::get_steam_install_path() + "/logs/parental_log.txt");
std::ifstream input(file_path, std::ios::in);
std::string word;
@ -130,13 +135,27 @@ std::string MySteam::get_user_steamId3() {
input.close();
std::cerr << "User ID is " << latest_id << std::endl;
return latest_id;
}
std::string MySteam::get_steam_install_path() {
static const std::string home_path(getenv("HOME"));
if(file_exists(home_path + "/.local/share/Steam/appcache/appinfo.vdf")) {
return std::string(home_path + "/.local/share/Steam");
}
else if(file_exists(home_path + "/.steam/appcache/appinfo.vdf")) {
return std::string(home_path + "/.steam");
}
else {
std::cerr << "Unable to locate the steam directory. TODO: implement a folder picker here" << std::endl;
exit(EXIT_FAILURE);
}
}
void MySteam::print_all_owned_games() const {
std::cerr << "Summary of owned apps with stats or achievements" << std::endl << "========================" << std::endl;
for(Game_t i : m_all_subscribed_apps) {
std::cerr << "App owned: " << i.app_name << std::endl;
std::cerr << i.app_id << " -> " << i.app_name << std::endl;
}
}

View File

@ -7,6 +7,7 @@
#include <chrono>
#include <thread>
#include <csignal>
#include <dirent.h>
#include "../common/c_processes.h"
#include "Game.h"
#include "../steam/steam_api.h"
@ -19,8 +20,10 @@ public:
// Below are the most useful methods
bool launch_game(std::string appId);
bool quit_game();
std::string get_user_steamId3();
static std::string get_user_steamId3();
static std::string get_steam_install_path();
void print_all_owned_games() const;
void refresh_owned_apps();
MySteam(MySteam const&) = delete;
void operator=(MySteam const&) = delete;
@ -28,8 +31,6 @@ public:
private:
MySteam();
~MySteam();
void get_all_owned_games();
pid_t m_child_pid;
std::vector<Game_t> m_all_subscribed_apps;

View File

@ -1,4 +1,7 @@
#define DEBUG
/**
* Please read the license before modifying or distributing any of the code from
* this project. Thank you.
*/
#include <iostream>
#include <stdlib.h>
@ -6,10 +9,18 @@
#include <gtk/gtk.h>
#include <gmodule.h>
#include "MySteam.h"
#include "MainPickerWindow.h"
int launcher_main();
int main(int argc, char *argv[])
//Globals
//Reason for the globals is that it's easier to access
//in GTK callbacks
MySteam *g_steam = nullptr; // The Model
MainPickerWindow *g_main_gui = nullptr; // The view
int
main(int argc, char *argv[])
{
if(!g_module_supported()) {
std::cerr << "Sorry, but gmodules are not supported on your platform :(. Try installing as many gnome libs as you can maybe.." << std::endl;
@ -17,50 +28,21 @@ int main(int argc, char *argv[])
}
gtk_init(&argc, &argv);
setenv("SteamAppId", "480", 1);
if(!SteamAPI_Init()){
std::cerr << std::endl << "Make sure you have launched steam and that you are logged in." << std::endl;
GError *error = NULL;
GtkBuilder *builder = gtk_builder_new();
const char ui_file[] = "glade/error_initialize.glade";
gtk_builder_add_from_file (builder, ui_file, &error);
if(error != NULL) {
std::cerr << "You won't believe it, but an error occurred opening the error message's window.. Make sure " << ui_file << " exists and is a valid file." << std::endl;
exit(EXIT_FAILURE);
}
// Will connect "on_close_button_clicked"
gtk_builder_connect_signals(builder, NULL);
GtkWidget *close_button;
GtkWidget *popup_window;
popup_window = GTK_WIDGET(gtk_builder_get_object(builder, "dialog_window"));
close_button = GTK_WIDGET(gtk_builder_get_object(builder, "button_close"));
g_object_unref(builder);
gtk_widget_show(popup_window);
gtk_main();
exit(EXIT_FAILURE);
}
launcher_main();
return 0;
}
int launcher_main() {
int
launcher_main() {
MySteam *steam = MySteam::get_instance();
steam->print_all_owned_games();
g_main_gui = new MainPickerWindow();
gtk_widget_show(g_main_gui->get_main_window());
gtk_main();
//steam->launch_game("368230");
//std::this_thread::sleep_for(std::chrono::seconds(5));
//steam->quit_game();
@ -69,10 +51,34 @@ int launcher_main() {
}
//Gtk Callbacks
//Controller
extern "C"
{
// When you click on the close button if steam is not running
void on_close_button_clicked () {
void
on_close_button_clicked() {
gtk_main_quit();
std::cerr << "Gtk did main quit" << std::endl;
delete g_main_gui;
g_main_gui = nullptr;
}
void
on_ask_game_refresh() {
std::cerr << "Game refresh started." << std::endl;
g_main_gui->reset_game_list();
//Only call that here so that the constructor is executed when the
//window is already showing.
g_steam = MySteam::get_instance();
g_steam->refresh_owned_apps();
g_main_gui->add_to_game_list("My Game name");
}
void
on_main_window_show() {
on_ask_game_refresh();
}
}

159
glade/main_window.glade Normal file
View File

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkPopoverMenu" id="popovermenu">
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="text" translatable="yes">About</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="text" translatable="yes">Refresh Games</property>
<signal name="clicked" handler="on_ask_game_refresh" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="submenu">main</property>
<property name="position">1</property>
</packing>
</child>
</object>
<object class="GtkApplicationWindow" id="main_window">
<property name="width_request">800</property>
<property name="height_request">500</property>
<property name="can_focus">False</property>
<property name="icon_name">face-wink</property>
<signal name="action-removed" handler="on_close_button_clicked" swapped="no"/>
<signal name="delete-event" handler="on_close_button_clicked" swapped="no"/>
<signal name="show" handler="on_main_window_show" swapped="no"/>
<child>
<object class="GtkStack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">slide-left-right</property>
<child>
<object class="GtkBox" id="game_list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
<child type="center">
<object class="GtkBox" id="loading_game_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Loading your game library...</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="name">page0</property>
<property name="title" translatable="yes">page0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="achievements_list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="homogeneous">True</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">page1</property>
<property name="title" translatable="yes">page1</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title">SamRewritten</property>
<property name="subtitle">Steam Achievements Manager</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="popover">popovermenu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">open-menu-symbolic</property>
<property name="icon_size">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@ -1,17 +1,7 @@
this._IconDownloader.DownloadDataAsync(
new Uri(string.Format("http://media.steamcommunity.com/steamcommunity/public/images/apps/{0}/{1}",
this._GameId,
info.IsAchieved == true ? info.IconNormal : info.IconLocked)),
info);
https://github.com/jshackles/idle_master/blob/master/steam-idle%20Source/steam-idle/Program.cs
Most recent logged in user (useless) from cache:
/home/paul/.local/share/Steam/config/loginusers.vdf
All owned games from cache (WRONG):
/home/paul/.local/share/Steam/userdata/<steamid3>/config/localconfig.vdf
SEE if I cannot get all owned games with stats from /appcache.