1 /*
2 * Copyright (c) 2010 Mike Massonnet, <mmassonnet@xfce.org>
3 * Copyright (c) 2018 Rozhuk Ivan <rozhuk.im@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 */
10
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <stdlib.h>
16 #include <glib-object.h>
17 #include <gtk/gtk.h>
18 #define WNCK_I_KNOW_THIS_IS_UNSTABLE
19 #include <libwnck/libwnck.h>
20
21 #include "app-manager.h"
22 #include "task-manager.h"
23
24
25
26 typedef struct _XtmAppManagerClass XtmAppManagerClass;
27 struct _XtmAppManagerClass
28 {
29 GObjectClass parent_class;
30 };
31 struct _XtmAppManager
32 {
33 GObject parent;
34 /*<private>*/
35 GArray * apps;
36 };
37 G_DEFINE_TYPE (XtmAppManager, xtm_app_manager, G_TYPE_OBJECT)
38
39 static void xtm_app_manager_finalize (GObject *object);
40
41 static GPid app_get_pid (WnckApplication *application);
42 static gint app_pid_compare_fn (gconstpointer a, gconstpointer b);
43
44 static void apps_add_application (GArray *apps, WnckApplication *application, GPid pid);
45 static void apps_remove_application (GArray *apps, WnckApplication *application);
46 static App * apps_lookup_pid (GArray *apps, GPid pid);
47 static App * apps_lookup_app (GArray *apps, WnckApplication *application);
48 static void application_opened (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager);
49 static void application_closed (WnckScreen *screen, WnckApplication *application, XtmAppManager *manager);
50
51
52
53 static void
xtm_app_manager_class_init(XtmAppManagerClass * klass)54 xtm_app_manager_class_init (XtmAppManagerClass *klass)
55 {
56 GObjectClass *class = G_OBJECT_CLASS (klass);
57 xtm_app_manager_parent_class = g_type_class_peek_parent (klass);
58 class->finalize = xtm_app_manager_finalize;
59 }
60
61 static void
xtm_app_manager_init(XtmAppManager * manager)62 xtm_app_manager_init (XtmAppManager *manager)
63 {
64 WnckApplication *application;
65 WnckScreen *screen = wnck_screen_get_default ();
66 GList *windows, *l;
67
68 /* Retrieve initial applications */
69 while (gtk_events_pending ())
70 gtk_main_iteration ();
71
72 manager->apps = g_array_new (FALSE, FALSE, sizeof (App));
73 windows = wnck_screen_get_windows (screen);
74 for (l = windows; l != NULL; l = l->next)
75 {
76 WnckWindow *window = WNCK_WINDOW (l->data);
77 if (wnck_window_get_window_type (window) != WNCK_WINDOW_NORMAL)
78 continue;
79
80 application = wnck_window_get_application (window);
81 apps_add_application (manager->apps, application, app_get_pid (application));
82 }
83
84 G_DEBUG_FMT ("Initial applications: %d", manager->apps->len);
85
86 /* Connect signals */
87 g_signal_connect (screen, "application-opened", G_CALLBACK (application_opened), manager);
88 g_signal_connect (screen, "application-closed", G_CALLBACK (application_closed), manager);
89 }
90
91 static void
xtm_app_manager_finalize(GObject * object)92 xtm_app_manager_finalize (GObject *object)
93 {
94 g_array_free (XTM_APP_MANAGER (object)->apps, TRUE);
95 }
96
97 static GPid
app_get_pid(WnckApplication * application)98 app_get_pid(WnckApplication *application)
99 {
100 GPid pid;
101 GList *windows;
102
103 if (NULL == application)
104 return (0);
105 pid = wnck_application_get_pid (application);
106 if (pid != 0)
107 return (pid);
108 windows = wnck_application_get_windows (application);
109 if (NULL != windows && NULL != windows->data)
110 return (wnck_window_get_pid (WNCK_WINDOW (windows->data)));
111 return (0);
112 }
113
114 static gint
app_pid_compare_fn(gconstpointer a,gconstpointer b)115 app_pid_compare_fn(gconstpointer a, gconstpointer b)
116 {
117 return (((const App*)a)->pid - ((const App*)b)->pid);
118 }
119
120 static void
apps_add_application(GArray * apps,WnckApplication * application,GPid pid)121 apps_add_application (GArray *apps, WnckApplication *application, GPid pid)
122 {
123 App app;
124
125 if (apps_lookup_pid (apps, pid))
126 return;
127
128 app.application = application;
129 app.pid = pid;
130 g_snprintf (app.name, sizeof(app.name), "%s", wnck_application_get_name (application));
131 app.icon = wnck_application_get_mini_icon (application);
132 g_object_ref (app.icon);
133
134 g_array_append_val (apps, app);
135 g_array_sort (apps, app_pid_compare_fn);
136 }
137
138 static void
apps_remove_application(GArray * apps,WnckApplication * application)139 apps_remove_application (GArray *apps, WnckApplication *application)
140 {
141 App *app = apps_lookup_pid(apps, app_get_pid (application));
142
143 if (app == NULL)
144 app = apps_lookup_app(apps, application);
145 if (app == NULL)
146 return;
147 g_object_unref (app->icon);
148 g_array_remove_index (apps, (guint)(((size_t)app - (size_t)apps->data) / sizeof(App)));
149 }
150
151 static App *
apps_lookup_pid(GArray * apps,GPid pid)152 apps_lookup_pid (GArray *apps, GPid pid)
153 {
154 App tapp;
155
156 tapp.pid = pid;
157
158 return (bsearch(&tapp, apps->data, apps->len, sizeof(App), app_pid_compare_fn));
159 }
160
161 static App *
apps_lookup_app(GArray * apps,WnckApplication * application)162 apps_lookup_app (GArray *apps, WnckApplication *application)
163 {
164 App *tapp;
165 guint i;
166
167 for (i = 0; i < apps->len; i++) {
168 tapp = &g_array_index (apps, App, i);
169 if (tapp->application == application)
170 return (tapp);
171 }
172
173 return (NULL);
174 }
175
176 static void
application_opened(WnckScreen * screen __unused,WnckApplication * application,XtmAppManager * manager)177 application_opened (WnckScreen *screen __unused, WnckApplication *application, XtmAppManager *manager)
178 {
179 GPid pid = app_get_pid (application);
180 G_DEBUG_FMT ("Application opened %p %d", (void*)application, pid);
181 apps_add_application (manager->apps, application, pid);
182 }
183
184 static void
application_closed(WnckScreen * screen __unused,WnckApplication * application,XtmAppManager * manager)185 application_closed (WnckScreen *screen __unused, WnckApplication *application, XtmAppManager *manager)
186 {
187 G_DEBUG_FMT ("Application closed %p", (void*)application);
188 apps_remove_application (manager->apps, application);
189 }
190
191
192
193 XtmAppManager *
xtm_app_manager_new(void)194 xtm_app_manager_new (void)
195 {
196 return g_object_new (XTM_TYPE_APP_MANAGER, NULL);
197 }
198
199 App *
xtm_app_manager_get_app_from_pid(XtmAppManager * manager,GPid pid)200 xtm_app_manager_get_app_from_pid (XtmAppManager *manager, GPid pid)
201 {
202 return apps_lookup_pid (manager->apps, pid);
203 }
204