73
75
char *name_collation_key;
74
76
char *casefolded_description;
75
77
char *casefolded_exec;
78
char **casefolded_keywords;
78
G_DEFINE_TYPE (ShellApp, shell_app, G_TYPE_OBJECT);
90
95
static guint shell_app_signals[LAST_SIGNAL] = { 0 };
92
97
static void create_running_state (ShellApp *app);
98
static void setup_running_state (ShellApp *app, MetaWindow *window);
93
99
static void unref_running_state (ShellAppRunningState *state);
101
G_DEFINE_TYPE (ShellApp, shell_app, G_TYPE_OBJECT)
96
104
shell_app_get_property (GObject *gobject,
106
114
g_value_set_enum (value, app->state);
117
g_value_set_string (value, shell_app_get_id (app));
119
case PROP_ACTION_GROUP:
120
if (app->running_state)
121
g_value_set_object (value, app->running_state->muxer);
124
if (app->running_state)
125
g_value_set_object (value, app->running_state->remote_menu);
109
128
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
509
528
window = most_recent_transient;
512
if (!shell_window_tracker_is_window_interesting (window))
514
/* We won't get notify::user-time signals for uninteresting windows,
515
* which means that an app's last_user_time won't get updated.
516
* Update it here instead.
518
app->running_state->last_user_time = timestamp;
521
531
if (active != workspace)
522
532
meta_workspace_activate_with_focus (workspace, window, timestamp);
540
shell_app_update_window_actions (ShellApp *app, MetaWindow *window)
542
const char *object_path;
544
object_path = meta_window_get_gtk_window_object_path (window);
545
if (object_path != NULL)
547
GActionGroup *actions;
549
actions = g_object_get_data (G_OBJECT (window), "actions");
552
actions = G_ACTION_GROUP (g_dbus_action_group_get (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
553
meta_window_get_gtk_unique_bus_name (window),
555
g_object_set_data_full (G_OBJECT (window), "actions", actions, g_object_unref);
558
if (!app->running_state->muxer)
559
app->running_state->muxer = g_action_muxer_new ();
561
g_action_muxer_insert (app->running_state->muxer, "win", actions);
562
g_object_notify (G_OBJECT (app), "action-group");
529
567
* shell_app_activate:
530
568
* @app: a #ShellApp
794
shell_app_get_last_user_time (ShellApp *app)
801
if (app->running_state != NULL)
803
for (iter = app->running_state->windows; iter; iter = iter->next)
804
last_user_time = MAX (last_user_time, meta_window_get_user_time (iter->data));
807
return last_user_time;
756
811
* shell_app_compare:
872
928
g_assert (app->running_state != NULL);
874
app->running_state->last_user_time = meta_window_get_user_time (window);
876
930
/* Ideally we don't want to emit windows-changed if the sort order
877
931
* isn't actually changing. This check catches most of those.
918
970
g_signal_connect (window, "unmanaged", G_CALLBACK(shell_app_on_unmanaged), app);
919
971
g_signal_connect (window, "notify::user-time", G_CALLBACK(shell_app_on_user_time_changed), app);
921
user_time = meta_window_get_user_time (window);
922
if (user_time > app->running_state->last_user_time)
923
app->running_state->last_user_time = user_time;
973
setup_running_state (app, window);
925
975
if (app->state != SHELL_APP_STATE_STARTING)
926
976
shell_app_state_transition (app, SHELL_APP_STATE_RUNNING);
1106
1158
if (workspace < 0)
1107
1159
workspace = meta_screen_get_active_workspace_index (screen);
1109
context = gdk_app_launch_context_new ();
1161
context = gdk_display_get_app_launch_context (gdisplay);
1110
1162
gdk_app_launch_context_set_timestamp (context, timestamp);
1111
1163
gdk_app_launch_context_set_desktop (context, workspace);
1160
1212
app->running_state->refcount = 1;
1161
1213
app->running_state->workspace_switch_id =
1162
1214
g_signal_connect (screen, "workspace-switched", G_CALLBACK(shell_app_on_ws_switch), app);
1216
app->running_state->muxer = g_action_muxer_new ();
1220
setup_running_state (ShellApp *app,
1223
/* We assume that 'gtk-unique-bus-name', gtk-application-object-path'
1224
* and 'gtk-app-menu-object-path' are the same for all windows which
1227
* It could be possible, however, that the first window we see
1228
* belonging to the app didn't have them set. For this reason, we
1229
* take the values from the first window that has them set and ignore
1230
* all the rest (until the app is stopped and restarted).
1233
if (app->running_state->remote_menu == NULL)
1235
const gchar *application_object_path;
1236
const gchar *app_menu_object_path;
1237
const gchar *unique_bus_name;
1238
GDBusConnection *session;
1239
GDBusActionGroup *actions;
1241
application_object_path = meta_window_get_gtk_application_object_path (window);
1242
app_menu_object_path = meta_window_get_gtk_app_menu_object_path (window);
1243
unique_bus_name = meta_window_get_gtk_unique_bus_name (window);
1245
if (application_object_path == NULL || app_menu_object_path == NULL || unique_bus_name == NULL)
1248
session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
1249
g_assert (session != NULL);
1250
app->running_state->remote_menu = g_dbus_menu_model_get (session, unique_bus_name, app_menu_object_path);
1251
actions = g_dbus_action_group_get (session, unique_bus_name, application_object_path);
1252
g_action_muxer_insert (app->running_state->muxer, "app", G_ACTION_GROUP (actions));
1253
g_object_unref (actions);
1254
g_object_unref (session);
1168
1261
MetaScreen *screen;
1263
g_assert (state->refcount > 0);
1170
1265
state->refcount--;
1171
1266
if (state->refcount > 0)
1174
1269
screen = shell_global_get_screen (shell_global_get ());
1176
1270
g_signal_handler_disconnect (screen, state->workspace_switch_id);
1272
g_clear_object (&state->remote_menu);
1273
g_clear_object (&state->muxer);
1177
1275
g_slice_free (ShellAppRunningState, state);
1216
1315
normalized_exec = shell_util_normalize_and_casefold (exec);
1217
1316
app->casefolded_exec = trim_exec_line (normalized_exec);
1218
1317
g_free (normalized_exec);
1319
keywords = g_desktop_app_info_get_keywords (appinfo);
1325
app->casefolded_keywords = g_new0 (char*, g_strv_length ((char **)keywords) + 1);
1330
app->casefolded_keywords[i] = shell_util_normalize_and_casefold (keywords[i]);
1333
app->casefolded_keywords[i] = NULL;
1336
app->casefolded_keywords = NULL;
1222
1340
* shell_app_compare_by_name:
1342
* @other: The other app
1226
1344
* Order two applications by name.
1228
* Returns: -1, 0, or 1; suitable for use as a comparison function for e.g. g_slist_sort()
1346
* Returns: -1, 0, or 1; suitable for use as a comparison function
1347
* for e.g. g_slist_sort()
1231
1350
shell_app_compare_by_name (ShellApp *app, ShellApp *other)
1283
1402
current_match = MATCH_SUBSTRING;
1405
if (app->casefolded_keywords)
1408
while (app->casefolded_keywords[i] && current_match < MATCH_PREFIX)
1410
p = strstr (app->casefolded_keywords[i], term);
1413
if (p == app->casefolded_keywords[i])
1414
current_match = MATCH_PREFIX;
1416
current_match = MATCH_SUBSTRING;
1286
1422
if (current_match == MATCH_NONE)
1287
1423
return current_match;
1348
1484
while (app->running_state->windows)
1349
1485
_shell_app_remove_window (app, app->running_state->windows->data);
1487
/* We should have been transitioned when we removed all of our windows */
1488
g_assert (app->state == SHELL_APP_STATE_STOPPED);
1489
g_assert (app->running_state == NULL);
1352
1491
G_OBJECT_CLASS(shell_app_parent_class)->dispose (object);
1363
1502
g_free (app->name_collation_key);
1364
1503
g_free (app->casefolded_description);
1365
1504
g_free (app->casefolded_exec);
1505
g_strfreev (app->casefolded_keywords);
1367
1507
G_OBJECT_CLASS(shell_app_parent_class)->finalize (object);
1398
1537
SHELL_TYPE_APP_STATE,
1399
1538
SHELL_APP_STATE_STOPPED,
1400
1539
G_PARAM_READABLE));
1544
* The id of this application (a desktop filename, or a special string
1545
* like window:0xabcd1234)
1547
g_object_class_install_property (gobject_class,
1549
g_param_spec_string ("id",
1551
"The desktop file id of this ShellApp",
1553
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1556
* ShellApp:action-group:
1558
* The #GDBusActionGroup associated with this ShellApp, if any. See the
1559
* documentation of #GApplication and #GActionGroup for details.
1561
g_object_class_install_property (gobject_class,
1563
g_param_spec_object ("action-group",
1564
"Application Action Group",
1565
"The action group exported by the remote application",
1566
G_TYPE_ACTION_GROUP,
1567
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1571
* The #GMenuProxy associated with this ShellApp, if any. See the
1572
* documentation of #GMenuModel for details.
1574
g_object_class_install_property (gobject_class,
1576
g_param_spec_object ("menu",
1578
"The primary menu exported by the remote application",
1580
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));